[cpp] 4.3 porting WIP

This commit is contained in:
Mario Zechner 2025-06-12 03:46:51 +02:00
parent da36386f4a
commit 98b9a056f3
14 changed files with 237 additions and 411 deletions

View File

@ -37,26 +37,37 @@
namespace spine {
class Skeleton;
/// Base class for all constraint data.
/// Base class for all constraint data types.
class SP_API ConstraintData : public SpineObject {
RTTI_DECL
public:
ConstraintData(const String &name);
virtual ~ConstraintData();
const String &getName() const;
private:
String _name;
};
/// Generic base class for all constraint data.
template<class T, class P>
class SP_API ConstraintData : public PosedData<P> {
class SP_API ConstraintDataGeneric : public PosedData<P>, public ConstraintData {
friend class SkeletonBinary;
friend class SkeletonJson;
public:
ConstraintData(const String &name);
virtual ~ConstraintData();
ConstraintDataGeneric(const String &name);
virtual ~ConstraintDataGeneric();
/// Creates a constraint instance.
virtual T* create(Skeleton& skeleton) = 0;
};
template<class T, class P>
ConstraintData<T, P>::ConstraintData(const String &name) : PosedData<P>(name) {
ConstraintDataGeneric<T, P>::ConstraintDataGeneric(const String &name) : PosedData<P>(name), ConstraintData(name) {
}
template<class T, class P>
ConstraintData<T, P>::~ConstraintData() {
ConstraintDataGeneric<T, P>::~ConstraintDataGeneric() {
}
}

View File

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

View File

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

View File

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

View File

@ -52,7 +52,12 @@ namespace spine {
class PhysicsConstraintData;
class ConstraintData;
/// Stores the setup pose and all of the stateless data for a skeleton.
///
/// See <a href="https://esotericsoftware.com/spine-runtime-architecture#Data-objects">Data objects</a> in the Spine Runtimes
/// Guide.
class SP_API SkeletonData : public SpineObject {
friend class SkeletonBinary;
@ -94,6 +99,8 @@ namespace spine {
/// @return May be NULL.
PhysicsConstraintData *findPhysicsConstraint(const String &constraintName);
/// The skeleton's name, which by default is the name of the skeleton data file when possible, or null when a name hasn't been
/// set.
const String &getName();
void setName(const String &inValue);
@ -101,6 +108,7 @@ namespace spine {
/// The skeleton's bones, sorted parent first. The root bone is always the first bone.
Vector<BoneData *> &getBones();
/// The skeleton's slots in the setup pose draw order.
Vector<SlotData *> &getSlots();
/// All skins, including the default skin.
@ -113,8 +121,10 @@ namespace spine {
void setDefaultSkin(Skin *inValue);
/// The skeleton's events.
Vector<spine::EventData *> &getEvents();
/// The skeleton's animations.
Vector<Animation *> &getAnimations();
Vector<IkConstraintData *> &getIkConstraints();
@ -125,22 +135,47 @@ namespace spine {
Vector<PhysicsConstraintData *> &getPhysicsConstraints();
/// The skeleton's constraints.
Vector<ConstraintData *> &getConstraints();
/// Finds a constraint by name and type.
/// @return May be NULL.
template<typename T>
T *findConstraint(const String &constraintName) {
getConstraints(); // Ensure constraints array is populated
for (size_t i = 0, n = _constraints.size(); i < n; i++) {
ConstraintData *constraint = _constraints[i];
if (constraint->getName().equals(constraintName)) {
if (constraint->rtti.isExactly(T::rtti)) {
return static_cast<T*>(constraint);
}
}
}
return NULL;
}
/// The X coordinate of the skeleton's axis aligned bounding box in the setup pose.
float getX();
void setX(float inValue);
/// The Y coordinate of the skeleton's axis aligned bounding box in the setup pose.
float getY();
void setY(float inValue);
/// The width of the skeleton's axis aligned bounding box in the setup pose.
float getWidth();
void setWidth(float inValue);
/// The height of the skeleton's axis aligned bounding box in the setup pose.
float getHeight();
void setHeight(float inValue);
/// Baseline scale factor for applying physics and other effects based on distance to non-scalable properties, such as angle or
/// scale. Default is 100.
float getReferenceScale();
void setReferenceScale(float inValue);
@ -150,14 +185,17 @@ namespace spine {
void setVersion(const String &inValue);
/// The skeleton data hash. This value will change if any of the skeleton data has changed.
const String &getHash();
void setHash(const String &inValue);
/// The path to the images directory as defined in Spine, or null if nonessential data was not exported.
const String &getImagesPath();
void setImagesPath(const String &inValue);
/// The path to the audio directory as defined in Spine, or null if nonessential data was not exported.
const String &getAudioPath();
void setAudioPath(const String &inValue);
@ -179,6 +217,7 @@ namespace spine {
Vector<TransformConstraintData *> _transformConstraints;
Vector<PathConstraintData *> _pathConstraints;
Vector<PhysicsConstraintData *> _physicsConstraints;
Vector<ConstraintData *> _constraints;
float _x, _y, _width, _height;
float _referenceScale;
String _version;

View File

@ -30,83 +30,45 @@
#ifndef Spine_TransformConstraint_h
#define Spine_TransformConstraint_h
#include <spine/ConstraintData.h>
#include <spine/Constraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/TransformConstraintPose.h>
#include <spine/Vector.h>
namespace spine {
class TransformConstraintData;
class Skeleton;
class Bone;
class BonePose;
class SP_API TransformConstraint : public Updatable {
class SP_API TransformConstraint : public Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose> {
friend class Skeleton;
friend class TransformConstraintTimeline;
RTTI_DECL
public:
TransformConstraint(TransformConstraintData &data, Skeleton &skeleton);
TransformConstraint(TransformConstraintData& data, Skeleton& skeleton);
virtual void update(Physics physics);
TransformConstraint copy(Skeleton& skeleton);
virtual int getOrder();
/// Applies the constraint to the constrained bones.
void update(Skeleton& skeleton, Physics physics);
TransformConstraintData &getData();
void sort(Skeleton& skeleton);
Vector<Bone *> &getBones();
bool isSourceActive();
Bone *getTarget();
/// The bones that will be modified by this transform constraint.
Vector<BonePose*>& getBones();
void setTarget(Bone *inValue);
/// The bone whose world transform will be copied to the constrained bones.
Bone* getSource();
float getMixRotate();
void setMixRotate(float inValue);
float getMixX();
void setMixX(float inValue);
float getMixY();
void setMixY(float inValue);
float getMixScaleX();
void setMixScaleX(float inValue);
float getMixScaleY();
void setMixScaleY(float inValue);
float getMixShearY();
void setMixShearY(float inValue);
bool isActive();
void setActive(bool inValue);
void setToSetupPose();
void setSource(Bone* source);
private:
TransformConstraintData &_data;
Vector<Bone *> _bones;
Bone *_target;
float _mixRotate, _mixX, _mixY, _mixScaleX, _mixScaleY, _mixShearY;
bool _active;
void applyAbsoluteWorld();
void applyRelativeWorld();
void applyAbsoluteLocal();
void applyRelativeLocal();
Vector<BonePose*> _bones;
Bone* _source;
};
}

View File

@ -43,7 +43,6 @@ namespace spine {
/// Source property for a TransformConstraint.
class SP_API FromProperty : public SpineObject {
public:
RTTI_DECL
/// The value of this property that corresponds to ToProperty offset.
float offset;
@ -61,7 +60,6 @@ namespace spine {
/// Constrained property for a TransformConstraint.
class SP_API ToProperty : public SpineObject {
public:
RTTI_DECL
/// The value of this property that corresponds to FromProperty offset.
float offset;
@ -84,78 +82,66 @@ namespace spine {
class SP_API FromRotate : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToRotate : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
class SP_API FromX : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToX : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
class SP_API FromY : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToY : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
class SP_API FromScaleX : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToScaleX : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
class SP_API FromScaleY : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToScaleY : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
class SP_API FromShearY : public FromProperty {
public:
RTTI_DECL
float value(BonePose& source, bool local, float* offsets) override;
};
class SP_API ToShearY : public ToProperty {
public:
RTTI_DECL
float mix(TransformConstraintPose& pose) override;
void apply(TransformConstraintPose& pose, BonePose& bone, float value, bool local, bool additive) override;
};
@ -163,7 +149,7 @@ namespace spine {
/// Stores the setup pose for a TransformConstraint.
///
/// See https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide.
class SP_API TransformConstraintData : public ConstraintData<TransformConstraint, TransformConstraintPose> {
class SP_API TransformConstraintData : public ConstraintDataGeneric<TransformConstraint, TransformConstraintPose> {
public:
static const int ROTATION = 0, X = 1, Y = 2, SCALEX = 3, SCALEY = 4, SHEARY = 5;
friend class SkeletonBinary;

View File

@ -29,5 +29,16 @@
#include <spine/ConstraintData.h>
// Template class - implementation is in the header file
using namespace spine;
using namespace spine;
RTTI_IMPL_NOPARENT(ConstraintData)
ConstraintData::ConstraintData(const String &name) : _name(name) {
}
ConstraintData::~ConstraintData() {
}
const String &ConstraintData::getName() const {
return _name;
}

View File

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

View File

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

View File

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

View File

@ -31,6 +31,7 @@
#include <spine/Animation.h>
#include <spine/BoneData.h>
#include <spine/ConstraintData.h>
#include <spine/EventData.h>
#include <spine/IkConstraintData.h>
#include <spine/PathConstraintData.h>
@ -52,8 +53,9 @@ SkeletonData::SkeletonData() : _name(),
_referenceScale(100),
_version(),
_hash(),
_fps(0),
_imagesPath() {
_fps(30),
_imagesPath(),
_audioPath() {
}
SkeletonData::~SkeletonData() {
@ -69,6 +71,8 @@ SkeletonData::~SkeletonData() {
ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
ContainerUtil::cleanUpVectorOfPointers(_physicsConstraints);
// Note: _constraints contains pointers to objects already cleaned up above, so just clear
_constraints.clear();
for (size_t i = 0; i < _strings.size(); i++) {
SpineExtension::free(_strings[i], __FILE__, __LINE__);
}
@ -242,3 +246,21 @@ float SkeletonData::getFps() {
void SkeletonData::setFps(float inValue) {
_fps = inValue;
}
Vector<ConstraintData *> &SkeletonData::getConstraints() {
// Build unified constraints array by aggregating all constraint types
_constraints.clear();
for (size_t i = 0, n = _ikConstraints.size(); i < n; i++) {
_constraints.add(static_cast<ConstraintData*>(_ikConstraints[i]));
}
for (size_t i = 0, n = _transformConstraints.size(); i < n; i++) {
_constraints.add(static_cast<ConstraintData*>(_transformConstraints[i]));
}
for (size_t i = 0, n = _pathConstraints.size(); i < n; i++) {
_constraints.add(static_cast<ConstraintData*>(_pathConstraints[i]));
}
for (size_t i = 0, n = _physicsConstraints.size(); i < n; i++) {
_constraints.add(static_cast<ConstraintData*>(_physicsConstraints[i]));
}
return _constraints;
}

View File

@ -30,321 +30,116 @@
#include <spine/TransformConstraint.h>
#include <spine/Bone.h>
#include <spine/BonePose.h>
#include <spine/Skeleton.h>
#include <spine/TransformConstraintData.h>
#include <spine/MathUtil.h>
#include <spine/BoneData.h>
using namespace spine;
RTTI_IMPL(TransformConstraint, Updatable)
RTTI_IMPL_NOPARENT(TransformConstraint)
TransformConstraint::TransformConstraint(TransformConstraintData &data, Skeleton &skeleton) : Updatable(),
_data(data),
_target(skeleton.findBone(
data.getTarget()->getName())),
_mixRotate(
data.getMixRotate()),
_mixX(data.getMixX()),
_mixY(data.getMixY()),
_mixScaleX(
data.getMixScaleX()),
_mixScaleY(
data.getMixScaleY()),
_mixShearY(
data.getMixShearY()),
_active(false) {
_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()));
TransformConstraint::TransformConstraint(TransformConstraintData& data, Skeleton& skeleton) :
Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose>(data) {
if (&skeleton == NULL) throw;
_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());
}
_source = skeleton.findBone(data.getSource()->getName());
}
TransformConstraint TransformConstraint::copy(Skeleton& skeleton) {
TransformConstraint copy(_data, skeleton);
copy._applied->set(*_applied);
return copy;
}
/// Applies the constraint to the constrained bones.
void TransformConstraint::update(Skeleton& skeleton, Physics physics) {
TransformConstraintPose& p = *_applied;
if (p.getMixRotate() == 0 && p.getMixX() == 0 && p.getMixY() == 0 && p.getMixScaleX() == 0 && p.getMixScaleY() == 0 && p.getMixShearY() == 0) return;
TransformConstraintData& data = _data;
bool localSource = data.getLocalSource(), localTarget = data.getLocalTarget(), additive = data.getAdditive(), clamp = data.getClamp();
float* offsets = data._offsets; // Access friend field directly
BonePose& source = _source->getAppliedPose();
if (localSource) {
source.validateLocalTransform(skeleton);
}
Vector<FromProperty*>& properties = data.getProperties();
FromProperty** fromItems = properties.buffer();
size_t fn = properties.size();
int update = 1; // TODO: Add skeleton.update field
BonePose** bones = _bones.buffer();
for (size_t i = 0, n = _bones.size(); i < n; i++) {
BonePose* bone = bones[i];
if (localTarget) {
bone->modifyLocal(skeleton);
} else {
bone->modifyWorld(update);
}
for (size_t f = 0; f < fn; f++) {
FromProperty* from = fromItems[f];
float value = from->value(source, localSource, offsets) - from->offset;
Vector<ToProperty*>& toProps = from->to;
ToProperty** toItems = toProps.buffer();
for (size_t t = 0, tn = toProps.size(); t < tn; t++) {
ToProperty* to = toItems[t];
if (to->mix(p) != 0) {
float clamped = to->offset + value * to->scale;
if (clamp) {
if (to->offset < to->max)
clamped = MathUtil::clamp(clamped, to->offset, to->max);
else
clamped = MathUtil::clamp(clamped, to->max, to->offset);
}
to->apply(p, *bone, clamped, localTarget, additive);
}
}
}
}
}
void TransformConstraint::update(Physics) {
if (_mixRotate == 0 && _mixX == 0 && _mixY == 0 && _mixScaleX == 0 && _mixScaleY == 0 && _mixShearY == 0) return;
if (_data.isLocal()) {
if (_data.isRelative())
applyRelativeLocal();
else
applyAbsoluteLocal();
} else {
if (_data.isRelative())
applyRelativeWorld();
else
applyAbsoluteWorld();
}
void TransformConstraint::sort(Skeleton& skeleton) {
// if (!_data.getLocalSource()) skeleton.sortBone(_source); // TODO: sortBone is private, need friend access
BonePose** bones = _bones.buffer();
size_t boneCount = _bones.size();
bool worldTarget = !_data.getLocalTarget();
// if (worldTarget) {
// for (size_t i = 0; i < boneCount; i++)
// skeleton.sortBone(bones[i]->_bone); // TODO: sortBone is private, need friend access
// }
// skeleton._updateCache.add(this); // TODO: _updateCache is private, need friend access
// for (size_t i = 0; i < boneCount; i++) {
// Bone* bone = bones[i]->_bone;
// skeleton.sortReset(bone->getChildren()); // TODO: sortReset is private, need friend access
// // skeleton.constrained(bone); // TODO: Add constrained() method to Skeleton class
// }
// for (size_t i = 0; i < boneCount; i++)
// bones[i]->_bone->_sorted = worldTarget; // TODO: _sorted is private, need friend access
}
int TransformConstraint::getOrder() {
return (int) _data.getOrder();
bool TransformConstraint::isSourceActive() {
return _source->isActive();
}
TransformConstraintData &TransformConstraint::getData() {
return _data;
}
Vector<Bone *> &TransformConstraint::getBones() {
/// The bones that will be modified by this transform constraint.
Vector<BonePose*>& TransformConstraint::getBones() {
return _bones;
}
Bone *TransformConstraint::getTarget() {
return _target;
/// The bone whose world transform will be copied to the constrained bones.
Bone* TransformConstraint::getSource() {
return _source;
}
void TransformConstraint::setTarget(Bone *inValue) {
_target = inValue;
}
float TransformConstraint::getMixRotate() {
return _mixRotate;
}
void TransformConstraint::setMixRotate(float inValue) {
_mixRotate = inValue;
}
float TransformConstraint::getMixX() {
return _mixX;
}
void TransformConstraint::setMixX(float inValue) {
_mixX = inValue;
}
float TransformConstraint::getMixY() {
return _mixY;
}
void TransformConstraint::setMixY(float inValue) {
_mixY = inValue;
}
void TransformConstraint::setMixScaleX(float inValue) {
_mixScaleX = inValue;
}
float TransformConstraint::getMixScaleX() {
return _mixScaleX;
}
float TransformConstraint::getMixScaleY() {
return _mixScaleY;
}
void TransformConstraint::setMixScaleY(float inValue) {
_mixScaleY = inValue;
}
float TransformConstraint::getMixShearY() {
return _mixShearY;
}
void TransformConstraint::setMixShearY(float inValue) {
_mixShearY = inValue;
}
void TransformConstraint::applyAbsoluteWorld() {
float mixRotate = _mixRotate, mixX = _mixX, mixY = _mixY, mixScaleX = _mixScaleX, mixScaleY = _mixScaleY, mixShearY = _mixShearY;
bool translate = mixX != 0 || mixY != 0;
Bone &target = *_target;
float ta = target._a, tb = target._b, tc = target._c, td = target._d;
float degRadReflect = ta * td - tb * tc > 0 ? MathUtil::Deg_Rad : -MathUtil::Deg_Rad;
float offsetRotation = _data._offsetRotation * degRadReflect, offsetShearY = _data._offsetShearY * degRadReflect;
for (size_t i = 0; i < _bones.size(); ++i) {
Bone *item = _bones[i];
Bone &bone = *item;
if (mixRotate != 0) {
float a = bone._a, b = bone._b, c = bone._c, d = bone._d;
float r = MathUtil::atan2(tc, ta) - MathUtil::atan2(c, a) + offsetRotation;
if (r > MathUtil::Pi)
r -= MathUtil::Pi_2;
else if (r < -MathUtil::Pi)
r += MathUtil::Pi_2;
r *= mixRotate;
float cos = MathUtil::cos(r), sin = MathUtil::sin(r);
bone._a = cos * a - sin * c;
bone._b = cos * b - sin * d;
bone._c = sin * a + cos * c;
bone._d = sin * b + cos * d;
}
if (translate) {
float tx, ty;
target.localToWorld(_data._offsetX, _data._offsetY, tx, ty);
bone._worldX += (tx - bone._worldX) * mixX;
bone._worldY += (ty - bone._worldY) * mixY;
}
if (mixScaleX > 0) {
float s = MathUtil::sqrt(bone._a * bone._a + bone._c * bone._c);
if (s != 0) s = (s + (MathUtil::sqrt(ta * ta + tc * tc) - s + _data._offsetScaleX) * mixScaleX) / s;
bone._a *= s;
bone._c *= s;
}
if (mixScaleY > 0) {
float s = MathUtil::sqrt(bone._b * bone._b + bone._d * bone._d);
if (s != 0) s = (s + (MathUtil::sqrt(tb * tb + td * td) - s + _data._offsetScaleY) * mixScaleY) / s;
bone._b *= s;
bone._d *= s;
}
if (mixShearY > 0) {
float b = bone._b, d = bone._d;
float by = MathUtil::atan2(d, b);
float r = MathUtil::atan2(td, tb) - MathUtil::atan2(tc, ta) - (by - MathUtil::atan2(bone._c, bone._a));
if (r > MathUtil::Pi)
r -= MathUtil::Pi_2;
else if (r < -MathUtil::Pi)
r += MathUtil::Pi_2;
r = by + (r + offsetShearY) * mixShearY;
float s = MathUtil::sqrt(b * b + d * d);
bone._b = MathUtil::cos(r) * s;
bone._d = MathUtil::sin(r) * s;
}
bone.updateAppliedTransform();
}
}
void TransformConstraint::applyRelativeWorld() {
float mixRotate = _mixRotate, mixX = _mixX, mixY = _mixY, mixScaleX = _mixScaleX, mixScaleY = _mixScaleY, mixShearY = _mixShearY;
bool translate = mixX != 0 || mixY != 0;
Bone &target = *_target;
float ta = target._a, tb = target._b, tc = target._c, td = target._d;
float degRadReflect = ta * td - tb * tc > 0 ? MathUtil::Deg_Rad : -MathUtil::Deg_Rad;
float offsetRotation = _data._offsetRotation * degRadReflect, offsetShearY = _data._offsetShearY * degRadReflect;
for (size_t i = 0; i < _bones.size(); ++i) {
Bone *item = _bones[i];
Bone &bone = *item;
if (mixRotate != 0) {
float a = bone._a, b = bone._b, c = bone._c, d = bone._d;
float r = MathUtil::atan2(tc, ta) + offsetRotation;
if (r > MathUtil::Pi)
r -= MathUtil::Pi_2;
else if (r < -MathUtil::Pi)
r += MathUtil::Pi_2;
r *= mixRotate;
float cos = MathUtil::cos(r), sin = MathUtil::sin(r);
bone._a = cos * a - sin * c;
bone._b = cos * b - sin * d;
bone._c = sin * a + cos * c;
bone._d = sin * b + cos * d;
}
if (translate) {
float tx, ty;
target.localToWorld(_data._offsetX, _data._offsetY, tx, ty);
bone._worldX += tx * mixX;
bone._worldY += ty * mixY;
}
if (mixScaleX != 0) {
float s = (MathUtil::sqrt(ta * ta + tc * tc) - 1 + _data._offsetScaleX) * mixScaleX + 1;
bone._a *= s;
bone._c *= s;
}
if (mixScaleY != 0) {
float s = (MathUtil::sqrt(tb * tb + td * td) - 1 + _data._offsetScaleY) * mixScaleY + 1;
bone._b *= s;
bone._d *= s;
}
if (mixShearY > 0) {
float r = MathUtil::atan2(td, tb) - MathUtil::atan2(tc, ta);
if (r > MathUtil::Pi)
r -= MathUtil::Pi_2;
else if (r < -MathUtil::Pi)
r += MathUtil::Pi_2;
float b = bone._b, d = bone._d;
r = MathUtil::atan2(d, b) + (r - MathUtil::Pi / 2 + offsetShearY) * mixShearY;
float s = MathUtil::sqrt(b * b + d * d);
bone._b = MathUtil::cos(r) * s;
bone._d = MathUtil::sin(r) * s;
}
bone.updateAppliedTransform();
}
}
void TransformConstraint::applyAbsoluteLocal() {
float mixRotate = _mixRotate, mixX = _mixX, mixY = _mixY, mixScaleX = _mixScaleX, mixScaleY = _mixScaleY, mixShearY = _mixShearY;
Bone &target = *_target;
for (size_t i = 0; i < _bones.size(); ++i) {
Bone *item = _bones[i];
Bone &bone = *item;
float rotation = bone._arotation;
if (mixRotate != 0) {
float r = target._arotation - rotation + _data._offsetRotation;
r -= MathUtil::ceil(r / 360 - 0.5) * 360;
rotation += r * mixRotate;
}
float x = bone._ax, y = bone._ay;
x += (target._ax - x + _data._offsetX) * mixX;
y += (target._ay - y + _data._offsetY) * mixY;
float scaleX = bone._ascaleX, scaleY = bone._ascaleY;
if (mixScaleX != 0 && scaleX != 0)
scaleX = (scaleX + (target._ascaleX - scaleX + _data._offsetScaleX) * mixScaleX) / scaleX;
if (mixScaleY != 0 && scaleY != 0)
scaleY = (scaleY + (target._ascaleY - scaleY + _data._offsetScaleY) * mixScaleY) / scaleY;
float shearY = bone._ashearY;
if (mixShearY != 0) {
float r = target._ashearY - shearY + _data._offsetShearY;
r -= MathUtil::ceil(r / 360 - 0.5) * 360;
bone._shearY += r * mixShearY;
}
bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone._ashearX, shearY);
}
}
void TransformConstraint::applyRelativeLocal() {
float mixRotate = _mixRotate, mixX = _mixX, mixY = _mixY, mixScaleX = _mixScaleX, mixScaleY = _mixScaleY, mixShearY = _mixShearY;
Bone &target = *_target;
for (size_t i = 0; i < _bones.size(); ++i) {
Bone *item = _bones[i];
Bone &bone = *item;
float rotation = bone._arotation + (target._arotation + _data._offsetRotation) * mixRotate;
float x = bone._ax + (target._ax + _data._offsetX) * mixX;
float y = bone._ay + (target._ay + _data._offsetY) * mixY;
float scaleX = bone._ascaleX * (((target._ascaleX - 1 + _data._offsetScaleX) * mixScaleX) + 1);
float scaleY = bone._ascaleY * (((target._ascaleY - 1 + _data._offsetScaleY) * mixScaleY) + 1);
float shearY = bone._ashearY + (target._ashearY + _data._offsetShearY) * mixShearY;
bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone._ashearX, shearY);
}
}
bool TransformConstraint::isActive() {
return _active;
}
void TransformConstraint::setActive(bool inValue) {
_active = inValue;
}
void TransformConstraint::setToSetupPose() {
TransformConstraintData &data = this->_data;
this->_mixRotate = data._mixRotate;
this->_mixX = data._mixX;
this->_mixY = data._mixY;
this->_mixScaleX = data._mixScaleX;
this->_mixScaleY = data._mixScaleY;
this->_mixShearY = data._mixShearY;
}
void TransformConstraint::setSource(Bone* source) {
if (source == NULL) throw;
_source = source;
}

View File

@ -36,9 +36,9 @@
using namespace spine;
RTTI_IMPL_NOPARENT(TransformConstraintData)
RTTI_IMPL(TransformConstraintData, ConstraintData)
TransformConstraintData::TransformConstraintData(const String &name) : ConstraintData<TransformConstraint, TransformConstraintPose>(name),
TransformConstraintData::TransformConstraintData(const String &name) : ConstraintDataGeneric<TransformConstraint, TransformConstraintPose>(name),
_source(NULL),
_localSource(false),
_localTarget(false),
@ -149,7 +149,7 @@ Vector<FromProperty*>& TransformConstraintData::getProperties() {
// Property Classes
// ============================================================================
RTTI_IMPL_NOPARENT(FromProperty)
// No RTTI for FromProperty
FromProperty::FromProperty() : SpineObject(), offset(0) {
}
@ -157,7 +157,7 @@ FromProperty::FromProperty() : SpineObject(), offset(0) {
FromProperty::~FromProperty() {
}
RTTI_IMPL_NOPARENT(ToProperty)
// No RTTI for ToProperty
ToProperty::ToProperty() : offset(0), max(0), scale(1) {
}
@ -165,17 +165,17 @@ ToProperty::ToProperty() : offset(0), max(0), scale(1) {
ToProperty::~ToProperty() {
}
RTTI_IMPL(FromRotate, FromProperty)
// No RTTI for FromRotate
float FromRotate::value(BonePose& source, bool local, float* offsets) {
if (local) return source.getRotation() + offsets[ROTATION];
if (local) return source.getRotation() + offsets[TransformConstraintData::ROTATION];
float value = MathUtil::atan2(source._c, source._a) * MathUtil::Rad_Deg
+ (source._a * source._d - source._b * source._c > 0 ? offsets[ROTATION] : -offsets[ROTATION]);
+ (source._a * source._d - source._b * source._c > 0 ? offsets[TransformConstraintData::ROTATION] : -offsets[TransformConstraintData::ROTATION]);
if (value < 0) value += 360;
return value;
}
RTTI_IMPL(ToRotate, ToProperty)
// No RTTI for ToRotate
float ToRotate::mix(TransformConstraintPose& pose) {
return pose._mixRotate;
@ -202,13 +202,13 @@ void ToRotate::apply(TransformConstraintPose& pose, BonePose& bone, float value,
}
}
RTTI_IMPL(FromX, FromProperty)
// No RTTI for FromX
float FromX::value(BonePose& source, bool local, float* offsets) {
return local ? source.getX() + offsets[X] : offsets[X] * source._a + offsets[Y] * source._b + source.getWorldX();
return local ? source.getX() + offsets[TransformConstraintData::X] : offsets[TransformConstraintData::X] * source._a + offsets[TransformConstraintData::Y] * source._b + source.getWorldX();
}
RTTI_IMPL(ToX, ToProperty)
// No RTTI for ToX
float ToX::mix(TransformConstraintPose& pose) {
return pose._mixX;
@ -224,13 +224,13 @@ void ToX::apply(TransformConstraintPose& pose, BonePose& bone, float value, bool
}
}
RTTI_IMPL(FromY, FromProperty)
// No RTTI for FromY
float FromY::value(BonePose& source, bool local, float* offsets) {
return local ? source.getY() + offsets[Y] : offsets[X] * source._c + offsets[Y] * source._d + source.getWorldY();
return local ? source.getY() + offsets[TransformConstraintData::Y] : offsets[TransformConstraintData::X] * source._c + offsets[TransformConstraintData::Y] * source._d + source.getWorldY();
}
RTTI_IMPL(ToY, ToProperty)
// No RTTI for ToY
float ToY::mix(TransformConstraintPose& pose) {
return pose._mixY;
@ -246,13 +246,13 @@ void ToY::apply(TransformConstraintPose& pose, BonePose& bone, float value, bool
}
}
RTTI_IMPL(FromScaleX, FromProperty)
// No RTTI for FromScaleX
float FromScaleX::value(BonePose& source, bool local, float* offsets) {
return (local ? source.getScaleX() : MathUtil::sqrt(source._a * source._a + source._c * source._c)) + offsets[SCALEX];
return (local ? source.getScaleX() : MathUtil::sqrt(source._a * source._a + source._c * source._c)) + offsets[TransformConstraintData::SCALEX];
}
RTTI_IMPL(ToScaleX, ToProperty)
// No RTTI for ToScaleX
float ToScaleX::mix(TransformConstraintPose& pose) {
return pose._mixScaleX;
@ -277,13 +277,13 @@ void ToScaleX::apply(TransformConstraintPose& pose, BonePose& bone, float value,
}
}
RTTI_IMPL(FromScaleY, FromProperty)
// No RTTI for FromScaleY
float FromScaleY::value(BonePose& source, bool local, float* offsets) {
return (local ? source.getScaleY() : MathUtil::sqrt(source._b * source._b + source._d * source._d)) + offsets[SCALEY];
return (local ? source.getScaleY() : MathUtil::sqrt(source._b * source._b + source._d * source._d)) + offsets[TransformConstraintData::SCALEY];
}
RTTI_IMPL(ToScaleY, ToProperty)
// No RTTI for ToScaleY
float ToScaleY::mix(TransformConstraintPose& pose) {
return pose._mixScaleY;
@ -308,13 +308,13 @@ void ToScaleY::apply(TransformConstraintPose& pose, BonePose& bone, float value,
}
}
RTTI_IMPL(FromShearY, FromProperty)
// No RTTI for FromShearY
float FromShearY::value(BonePose& source, bool local, float* offsets) {
return (local ? source.getShearY() : (MathUtil::atan2(source._d, source._b) - MathUtil::atan2(source._c, source._a)) * MathUtil::Rad_Deg - 90) + offsets[SHEARY];
return (local ? source.getShearY() : (MathUtil::atan2(source._d, source._b) - MathUtil::atan2(source._c, source._a)) * MathUtil::Rad_Deg - 90) + offsets[TransformConstraintData::SHEARY];
}
RTTI_IMPL(ToShearY, ToProperty)
// No RTTI for ToShearY
float ToShearY::mix(TransformConstraintPose& pose) {
return pose._mixShearY;