mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
wip
This commit is contained in:
parent
8ebb36daa9
commit
210e492d79
@ -33,361 +33,149 @@
|
|||||||
|
|
||||||
#include <spine/Updatable.h>
|
#include <spine/Updatable.h>
|
||||||
|
|
||||||
|
#include <spine/SimpleArray.h>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
|
class BoneData;
|
||||||
|
class Skeleton;
|
||||||
|
|
||||||
/// Stores a bone's current pose.
|
/// Stores a bone's current pose.
|
||||||
///
|
///
|
||||||
/// A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a
|
/// A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a
|
||||||
/// local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a
|
/// local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a
|
||||||
/// constraint or application code modifies the world transform after it was computed from the local transform.
|
/// constraint or application code modifies the world transform after it was computed from the local transform.
|
||||||
///
|
|
||||||
class Bone : public Updatable
|
class Bone : public Updatable
|
||||||
{
|
{
|
||||||
friend class RotateTimeline;
|
friend class RotateTimeline;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
private:
|
|
||||||
static public bool yDown;
|
|
||||||
|
|
||||||
internal BoneData _data;
|
|
||||||
internal Skeleton _skeleton;
|
|
||||||
internal Bone _parent;
|
|
||||||
internal ExposedList<Bone> _children = new ExposedList<Bone>();
|
|
||||||
internal float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
|
|
||||||
internal float _ax, _ay, _arotation, _ascaleX, _ascaleY, _ashearX, _ashearY;
|
|
||||||
internal bool _appliedValid;
|
|
||||||
|
|
||||||
internal float _a, _b, _worldX;
|
|
||||||
internal float _c, _d, _worldY;
|
|
||||||
|
|
||||||
// internal float worldSignX, worldSignY;
|
|
||||||
// public float WorldSignX { get { return worldSignX; } }
|
|
||||||
// public float WorldSignY { get { return worldSignY; } }
|
|
||||||
|
|
||||||
internal bool _sorted;
|
|
||||||
|
|
||||||
public BoneData Data { get { return data; } }
|
|
||||||
public Skeleton Skeleton { get { return skeleton; } }
|
|
||||||
public Bone Parent { get { return parent; } }
|
|
||||||
public ExposedList<Bone> Children { get { return children; } }
|
|
||||||
/// The local X translation.
|
|
||||||
public float X { get { return x; } set { x = value; } }
|
|
||||||
/// The local Y translation.
|
|
||||||
public float Y { get { return y; } set { y = value; } }
|
|
||||||
/// The local rotation.
|
|
||||||
public float Rotation { get { return rotation; } set { rotation = value; } }
|
|
||||||
|
|
||||||
/// The local scaleX.
|
|
||||||
public float ScaleX { get { return scaleX; } set { scaleX = value; } }
|
|
||||||
|
|
||||||
/// The local scaleY.
|
|
||||||
public float ScaleY { get { return scaleY; } set { scaleY = value; } }
|
|
||||||
|
|
||||||
/// The local shearX.
|
|
||||||
public float ShearX { get { return shearX; } set { shearX = value; } }
|
|
||||||
|
|
||||||
/// The local shearY.
|
|
||||||
public float ShearY { get { return shearY; } set { shearY = value; } }
|
|
||||||
|
|
||||||
/// The rotation, as calculated by any constraints.
|
|
||||||
public float AppliedRotation { get { return arotation; } set { arotation = value; } }
|
|
||||||
|
|
||||||
/// The applied local x translation.
|
|
||||||
public float AX { get { return ax; } set { ax = value; } }
|
|
||||||
|
|
||||||
/// The applied local y translation.
|
|
||||||
public float AY { get { return ay; } set { ay = value; } }
|
|
||||||
|
|
||||||
/// The applied local scaleX.
|
|
||||||
public float AScaleX { get { return ascaleX; } set { ascaleX = value; } }
|
|
||||||
|
|
||||||
/// The applied local scaleY.
|
|
||||||
public float AScaleY { get { return ascaleY; } set { ascaleY = value; } }
|
|
||||||
|
|
||||||
/// The applied local shearX.
|
|
||||||
public float AShearX { get { return ashearX; } set { ashearX = value; } }
|
|
||||||
|
|
||||||
/// The applied local shearY.
|
|
||||||
public float AShearY { get { return ashearY; } set { ashearY = value; } }
|
|
||||||
|
|
||||||
public float A { get { return a; } }
|
|
||||||
public float B { get { return b; } }
|
|
||||||
public float C { get { return c; } }
|
|
||||||
public float D { get { return d; } }
|
|
||||||
|
|
||||||
public float WorldX { get { return worldX; } }
|
|
||||||
public float WorldY { get { return worldY; } }
|
|
||||||
public float WorldRotationX { get { return MathUtils.Atan2(c, a) * MathUtils.RadDeg; } }
|
|
||||||
public float WorldRotationY { get { return MathUtils.Atan2(d, b) * MathUtils.RadDeg; } }
|
|
||||||
|
|
||||||
/// Returns the magnitide (always positive) of the world scale X.
|
|
||||||
public float WorldScaleX { get { return (float)Math.Sqrt(a * a + c * c); } }
|
|
||||||
/// Returns the magnitide (always positive) of the world scale Y.
|
|
||||||
public float WorldScaleY { get { return (float)Math.Sqrt(b * b + d * d); } }
|
|
||||||
|
|
||||||
/// @param parent May be null.
|
/// @param parent May be null.
|
||||||
public Bone (BoneData data, Skeleton skeleton, Bone parent) {
|
Bone(BoneData& data, Skeleton& skeleton, Bone* parent);
|
||||||
if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
|
|
||||||
if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null.");
|
|
||||||
this.data = data;
|
|
||||||
this.skeleton = skeleton;
|
|
||||||
this.parent = parent;
|
|
||||||
SetToSetupPose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as <see cref="UpdateWorldTransform"/>. This method exists for Bone to implement <see cref="Spine.IUpdatable"/>.
|
/// Same as updateWorldTransform. This method exists for Bone to implement Spine::Updatable.
|
||||||
public void Update () {
|
virtual void update();
|
||||||
UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the world transform using the parent bone and this bone's local transform.
|
/// Computes the world transform using the parent bone and this bone's local transform.
|
||||||
public void UpdateWorldTransform () {
|
void updateWorldTransform();
|
||||||
UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the world transform using the parent bone and the specified local transform.
|
/// Computes the world transform using the parent bone and the specified local transform.
|
||||||
public void UpdateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
|
void updateWorldTransform(float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY);
|
||||||
ax = x;
|
|
||||||
ay = y;
|
|
||||||
arotation = rotation;
|
|
||||||
ascaleX = scaleX;
|
|
||||||
ascaleY = scaleY;
|
|
||||||
ashearX = shearX;
|
|
||||||
ashearY = shearY;
|
|
||||||
appliedValid = true;
|
|
||||||
Skeleton skeleton = this.skeleton;
|
|
||||||
|
|
||||||
Bone parent = this.parent;
|
|
||||||
if (parent == null) { // Root bone.
|
|
||||||
float rotationY = rotation + 90 + shearY;
|
|
||||||
float la = MathUtils.CosDeg(rotation + shearX) * scaleX;
|
|
||||||
float lb = MathUtils.CosDeg(rotationY) * scaleY;
|
|
||||||
float lc = MathUtils.SinDeg(rotation + shearX) * scaleX;
|
|
||||||
float ld = MathUtils.SinDeg(rotationY) * scaleY;
|
|
||||||
if (skeleton.flipX) {
|
|
||||||
x = -x;
|
|
||||||
la = -la;
|
|
||||||
lb = -lb;
|
|
||||||
}
|
|
||||||
if (skeleton.flipY != yDown) {
|
|
||||||
y = -y;
|
|
||||||
lc = -lc;
|
|
||||||
ld = -ld;
|
|
||||||
}
|
|
||||||
a = la;
|
|
||||||
b = lb;
|
|
||||||
c = lc;
|
|
||||||
d = ld;
|
|
||||||
worldX = x + skeleton.x;
|
|
||||||
worldY = y + skeleton.y;
|
|
||||||
// worldSignX = Math.Sign(scaleX);
|
|
||||||
// worldSignY = Math.Sign(scaleY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
|
||||||
worldX = pa * x + pb * y + parent.worldX;
|
|
||||||
worldY = pc * x + pd * y + parent.worldY;
|
|
||||||
// worldSignX = parent.worldSignX * Math.Sign(scaleX);
|
|
||||||
// worldSignY = parent.worldSignY * Math.Sign(scaleY);
|
|
||||||
|
|
||||||
switch (data.transformMode) {
|
|
||||||
case TransformMode.Normal: {
|
|
||||||
float rotationY = rotation + 90 + shearY;
|
|
||||||
float la = MathUtils.CosDeg(rotation + shearX) * scaleX;
|
|
||||||
float lb = MathUtils.CosDeg(rotationY) * scaleY;
|
|
||||||
float lc = MathUtils.SinDeg(rotation + shearX) * scaleX;
|
|
||||||
float ld = MathUtils.SinDeg(rotationY) * scaleY;
|
|
||||||
a = pa * la + pb * lc;
|
|
||||||
b = pa * lb + pb * ld;
|
|
||||||
c = pc * la + pd * lc;
|
|
||||||
d = pc * lb + pd * ld;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case TransformMode.OnlyTranslation: {
|
|
||||||
float rotationY = rotation + 90 + shearY;
|
|
||||||
a = MathUtils.CosDeg(rotation + shearX) * scaleX;
|
|
||||||
b = MathUtils.CosDeg(rotationY) * scaleY;
|
|
||||||
c = MathUtils.SinDeg(rotation + shearX) * scaleX;
|
|
||||||
d = MathUtils.SinDeg(rotationY) * scaleY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TransformMode.NoRotationOrReflection: {
|
|
||||||
float s = pa * pa + pc * pc, prx;
|
|
||||||
if (s > 0.0001f) {
|
|
||||||
s = Math.Abs(pa * pd - pb * pc) / s;
|
|
||||||
pb = pc * s;
|
|
||||||
pd = pa * s;
|
|
||||||
prx = MathUtils.Atan2(pc, pa) * MathUtils.RadDeg;
|
|
||||||
} else {
|
|
||||||
pa = 0;
|
|
||||||
pc = 0;
|
|
||||||
prx = 90 - MathUtils.Atan2(pd, pb) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
float rx = rotation + shearX - prx;
|
|
||||||
float ry = rotation + shearY - prx + 90;
|
|
||||||
float la = MathUtils.CosDeg(rx) * scaleX;
|
|
||||||
float lb = MathUtils.CosDeg(ry) * scaleY;
|
|
||||||
float lc = MathUtils.SinDeg(rx) * scaleX;
|
|
||||||
float ld = MathUtils.SinDeg(ry) * scaleY;
|
|
||||||
a = pa * la - pb * lc;
|
|
||||||
b = pa * lb - pb * ld;
|
|
||||||
c = pc * la + pd * lc;
|
|
||||||
d = pc * lb + pd * ld;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TransformMode.NoScale:
|
|
||||||
case TransformMode.NoScaleOrReflection: {
|
|
||||||
float cos = MathUtils.CosDeg(rotation), sin = MathUtils.SinDeg(rotation);
|
|
||||||
float za = pa * cos + pb * sin;
|
|
||||||
float zc = pc * cos + pd * sin;
|
|
||||||
float s = (float)Math.Sqrt(za * za + zc * zc);
|
|
||||||
if (s > 0.00001f) s = 1 / s;
|
|
||||||
za *= s;
|
|
||||||
zc *= s;
|
|
||||||
s = (float)Math.Sqrt(za * za + zc * zc);
|
|
||||||
float r = MathUtils.PI / 2 + MathUtils.Atan2(zc, za);
|
|
||||||
float zb = MathUtils.Cos(r) * s;
|
|
||||||
float zd = MathUtils.Sin(r) * s;
|
|
||||||
float la = MathUtils.CosDeg(shearX) * scaleX;
|
|
||||||
float lb = MathUtils.CosDeg(90 + shearY) * scaleY;
|
|
||||||
float lc = MathUtils.SinDeg(shearX) * scaleX;
|
|
||||||
float ld = MathUtils.SinDeg(90 + shearY) * scaleY;
|
|
||||||
if (data.transformMode != TransformMode.NoScaleOrReflection? pa * pd - pb* pc< 0 : skeleton.flipX != skeleton.flipY) {
|
|
||||||
zb = -zb;
|
|
||||||
zd = -zd;
|
|
||||||
}
|
|
||||||
a = za * la + zb * lc;
|
|
||||||
b = za * lb + zb * ld;
|
|
||||||
c = zc * la + zd * lc;
|
|
||||||
d = zc * lb + zd * ld;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skeleton.flipX) {
|
|
||||||
a = -a;
|
|
||||||
b = -b;
|
|
||||||
}
|
|
||||||
if (skeleton.flipY != Bone.yDown) {
|
|
||||||
c = -c;
|
|
||||||
d = -d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetToSetupPose () {
|
void setToSetupPose();
|
||||||
BoneData data = this.data;
|
|
||||||
x = data.x;
|
void worldToLocal(float worldX, float worldY, float& outLocalX, float& outLocalY);
|
||||||
y = data.y;
|
|
||||||
rotation = data.rotation;
|
void localToWorld(float localX, float localY, float& outWorldX, float& outWorldY);
|
||||||
scaleX = data.scaleX;
|
|
||||||
scaleY = data.scaleY;
|
float worldToLocalRotation(float worldRotation);
|
||||||
shearX = data.shearX;
|
|
||||||
shearY = data.shearY;
|
float localToWorldRotation(float localRotation);
|
||||||
}
|
|
||||||
|
///
|
||||||
|
/// Rotates the world transform the specified amount and sets isAppliedValid to false.
|
||||||
|
///
|
||||||
|
/// @param degrees Degrees.
|
||||||
|
void rotateWorld(float degrees);
|
||||||
|
|
||||||
|
float getWorldToLocalRotationX();
|
||||||
|
|
||||||
|
float getWorldToLocalRotationY();
|
||||||
|
|
||||||
|
BoneData& getData();
|
||||||
|
Skeleton& getSkeleton();
|
||||||
|
Bone* getParent();
|
||||||
|
SimpleArray<Bone*>& getChildren();
|
||||||
|
|
||||||
|
/// The local X translation.
|
||||||
|
float getX();
|
||||||
|
void setX(float inValue);
|
||||||
|
|
||||||
|
/// The local Y translation.
|
||||||
|
float getY();
|
||||||
|
void setY(float inValue);
|
||||||
|
|
||||||
|
/// The local rotation.
|
||||||
|
float getRotation();
|
||||||
|
void setRotation(float inValue);
|
||||||
|
|
||||||
|
/// The local scaleX.
|
||||||
|
float getScaleX();
|
||||||
|
void setScaleX(float inValue);
|
||||||
|
|
||||||
|
/// The local scaleY.
|
||||||
|
float getScaleY();
|
||||||
|
void setScaleY(float inValue);
|
||||||
|
|
||||||
|
/// The local shearX.
|
||||||
|
float getShearX();
|
||||||
|
void setShearX(float inValue);
|
||||||
|
|
||||||
|
/// The local shearY.
|
||||||
|
float getShearY();
|
||||||
|
void setShearY(float inValue);
|
||||||
|
|
||||||
|
/// The rotation, as calculated by any constraints.
|
||||||
|
float getAppliedRotation();
|
||||||
|
void setAppliedRotation(float inValue);
|
||||||
|
|
||||||
|
/// The applied local x translation.
|
||||||
|
float getAX();
|
||||||
|
void setAX(float inValue);
|
||||||
|
|
||||||
|
/// The applied local y translation.
|
||||||
|
float getAY();
|
||||||
|
void setAY(float inValue);
|
||||||
|
|
||||||
|
/// The applied local scaleX.
|
||||||
|
float getAScaleX();
|
||||||
|
void setAScaleX(float inValue);
|
||||||
|
|
||||||
|
/// The applied local scaleY.
|
||||||
|
float getAScaleY();
|
||||||
|
void setAScaleY(float inValue);
|
||||||
|
|
||||||
|
/// The applied local shearX.
|
||||||
|
float getAShearX();
|
||||||
|
void setAShearX(float inValue);
|
||||||
|
|
||||||
|
/// The applied local shearY.
|
||||||
|
float getAShearY();
|
||||||
|
void setAShearY(float inValue);
|
||||||
|
|
||||||
|
float getA();
|
||||||
|
float getB();
|
||||||
|
float getC();
|
||||||
|
float getD();
|
||||||
|
|
||||||
|
float getWorldX();
|
||||||
|
float getWorldY();
|
||||||
|
float getWorldRotationX();
|
||||||
|
float getWorldRotationY();
|
||||||
|
|
||||||
|
/// Returns the magnitide (always positive) of the world scale X.
|
||||||
|
float getWorldScaleX();
|
||||||
|
|
||||||
|
/// Returns the magnitide (always positive) of the world scale Y.
|
||||||
|
float getWorldScaleY();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BoneData& _data;
|
||||||
|
Skeleton& _skeleton;
|
||||||
|
Bone* _parent;
|
||||||
|
SimpleArray<Bone*> _children;
|
||||||
|
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
|
||||||
|
float _ax, _ay, _arotation, _ascaleX, _ascaleY, _ashearX, _ashearY;
|
||||||
|
bool _appliedValid;
|
||||||
|
float _a, _b, _worldX;
|
||||||
|
float _c, _d, _worldY;
|
||||||
|
bool _sorted;
|
||||||
|
|
||||||
///
|
|
||||||
/// Computes the individual applied transform values from the world transform. This can be useful to perform processing using
|
/// Computes the individual applied transform values from the world transform. This can be useful to perform processing using
|
||||||
/// the applied transform after the world transform has been modified directly (eg, by a constraint)..
|
/// the applied transform after the world transform has been modified directly (eg, by a constraint)..
|
||||||
///
|
///
|
||||||
/// Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation.
|
/// Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation.
|
||||||
///
|
void updateAppliedTransform();
|
||||||
internal void UpdateAppliedTransform () {
|
|
||||||
appliedValid = true;
|
|
||||||
Bone parent = this.parent;
|
|
||||||
if (parent == null) {
|
|
||||||
ax = worldX;
|
|
||||||
ay = worldY;
|
|
||||||
arotation = MathUtils.Atan2(c, a) * MathUtils.RadDeg;
|
|
||||||
ascaleX = (float)Math.Sqrt(a * a + c * c);
|
|
||||||
ascaleY = (float)Math.Sqrt(b * b + d * d);
|
|
||||||
ashearX = 0;
|
|
||||||
ashearY = MathUtils.Atan2(a * b + c * d, a * d - b * c) * MathUtils.RadDeg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
|
||||||
float pid = 1 / (pa * pd - pb * pc);
|
|
||||||
float dx = worldX - parent.worldX, dy = worldY - parent.worldY;
|
|
||||||
ax = (dx * pd * pid - dy * pb * pid);
|
|
||||||
ay = (dy * pa * pid - dx * pc * pid);
|
|
||||||
float ia = pid * pd;
|
|
||||||
float id = pid * pa;
|
|
||||||
float ib = pid * pb;
|
|
||||||
float ic = pid * pc;
|
|
||||||
float ra = ia * a - ib * c;
|
|
||||||
float rb = ia * b - ib * d;
|
|
||||||
float rc = id * c - ic * a;
|
|
||||||
float rd = id * d - ic * b;
|
|
||||||
ashearX = 0;
|
|
||||||
ascaleX = (float)Math.Sqrt(ra * ra + rc * rc);
|
|
||||||
if (ascaleX > 0.0001f) {
|
|
||||||
float det = ra * rd - rb * rc;
|
|
||||||
ascaleY = det / ascaleX;
|
|
||||||
ashearY = MathUtils.Atan2(ra * rb + rc * rd, det) * MathUtils.RadDeg;
|
|
||||||
arotation = MathUtils.Atan2(rc, ra) * MathUtils.RadDeg;
|
|
||||||
} else {
|
|
||||||
ascaleX = 0;
|
|
||||||
ascaleY = (float)Math.Sqrt(rb * rb + rd * rd);
|
|
||||||
ashearY = 0;
|
|
||||||
arotation = 90 - MathUtils.Atan2(rd, rb) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WorldToLocal (float worldX, float worldY, out float localX, out float localY) {
|
|
||||||
float a = this.a, b = this.b, c = this.c, d = this.d;
|
|
||||||
float invDet = 1 / (a * d - b * c);
|
|
||||||
float x = worldX - this.worldX, y = worldY - this.worldY;
|
|
||||||
localX = (x * d * invDet - y * b * invDet);
|
|
||||||
localY = (y * a * invDet - x * c * invDet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LocalToWorld (float localX, float localY, out float worldX, out float worldY) {
|
|
||||||
worldX = localX * a + localY * b + this.worldX;
|
|
||||||
worldY = localX * c + localY * d + this.worldY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float WorldToLocalRotationX {
|
|
||||||
get {
|
|
||||||
Bone parent = this.parent;
|
|
||||||
if (parent == null) return arotation;
|
|
||||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c;
|
|
||||||
return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float WorldToLocalRotationY {
|
|
||||||
get {
|
|
||||||
Bone parent = this.parent;
|
|
||||||
if (parent == null) return arotation;
|
|
||||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d;
|
|
||||||
return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float WorldToLocalRotation (float worldRotation) {
|
|
||||||
float sin = MathUtils.SinDeg(worldRotation), cos = MathUtils.CosDeg(worldRotation);
|
|
||||||
return MathUtils.Atan2(a * sin - c * cos, d * cos - b * sin) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float LocalToWorldRotation (float localRotation) {
|
|
||||||
float sin = MathUtils.SinDeg(localRotation), cos = MathUtils.CosDeg(localRotation);
|
|
||||||
return MathUtils.Atan2(cos * c + sin * d, cos * a + sin * b) * MathUtils.RadDeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Rotates the world transform the specified amount and sets isAppliedValid to false.
|
|
||||||
///
|
|
||||||
/// @param degrees Degrees.
|
|
||||||
public void RotateWorld (float degrees)
|
|
||||||
{
|
|
||||||
float a = this.a, b = this.b, c = this.c, d = this.d;
|
|
||||||
float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees);
|
|
||||||
this.a = cos * a - sin * c;
|
|
||||||
this.b = cos * b - sin * d;
|
|
||||||
this.c = sin * a + cos * c;
|
|
||||||
this.d = sin * b + cos * d;
|
|
||||||
appliedValid = false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,9 +32,69 @@
|
|||||||
#define Spine_MathUtil_h
|
#define Spine_MathUtil_h
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#define SPINE_PI 3.1415927f
|
||||||
|
#define SPINE_PI_2 PI * 2
|
||||||
|
#define RadDeg 180.0f / SPINE_PI
|
||||||
|
#define DegRad SPINE_PI / 180.0f
|
||||||
|
#define SIN_BITS 14 // 16KB. Adjust for accuracy.
|
||||||
|
#define SIN_MASK ~(-(1 << SIN_BITS))
|
||||||
|
#define SIN_COUNT SIN_MASK + 1
|
||||||
|
#define RadFull SPINE_PI * 2
|
||||||
|
#define DegFull 360
|
||||||
|
#define RadToIndex SIN_COUNT / RadFull
|
||||||
|
#define DegToIndex SIN_COUNT / DegFull
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
|
inline bool areFloatsPracticallyEqual(float A, float B, float maxDiff = 0.0000000000000001f, float maxRelDiff = FLT_EPSILON)
|
||||||
|
{
|
||||||
|
// Check if the numbers are really close -- needed
|
||||||
|
// when comparing numbers near zero.
|
||||||
|
float diff = fabs(A - B);
|
||||||
|
if (diff <= maxDiff)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
A = fabs(A);
|
||||||
|
B = fabs(B);
|
||||||
|
|
||||||
|
float largest = (B > A) ? B : A;
|
||||||
|
|
||||||
|
if (diff <= largest * maxRelDiff)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MathUtil
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static float SIN_TABLE[SIN_COUNT];
|
||||||
|
|
||||||
|
MathUtil();
|
||||||
|
|
||||||
|
/// Returns the sine in radians from a lookup table.
|
||||||
|
static float sin(float radians);
|
||||||
|
|
||||||
|
/// Returns the cosine in radians from a lookup table.
|
||||||
|
static float cos(float radians);
|
||||||
|
|
||||||
|
/// Returns the sine in radians from a lookup table.
|
||||||
|
static float sinDeg(float degrees);
|
||||||
|
|
||||||
|
/// Returns the cosine in radians from a lookup table.
|
||||||
|
static float cosDeg(float degrees);
|
||||||
|
|
||||||
|
/// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323
|
||||||
|
/// degrees), largest error of 0.00488 radians (0.2796 degrees).
|
||||||
|
static float atan2(float y, float x);
|
||||||
|
};
|
||||||
|
|
||||||
inline float clamp(float x, float lower, float upper)
|
inline float clamp(float x, float lower, float upper)
|
||||||
{
|
{
|
||||||
return fminf(upper, fmaxf(x, lower));
|
return fminf(upper, fmaxf(x, lower));
|
||||||
|
|||||||
@ -30,7 +30,570 @@
|
|||||||
|
|
||||||
#include <spine/Bone.h>
|
#include <spine/Bone.h>
|
||||||
|
|
||||||
|
#include <spine/BoneData.h>
|
||||||
|
#include <spine/Skeleton.h>
|
||||||
|
|
||||||
|
#include <spine/MathUtil.h>
|
||||||
|
#include <spine/TransformMode.h>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
// TODO
|
Bone::Bone(BoneData& data, Skeleton& skeleton, Bone* parent) : Updatable(),
|
||||||
|
_data(data),
|
||||||
|
_skeleton(skeleton),
|
||||||
|
_parent(parent),
|
||||||
|
_x(0),
|
||||||
|
_y(0),
|
||||||
|
_rotation(0),
|
||||||
|
_scaleX(0),
|
||||||
|
_scaleY(0),
|
||||||
|
_shearX(0),
|
||||||
|
_shearY(0),
|
||||||
|
_ax(0),
|
||||||
|
_ay(0),
|
||||||
|
_arotation(0),
|
||||||
|
_ascaleX(0),
|
||||||
|
_ascaleY(0),
|
||||||
|
_ashearX(0),
|
||||||
|
_ashearY(0),
|
||||||
|
_appliedValid(false),
|
||||||
|
_a(0),
|
||||||
|
_b(0),
|
||||||
|
_worldX(0),
|
||||||
|
_c(0),
|
||||||
|
_d(0),
|
||||||
|
_worldY(0),
|
||||||
|
_sorted(false)
|
||||||
|
{
|
||||||
|
setToSetupPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::update()
|
||||||
|
{
|
||||||
|
updateWorldTransform(_x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::updateWorldTransform()
|
||||||
|
{
|
||||||
|
updateWorldTransform(_x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY)
|
||||||
|
{
|
||||||
|
_ax = x;
|
||||||
|
_ay = y;
|
||||||
|
_arotation = rotation;
|
||||||
|
_ascaleX = scaleX;
|
||||||
|
_ascaleY = scaleY;
|
||||||
|
_ashearX = shearX;
|
||||||
|
_ashearY = shearY;
|
||||||
|
_appliedValid = true;
|
||||||
|
Skeleton& skeleton = _skeleton;
|
||||||
|
|
||||||
|
Bone* parent = _parent;
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
// Root bone.
|
||||||
|
float rotationY = rotation + 90 + shearY;
|
||||||
|
float la = MathUtil::cosDeg(rotation + shearX) * scaleX;
|
||||||
|
float lb = MathUtil::cosDeg(rotationY) * scaleY;
|
||||||
|
float lc = MathUtil::sinDeg(rotation + shearX) * scaleX;
|
||||||
|
float ld = MathUtil::sinDeg(rotationY) * scaleY;
|
||||||
|
if (_skeleton.isFlipX())
|
||||||
|
{
|
||||||
|
x = -x;
|
||||||
|
la = -la;
|
||||||
|
lb = -lb;
|
||||||
|
}
|
||||||
|
|
||||||
|
_a = la;
|
||||||
|
_b = lb;
|
||||||
|
_c = lc;
|
||||||
|
_d = ld;
|
||||||
|
_worldX = x + _skeleton.getX();
|
||||||
|
_worldY = y + _skeleton.getY();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pa = parent->_a;
|
||||||
|
float pb = parent->_b;
|
||||||
|
float pc = parent->_c;
|
||||||
|
float pd = parent->_d;
|
||||||
|
|
||||||
|
_worldX = pa * x + pb * y + parent->_worldX;
|
||||||
|
_worldY = pc * x + pd * y + parent->_worldY;
|
||||||
|
|
||||||
|
switch (_data.getTransformMode())
|
||||||
|
{
|
||||||
|
case TransformMode_Normal:
|
||||||
|
{
|
||||||
|
float rotationY = rotation + 90 + shearY;
|
||||||
|
float la = MathUtil::cosDeg(rotation + shearX) * scaleX;
|
||||||
|
float lb = MathUtil::cosDeg(rotationY) * scaleY;
|
||||||
|
float lc = MathUtil::sinDeg(rotation + shearX) * scaleX;
|
||||||
|
float ld = MathUtil::sinDeg(rotationY) * scaleY;
|
||||||
|
_a = pa * la + pb * lc;
|
||||||
|
_b = pa * lb + pb * ld;
|
||||||
|
_c = pc * la + pd * lc;
|
||||||
|
_d = pc * lb + pd * ld;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case TransformMode_OnlyTranslation:
|
||||||
|
{
|
||||||
|
float rotationY = rotation + 90 + shearY;
|
||||||
|
_a = MathUtil::cosDeg(rotation + shearX) * scaleX;
|
||||||
|
_b = MathUtil::cosDeg(rotationY) * scaleY;
|
||||||
|
_c = MathUtil::sinDeg(rotation + shearX) * scaleX;
|
||||||
|
_d = MathUtil::sinDeg(rotationY) * scaleY;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TransformMode_NoRotationOrReflection:
|
||||||
|
{
|
||||||
|
float s = pa * pa + pc * pc, prx;
|
||||||
|
if (s > 0.0001f)
|
||||||
|
{
|
||||||
|
s = fabs(pa * pd - pb * pc) / s;
|
||||||
|
pb = pc * s;
|
||||||
|
pd = pa * s;
|
||||||
|
prx = MathUtil::atan2(pc, pa) * RadDeg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pa = 0;
|
||||||
|
pc = 0;
|
||||||
|
prx = 90 - MathUtil::atan2(pd, pb) * RadDeg;
|
||||||
|
}
|
||||||
|
float rx = rotation + shearX - prx;
|
||||||
|
float ry = rotation + shearY - prx + 90;
|
||||||
|
float la = MathUtil::cosDeg(rx) * scaleX;
|
||||||
|
float lb = MathUtil::cosDeg(ry) * scaleY;
|
||||||
|
float lc = MathUtil::sinDeg(rx) * scaleX;
|
||||||
|
float ld = MathUtil::sinDeg(ry) * scaleY;
|
||||||
|
|
||||||
|
_a = pa * la - pb * lc;
|
||||||
|
_b = pa * lb - pb * ld;
|
||||||
|
_c = pc * la + pd * lc;
|
||||||
|
_d = pc * lb + pd * ld;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TransformMode_NoScale:
|
||||||
|
case TransformMode_NoScaleOrReflection:
|
||||||
|
{
|
||||||
|
float cos = MathUtil::cosDeg(rotation);
|
||||||
|
float sin = MathUtil::sinDeg(rotation);
|
||||||
|
float za = pa * cos + pb * sin;
|
||||||
|
float zc = pc * cos + pd * sin;
|
||||||
|
float s = sqrt(za * za + zc * zc);
|
||||||
|
if (s > 0.00001f)
|
||||||
|
{
|
||||||
|
s = 1 / s;
|
||||||
|
}
|
||||||
|
|
||||||
|
za *= s;
|
||||||
|
zc *= s;
|
||||||
|
s = sqrt(za * za + zc * zc);
|
||||||
|
float r = SPINE_PI / 2 + MathUtil::atan2(zc, za);
|
||||||
|
float zb = MathUtil::cos(r) * s;
|
||||||
|
float zd = MathUtil::sin(r) * s;
|
||||||
|
float la = MathUtil::cosDeg(shearX) * scaleX;
|
||||||
|
float lb = MathUtil::cosDeg(90 + shearY) * scaleY;
|
||||||
|
float lc = MathUtil::sinDeg(shearX) * scaleX;
|
||||||
|
float ld = MathUtil::sinDeg(90 + shearY) * scaleY;
|
||||||
|
|
||||||
|
if (_data.getTransformMode() != TransformMode_NoScaleOrReflection ? pa * pd - pb * pc < 0 : _skeleton.isFlipX() != _skeleton.isFlipY())
|
||||||
|
{
|
||||||
|
zb = -zb;
|
||||||
|
zd = -zd;
|
||||||
|
}
|
||||||
|
|
||||||
|
_a = za * la + zb * lc;
|
||||||
|
_b = za * lb + zb * ld;
|
||||||
|
_c = zc * la + zd * lc;
|
||||||
|
_d = zc * lb + zd * ld;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_skeleton.isFlipX())
|
||||||
|
{
|
||||||
|
_a = -_a;
|
||||||
|
_b = -_b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setToSetupPose()
|
||||||
|
{
|
||||||
|
BoneData& data = _data;
|
||||||
|
_x = data.getX();
|
||||||
|
_y = data.getY();
|
||||||
|
_rotation = data.getRotation();
|
||||||
|
_scaleX = data.getScaleX();
|
||||||
|
_scaleY = data.getScaleY();
|
||||||
|
_shearX = data.getShearX();
|
||||||
|
_shearY = data.getShearY();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::worldToLocal(float worldX, float worldY, float& outLocalX, float& outLocalY)
|
||||||
|
{
|
||||||
|
float a = _a;
|
||||||
|
float b = _b;
|
||||||
|
float c = _c;
|
||||||
|
float d = _d;
|
||||||
|
|
||||||
|
float invDet = 1 / (a * d - b * c);
|
||||||
|
float x = worldX - _worldX;
|
||||||
|
float y = worldY - _worldY;
|
||||||
|
|
||||||
|
outLocalX = (x * d * invDet - y * b * invDet);
|
||||||
|
outLocalY = (y * a * invDet - x * c * invDet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::localToWorld(float localX, float localY, float& outWorldX, float& outWorldY)
|
||||||
|
{
|
||||||
|
outWorldX = localX * _a + localY * _b + _worldX;
|
||||||
|
outWorldY = localX * _c + localY * _d + _worldY;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::worldToLocalRotation(float worldRotation)
|
||||||
|
{
|
||||||
|
float sin = MathUtil::sinDeg(worldRotation);
|
||||||
|
float cos = MathUtil::cosDeg(worldRotation);
|
||||||
|
|
||||||
|
return MathUtil::atan2(_a * sin - _c * cos, _d * cos - _b * sin) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::localToWorldRotation(float localRotation)
|
||||||
|
{
|
||||||
|
float sin = MathUtil::sinDeg(localRotation);
|
||||||
|
float cos = MathUtil::cosDeg(localRotation);
|
||||||
|
|
||||||
|
return MathUtil::atan2(cos * _c + sin * _d, cos * _a + sin * _b) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::rotateWorld(float degrees)
|
||||||
|
{
|
||||||
|
float a = _a;
|
||||||
|
float b = _b;
|
||||||
|
float c = _c;
|
||||||
|
float d = _d;
|
||||||
|
|
||||||
|
float cos = MathUtil::cosDeg(degrees);
|
||||||
|
float sin = MathUtil::sinDeg(degrees);
|
||||||
|
|
||||||
|
_a = cos * a - sin * c;
|
||||||
|
_b = cos * b - sin * d;
|
||||||
|
_c = sin * a + cos * c;
|
||||||
|
_d = sin * b + cos * d;
|
||||||
|
|
||||||
|
_appliedValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldToLocalRotationX()
|
||||||
|
{
|
||||||
|
Bone* parent = _parent;
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
return _arotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pa = parent->_a;
|
||||||
|
float pb = parent->_b;
|
||||||
|
float pc = parent->_c;
|
||||||
|
float pd = parent->_d;
|
||||||
|
float a = _a;
|
||||||
|
float c = _c;
|
||||||
|
|
||||||
|
return MathUtil::atan2(pa * c - pc * a, pd * a - pb * c) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldToLocalRotationY()
|
||||||
|
{
|
||||||
|
Bone* parent = _parent;
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
return _arotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pa = parent->_a;
|
||||||
|
float pb = parent->_b;
|
||||||
|
float pc = parent->_c;
|
||||||
|
float pd = parent->_d;
|
||||||
|
float b = _b;
|
||||||
|
float d = _d;
|
||||||
|
|
||||||
|
return MathUtil::atan2(pa * d - pc * b, pd * b - pb * d) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoneData& Bone::getData()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Skeleton& Bone::getSkeleton()
|
||||||
|
{
|
||||||
|
return _skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bone* Bone::getParent()
|
||||||
|
{
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleArray<Bone*>& Bone::getChildren()
|
||||||
|
{
|
||||||
|
return _children;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getX()
|
||||||
|
{
|
||||||
|
return _x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setX(float inValue)
|
||||||
|
{
|
||||||
|
_x = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getY()
|
||||||
|
{
|
||||||
|
return _y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setY(float inValue)
|
||||||
|
{
|
||||||
|
_y = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getRotation()
|
||||||
|
{
|
||||||
|
return _rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setRotation(float inValue)
|
||||||
|
{
|
||||||
|
_rotation = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getScaleX()
|
||||||
|
{
|
||||||
|
return _scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setScaleX(float inValue)
|
||||||
|
{
|
||||||
|
_scaleX = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getScaleY()
|
||||||
|
{
|
||||||
|
return _scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setScaleY(float inValue)
|
||||||
|
{
|
||||||
|
_scaleY = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getShearX()
|
||||||
|
{
|
||||||
|
return _shearX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setShearX(float inValue)
|
||||||
|
{
|
||||||
|
_shearX = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getShearY()
|
||||||
|
{
|
||||||
|
return _shearY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setShearY(float inValue)
|
||||||
|
{
|
||||||
|
_shearY = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAppliedRotation()
|
||||||
|
{
|
||||||
|
return _arotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAppliedRotation(float inValue)
|
||||||
|
{
|
||||||
|
_arotation = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAX()
|
||||||
|
{
|
||||||
|
return _ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAX(float inValue)
|
||||||
|
{
|
||||||
|
_ax = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAY()
|
||||||
|
{
|
||||||
|
return _ay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAY(float inValue)
|
||||||
|
{
|
||||||
|
_ay = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAScaleX()
|
||||||
|
{
|
||||||
|
return _ascaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAScaleX(float inValue)
|
||||||
|
{
|
||||||
|
_ascaleX = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAScaleY()
|
||||||
|
{
|
||||||
|
return _ascaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAScaleY(float inValue)
|
||||||
|
{
|
||||||
|
_ascaleY = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAShearX()
|
||||||
|
{
|
||||||
|
return _ashearX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAShearX(float inValue)
|
||||||
|
{
|
||||||
|
_ashearX = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getAShearY()
|
||||||
|
{
|
||||||
|
return _ashearY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::setAShearY(float inValue)
|
||||||
|
{
|
||||||
|
_ashearY = inValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getA()
|
||||||
|
{
|
||||||
|
return _a;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getB()
|
||||||
|
{
|
||||||
|
return _b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getC()
|
||||||
|
{
|
||||||
|
return _c;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getD()
|
||||||
|
{
|
||||||
|
return _d;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldX()
|
||||||
|
{
|
||||||
|
return _worldX;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldY()
|
||||||
|
{
|
||||||
|
return _worldY;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldRotationX()
|
||||||
|
{
|
||||||
|
return MathUtil::atan2(_c, _a) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldRotationY()
|
||||||
|
{
|
||||||
|
return MathUtil::atan2(_d, _b) * RadDeg;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldScaleX()
|
||||||
|
{
|
||||||
|
return sqrt(_a * _a + _c * _c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Bone::getWorldScaleY()
|
||||||
|
{
|
||||||
|
return sqrt(_b * _b + _d * _d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bone::updateAppliedTransform()
|
||||||
|
{
|
||||||
|
_appliedValid = true;
|
||||||
|
Bone* parent = _parent;
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
_ax = _worldX;
|
||||||
|
_ay = _worldY;
|
||||||
|
_arotation = MathUtil::atan2(_c, _a) * RadDeg;
|
||||||
|
_ascaleX = sqrt(_a * _a + _c * _c);
|
||||||
|
_ascaleY = sqrt(_b * _b + _d * _d);
|
||||||
|
_ashearX = 0;
|
||||||
|
_ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * RadDeg;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pa = parent->_a;
|
||||||
|
float pb = parent->_b;
|
||||||
|
float pc = parent->_c;
|
||||||
|
float pd = parent->_d;
|
||||||
|
|
||||||
|
float pid = 1 / (pa * pd - pb * pc);
|
||||||
|
float dx = _worldX - parent->_worldX;
|
||||||
|
float dy = _worldY - parent->_worldY;
|
||||||
|
|
||||||
|
_ax = (dx * pd * pid - dy * pb * pid);
|
||||||
|
_ay = (dy * pa * pid - dx * pc * pid);
|
||||||
|
|
||||||
|
float ia = pid * pd;
|
||||||
|
float id = pid * pa;
|
||||||
|
float ib = pid * pb;
|
||||||
|
float ic = pid * pc;
|
||||||
|
|
||||||
|
float ra = ia * _a - ib * _c;
|
||||||
|
float rb = ia * _b - ib * _d;
|
||||||
|
float rc = id * _c - ic * _a;
|
||||||
|
float rd = id * _d - ic * _b;
|
||||||
|
|
||||||
|
_ashearX = 0;
|
||||||
|
_ascaleX = sqrt(ra * ra + rc * rc);
|
||||||
|
|
||||||
|
if (_ascaleX > 0.0001f)
|
||||||
|
{
|
||||||
|
float det = ra * rd - rb * rc;
|
||||||
|
_ascaleY = det / _ascaleX;
|
||||||
|
_ashearY = MathUtil::atan2(ra * rb + rc * rd, det) * RadDeg;
|
||||||
|
_arotation = MathUtil::atan2(rc, ra) * RadDeg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ascaleX = 0;
|
||||||
|
_ascaleY = sqrt(rb * rb + rd * rd);
|
||||||
|
_ashearY = 0;
|
||||||
|
_arotation = 90 - MathUtil::atan2(rd, rb) * RadDeg;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
110
spine-cpp/spine-cpp/src/spine/MathUtil.cpp
Normal file
110
spine-cpp/spine-cpp/src/spine/MathUtil.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes Software License v2.5
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2016, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||||
|
* non-transferable license to use, install, execute, and perform the Spine
|
||||||
|
* Runtimes software and derivative works solely for personal or internal
|
||||||
|
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||||
|
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||||
|
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||||
|
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||||
|
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||||
|
* or other intellectual property or proprietary rights notices on or in the
|
||||||
|
* Software, including any copy thereof. Redistributions in binary or source
|
||||||
|
* form must include this license and terms.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||||
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <spine/MathUtil.h>
|
||||||
|
|
||||||
|
namespace Spine
|
||||||
|
{
|
||||||
|
float MathUtil::SIN_TABLE[SIN_COUNT] = {0.0f};
|
||||||
|
|
||||||
|
MathUtil::MathUtil()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIN_COUNT; ++i)
|
||||||
|
{
|
||||||
|
SIN_TABLE[i] = (float)sin((i + 0.5f) / SIN_COUNT * RadFull);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 360; i += 90)
|
||||||
|
{
|
||||||
|
SIN_TABLE[(int)(i * DegToIndex) & SIN_MASK] = (float)sin(i * DegRad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sine in radians from a lookup table.
|
||||||
|
float MathUtil::sin(float radians)
|
||||||
|
{
|
||||||
|
return SIN_TABLE[(int)(radians * RadToIndex) & SIN_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the cosine in radians from a lookup table.
|
||||||
|
float MathUtil::cos(float radians)
|
||||||
|
{
|
||||||
|
return SIN_TABLE[(int)((radians + SPINE_PI / 2) * RadToIndex) & SIN_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the sine in radians from a lookup table.
|
||||||
|
float MathUtil::sinDeg(float degrees)
|
||||||
|
{
|
||||||
|
return SIN_TABLE[(int)(degrees * DegToIndex) & SIN_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the cosine in radians from a lookup table.
|
||||||
|
float MathUtil::cosDeg(float degrees)
|
||||||
|
{
|
||||||
|
return SIN_TABLE[(int)((degrees + 90) * DegToIndex) & SIN_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323
|
||||||
|
/// degrees), largest error of 0.00488 radians (0.2796 degrees).
|
||||||
|
float MathUtil::atan2(float y, float x)
|
||||||
|
{
|
||||||
|
if (areFloatsPracticallyEqual(x, 0.0f))
|
||||||
|
{
|
||||||
|
if (y > 0.0f)
|
||||||
|
{
|
||||||
|
return SPINE_PI / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (areFloatsPracticallyEqual(y, 0.0f))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -SPINE_PI / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float atan, z = y / x;
|
||||||
|
|
||||||
|
if (fabs(z) < 1.0f)
|
||||||
|
{
|
||||||
|
atan = z / (1.0f + 0.28f * z * z);
|
||||||
|
if (x < 0.0f)
|
||||||
|
{
|
||||||
|
return atan + (y < 0.0f ? -SPINE_PI : SPINE_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atan;
|
||||||
|
}
|
||||||
|
|
||||||
|
atan = SPINE_PI / 2 - z / (z * z + 0.28f);
|
||||||
|
|
||||||
|
return y < 0.0f ? atan - SPINE_PI : atan;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user