[cpp] 4.3 porting WIP

This commit is contained in:
Mario Zechner 2025-06-23 23:18:49 +02:00
parent d22ada68e5
commit fe46a6cfa8
32 changed files with 693 additions and 837 deletions

View File

@ -48,6 +48,7 @@ namespace spine {
class AnimationState; class AnimationState;
/// Stores a list of timelines to animate a skeleton's pose over time.
class SP_API Animation : public SpineObject { class SP_API Animation : public SpineObject {
friend class AnimationState; friend class AnimationState;
@ -97,35 +98,58 @@ namespace spine {
friend class TwoColorTimeline; friend class TwoColorTimeline;
friend class Slider;
public: public:
Animation(const String &name, Vector<Timeline *> &timelines, float duration); Animation(const String &name, Vector<Timeline *> &timelines, float duration);
~Animation(); ~Animation();
/// Applies all the animation's timelines to the specified skeleton. /// If the returned array or the timelines it contains are modified, setTimelines() must be called.
/// See also Timeline::apply(Skeleton&, float, float, Vector, float, MixPose, MixDirection)
void apply(Skeleton &skeleton, float lastTime, float time, bool loop, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose);
const String &getName();
Vector<Timeline *> &getTimelines(); Vector<Timeline *> &getTimelines();
void setTimelines(Vector<Timeline *> &timelines); void setTimelines(Vector<Timeline *> &timelines);
/// Returns true if this animation contains a timeline with any of the specified property IDs.
bool hasTimeline(Vector<PropertyId> &ids); bool hasTimeline(Vector<PropertyId> &ids);
/// The duration of the animation in seconds, which is usually the highest time of all frames in the timeline. The duration is
/// used to know when it has completed and when it should loop back to the start.
float getDuration(); float getDuration();
void setDuration(float inValue); void setDuration(float inValue);
/// Applies the animation's timelines to the specified skeleton.
///
/// See Timeline::apply().
/// @param skeleton The skeleton the animation is being applied to. This provides access to the bones, slots, and other skeleton
/// components the timelines may change.
/// @param lastTime The last time in seconds this animation was applied. Some timelines trigger only at specific times rather
/// than every frame. Pass -1 the first time an animation is applied to ensure frame 0 is triggered.
/// @param time The time in seconds the skeleton is being posed for. Most timelines find the frame before and the frame after
/// this time and interpolate between the frame values. If beyond the getDuration() and loop is
/// true then the animation will repeat, else the last frame will be applied.
/// @param loop If true, the animation repeats after the getDuration().
/// @param events If any events are fired, they are added to this list. Can be null to ignore fired events or if no timelines
/// fire events.
/// @param alpha 0 applies the current or setup values (depending on blend). 1 applies the timeline values. Between
/// 0 and 1 applies values between the current or setup values and the timeline values. By adjusting
/// alpha over time, an animation can be mixed in or out. alpha can also be useful to apply
/// animations on top of each other (layering).
/// @param blend Controls how mixing is applied when alpha < 1.
/// @param direction Indicates whether the timelines are mixing in or out. Used by timelines which perform instant transitions,
/// such as DrawOrderTimeline or AttachmentTimeline.
void apply(Skeleton &skeleton, float lastTime, float time, bool loop, Vector<Event *> *pEvents, float alpha,
MixBlend blend, MixDirection direction, bool appliedPose);
/// The animation's name, which is unique across all animations in the skeleton.
const String &getName();
/// @param target After the first and before the last entry. /// @param target After the first and before the last entry.
static int search(Vector<float> &values, float target); static int search(Vector<float> &values, float target);
static int search(Vector<float> &values, float target, int step); static int search(Vector<float> &values, float target, int step);
protected:
Vector<int> &getBones();
private:
Vector<Timeline *> _timelines; Vector<Timeline *> _timelines;
HashMap<PropertyId, bool> _timelineIds; HashMap<PropertyId, bool> _timelineIds;
Vector<int> _bones; Vector<int> _bones;

View File

@ -52,6 +52,7 @@ namespace spine {
friend class PathConstraint; friend class PathConstraint;
friend class PhysicsConstraint; friend class PhysicsConstraint;
friend class Skeleton; friend class Skeleton;
friend class Slider;
friend class RegionAttachment; friend class RegionAttachment;
friend class PointAttachment; friend class PointAttachment;
friend class AttachmentTimeline; friend class AttachmentTimeline;
@ -83,7 +84,11 @@ namespace spine {
/// The immediate children of this bone. /// The immediate children of this bone.
Vector<Bone*>& getChildren(); Vector<Bone*>& getChildren();
static bool isYDown() { return yDown; }
static void setYDown(bool value) { yDown = value; }
private: private:
static bool yDown;
Bone* const _parent; Bone* const _parent;
Vector<Bone*> _children; Vector<Bone*> _children;
bool _sorted; bool _sorted;

View File

@ -51,6 +51,21 @@ namespace spine {
friend class TranslateTimeline; friend class TranslateTimeline;
friend class TranslateXTimeline; friend class TranslateXTimeline;
friend class TranslateYTimeline; friend class TranslateYTimeline;
friend class Skeleton;
friend class FromProperty;
friend class ToProperty;
friend class FromRotate;
friend class ToRotate;
friend class FromX;
friend class ToX;
friend class FromY;
friend class ToY;
friend class FromScaleX;
friend class ToScaleX;
friend class FromScaleY;
friend class ToScaleY;
friend class FromShearY;
friend class ToShearY;
protected: protected:
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY; float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;

View File

@ -57,6 +57,8 @@ namespace spine {
virtual void pose() = 0; virtual void pose() = 0;
virtual void setupPose() = 0;
// Inherited from Update // Inherited from Update
virtual void update(Skeleton &skeleton, Physics physics) override = 0; virtual void update(Skeleton &skeleton, Physics physics) override = 0;
@ -82,6 +84,10 @@ namespace spine {
virtual void pose() override { virtual void pose() override {
PosedGeneric<D, P, P>::pose(); PosedGeneric<D, P, P>::pose();
} }
virtual void setupPose() override {
PosedGeneric<D, P, P>::setupPose();
}
}; };
}// namespace spine }// namespace spine

View File

@ -32,24 +32,41 @@
#include <spine/SpineString.h> #include <spine/SpineString.h>
#include <spine/SpineObject.h> #include <spine/SpineObject.h>
#include <spine/PosedData.h>
#include <spine/RTTI.h> #include <spine/RTTI.h>
namespace spine { namespace spine {
class Skeleton; class Skeleton;
class Constraint; class Constraint;
/// Base class for all constraint data types.
class SP_API ConstraintData : public SpineObject { class SP_API ConstraintData : public SpineObject {
public:
RTTI_DECL_NOPARENT RTTI_DECL_NOPARENT
ConstraintData(const String &name); friend class Skeleton;
virtual ~ConstraintData(); friend class Constraint;
const String &getName() const;
public:
ConstraintData(const String &name) : SpineObject(name) {}
virtual ~ConstraintData() {}
virtual Constraint* create(Skeleton& skeleton) = 0; virtual Constraint* create(Skeleton& skeleton) = 0;
private: virtual const String &getName() const = 0;
String _name;
virtual const bool &isSkinRequired() const = 0;
};
/// Base class for all constraint data types.
template<class T, class P>
class SP_API ConstraintDataGeneric: public PosedDataGeneric<P>, public ConstraintData {
public:
ConstraintDataGeneric(const String &name) : PosedDataGeneric<P>(name), ConstraintData(name) {}
virtual ~ConstraintDataGeneric() {}
virtual Constraint* create(Skeleton& skeleton) = 0;
// Resolve ambiguity by forwarding to PosedData's implementation
virtual const String &getName() const override { return PosedDataGeneric<P>::getName(); }
virtual const bool &isSkinRequired() const override { return PosedDataGeneric<P>::isSkinRequired(); }
}; };
} }

View File

@ -49,6 +49,24 @@ namespace spine {
RTTI_DECL RTTI_DECL
public: public:
IkConstraint(IkConstraintData &data, Skeleton &skeleton);
virtual IkConstraint* copy(Skeleton& skeleton);
virtual void update(Skeleton& skeleton, Physics physics) override;
virtual void sort(Skeleton& skeleton) override;
virtual bool isSourceActive() override;
IkConstraintData &getData();
Vector<BonePose *> &getBones();
Bone *getTarget();
void setTarget(Bone *inValue);
/// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified
/// in the world coordinate system. /// in the world coordinate system.
static void static void
@ -61,24 +79,6 @@ namespace spine {
apply(Skeleton& skeleton, BonePose& parent, BonePose& child, float targetX, float targetY, int bendDirection, bool stretch, bool uniform, apply(Skeleton& skeleton, BonePose& parent, BonePose& child, float targetX, float targetY, int bendDirection, bool stretch, bool uniform,
float softness, float mix); float softness, float mix);
IkConstraint(IkConstraintData &data, Skeleton &skeleton);
virtual void update(Skeleton& skeleton, Physics physics) override;
virtual void sort(Skeleton& skeleton) override;
virtual bool isSourceActive() override;
virtual IkConstraint* copy(Skeleton& skeleton);
IkConstraintData &getData();
Vector<BonePose *> &getBones();
Bone *getTarget();
void setTarget(Bone *inValue);
private: private:
Vector<BonePose *> _bones; Vector<BonePose *> _bones;
Bone *_target; Bone *_target;

View File

@ -41,7 +41,7 @@ namespace spine {
class BoneData; class BoneData;
class IkConstraint; class IkConstraint;
class SP_API IkConstraintData : public ConstraintData, public PosedDataGeneric<IkConstraintPose> { class SP_API IkConstraintData : public ConstraintDataGeneric<IkConstraint, IkConstraintPose> {
friend class SkeletonBinary; friend class SkeletonBinary;
friend class SkeletonJson; friend class SkeletonJson;

View File

@ -48,7 +48,7 @@ namespace spine {
/// Stores the setup pose for a PathConstraint. /// Stores the setup pose for a PathConstraint.
/// ///
/// See https://esotericsoftware.com/spine-path-constraints Path constraints in the Spine User Guide. /// See https://esotericsoftware.com/spine-path-constraints Path constraints in the Spine User Guide.
class SP_API PathConstraintData : public ConstraintData, public PosedDataGeneric<PathConstraintPose> { class SP_API PathConstraintData : public ConstraintDataGeneric<PathConstraint, PathConstraintPose> {
friend class SkeletonBinary; friend class SkeletonBinary;
friend class SkeletonJson; friend class SkeletonJson;

View File

@ -66,14 +66,14 @@ namespace spine {
bool isSourceActive() override; bool isSourceActive() override;
PhysicsConstraint* copy(Skeleton& skeleton); PhysicsConstraint* copy(Skeleton& skeleton);
void reset(Skeleton& skeleton);
/// Translates the physics constraint so next update() forces are applied as if the bone moved an additional amount in world space. /// Translates the physics constraint so next update() forces are applied as if the bone moved an additional amount in world space.
void translate(float x, float y); void translate(float x, float y);
/// Rotates the physics constraint so next update() forces are applied as if the bone rotated around the specified point in world space. /// Rotates the physics constraint so next update() forces are applied as if the bone rotated around the specified point in world space.
void rotate(float x, float y, float degrees); void rotate(float x, float y, float degrees);
void reset(Skeleton& skeleton);
/// The bone constrained by this physics constraint. /// The bone constrained by this physics constraint.
BonePose& getBone(); BonePose& getBone();
void setBone(BonePose& bone); void setBone(BonePose& bone);

View File

@ -41,7 +41,7 @@ namespace spine {
/// Stores the setup pose for a PhysicsConstraint. /// Stores the setup pose for a PhysicsConstraint.
/// ///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide. /// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API PhysicsConstraintData : public ConstraintData, public PosedDataGeneric<PhysicsConstraintPose> { class SP_API PhysicsConstraintData : public ConstraintDataGeneric<PhysicsConstraint, PhysicsConstraintPose> {
friend class SkeletonBinary; friend class SkeletonBinary;
friend class SkeletonJson; friend class SkeletonJson;
friend class PhysicsConstraint; friend class PhysicsConstraint;

View File

@ -41,11 +41,13 @@ namespace spine {
virtual void setupPose() = 0; virtual void setupPose() = 0;
virtual void resetConstrained() = 0;
virtual void pose() = 0; virtual void pose() = 0;
virtual void constrained() = 0; virtual void constrained() = 0;
virtual void resetConstrained() = 0;
virtual bool isPoseEqualToApplied() const = 0;
}; };
template<class D, class P, class A> template<class D, class P, class A>
@ -78,6 +80,7 @@ namespace spine {
friend class TranslateXTimeline; friend class TranslateXTimeline;
friend class TranslateYTimeline; friend class TranslateYTimeline;
friend class InheritTimeline; friend class InheritTimeline;
friend class Skeleton;
public: public:
PosedGeneric(D &data) : _data(data), _pose(), _constrained(), _applied(&_pose) { PosedGeneric(D &data) : _data(data), _pose(), _constrained(), _applied(&_pose) {
@ -117,6 +120,10 @@ namespace spine {
_applied = &_constrained; _applied = &_constrained;
} }
virtual bool isPoseEqualToApplied() const override {
return _applied == &_pose;
}
protected: protected:
D &_data; D &_data;
A _pose; ///< Stored as A type (concrete pose type) to match Java behavior A _pose; ///< Stored as A type (concrete pose type) to match Java behavior

View File

@ -59,6 +59,7 @@ namespace spine {
friend class TranslateXTimeline; friend class TranslateXTimeline;
friend class TranslateYTimeline; friend class TranslateYTimeline;
friend class InheritTimeline; friend class InheritTimeline;
friend class Skeleton;
public: public:
PosedData(const spine::String& name); PosedData(const spine::String& name);

View File

@ -250,6 +250,8 @@ namespace spine {
void setColor(Color &color); void setColor(Color &color);
void setColor(float r, float g, float b, float a);
float getScaleX(); float getScaleX();
void setScaleX(float inValue); void setScaleX(float inValue);

View File

@ -35,26 +35,26 @@
namespace spine { namespace spine {
class Slot; class Slot;
class Skeleton;
class ClippingAttachment; class ClippingAttachment;
class SP_API SkeletonClipping : public SpineObject { class SP_API SkeletonClipping : public SpineObject {
public: public:
SkeletonClipping(); SkeletonClipping();
size_t clipStart(Slot &slot, ClippingAttachment *clip); size_t clipStart(Skeleton &skeleton, Slot &slot, ClippingAttachment *clip);
void clipEnd(Slot &slot); void clipEnd(Slot &slot);
void clipEnd(); void clipEnd();
void bool
clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength); clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength);
void bool
clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride); clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride);
void bool
clipTriangles(Vector<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs, size_t stride); clipTriangles(Vector<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs, size_t stride);
bool isClipping(); bool isClipping();

View File

@ -45,7 +45,7 @@ namespace spine {
/// Stores the setup pose for a PhysicsConstraint. /// Stores the setup pose for a PhysicsConstraint.
/// ///
/// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide. /// See https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide.
class SP_API SliderData : public ConstraintData, public PosedDataGeneric<SliderPose> { class SP_API SliderData : public ConstraintDataGeneric<Slider, SliderPose> {
friend class SkeletonBinary; friend class SkeletonBinary;
friend class SkeletonJson; friend class SkeletonJson;
friend class Slider; friend class Slider;
@ -76,6 +76,9 @@ namespace spine {
float getScale(); float getScale();
void setScale(float scale); void setScale(float scale);
float getOffset();
void setOffset(float offset);
bool getLocal(); bool getLocal();
void setLocal(bool local); void setLocal(bool local);
@ -85,6 +88,7 @@ namespace spine {
bool _loop; bool _loop;
BoneData* _bone; BoneData* _bone;
FromProperty* _property; FromProperty* _property;
float _offset;
float _scale; float _scale;
bool _local; bool _local;
}; };

View File

@ -34,8 +34,11 @@
#include <spine/RTTI.h> #include <spine/RTTI.h>
namespace spine { namespace spine {
class Slider;
/// Stores a pose for a slider. /// Stores a pose for a slider.
class SP_API SliderPose : public Pose<SliderPose> { class SP_API SliderPose : public Pose<SliderPose> {
friend class Slider;
private: private:
float _time, _mix; float _time, _mix;

View File

@ -97,7 +97,7 @@ namespace spine {
/// The bone this slot belongs to. /// The bone this slot belongs to.
Bone &getBone(); Bone &getBone();
void setupPose(); void setupPose() override;
private: private:
Skeleton &_skeleton; Skeleton &_skeleton;

View File

@ -49,7 +49,7 @@ namespace spine {
public: public:
TransformConstraint(TransformConstraintData& data, Skeleton& skeleton); TransformConstraint(TransformConstraintData& data, Skeleton& skeleton);
TransformConstraint copy(Skeleton& skeleton); virtual TransformConstraint* copy(Skeleton& skeleton);
/// Applies the constraint to the constrained bones. /// Applies the constraint to the constrained bones.
void update(Skeleton& skeleton, Physics physics) override; void update(Skeleton& skeleton, Physics physics) override;

View File

@ -55,7 +55,7 @@ namespace spine {
virtual ~FromProperty(); virtual ~FromProperty();
/// Reads this property from the specified bone. /// Reads this property from the specified bone.
virtual float value(BonePose& source, bool local, float* offsets) = 0; virtual float value(Skeleton& skeleton, BonePose& source, bool local, float* offsets) = 0;
}; };
/// Constrained property for a TransformConstraint. /// Constrained property for a TransformConstraint.
@ -78,79 +78,79 @@ namespace spine {
virtual float mix(TransformConstraintPose& pose) = 0; virtual float mix(TransformConstraintPose& pose) = 0;
/// Applies the value to this property. /// Applies the value to this property.
virtual void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) = 0; virtual void apply(Skeleton& skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) = 0;
}; };
class SP_API FromRotate : public FromProperty { class SP_API FromRotate : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToRotate : public ToProperty { class SP_API ToRotate : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
class SP_API FromX : public FromProperty { class SP_API FromX : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToX : public ToProperty { class SP_API ToX : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
class SP_API FromY : public FromProperty { class SP_API FromY : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToY : public ToProperty { class SP_API ToY : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
class SP_API FromScaleX : public FromProperty { class SP_API FromScaleX : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToScaleX : public ToProperty { class SP_API ToScaleX : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
class SP_API FromScaleY : public FromProperty { class SP_API FromScaleY : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToScaleY : public ToProperty { class SP_API ToScaleY : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
class SP_API FromShearY : public FromProperty { class SP_API FromShearY : public FromProperty {
public: public:
float value(BonePose& source, bool local, float* offsets) override; float value(Skeleton &skeleton, BonePose& source, bool local, float* offsets) override;
}; };
class SP_API ToShearY : public ToProperty { class SP_API ToShearY : public ToProperty {
public: public:
float mix(TransformConstraintPose& pose) override; float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override; void apply(Skeleton &skeleton, TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
}; };
/// Stores the setup pose for a TransformConstraint. /// Stores the setup pose for a TransformConstraint.
/// ///
/// See https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide. /// See https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide.
class SP_API TransformConstraintData : public ConstraintData, public PosedDataGeneric<TransformConstraintPose> { class SP_API TransformConstraintData : public ConstraintDataGeneric<TransformConstraint, TransformConstraintPose> {
public: public:
RTTI_DECL RTTI_DECL
static const int ROTATION = 0, X = 1, Y = 2, SCALEX = 3, SCALEY = 4, SHEARY = 5; static const int ROTATION = 0, X = 1, Y = 2, SCALEX = 3, SCALEY = 4, SHEARY = 5;

View File

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

View File

@ -36,6 +36,8 @@ using namespace spine;
RTTI_IMPL_NOPARENT(Bone) RTTI_IMPL_NOPARENT(Bone)
bool Bone::yDown = true;
Bone::Bone(BoneData &data, Bone *parent) : PosedGeneric<BoneData, BoneLocal, BonePose>(data), Bone::Bone(BoneData &data, Bone *parent) : PosedGeneric<BoneData, BoneLocal, BonePose>(data),
PosedActive(), PosedActive(),
_parent(parent), _parent(parent),

View File

@ -32,13 +32,3 @@
using namespace spine; using namespace spine;
RTTI_IMPL_NOPARENT(ConstraintData) RTTI_IMPL_NOPARENT(ConstraintData)
ConstraintData::ConstraintData(const String &name) : _name(name) {
}
ConstraintData::~ConstraintData() {
}
const String &ConstraintData::getName() const {
return _name;
}

View File

@ -41,22 +41,84 @@ using namespace spine;
RTTI_IMPL(IkConstraint, Constraint) RTTI_IMPL(IkConstraint, Constraint)
IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) : ConstraintGeneric<IkConstraint, IkConstraintData, IkConstraintPose>(data),
_target(skeleton._bones[data._target->getIndex()]) {
_bones.ensureCapacity(data._bones.size());
for (size_t i = 0; i < data._bones.size(); i++) {
BoneData *boneData = data._bones[i];
_bones.add(&skeleton._bones[boneData->getIndex()]->_constrained);
}
}
IkConstraint *IkConstraint::copy(Skeleton &skeleton) {
IkConstraint *copy = new (__FILE__, __LINE__) IkConstraint(_data, skeleton);
copy->_pose.set(_pose);
return copy;
}
void IkConstraint::update(Skeleton &skeleton, Physics physics) {
IkConstraintPose &p = _pose;
if (p._mix == 0) return;
BonePose &target = *_target->_applied;
switch (_bones.size()) {
case 1: {
apply(skeleton, *_bones[0], target._worldX, target._worldY, p._compress, p._stretch, _data._uniform, p._mix);
} break;
case 2: {
apply(skeleton, *_bones[0], *_bones[1], target._worldX, target._worldY, p._bendDirection, p._stretch, _data._uniform,
p._softness, p._mix);
} break;
}
}
void IkConstraint::sort(Skeleton &skeleton) {
skeleton.sortBone(_target);
Bone *parent = _bones[0]->_bone;
skeleton.sortBone(parent);
skeleton._updateCache.add(this);
parent->_sorted = false;
skeleton.sortReset(parent->_children);
skeleton.constrained(*parent);
if (_bones.size() > 1) skeleton.constrained(*_bones[1]->_bone);
}
IkConstraintData &IkConstraint::getData() {
return _data;
}
Vector<BonePose *> &IkConstraint::getBones() {
return _bones;
}
Bone *IkConstraint::getTarget() {
return _target;
}
void IkConstraint::setTarget(Bone *target) {
_target = target;
}
bool IkConstraint::isSourceActive() {
return _target->_active;
}
void IkConstraint::apply(Skeleton &skeleton, BonePose &bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float mix) { void IkConstraint::apply(Skeleton &skeleton, BonePose &bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float mix) {
bone.modifyLocal(skeleton); bone.modifyLocal(skeleton);
BonePose &p = bone._bone->getParent()->getAppliedPose(); BonePose &p = *bone._bone->_parent->_applied;
float pa = p._a, pb = p._b, pc = p._c, pd = p._d; float pa = p._a, pb = p._b, pc = p._c, pd = p._d;
float rotationIK = -bone._shearX - bone._rotation, tx, ty; float rotationIK = -bone._shearX - bone._rotation, tx, ty;
switch (bone._inherit) { switch (bone._inherit) {
case Inherit_OnlyTranslation: case Inherit_OnlyTranslation:
tx = (targetX - bone._worldX) * MathUtil::sign(skeleton.getScaleX()); tx = (targetX - bone._worldX) * MathUtil::sign(skeleton._scaleX);
ty = (targetY - bone._worldY) * MathUtil::sign(skeleton.getScaleY()); ty = (targetY - bone._worldY) * MathUtil::sign(skeleton._scaleY);
break; break;
case Inherit_NoRotationOrReflection: { case Inherit_NoRotationOrReflection: {
float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc); float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc);
float sa = pa / skeleton.getScaleX(); float sa = pa / skeleton._scaleX;
float sc = pc / skeleton.getScaleY(); float sc = pc / skeleton._scaleY;
pb = -sc * s * skeleton.getScaleX(); pb = -sc * s * skeleton._scaleX;
pd = sa * s * skeleton.getScaleY(); pd = sa * s * skeleton._scaleY;
rotationIK += MathUtil::atan2Deg(sc, sa); rotationIK += MathUtil::atan2Deg(sc, sa);
// Fall through. // Fall through.
} }
@ -88,7 +150,7 @@ void IkConstraint::apply(Skeleton &skeleton, BonePose &bone, float targetX, floa
default: default:
break; break;
} }
float b = bone._bone->getData().getLength() * bone._scaleX; float b = bone._bone->_data.getLength() * bone._scaleX;
if (b > 0.0001f) { if (b > 0.0001f) {
float dd = tx * tx + ty * ty; float dd = tx * tx + ty * ty;
if ((compress && dd < b * b) || (stretch && dd > b * b)) { if ((compress && dd < b * b) || (stretch && dd > b * b)) {
@ -134,7 +196,7 @@ void IkConstraint::apply(Skeleton &skeleton, BonePose &parent, BonePose &child,
cwx = a * child._x + b * child._y + parent._worldX; cwx = a * child._x + b * child._y + parent._worldX;
cwy = c * child._x + d * child._y + parent._worldY; cwy = c * child._x + d * child._y + parent._worldY;
} }
BonePose &pp = parent._bone->getParent()->getAppliedPose(); BonePose &pp = *parent._bone->_parent->_applied;
a = pp._a; a = pp._a;
b = pp._b; b = pp._b;
c = pp._c; c = pp._c;
@ -142,7 +204,7 @@ void IkConstraint::apply(Skeleton &skeleton, BonePose &parent, BonePose &child,
float id = a * d - b * c, x = cwx - pp._worldX, y = cwy - pp._worldY; float id = a * d - b * c, x = cwx - pp._worldX, y = cwy - pp._worldY;
id = MathUtil::abs(id) <= 0.0001f ? 0 : 1 / id; id = MathUtil::abs(id) <= 0.0001f ? 0 : 1 / id;
float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
float l1 = MathUtil::sqrt(dx * dx + dy * dy), l2 = child._bone->getData().getLength() * csx, a1, a2; float l1 = MathUtil::sqrt(dx * dx + dy * dy), l2 = child._bone->_data.getLength() * csx, a1, a2;
if (l1 < 0.0001f) { if (l1 < 0.0001f) {
apply(skeleton, parent, targetX, targetY, false, stretch, false, mix); apply(skeleton, parent, targetX, targetY, false, stretch, false, mix);
child._rotation = 0; child._rotation = 0;
@ -163,7 +225,7 @@ void IkConstraint::apply(Skeleton &skeleton, BonePose &parent, BonePose &child,
dd = tx * tx + ty * ty; dd = tx * tx + ty * ty;
} }
} }
outer:
if (u) { if (u) {
l2 *= psx; l2 *= psx;
float cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); float cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@ -249,65 +311,3 @@ outer_break:
child._rotation += a2 * mix; child._rotation += a2 * mix;
} }
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];
_bones.add(&skeleton.findBone(boneData->getName())->getAppliedPose());
}
}
void IkConstraint::update(Skeleton &skeleton, Physics physics) {
IkConstraintPose &p = *_applied;
if (p._mix == 0) return;
BonePose &target = _target->getAppliedPose();
switch (_bones.size()) {
case 1: {
apply(skeleton, *_bones[0], target._worldX, target._worldY, p._compress, p._stretch, _data._uniform, p._mix);
} break;
case 2: {
apply(skeleton, *_bones[0], *_bones[1], target._worldX, target._worldY, p._bendDirection, p._stretch, _data._uniform,
p._softness, p._mix);
} break;
}
}
IkConstraintData &IkConstraint::getData() {
return _data;
}
Vector<BonePose *> &IkConstraint::getBones() {
return _bones;
}
Bone *IkConstraint::getTarget() {
return _target;
}
void IkConstraint::setTarget(Bone *target) {
_target = target;
}
void IkConstraint::sort(Skeleton &skeleton) {
skeleton.sortBone(_target);
Bone *parent = _bones[0]->_bone;
skeleton.sortBone(parent);
skeleton._updateCache.add(this);
parent->_sorted = false;
skeleton.sortReset(parent->_children);
skeleton.constrained(*parent);
if (_bones.size() > 1) skeleton.constrained(*_bones[1]->_bone);
}
bool IkConstraint::isSourceActive() {
return _target->_active;
}
IkConstraint *IkConstraint::copy(Skeleton &skeleton) {
IkConstraint *copy = new IkConstraint(_data, skeleton);
copy->_pose.set(_pose);
return copy;
}

View File

@ -36,8 +36,7 @@ using namespace spine;
RTTI_IMPL(IkConstraintData, ConstraintData) RTTI_IMPL(IkConstraintData, ConstraintData)
IkConstraintData::IkConstraintData(const String &name) : ConstraintData(name), IkConstraintData::IkConstraintData(const String &name) : ConstraintDataGeneric<IkConstraint, IkConstraintPose>(name),
PosedDataGeneric<IkConstraintPose>(name),
_target(NULL), _target(NULL),
_uniform(false) { _uniform(false) {
} }

View File

@ -37,8 +37,7 @@ using namespace spine;
RTTI_IMPL(PathConstraintData, ConstraintData) RTTI_IMPL(PathConstraintData, ConstraintData)
PathConstraintData::PathConstraintData(const String &name) : ConstraintData(name), PathConstraintData::PathConstraintData(const String &name) : ConstraintDataGeneric<PathConstraint, PathConstraintPose>(name),
PosedDataGeneric<PathConstraintPose>(name),
_slot(NULL), _slot(NULL),
_positionMode(PositionMode_Fixed), _positionMode(PositionMode_Fixed),
_spacingMode(SpacingMode_Length), _spacingMode(SpacingMode_Length),

View File

@ -47,35 +47,15 @@ PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skel
_rotateOffset(0), _rotateLag(0), _rotateVelocity(0), _scaleOffset(0), _scaleLag(0), _scaleVelocity(0), _rotateOffset(0), _rotateLag(0), _rotateVelocity(0), _scaleOffset(0), _scaleLag(0), _scaleVelocity(0),
_remaining(0), _lastTime(0) { _remaining(0), _lastTime(0) {
_bone = &skeleton.getBones()[(size_t) data.getBone()->getIndex()]->getAppliedPose(); _bone = &skeleton._bones[(size_t) data._bone->getIndex()]->_constrained;
} }
PhysicsConstraint *PhysicsConstraint::copy(Skeleton &skeleton) { PhysicsConstraint *PhysicsConstraint::copy(Skeleton &skeleton) {
PhysicsConstraint *copy = new (__FILE__, __LINE__) PhysicsConstraint(_data, skeleton); PhysicsConstraint *copy = new (__FILE__, __LINE__) PhysicsConstraint(_data, skeleton);
copy->_applied->set(*_applied); copy->_pose.set(_pose);
return copy; return copy;
} }
void PhysicsConstraint::sort(Skeleton &skeleton) {
Bone *bone = _bone->_bone;
skeleton.sortBone(bone);
skeleton._updateCache.add(this);
skeleton.sortReset(bone->_children);
skeleton.constrained(*bone);
}
bool PhysicsConstraint::isSourceActive() {
return _bone->_bone->isActive();
}
BonePose &PhysicsConstraint::getBone() {
return *_bone;
}
void PhysicsConstraint::setBone(BonePose &bone) {
_bone = &bone;
}
void PhysicsConstraint::reset(Skeleton &skeleton) { void PhysicsConstraint::reset(Skeleton &skeleton) {
_remaining = 0; _remaining = 0;
_lastTime = skeleton.getTime(); _lastTime = skeleton.getTime();
@ -94,14 +74,27 @@ void PhysicsConstraint::reset(Skeleton &skeleton) {
_scaleVelocity = 0; _scaleVelocity = 0;
} }
void PhysicsConstraint::translate(float x, float y) {
_ux -= x;
_uy -= y;
_cx -= x;
_cy -= y;
}
void PhysicsConstraint::rotate(float x, float y, float degrees) {
float r = degrees * MathUtil::Deg_Rad, cosVal = MathUtil::cos(r), sinVal = MathUtil::sin(r);
float dx = _cx - x, dy = _cy - y;
translate(dx * cosVal - dy * sinVal - dx, dx * sinVal + dy * cosVal - dy);
}
void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) { void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
PhysicsConstraintPose &p = *_applied; PhysicsConstraintPose &p = _pose;
float mix = p.getMix(); float mix = p._mix;
if (mix == 0) return; if (mix == 0) return;
bool x = _data.getX() > 0, y = _data.getY() > 0, rotateOrShearX = _data._rotate > 0 || _data._shearX > 0, scaleX = _data.getScaleX() > 0; bool x = _data._x > 0, y = _data._y > 0, rotateOrShearX = _data._rotate > 0 || _data._shearX > 0, scaleX = _data._scaleX > 0;
BonePose *bone = _bone; BonePose *bone = _bone;
float l = bone->_bone->getData().getLength(), t = _data.getStep(), z = 0; float l = bone->_bone->_data.getLength(), t = _data._step, z = 0;
switch (physics) { switch (physics) {
case Physics_None: case Physics_None:
@ -110,9 +103,9 @@ void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
reset(skeleton); reset(skeleton);
// Fall through. // Fall through.
case Physics_Update: { case Physics_Update: {
float delta = MathUtil::max(skeleton.getTime() - _lastTime, 0.0f), aa = _remaining; float delta = MathUtil::max(skeleton._time - _lastTime, 0.0f), aa = _remaining;
_remaining += delta; _remaining += delta;
_lastTime = skeleton.getTime(); _lastTime = skeleton._time;
float bx = bone->_worldX, by = bone->_worldY; float bx = bone->_worldX, by = bone->_worldY;
if (_reset) { if (_reset) {
@ -120,9 +113,9 @@ void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
_ux = bx; _ux = bx;
_uy = by; _uy = by;
} else { } else {
float a = _remaining, i = p.getInertia(), f = skeleton.getData()->getReferenceScale(), d = -1, m = 0, e = 0, qx = _data.getLimit() * delta, float a = _remaining, i = p._inertia, f = skeleton._data.getReferenceScale(), d = -1, m = 0, e = 0, ax = 0, ay = 0,
qy = qx * MathUtil::abs(skeleton.getScaleY()); qx = _data._limit * delta, qy = qx * MathUtil::abs(skeleton.getScaleY());
qx *= MathUtil::abs(skeleton.getScaleX()); qx *= MathUtil::abs(skeleton._scaleX);
if (x || y) { if (x || y) {
if (x) { if (x) {
float u = (_ux - bx) * i; float u = (_ux - bx) * i;
@ -141,8 +134,9 @@ void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
d = MathUtil::pow(p._damping, 60 * t); d = MathUtil::pow(p._damping, 60 * t);
m = t * p._massInverse; m = t * p._massInverse;
e = p._strength; e = p._strength;
float w = f * p._wind * skeleton.getScaleX(), g = f * p._gravity * skeleton.getScaleY(), float w = f * p._wind, g = f * p._gravity;
ax = w * skeleton.getWindX() + g * skeleton.getGravityX(), ay = w * skeleton.getWindY() + g * skeleton.getGravityY(); ax = (w * skeleton._windX + g * skeleton._gravityX) * skeleton._scaleX;
ay = (w * skeleton._windY + g * skeleton._gravityY) * skeleton.getScaleY();
do { do {
if (x) { if (x) {
_xVelocity += (ax - _xOffset * e) * m; _xVelocity += (ax - _xOffset * e) * m;
@ -197,10 +191,11 @@ void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
d = MathUtil::pow(p._damping, 60 * t); d = MathUtil::pow(p._damping, 60 * t);
m = t * p._massInverse; m = t * p._massInverse;
e = p._strength; e = p._strength;
float w = f * p._wind, g = f * p._gravity;
ax = (w * skeleton._windX + g * skeleton._gravityX) * skeleton._scaleX;
ay = (w * skeleton._windY + g * skeleton._gravityY) * skeleton.getScaleY();
} }
float rs = _rotateOffset, ss = _scaleOffset, h = l / f, float rs = _rotateOffset, ss = _scaleOffset, h = l / f;
ax = p._wind * skeleton.getWindX() + p._gravity * skeleton.getGravityX(),
ay = p._wind * skeleton.getWindY() + p._gravity * skeleton.getGravityY();
while (true) { while (true) {
a -= t; a -= t;
if (scaleX) { if (scaleX) {
@ -277,18 +272,25 @@ void PhysicsConstraint::update(Skeleton &skeleton, Physics physics) {
_tx = l * bone->_a; _tx = l * bone->_a;
_ty = l * bone->_c; _ty = l * bone->_c;
} }
// bone->modifyWorld(skeleton.getUpdate()); // TODO: Implement getUpdate method in Skeleton bone->modifyWorld(skeleton._update);
} }
void PhysicsConstraint::translate(float x, float y) { void PhysicsConstraint::sort(Skeleton &skeleton) {
_ux -= x; Bone *bone = _bone->_bone;
_uy -= y; skeleton.sortBone(bone);
_cx -= x; skeleton._updateCache.add(this);
_cy -= y; skeleton.sortReset(bone->_children);
skeleton.constrained(*bone);
} }
void PhysicsConstraint::rotate(float x, float y, float degrees) { bool PhysicsConstraint::isSourceActive() {
float r = degrees * MathUtil::Deg_Rad, cosVal = MathUtil::cos(r), sinVal = MathUtil::sin(r); return _bone->_bone->isActive();
float dx = _cx - x, dy = _cy - y; }
translate(dx * cosVal - dy * sinVal - dx, dx * sinVal + dy * cosVal - dy);
BonePose &PhysicsConstraint::getBone() {
return *_bone;
}
void PhysicsConstraint::setBone(BonePose &bone) {
_bone = &bone;
} }

View File

@ -36,8 +36,7 @@ using namespace spine;
RTTI_IMPL(PhysicsConstraintData, ConstraintData) RTTI_IMPL(PhysicsConstraintData, ConstraintData)
PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintData(name), PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintDataGeneric<PhysicsConstraint, PhysicsConstraintPose>(name),
PosedDataGeneric<PhysicsConstraintPose>(name),
_bone(NULL), _bone(NULL),
_x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0), _limit(0), _step(0), _x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0), _limit(0), _step(0),
_inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false), _inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false),

View File

@ -31,6 +31,7 @@
#include <spine/Attachment.h> #include <spine/Attachment.h>
#include <spine/Bone.h> #include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/IkConstraint.h> #include <spine/IkConstraint.h>
#include <spine/PathConstraint.h> #include <spine/PathConstraint.h>
#include <spine/PhysicsConstraint.h> #include <spine/PhysicsConstraint.h>
@ -57,75 +58,46 @@
using namespace spine; using namespace spine;
Skeleton::Skeleton(SkeletonData *skeletonData) Skeleton::Skeleton(SkeletonData &skeletonData) : _data(skeletonData), _skin(NULL), _color(1, 1, 1, 1), _x(0), _y(0),
: _data(skeletonData), _skin(NULL), _color(1, 1, 1, 1), _scaleX(1), _scaleX(1), _scaleY(1), _windX(1), _windY(0), _gravityX(0), _gravityY(1), _time(0), _update(0) {
_scaleY(1), _x(0), _y(0), _time(0), _windX(1), _windY(0), _gravityX(0), _gravityY(1) {
_bones.ensureCapacity(_data->getBones().size()); _bones.ensureCapacity(_data.getBones().size());
for (size_t i = 0; i < _data->getBones().size(); ++i) { for (size_t i = 0; i < _data.getBones().size(); ++i) {
BoneData *data = _data->getBones()[i]; BoneData *data = _data.getBones()[i];
Bone *bone; Bone *bone;
if (data->getParent() == NULL) { if (data->getParent() == NULL) {
bone = new (__FILE__, __LINE__) Bone(*data, *this, NULL); bone = new (__FILE__, __LINE__) Bone(*data, NULL);
} else { } else {
Bone *parent = _bones[data->getParent()->getIndex()]; Bone *parent = _bones[data->getParent()->getIndex()];
bone = new (__FILE__, __LINE__) Bone(*data, *this, parent); bone = new (__FILE__, __LINE__) Bone(*data, parent);
parent->getChildren().add(bone); parent->getChildren().add(bone);
} }
_bones.add(bone); _bones.add(bone);
} }
_slots.ensureCapacity(_data->getSlots().size()); _slots.ensureCapacity(_data.getSlots().size());
_drawOrder.ensureCapacity(_data->getSlots().size()); _drawOrder.ensureCapacity(_data.getSlots().size());
for (size_t i = 0; i < _data->getSlots().size(); ++i) { for (size_t i = 0; i < _data.getSlots().size(); ++i) {
SlotData *data = _data->getSlots()[i]; SlotData *data = _data.getSlots()[i];
Bone *bone = _bones[data->getBoneData().getIndex()]; Bone *bone = _bones[data->getBoneData().getIndex()];
Slot *slot = new (__FILE__, __LINE__) Slot(*data, *bone); Slot *slot = new (__FILE__, __LINE__) Slot(*data, *this);
_slots.add(slot); _slots.add(slot);
_drawOrder.add(slot); _drawOrder.add(slot);
} }
_ikConstraints.ensureCapacity(_data->getIkConstraints().size()); _physics.ensureCapacity(8);
for (size_t i = 0; i < _data->getIkConstraints().size(); ++i) { _constraints.ensureCapacity(_data.getConstraints().size());
IkConstraintData *data = _data->getIkConstraints()[i]; for (size_t i = 0; i < _data.getConstraints().size(); ++i) {
ConstraintData *constraintData = _data.getConstraints()[i];
IkConstraint *constraint = Constraint *constraint = constraintData->create(*this);
new (__FILE__, __LINE__) IkConstraint(*data, *this); if (constraint->getRTTI().instanceOf(PhysicsConstraint::rtti)) {
_physics.add(static_cast<PhysicsConstraint*>(constraint));
_ikConstraints.add(constraint);
} }
_constraints.add(constraint);
_transformConstraints.ensureCapacity(_data->getTransformConstraints().size());
for (size_t i = 0; i < _data->getTransformConstraints().size(); ++i) {
TransformConstraintData *data = _data->getTransformConstraints()[i];
TransformConstraint *constraint =
new (__FILE__, __LINE__) TransformConstraint(*data, *this);
_transformConstraints.add(constraint);
}
_pathConstraints.ensureCapacity(_data->getPathConstraints().size());
for (size_t i = 0; i < _data->getPathConstraints().size(); ++i) {
PathConstraintData *data = _data->getPathConstraints()[i];
PathConstraint *constraint =
new (__FILE__, __LINE__) PathConstraint(*data, *this);
_pathConstraints.add(constraint);
}
_physicsConstraints.ensureCapacity(_data->getPhysicsConstraints().size());
for (size_t i = 0; i < _data->getPhysicsConstraints().size(); ++i) {
PhysicsConstraintData *data = _data->getPhysicsConstraints()[i];
PhysicsConstraint *constraint =
new (__FILE__, __LINE__) PhysicsConstraint(*data, *this);
_physicsConstraints.add(constraint);
} }
updateCache(); updateCache();
@ -134,19 +106,25 @@ Skeleton::Skeleton(SkeletonData *skeletonData)
Skeleton::~Skeleton() { Skeleton::~Skeleton() {
ContainerUtil::cleanUpVectorOfPointers(_bones); ContainerUtil::cleanUpVectorOfPointers(_bones);
ContainerUtil::cleanUpVectorOfPointers(_slots); ContainerUtil::cleanUpVectorOfPointers(_slots);
ContainerUtil::cleanUpVectorOfPointers(_ikConstraints); ContainerUtil::cleanUpVectorOfPointers(_constraints);
ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
ContainerUtil::cleanUpVectorOfPointers(_physicsConstraints);
} }
void Skeleton::updateCache() { void Skeleton::updateCache() {
_updateCache.clear(); _updateCache.clear();
_resetCache.clear();
for (size_t i = 0, n = _bones.size(); i < n; ++i) { Slot **slots = _slots.buffer();
Bone *bone = _bones[i]; for (size_t i = 0, n = _slots.size(); i < n; i++) {
slots[i]->pose();
}
size_t boneCount = _bones.size();
Bone **bones = _bones.buffer();
for (size_t i = 0; i < boneCount; i++) {
Bone *bone = bones[i];
bone->_sorted = bone->_data.isSkinRequired(); bone->_sorted = bone->_data.isSkinRequired();
bone->_active = !bone->_sorted; bone->_active = !bone->_sorted;
bone->pose();
} }
if (_skin) { if (_skin) {
@ -161,61 +139,35 @@ void Skeleton::updateCache() {
} }
} }
size_t ikCount = _ikConstraints.size(); Constraint **constraints = _constraints.buffer();
size_t transformCount = _transformConstraints.size(); size_t n = _constraints.size();
size_t pathCount = _pathConstraints.size(); for (size_t i = 0; i < n; i++) {
size_t physicsCount = _physicsConstraints.size(); constraints[i]->pose();
size_t constraintCount = ikCount + transformCount + pathCount + physicsCount;
size_t i = 0;
continue_outer:
for (; i < constraintCount; ++i) {
for (size_t ii = 0; ii < ikCount; ++ii) {
IkConstraint *constraint = _ikConstraints[ii];
if (constraint->getData().getOrder() == i) {
sortIkConstraint(constraint);
i++;
goto continue_outer;
} }
for (size_t i = 0; i < n; i++) {
Constraint *constraint = constraints[i];
constraint->_active = constraint->isSourceActive() &&
(!constraint->getData().isSkinRequired()) || (_skin && _skin->_constraints.contains(&constraint->getData()));
if (constraint->_active) constraint->sort(*this);
} }
for (size_t ii = 0; ii < transformCount; ++ii) { for (size_t i = 0; i < boneCount; i++) {
TransformConstraint *constraint = _transformConstraints[ii]; sortBone(bones[i]);
if (constraint->getData().getOrder() == i) {
sortTransformConstraint(constraint);
i++;
goto continue_outer;
}
} }
for (size_t ii = 0; ii < pathCount; ++ii) { Update **updateCache = _updateCache.buffer();
PathConstraint *constraint = _pathConstraints[ii]; n = _updateCache.size();
if (constraint->getData().getOrder() == i) { for (size_t i = 0; i < n; i++) {
sortPathConstraint(constraint); if (updateCache[i]->getRTTI().instanceOf(Bone::rtti)) {
i++; Bone *bone = (Bone*)(updateCache[i]);
goto continue_outer; updateCache[i] = bone->_applied;
} }
} }
for (size_t ii = 0; ii < physicsCount; ++ii) {
PhysicsConstraint *constraint = _physicsConstraints[ii];
if (constraint->getData().getOrder() == i) {
sortPhysicsConstraint(constraint);
i++;
goto continue_outer;
}
}
}
size_t n = _bones.size();
for (i = 0; i < n; ++i) {
sortBone(_bones[i]);
}
} }
void Skeleton::printUpdateCache() { void Skeleton::printUpdateCache() {
for (size_t i = 0; i < _updateCache.size(); i++) { for (size_t i = 0; i < _updateCache.size(); i++) {
Updatable *updatable = _updateCache[i]; Update *updatable = _updateCache[i];
if (updatable->getRTTI().isExactly(Bone::rtti)) { if (updatable->getRTTI().isExactly(Bone::rtti)) {
printf("bone %s\n", ((Bone *) updatable)->getData().getName().buffer()); printf("bone %s\n", ((Bone *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(TransformConstraint::rtti)) { } else if (updatable->getRTTI().isExactly(TransformConstraint::rtti)) {
@ -234,28 +186,58 @@ void Skeleton::printUpdateCache() {
} }
} }
void Skeleton::constrained(Posed &object) {
if (object.isPoseEqualToApplied()) {
object.constrained();
_resetCache.add(&object);
}
}
void Skeleton::sortBone(Bone *bone) {
if (bone->_sorted || !bone->_active) return;
Bone *parent = bone->_parent;
if (parent != NULL) sortBone(parent);
bone->_sorted = true;
_updateCache.add((Update *)bone);
}
void Skeleton::sortReset(Vector<Bone *> &bones) {
Bone **items = bones.buffer();
for (size_t i = 0, n = bones.size(); i < n; i++) {
Bone *bone = items[i];
if (bone->_active) {
if (bone->_sorted) sortReset(bone->getChildren());
bone->_sorted = false;
}
}
}
void Skeleton::updateWorldTransform(Physics physics) { void Skeleton::updateWorldTransform(Physics physics) {
for (size_t i = 0, n = _bones.size(); i < n; i++) { _update++;
Bone *bone = _bones[i];
bone->_ax = bone->_x; Posed **resetCache = _resetCache.buffer();
bone->_ay = bone->_y; for (size_t i = 0, n = _resetCache.size(); i < n; i++) {
bone->_arotation = bone->_rotation; resetCache[i]->resetConstrained();
bone->_ascaleX = bone->_scaleX;
bone->_ascaleY = bone->_scaleY;
bone->_ashearX = bone->_shearX;
bone->_ashearY = bone->_shearY;
} }
for (size_t i = 0, n = _updateCache.size(); i < n; ++i) { Update **updateCache = _updateCache.buffer();
Updatable *updatable = _updateCache[i]; for (size_t i = 0, n = _updateCache.size(); i < n; i++) {
updatable->update(physics); updateCache[i]->update(*this, physics);
} }
} }
void Skeleton::updateWorldTransform(Physics physics, Bone *parent) { void Skeleton::updateWorldTransform(Physics physics, BonePose *parent) {
// Apply the parent bone transform to the root bone. The root bone always if (parent == NULL) return;
// inherits scale, rotation and reflection.
Bone *rootBone = getRootBone(); _update++;
Posed **resetCache = _resetCache.buffer();
for (size_t i = 0, n = _resetCache.size(); i < n; i++) {
resetCache[i]->resetConstrained();
}
// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
BonePose *rootBone = getRootBone()->_applied;
float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d; float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d;
rootBone->_worldX = pa * _x + pb * _y + parent->_worldX; rootBone->_worldX = pa * _x + pb * _y + parent->_worldX;
rootBone->_worldY = pc * _x + pd * _y + parent->_worldY; rootBone->_worldY = pc * _x + pd * _y + parent->_worldY;
@ -272,259 +254,211 @@ void Skeleton::updateWorldTransform(Physics physics, Bone *parent) {
rootBone->_d = (pc * lb + pd * ld) * _scaleY; rootBone->_d = (pc * lb + pd * ld) * _scaleY;
// Update everything except root bone. // Update everything except root bone.
Bone *rb = getRootBone(); Update **updateCache = _updateCache.buffer();
for (size_t i = 0, n = _updateCache.size(); i < n; i++) { for (size_t i = 0, n = _updateCache.size(); i < n; i++) {
Updatable *updatable = _updateCache[i]; Update *updatable = updateCache[i];
if (updatable != rb) if (updatable != rootBone) updatable->update(*this, physics);
updatable->update(physics);
} }
} }
void Skeleton::setToSetupPose() { void Skeleton::setupPose() {
setBonesToSetupPose(); setupPoseBones();
setSlotsToSetupPose(); setupPoseSlots();
} }
void Skeleton::setBonesToSetupPose() { void Skeleton::setupPoseBones() {
Bone **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; ++i) { for (size_t i = 0, n = _bones.size(); i < n; ++i) {
_bones[i]->setToSetupPose(); bones[i]->setupPose();
} }
for (size_t i = 0, n = _ikConstraints.size(); i < n; ++i) { Constraint **constraints = _constraints.buffer();
_ikConstraints[i]->setToSetupPose(); for (size_t i = 0, n = _constraints.size(); i < n; ++i) {
} constraints[i]->setupPose();
for (size_t i = 0, n = _transformConstraints.size(); i < n; ++i) {
_transformConstraints[i]->setToSetupPose();
}
for (size_t i = 0, n = _pathConstraints.size(); i < n; ++i) {
_pathConstraints[i]->setToSetupPose();
}
for (size_t i = 0, n = _physicsConstraints.size(); i < n; ++i) {
_physicsConstraints[i]->setToSetupPose();
} }
} }
void Skeleton::setSlotsToSetupPose() { void Skeleton::setupPoseSlots() {
Slot **slots = _slots.buffer();
size_t n = _slots.size();
_drawOrder.clear(); _drawOrder.clear();
for (size_t i = 0, n = _slots.size(); i < n; ++i) { _drawOrder.setSize(n, 0);
_drawOrder.add(_slots[i]); for (size_t i = 0; i < n; ++i) {
_drawOrder[i] = _slots[i];
} }
for (size_t i = 0, n = _slots.size(); i < n; ++i) { for (size_t i = 0; i < n; ++i) {
_slots[i]->setToSetupPose(); slots[i]->setupPose();
} }
} }
SkeletonData *Skeleton::getData() {
return &_data;
}
Vector<Bone *> &Skeleton::getBones() {
return _bones;
}
Vector<Update *> &Skeleton::getUpdateCache() {
return _updateCache;
}
Bone *Skeleton::getRootBone() {
return _bones.size() == 0 ? NULL : _bones[0];
}
Bone *Skeleton::findBone(const String &boneName) { Bone *Skeleton::findBone(const String &boneName) {
return ContainerUtil::findWithDataName(_bones, boneName); if (boneName.isEmpty()) return NULL;
Bone **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; i++) {
if (bones[i]->_data.getName() == boneName) return bones[i];
}
return NULL;
}
Vector<Slot *> &Skeleton::getSlots() {
return _slots;
} }
Slot *Skeleton::findSlot(const String &slotName) { Slot *Skeleton::findSlot(const String &slotName) {
return ContainerUtil::findWithDataName(_slots, slotName); if (slotName.isEmpty()) return NULL;
Slot **slots = _slots.buffer();
for (size_t i = 0, n = _slots.size(); i < n; i++) {
if (slots[i]->_data.getName() == slotName) return slots[i];
}
return NULL;
}
Vector<Slot *> &Skeleton::getDrawOrder() {
return _drawOrder;
}
Skin *Skeleton::getSkin() {
return _skin;
} }
void Skeleton::setSkin(const String &skinName) { void Skeleton::setSkin(const String &skinName) {
Skin *foundSkin = skinName.isEmpty() ? NULL : _data->findSkin(skinName); Skin *skin = skinName.isEmpty() ? NULL : _data.findSkin(skinName);
setSkin(foundSkin); if (skin == NULL) return;
setSkin(skin);
} }
void Skeleton::setSkin(Skin *newSkin) { void Skeleton::setSkin(Skin *newSkin) {
if (_skin == newSkin) if (_skin == newSkin) return;
return;
if (newSkin != NULL) { if (newSkin != NULL) {
if (_skin != NULL) { if (_skin != NULL) {
Skeleton &thisRef = *this; newSkin->attachAll(*this, *_skin);
newSkin->attachAll(thisRef, *_skin);
} else { } else {
Slot **slots = _slots.buffer();
for (size_t i = 0, n = _slots.size(); i < n; ++i) { for (size_t i = 0, n = _slots.size(); i < n; ++i) {
Slot *slotP = _slots[i]; Slot *slot = slots[i];
Slot &slot = *slotP; const String &name = slot->_data.getAttachmentName();
const String &name = slot._data.getAttachmentName();
if (name.length() > 0) { if (name.length() > 0) {
Attachment *attachment = newSkin->getAttachment(i, name); Attachment *attachment = newSkin->getAttachment(i, name);
if (attachment != NULL) { if (attachment != NULL) {
slot.setAttachment(attachment); slot->_pose.setAttachment(attachment);
} }
} }
} }
} }
} }
_skin = newSkin; _skin = newSkin;
updateCache(); updateCache();
} }
Attachment *Skeleton::getAttachment(const String &slotName, Attachment *Skeleton::getAttachment(const String &slotName, const String &attachmentName) {
const String &attachmentName) { SlotData *slot = _data.findSlot(slotName);
return getAttachment(_data->findSlot(slotName)->getIndex(), attachmentName); if (slot == NULL) return NULL;
return getAttachment(slot->getIndex(), attachmentName);
} }
Attachment *Skeleton::getAttachment(int slotIndex, Attachment *Skeleton::getAttachment(int slotIndex, const String &attachmentName) {
const String &attachmentName) { if (attachmentName.isEmpty()) return NULL;
if (attachmentName.isEmpty())
return NULL;
if (_skin != NULL) { if (_skin != NULL) {
Attachment *attachment = _skin->getAttachment(slotIndex, attachmentName); Attachment *attachment = _skin->getAttachment(slotIndex, attachmentName);
if (attachment != NULL) { if (attachment != NULL) return attachment;
return attachment;
} }
if (_data.getDefaultSkin() != NULL) return _data.getDefaultSkin()->getAttachment(slotIndex, attachmentName);
return NULL;
} }
return _data->getDefaultSkin() != NULL void Skeleton::setAttachment(const String &slotName, const String &attachmentName) {
? _data->getDefaultSkin()->getAttachment(slotIndex, attachmentName) if (slotName.isEmpty()) return;
: NULL; Slot *slot = findSlot(slotName);
} if (slot == NULL) return;
void Skeleton::setAttachment(const String &slotName,
const String &attachmentName) {
assert(slotName.length() > 0);
for (size_t i = 0, n = _slots.size(); i < n; ++i) {
Slot *slot = _slots[i];
if (slot->_data.getName() == slotName) {
Attachment *attachment = NULL; Attachment *attachment = NULL;
if (attachmentName.length() > 0) { if (!attachmentName.isEmpty()) {
attachment = getAttachment((int) i, attachmentName); attachment = getAttachment(slot->_data.getIndex(), attachmentName);
if (attachment == NULL) return;
assert(attachment != NULL); }
slot->_pose.setAttachment(attachment);
} }
slot->setAttachment(attachment); Vector<Constraint *> &Skeleton::getConstraints() {
return _constraints;
return;
}
} }
printf("Slot not found: %s", slotName.buffer()); Vector<PhysicsConstraint *> &Skeleton::getPhysicsConstraints() {
return _physics;
assert(false);
} }
IkConstraint *Skeleton::findIkConstraint(const String &constraintName) { void Skeleton::getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector<float> &outVertexBuffer) {
assert(constraintName.length() > 0);
for (size_t i = 0, n = _ikConstraints.size(); i < n; ++i) {
IkConstraint *ikConstraint = _ikConstraints[i];
if (ikConstraint->_data.getName() == constraintName) {
return ikConstraint;
}
}
return NULL;
}
TransformConstraint *
Skeleton::findTransformConstraint(const String &constraintName) {
assert(constraintName.length() > 0);
for (size_t i = 0, n = _transformConstraints.size(); i < n; ++i) {
TransformConstraint *transformConstraint = _transformConstraints[i];
if (transformConstraint->_data.getName() == constraintName) {
return transformConstraint;
}
}
return NULL;
}
PathConstraint *Skeleton::findPathConstraint(const String &constraintName) {
assert(constraintName.length() > 0);
for (size_t i = 0, n = _pathConstraints.size(); i < n; ++i) {
PathConstraint *constraint = _pathConstraints[i];
if (constraint->_data.getName() == constraintName) {
return constraint;
}
}
return NULL;
}
PhysicsConstraint *
Skeleton::findPhysicsConstraint(const String &constraintName) {
assert(constraintName.length() > 0);
for (size_t i = 0, n = _physicsConstraints.size(); i < n; ++i) {
PhysicsConstraint *constraint = _physicsConstraints[i];
if (constraint->_data.getName() == constraintName) {
return constraint;
}
}
return NULL;
}
void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
float &outHeight, Vector<float> &outVertexBuffer) {
getBounds(outX, outY, outWidth, outHeight, outVertexBuffer, NULL); getBounds(outX, outY, outWidth, outHeight, outVertexBuffer, NULL);
} }
void Skeleton::getBounds(float &outX, float &outY, float &outWidth, void Skeleton::getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector<float> &outVertexBuffer, SkeletonClipping *clipper) {
float &outHeight, Vector<float> &outVertexBuffer, SkeletonClipping *clipper) {
static unsigned short quadIndices[] = {0, 1, 2, 2, 3, 0}; static unsigned short quadIndices[] = {0, 1, 2, 2, 3, 0};
float minX = FLT_MAX; float minX = FLT_MAX;
float minY = FLT_MAX; float minY = FLT_MAX;
float maxX = -FLT_MAX; float maxX = -FLT_MAX;
float maxY = -FLT_MAX; float maxY = -FLT_MAX;
for (size_t i = 0; i < _drawOrder.size(); ++i) { Slot **drawOrder = _drawOrder.buffer();
Slot *slot = _drawOrder[i]; for (size_t i = 0, n = _drawOrder.size(); i < n; ++i) {
if (!slot->_bone._active) Slot *slot = drawOrder[i];
continue; if (!slot->_bone._active) continue;
size_t verticesLength = 0; size_t verticesLength = 0;
Attachment *attachment = slot->getAttachment(); float *vertices = NULL;
unsigned short *triangles = NULL; unsigned short *triangles = NULL;
size_t trianglesLength = 0; size_t trianglesLength = 0;
Attachment *attachment = slot->_pose.getAttachment();
if (attachment != NULL && if (attachment != NULL) {
attachment->getRTTI().instanceOf(RegionAttachment::rtti)) { if (attachment->getRTTI().instanceOf(RegionAttachment::rtti)) {
RegionAttachment *regionAttachment = RegionAttachment *regionAttachment = static_cast<RegionAttachment *>(attachment);
static_cast<RegionAttachment *>(attachment);
verticesLength = 8; verticesLength = 8;
if (outVertexBuffer.size() < 8) {
outVertexBuffer.setSize(8, 0); outVertexBuffer.setSize(8, 0);
} regionAttachment->computeWorldVertices(*slot, outVertexBuffer.buffer(), 0, 2);
regionAttachment->computeWorldVertices(*slot, outVertexBuffer, 0); vertices = outVertexBuffer.buffer();
triangles = quadIndices; triangles = quadIndices;
trianglesLength = 6; trianglesLength = 6;
} else if (attachment != NULL && } else if (attachment->getRTTI().instanceOf(MeshAttachment::rtti)) {
attachment->getRTTI().instanceOf(MeshAttachment::rtti)) {
MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment); MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment);
verticesLength = mesh->getWorldVerticesLength(); verticesLength = mesh->getWorldVerticesLength();
if (outVertexBuffer.size() < verticesLength) {
outVertexBuffer.setSize(verticesLength, 0); outVertexBuffer.setSize(verticesLength, 0);
} mesh->computeWorldVertices(*this, *slot, 0, verticesLength, outVertexBuffer.buffer(), 0, 2);
vertices = outVertexBuffer.buffer();
mesh->computeWorldVertices(*slot, 0, verticesLength,
outVertexBuffer.buffer(), 0);
triangles = mesh->getTriangles().buffer(); triangles = mesh->getTriangles().buffer();
trianglesLength = mesh->getTriangles().size(); trianglesLength = mesh->getTriangles().size();
} else if (attachment != NULL && } else if (attachment->getRTTI().instanceOf(ClippingAttachment::rtti) && clipper != NULL) {
attachment->getRTTI().instanceOf(ClippingAttachment::rtti) && clipper != NULL) { clipper->clipEnd(*slot);
clipper->clipStart(*slot, static_cast<ClippingAttachment *>(attachment)); clipper->clipStart(*this, *slot, static_cast<ClippingAttachment *>(attachment));
continue; continue;
} }
if (verticesLength > 0) { if (vertices != NULL) {
float *vertices = outVertexBuffer.buffer(); if (clipper != NULL && clipper->isClipping() && clipper->clipTriangles(vertices, triangles, trianglesLength)) {
if (clipper != NULL && clipper->isClipping()) {
clipper->clipTriangles(outVertexBuffer.buffer(), triangles, trianglesLength);
vertices = clipper->getClippedVertices().buffer(); vertices = clipper->getClippedVertices().buffer();
verticesLength = clipper->getClippedVertices().size(); verticesLength = clipper->getClippedVertices().size();
} }
for (size_t ii = 0; ii < verticesLength; ii += 2) { for (size_t ii = 0; ii < verticesLength; ii += 2) {
float vx = vertices[ii]; float x = vertices[ii], y = vertices[ii + 1];
float vy = vertices[ii + 1]; minX = MathUtil::min(minX, x);
minY = MathUtil::min(minY, y);
minX = MathUtil::min(minX, vx); maxX = MathUtil::max(maxX, x);
minY = MathUtil::min(minY, vy); maxY = MathUtil::max(maxY, y);
maxX = MathUtil::max(maxX, vx); }
maxY = MathUtil::max(maxY, vy);
} }
} }
if (clipper != NULL) clipper->clipEnd(*slot); if (clipper != NULL) clipper->clipEnd(*slot);
@ -537,254 +471,114 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
outHeight = maxY - minY; outHeight = maxY - minY;
} }
Bone *Skeleton::getRootBone() { return _bones.size() == 0 ? NULL : _bones[0]; } Color &Skeleton::getColor() {
return _color;
SkeletonData *Skeleton::getData() { return _data; }
Vector<Bone *> &Skeleton::getBones() { return _bones; }
Vector<Updatable *> &Skeleton::getUpdateCacheList() { return _updateCache; }
Vector<Slot *> &Skeleton::getSlots() { return _slots; }
Vector<Slot *> &Skeleton::getDrawOrder() { return _drawOrder; }
Vector<IkConstraint *> &Skeleton::getIkConstraints() { return _ikConstraints; }
Vector<PathConstraint *> &Skeleton::getPathConstraints() {
return _pathConstraints;
} }
Vector<TransformConstraint *> &Skeleton::getTransformConstraints() { void Skeleton::setColor(Color &color) {
return _transformConstraints; _color.set(color.r, color.g, color.b, color.a);
} }
Vector<PhysicsConstraint *> &Skeleton::getPhysicsConstraints() { void Skeleton::setColor(float r, float g, float b, float a) {
return _physicsConstraints; _color.set(r, g, b, a);
} }
Skin *Skeleton::getSkin() { return _skin; } float Skeleton::getScaleX() {
return _scaleX;
}
Color &Skeleton::getColor() { return _color; } void Skeleton::setScaleX(float inValue) {
_scaleX = inValue;
}
float Skeleton::getScaleY() {
return _scaleY * (Bone::isYDown() ? -1 : 1);
}
void Skeleton::setScaleY(float inValue) {
_scaleY = inValue;
}
void Skeleton::setScale(float scaleX, float scaleY) {
_scaleX = scaleX;
_scaleY = scaleY;
}
float Skeleton::getX() {
return _x;
}
void Skeleton::setX(float inValue) {
_x = inValue;
}
float Skeleton::getY() {
return _y;
}
void Skeleton::setY(float inValue) {
_y = inValue;
}
void Skeleton::setPosition(float x, float y) { void Skeleton::setPosition(float x, float y) {
_x = x; _x = x;
_y = y; _y = y;
} }
float Skeleton::getX() { return _x; } float Skeleton::getWindX() {
return _windX;
void Skeleton::setX(float inValue) { _x = inValue; }
float Skeleton::getY() { return _y; }
void Skeleton::setY(float inValue) { _y = inValue; }
float Skeleton::getScaleX() { return _scaleX; }
void Skeleton::setScaleX(float inValue) { _scaleX = inValue; }
float Skeleton::getScaleY() { return _scaleY * (Bone::isYDown() ? -1 : 1); }
void Skeleton::setScaleY(float inValue) { _scaleY = inValue; }
void Skeleton::sortIkConstraint(IkConstraint *constraint) {
constraint->_active =
constraint->_target->_active &&
(!constraint->_data.isSkinRequired() ||
(_skin && _skin->_constraints.contains(&constraint->_data)));
if (!constraint->_active)
return;
Bone *target = constraint->getTarget();
sortBone(target);
Vector<Bone *> &constrained = constraint->getBones();
Bone *parent = constrained[0];
sortBone(parent);
if (constrained.size() == 1) {
_updateCache.add(constraint);
sortReset(parent->_children);
} else {
Bone *child = constrained[constrained.size() - 1];
sortBone(child);
_updateCache.add(constraint);
sortReset(parent->_children);
child->_sorted = true;
}
} }
void Skeleton::sortPathConstraint(PathConstraint *constraint) { void Skeleton::setWindX(float windX) {
constraint->_active = _windX = windX;
constraint->_target->_bone._active &&
(!constraint->_data.isSkinRequired() ||
(_skin && _skin->_constraints.contains(&constraint->_data)));
if (!constraint->_active)
return;
Slot *slot = constraint->getTarget();
int slotIndex = slot->getData().getIndex();
Bone &slotBone = slot->getBone();
if (_skin != NULL)
sortPathConstraintAttachment(_skin, slotIndex, slotBone);
if (_data->_defaultSkin != NULL && _data->_defaultSkin != _skin)
sortPathConstraintAttachment(_data->_defaultSkin, slotIndex, slotBone);
for (size_t ii = 0, nn = _data->_skins.size(); ii < nn; ii++)
sortPathConstraintAttachment(_data->_skins[ii], slotIndex, slotBone);
Attachment *attachment = slot->getAttachment();
if (attachment != NULL &&
attachment->getRTTI().instanceOf(PathAttachment::rtti))
sortPathConstraintAttachment(attachment, slotBone);
Vector<Bone *> &constrained = constraint->getBones();
size_t boneCount = constrained.size();
for (size_t i = 0; i < boneCount; ++i) {
sortBone(constrained[i]);
} }
_updateCache.add(constraint); float Skeleton::getWindY() {
return _windY;
for (size_t i = 0; i < boneCount; i++)
sortReset(constrained[i]->getChildren());
for (size_t i = 0; i < boneCount; i++)
constrained[i]->_sorted = true;
} }
void Skeleton::sortTransformConstraint(TransformConstraint *constraint) { void Skeleton::setWindY(float windY) {
constraint->_active = _windY = windY;
constraint->_target->_active &&
(!constraint->_data.isSkinRequired() ||
(_skin && _skin->_constraints.contains(&constraint->_data)));
if (!constraint->_active)
return;
sortBone(constraint->getTarget());
Vector<Bone *> &constrained = constraint->getBones();
size_t boneCount = constrained.size();
if (constraint->_data.isLocal()) {
for (size_t i = 0; i < boneCount; i++) {
Bone *child = constrained[i];
sortBone(child->getParent());
sortBone(child);
}
} else {
for (size_t i = 0; i < boneCount; ++i) {
sortBone(constrained[i]);
}
} }
_updateCache.add(constraint); float Skeleton::getGravityX() {
return _gravityX;
for (size_t i = 0; i < boneCount; ++i)
sortReset(constrained[i]->getChildren());
for (size_t i = 0; i < boneCount; ++i)
constrained[i]->_sorted = true;
} }
void Skeleton::sortPhysicsConstraint(PhysicsConstraint *constraint) { void Skeleton::setGravityX(float gravityX) {
Bone *bone = constraint->getBone(); _gravityX = gravityX;
constraint->_active =
bone->_active &&
(!constraint->_data.isSkinRequired() ||
(_skin && _skin->_constraints.contains(&constraint->_data)));
if (!constraint->_active)
return;
sortBone(bone);
_updateCache.add(constraint);
sortReset(bone->getChildren());
bone->_sorted = true;
} }
void Skeleton::sortPathConstraintAttachment(Skin *skin, size_t slotIndex, float Skeleton::getGravityY() {
Bone &slotBone) { return _gravityY;
Skin::AttachmentMap::Entries attachments = skin->getAttachments();
while (attachments.hasNext()) {
Skin::AttachmentMap::Entry entry = attachments.next();
if (entry._slotIndex == slotIndex) {
Attachment *value = entry._attachment;
sortPathConstraintAttachment(value, slotBone);
}
}
} }
void Skeleton::sortPathConstraintAttachment(Attachment *attachment, void Skeleton::setGravityY(float gravityY) {
Bone &slotBone) { _gravityY = gravityY;
if (attachment == NULL ||
!attachment->getRTTI().instanceOf(PathAttachment::rtti))
return;
Vector<int> &pathBones =
static_cast<PathAttachment *>(attachment)->getBones();
if (pathBones.size() == 0)
sortBone(&slotBone);
else {
for (size_t i = 0, n = pathBones.size(); i < n;) {
size_t nn = pathBones[i++];
nn += i;
while (i < nn) {
sortBone(_bones[pathBones[i++]]);
} }
}
}
}
void Skeleton::sortBone(Bone *bone) {
if (bone->_sorted)
return;
Bone *parent = bone->_parent;
if (parent != NULL)
sortBone(parent);
bone->_sorted = true;
_updateCache.add(bone);
}
void Skeleton::sortReset(Vector<Bone *> &bones) {
for (size_t i = 0, n = bones.size(); i < n; ++i) {
Bone *bone = bones[i];
if (!bone->_active)
continue;
if (bone->_sorted)
sortReset(bone->getChildren());
bone->_sorted = false;
}
}
float Skeleton::getTime() { return _time; }
void Skeleton::setTime(float time) { _time = time; }
void Skeleton::update(float delta) { _time += delta; }
void Skeleton::physicsTranslate(float x, float y) { void Skeleton::physicsTranslate(float x, float y) {
for (int i = 0; i < (int) _physicsConstraints.size(); i++) { PhysicsConstraint **constraints = _physics.buffer();
_physicsConstraints[i]->translate(x, y); for (size_t i = 0, n = _physics.size(); i < n; i++) {
constraints[i]->translate(x, y);
} }
} }
void Skeleton::physicsRotate(float x, float y, float degrees) { void Skeleton::physicsRotate(float x, float y, float degrees) {
for (int i = 0; i < (int) _physicsConstraints.size(); i++) { PhysicsConstraint **constraints = _physics.buffer();
_physicsConstraints[i]->rotate(x, y, degrees); for (size_t i = 0, n = _physics.size(); i < n; i++) {
constraints[i]->rotate(x, y, degrees);
} }
} }
float Skeleton::getWindX() { return _windX; } float Skeleton::getTime() {
return _time;
}
void Skeleton::setWindX(float windX) { _windX = windX; } void Skeleton::setTime(float time) {
_time = time;
}
float Skeleton::getWindY() { return _windY; } void Skeleton::update(float delta) {
_time += delta;
void Skeleton::setWindY(float windY) { _windY = windY; } }
float Skeleton::getGravityX() { return _gravityX; }
void Skeleton::setGravityX(float gravityX) { _gravityX = gravityX; }
float Skeleton::getGravityY() { return _gravityY; }
void Skeleton::setGravityY(float gravityY) { _gravityY = gravityY; }

View File

@ -41,7 +41,7 @@ SkeletonClipping::SkeletonClipping() : _clipAttachment(NULL) {
_clippedUVs.ensureCapacity(128); _clippedUVs.ensureCapacity(128);
} }
size_t SkeletonClipping::clipStart(Slot &slot, ClippingAttachment *clip) { size_t SkeletonClipping::clipStart(Skeleton &skeleton, Slot &slot, ClippingAttachment *clip) {
if (_clipAttachment != NULL) { if (_clipAttachment != NULL) {
return 0; return 0;
} }
@ -49,8 +49,11 @@ size_t SkeletonClipping::clipStart(Slot &slot, ClippingAttachment *clip) {
_clipAttachment = clip; _clipAttachment = clip;
int n = (int) clip->getWorldVerticesLength(); int n = (int) clip->getWorldVerticesLength();
if (n < 6) {
return 0;
}
_clippingPolygon.setSize(n, 0); _clippingPolygon.setSize(n, 0);
clip->computeWorldVertices(slot, 0, n, _clippingPolygon, 0, 2); clip->computeWorldVertices(skeleton, slot, 0, n, _clippingPolygon.buffer(), 0, 2);
makeClockwise(_clippingPolygon); makeClockwise(_clippingPolygon);
_clippingPolygons = &_triangulator.decompose(_clippingPolygon, _triangulator.triangulate(_clippingPolygon)); _clippingPolygons = &_triangulator.decompose(_clippingPolygon, _triangulator.triangulate(_clippingPolygon));
@ -82,7 +85,7 @@ void SkeletonClipping::clipEnd() {
_clippingPolygon.clear(); _clippingPolygon.clear();
} }
void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles, bool SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles,
size_t trianglesLength) { size_t trianglesLength) {
Vector<float> &clipOutput = _clipOutput; Vector<float> &clipOutput = _clipOutput;
Vector<float> &clippedVertices = _clippedVertices; Vector<float> &clippedVertices = _clippedVertices;
@ -94,11 +97,11 @@ void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles,
clippedVertices.clear(); clippedVertices.clear();
_clippedUVs.clear(); _clippedUVs.clear();
clippedTriangles.clear(); clippedTriangles.clear();
bool clipped = false;
int stride = 2; int stride = 2;
size_t i = 0;
continue_outer: for (int i = 0; i < trianglesLength; i += 3) {
for (; i < trianglesLength; i += 3) {
int vertexOffset = triangles[i] * stride; int vertexOffset = triangles[i] * stride;
float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
@ -113,6 +116,7 @@ continue_outer:
if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) { if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) {
size_t clipOutputLength = clipOutput.size(); size_t clipOutputLength = clipOutput.size();
if (clipOutputLength == 0) continue; if (clipOutputLength == 0) continue;
clipped = true;
size_t clipOutputCount = clipOutputLength >> 1; size_t clipOutputCount = clipOutputLength >> 1;
clippedVertices.setSize(s + clipOutputCount * 2, 0); clippedVertices.setSize(s + clipOutputCount * 2, 0);
@ -148,19 +152,19 @@ continue_outer:
clippedTriangles[s + 1] = (unsigned short) (index + 1); clippedTriangles[s + 1] = (unsigned short) (index + 1);
clippedTriangles[s + 2] = (unsigned short) (index + 2); clippedTriangles[s + 2] = (unsigned short) (index + 2);
index += 3; index += 3;
i += 3; break;
goto continue_outer;
} }
} }
} }
return clipped;
} }
void SkeletonClipping::clipTriangles(Vector<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs, bool SkeletonClipping::clipTriangles(Vector<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs,
size_t stride) { size_t stride) {
clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride); return clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride);
} }
void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles, bool SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles,
size_t trianglesLength, float *uvs, size_t stride) { size_t trianglesLength, float *uvs, size_t stride) {
Vector<float> &clipOutput = _clipOutput; Vector<float> &clipOutput = _clipOutput;
Vector<float> &clippedVertices = _clippedVertices; Vector<float> &clippedVertices = _clippedVertices;
@ -172,10 +176,9 @@ void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles,
clippedVertices.clear(); clippedVertices.clear();
_clippedUVs.clear(); _clippedUVs.clear();
clippedTriangles.clear(); clippedTriangles.clear();
bool clipped = false;
size_t i = 0; for (int i = 0; i < trianglesLength; i += 3) {
continue_outer:
for (; i < trianglesLength; i += 3) {
int vertexOffset = triangles[i] * (int) stride; int vertexOffset = triangles[i] * (int) stride;
float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
@ -193,6 +196,7 @@ continue_outer:
if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) { if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) {
size_t clipOutputLength = clipOutput.size(); size_t clipOutputLength = clipOutput.size();
if (clipOutputLength == 0) continue; if (clipOutputLength == 0) continue;
clipped = true;
float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
float d = 1 / (d0 * d2 + d1 * (y1 - y3)); float d = 1 / (d0 * d2 + d1 * (y1 - y3));
@ -246,10 +250,11 @@ continue_outer:
clippedTriangles[s + 2] = (unsigned short) (index + 2); clippedTriangles[s + 2] = (unsigned short) (index + 2);
index += 3; index += 3;
i += 3; i += 3;
goto continue_outer; break;
} }
} }
} }
return clipped;
} }
bool SkeletonClipping::isClipping() { bool SkeletonClipping::isClipping() {

View File

@ -35,13 +35,13 @@ using namespace spine;
RTTI_IMPL(SliderData, ConstraintData) RTTI_IMPL(SliderData, ConstraintData)
SliderData::SliderData(const String &name) : ConstraintData(name), SliderData::SliderData(const String &name) : ConstraintDataGeneric<Slider, SliderPose>(name),
PosedDataGeneric<SliderPose>(name),
_animation(NULL), _animation(NULL),
_additive(false), _additive(false),
_loop(false), _loop(false),
_bone(NULL), _bone(NULL),
_property(NULL), _property(NULL),
_offset(0.0f),
_scale(0.0f), _scale(0.0f),
_local(false) { _local(false) {
} }
@ -98,6 +98,14 @@ void SliderData::setScale(float scale) {
_scale = scale; _scale = scale;
} }
float SliderData::getOffset() {
return _offset;
}
void SliderData::setOffset(float offset) {
_offset = offset;
}
bool SliderData::getLocal() { bool SliderData::getLocal() {
return _local; return _local;
} }

View File

@ -46,33 +46,32 @@ TransformConstraint::TransformConstraint(TransformConstraintData &data, Skeleton
_bones.ensureCapacity(data.getBones().size()); _bones.ensureCapacity(data.getBones().size());
for (size_t i = 0; i < data.getBones().size(); i++) { for (size_t i = 0; i < data.getBones().size(); i++) {
BoneData *boneData = data.getBones()[i]; BoneData *boneData = data.getBones()[i];
_bones.add(&skeleton.findBone(boneData->getName())->getAppliedPose()); _bones.add(&skeleton._bones[boneData->getIndex()]->_constrained);
} }
_source = skeleton.findBone(data.getSource()->getName()); _source = skeleton._bones[data._source->getIndex()];
} }
TransformConstraint TransformConstraint::copy(Skeleton &skeleton) { TransformConstraint *TransformConstraint::copy(Skeleton &skeleton) {
TransformConstraint copy(_data, skeleton); TransformConstraint *copy = new (__FILE__, __LINE__) TransformConstraint(_data, skeleton);
copy._applied->set(*_applied); copy->_pose.set(_pose);
return copy; return copy;
} }
/// Applies the constraint to the constrained bones. /// Applies the constraint to the constrained bones.
void TransformConstraint::update(Skeleton &skeleton, Physics physics) { void TransformConstraint::update(Skeleton &skeleton, Physics physics) {
TransformConstraintPose &p = *_applied; TransformConstraintPose &p = *_applied;
if (p.getMixRotate() == 0 && p.getMixX() == 0 && p.getMixY() == 0 && p.getMixScaleX() == 0 && p.getMixScaleY() == 0 && p.getMixShearY() == 0) return; if (p._mixRotate == 0 && p._mixX == 0 && p._mixY == 0 && p._mixScaleX == 0 && p._mixScaleY == 0 && p._mixShearY == 0) return;
TransformConstraintData &data = _data; TransformConstraintData &data = _data;
bool localSource = data.getLocalSource(), localTarget = data.getLocalTarget(), additive = data.getAdditive(), clamp = data.getClamp(); bool localSource = data._localSource, localTarget = data._localTarget, additive = data._additive, clamp = data._clamp;
float *offsets = data._offsets;// Access friend field directly float *offsets = data._offsets;
BonePose &source = _source->getAppliedPose(); BonePose &source = *_source->_applied;
if (localSource) { if (localSource) {
source.validateLocalTransform(skeleton); source.validateLocalTransform(skeleton);
} }
Vector<FromProperty *> &properties = data.getProperties(); FromProperty **fromItems = data._properties.buffer();
FromProperty **fromItems = properties.buffer(); size_t fn = data._properties.size();
size_t fn = properties.size();
int update = skeleton._update; int update = skeleton._update;
BonePose **bones = _bones.buffer(); BonePose **bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; i++) { for (size_t i = 0, n = _bones.size(); i < n; i++) {
@ -84,7 +83,7 @@ void TransformConstraint::update(Skeleton &skeleton, Physics physics) {
} }
for (size_t f = 0; f < fn; f++) { for (size_t f = 0; f < fn; f++) {
FromProperty *from = fromItems[f]; FromProperty *from = fromItems[f];
float value = from->value(source, localSource, offsets) - from->offset; float value = from->value(skeleton, source, localSource, offsets) - from->offset;
Vector<ToProperty *> &toProps = from->to; Vector<ToProperty *> &toProps = from->to;
ToProperty **toItems = toProps.buffer(); ToProperty **toItems = toProps.buffer();
for (size_t t = 0, tn = toProps.size(); t < tn; t++) { for (size_t t = 0, tn = toProps.size(); t < tn; t++) {
@ -97,7 +96,7 @@ void TransformConstraint::update(Skeleton &skeleton, Physics physics) {
else else
clamped = MathUtil::clamp(clamped, to->max, to->offset); clamped = MathUtil::clamp(clamped, to->max, to->offset);
} }
to->apply(p, *bone, clamped, localTarget, additive); to->apply(skeleton, p, *bone, clamped, localTarget, additive);
} }
} }
} }
@ -105,10 +104,10 @@ void TransformConstraint::update(Skeleton &skeleton, Physics physics) {
} }
void TransformConstraint::sort(Skeleton &skeleton) { void TransformConstraint::sort(Skeleton &skeleton) {
if (!_data.getLocalSource()) skeleton.sortBone(_source); if (!_data._localSource) skeleton.sortBone(_source);
BonePose **bones = _bones.buffer(); BonePose **bones = _bones.buffer();
size_t boneCount = _bones.size(); size_t boneCount = _bones.size();
bool worldTarget = !_data.getLocalTarget(); bool worldTarget = !_data._localTarget;
if (worldTarget) { if (worldTarget) {
for (size_t i = 0; i < boneCount; i++) for (size_t i = 0; i < boneCount; i++)
skeleton.sortBone(bones[i]->_bone); skeleton.sortBone(bones[i]->_bone);
@ -116,7 +115,7 @@ void TransformConstraint::sort(Skeleton &skeleton) {
skeleton._updateCache.add(this); skeleton._updateCache.add(this);
for (size_t i = 0; i < boneCount; i++) { for (size_t i = 0; i < boneCount; i++) {
Bone *bone = bones[i]->_bone; Bone *bone = bones[i]->_bone;
skeleton.sortReset(bone->getChildren()); skeleton.sortReset(bone->_children);
skeleton.constrained(*bone); skeleton.constrained(*bone);
} }
for (size_t i = 0; i < boneCount; i++) for (size_t i = 0; i < boneCount; i++)
@ -124,7 +123,7 @@ void TransformConstraint::sort(Skeleton &skeleton) {
} }
bool TransformConstraint::isSourceActive() { bool TransformConstraint::isSourceActive() {
return _source->isActive(); return _source->_active;
} }
/// The bones that will be modified by this transform constraint. /// The bones that will be modified by this transform constraint.

View File

@ -40,8 +40,7 @@ using namespace spine;
RTTI_IMPL(TransformConstraintData, ConstraintData) RTTI_IMPL(TransformConstraintData, ConstraintData)
TransformConstraintData::TransformConstraintData(const String &name) : ConstraintData(name), TransformConstraintData::TransformConstraintData(const String &name) : ConstraintDataGeneric<TransformConstraint, TransformConstraintPose>(name),
PosedDataGeneric<TransformConstraintPose>(name),
_source(NULL), _source(NULL),
_localSource(false), _localSource(false),
_localTarget(false), _localTarget(false),
@ -148,53 +147,42 @@ Vector<FromProperty *> &TransformConstraintData::getProperties() {
return _properties; return _properties;
} }
// ============================================================================
// Property Classes
// ============================================================================
// No RTTI for FromProperty
FromProperty::FromProperty() : SpineObject(), offset(0) { FromProperty::FromProperty() : SpineObject(), offset(0) {
} }
FromProperty::~FromProperty() { FromProperty::~FromProperty() {
} }
// No RTTI for ToProperty
ToProperty::ToProperty() : offset(0), max(0), scale(1) { ToProperty::ToProperty() : offset(0), max(0), scale(1) {
} }
ToProperty::~ToProperty() { ToProperty::~ToProperty() {
} }
// No RTTI for FromRotate float FromRotate::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._rotation + offsets[TransformConstraintData::ROTATION];
float FromRotate::value(BonePose &source, bool local, float *offsets) { float value = MathUtil::atan2(source._c / skeleton.getScaleY(), source._a / skeleton.getScaleX()) * MathUtil::Rad_Deg
if (local) return source.getRotation() + offsets[TransformConstraintData::ROTATION]; + (source._a * source._d - source._b * source._c > 0 ? offsets[TransformConstraintData::ROTATION] : -offsets[TransformConstraintData::ROTATION]);
float value = MathUtil::atan2(source._c, source._a) * MathUtil::Rad_Deg + (source._a * source._d - source._b * source._c > 0 ? offsets[TransformConstraintData::ROTATION] : -offsets[TransformConstraintData::ROTATION]);
if (value < 0) value += 360; if (value < 0) value += 360;
return value; return value;
} }
// No RTTI for ToRotate
float ToRotate::mix(TransformConstraintPose &pose) { float ToRotate::mix(TransformConstraintPose &pose) {
return pose._mixRotate; return pose._mixRotate;
} }
void ToRotate::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToRotate::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (!additive) value -= bone.getRotation(); if (!additive) value -= bone._rotation;
bone.setRotation(bone.getRotation() + value * pose._mixRotate); bone._rotation += value * pose._mixRotate;
} else { } else {
float a = bone._a, b = bone._b, c = bone._c, d = bone._d; float a = bone._a, b = bone._b, c = bone._c, d = bone._d;
value *= MathUtil::Deg_Rad; value *= MathUtil::Deg_Rad;
if (!additive) value -= MathUtil::atan2(c, a); if (!additive) value -= MathUtil::atan2(c, a);
if (value > MathUtil::Pi) if (value > MathUtil::Pi)
value -= MathUtil::Pi * 2; value -= MathUtil::Pi_2;
else if (value < -MathUtil::Pi) else if (value < -MathUtil::Pi) //
value += MathUtil::Pi * 2; value += MathUtil::Pi_2;
value *= pose._mixRotate; value *= pose._mixRotate;
float cosVal = MathUtil::cos(value), sinVal = MathUtil::sin(value); float cosVal = MathUtil::cos(value), sinVal = MathUtil::sin(value);
bone._a = cosVal * a - sinVal * c; bone._a = cosVal * a - sinVal * c;
@ -204,74 +192,64 @@ void ToRotate::apply(TransformConstraintPose &pose, BonePose &bone, float value,
} }
} }
// No RTTI for FromX float FromX::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
return local ? source._x + offsets[TransformConstraintData::X] : (offsets[TransformConstraintData::X] * source._a + offsets[TransformConstraintData::Y] * source._b + source._worldX) / skeleton.getScaleX();
float FromX::value(BonePose &source, bool local, float *offsets) {
return local ? source.getX() + offsets[TransformConstraintData::X] : offsets[TransformConstraintData::X] * source._a + offsets[TransformConstraintData::Y] * source._b + source.getWorldX();
} }
// No RTTI for ToX
float ToX::mix(TransformConstraintPose &pose) { float ToX::mix(TransformConstraintPose &pose) {
return pose._mixX; return pose._mixX;
} }
void ToX::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToX::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (!additive) value -= bone.getX(); if (!additive) value -= bone._x;
bone.setX(bone.getX() + value * pose._mixX); bone._x += value * pose._mixX;
} else { } else {
if (!additive) value -= bone.getWorldX(); if (!additive) value -= bone._worldX;
bone.setWorldX(bone.getWorldX() + value * pose._mixX); bone._worldX += value * pose._mixX;
} }
} }
// No RTTI for FromY float FromY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
return local ? source._y + offsets[TransformConstraintData::Y] : (offsets[TransformConstraintData::X] * source._c + offsets[TransformConstraintData::Y] * source._d + source._worldY) / skeleton.getScaleY();
float FromY::value(BonePose &source, bool local, float *offsets) {
return local ? source.getY() + offsets[TransformConstraintData::Y] : offsets[TransformConstraintData::X] * source._c + offsets[TransformConstraintData::Y] * source._d + source.getWorldY();
} }
// No RTTI for ToY
float ToY::mix(TransformConstraintPose &pose) { float ToY::mix(TransformConstraintPose &pose) {
return pose._mixY; return pose._mixY;
} }
void ToY::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (!additive) value -= bone.getY(); if (!additive) value -= bone._y;
bone.setY(bone.getY() + value * pose._mixY); bone._y += value * pose._mixY;
} else { } else {
if (!additive) value -= bone.getWorldY(); if (!additive) value -= bone._worldY;
bone.setWorldY(bone.getWorldY() + value * pose._mixY); bone._worldY += value * pose._mixY;
} }
} }
// No RTTI for FromScaleX float FromScaleX::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._scaleX + offsets[TransformConstraintData::SCALEX];
float FromScaleX::value(BonePose &source, bool local, float *offsets) { float a = source._a / skeleton.getScaleX(), c = source._c / skeleton.getScaleY();
return (local ? source.getScaleX() : MathUtil::sqrt(source._a * source._a + source._c * source._c)) + offsets[TransformConstraintData::SCALEX]; return MathUtil::sqrt(a * a + c * c) + offsets[TransformConstraintData::SCALEX];
} }
// No RTTI for ToScaleX
float ToScaleX::mix(TransformConstraintPose &pose) { float ToScaleX::mix(TransformConstraintPose &pose) {
return pose._mixScaleX; return pose._mixScaleX;
} }
void ToScaleX::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToScaleX::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (additive) if (additive)
bone.setScaleX(bone.getScaleX() * (1 + ((value - 1) * pose._mixScaleX))); bone._scaleX *= 1 + ((value - 1) * pose._mixScaleX);
else if (bone.getScaleX() != 0) else if (bone._scaleX != 0) //
bone.setScaleX(bone.getScaleX() * (1 + (value / bone.getScaleX() - 1) * pose._mixScaleX)); bone._scaleX = 1 + (value / bone._scaleX - 1) * pose._mixScaleX;
} else { } else {
float s; float s;
if (additive) if (additive)
s = 1 + (value - 1) * pose._mixScaleX; s = 1 + (value - 1) * pose._mixScaleX;
else { else {
s = MathUtil::sqrt(bone._a * bone._a + bone._c * bone._c); s = MathUtil::sqrt(bone._a * bone._a + bone._c * bone._c) / skeleton.getScaleX();
if (s != 0) s = 1 + (value / s - 1) * pose._mixScaleX; if (s != 0) s = 1 + (value / s - 1) * pose._mixScaleX;
} }
bone._a *= s; bone._a *= s;
@ -279,30 +257,28 @@ void ToScaleX::apply(TransformConstraintPose &pose, BonePose &bone, float value,
} }
} }
// No RTTI for FromScaleY float FromScaleY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._scaleY + offsets[TransformConstraintData::SCALEY];
float FromScaleY::value(BonePose &source, bool local, float *offsets) { float b = source._b / skeleton.getScaleX(), d = source._d / skeleton.getScaleY();
return (local ? source.getScaleY() : MathUtil::sqrt(source._b * source._b + source._d * source._d)) + offsets[TransformConstraintData::SCALEY]; return MathUtil::sqrt(b * b + d * d) + offsets[TransformConstraintData::SCALEY];
} }
// No RTTI for ToScaleY
float ToScaleY::mix(TransformConstraintPose &pose) { float ToScaleY::mix(TransformConstraintPose &pose) {
return pose._mixScaleY; return pose._mixScaleY;
} }
void ToScaleY::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToScaleY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (additive) if (additive)
bone.setScaleY(bone.getScaleY() * (1 + ((value - 1) * pose._mixScaleY))); bone._scaleY *= 1 + ((value - 1) * pose._mixScaleY);
else if (bone.getScaleY() != 0) else if (bone._scaleY != 0) //
bone.setScaleY(bone.getScaleY() * (1 + (value / bone.getScaleY() - 1) * pose._mixScaleY)); bone._scaleY = 1 + (value / bone._scaleY - 1) * pose._mixScaleY;
} else { } else {
float s; float s;
if (additive) if (additive)
s = 1 + (value - 1) * pose._mixScaleY; s = 1 + (value - 1) * pose._mixScaleY;
else { else {
s = MathUtil::sqrt(bone._b * bone._b + bone._d * bone._d); s = MathUtil::sqrt(bone._b * bone._b + bone._d * bone._d) / skeleton.getScaleY();
if (s != 0) s = 1 + (value / s - 1) * pose._mixScaleY; if (s != 0) s = 1 + (value / s - 1) * pose._mixScaleY;
} }
bone._b *= s; bone._b *= s;
@ -310,22 +286,20 @@ void ToScaleY::apply(TransformConstraintPose &pose, BonePose &bone, float value,
} }
} }
// No RTTI for FromShearY float FromShearY::value(Skeleton &skeleton, BonePose &source, bool local, float *offsets) {
if (local) return source._shearY + offsets[TransformConstraintData::SHEARY];
float FromShearY::value(BonePose &source, bool local, float *offsets) { float sx = 1 / skeleton.getScaleX(), sy = 1 / skeleton.getScaleY();
return (local ? source.getShearY() : (MathUtil::atan2(source._d, source._b) - MathUtil::atan2(source._c, source._a)) * MathUtil::Rad_Deg - 90) + offsets[TransformConstraintData::SHEARY]; return (MathUtil::atan2(source._d * sy, source._b * sx) - MathUtil::atan2(source._c * sy, source._a * sx)) * MathUtil::Rad_Deg - 90 + offsets[TransformConstraintData::SHEARY];
} }
// No RTTI for ToShearY
float ToShearY::mix(TransformConstraintPose &pose) { float ToShearY::mix(TransformConstraintPose &pose) {
return pose._mixShearY; return pose._mixShearY;
} }
void ToShearY::apply(TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) { void ToShearY::apply(Skeleton &skeleton, TransformConstraintPose &pose, BonePose &bone, float value, bool local, bool additive) {
if (local) { if (local) {
if (!additive) value -= bone.getShearY(); if (!additive) value -= bone._shearY;
bone.setShearY(bone.getShearY() + value * pose._mixShearY); bone._shearY += value * pose._mixShearY;
} else { } else {
float b = bone._b, d = bone._d, by = MathUtil::atan2(d, b); float b = bone._b, d = bone._d, by = MathUtil::atan2(d, b);
value = (value + 90) * MathUtil::Deg_Rad; value = (value + 90) * MathUtil::Deg_Rad;
@ -334,9 +308,9 @@ void ToShearY::apply(TransformConstraintPose &pose, BonePose &bone, float value,
else { else {
value -= by - MathUtil::atan2(bone._c, bone._a); value -= by - MathUtil::atan2(bone._c, bone._a);
if (value > MathUtil::Pi) if (value > MathUtil::Pi)
value -= MathUtil::Pi * 2; value -= MathUtil::Pi_2;
else if (value < -MathUtil::Pi) else if (value < -MathUtil::Pi) //
value += MathUtil::Pi * 2; value += MathUtil::Pi_2;
} }
value = by + value * pose._mixShearY; value = by + value * pose._mixShearY;
float s = MathUtil::sqrt(b * b + d * d); float s = MathUtil::sqrt(b * b + d * d);