[cpp] Fixed up Bone and MathUtil.

This commit is contained in:
badlogic 2018-02-23 16:15:25 +01:00
parent 7a18b81226
commit d631b252be
3 changed files with 105 additions and 153 deletions

View File

@ -37,10 +37,10 @@
#include <string.h> #include <string.h>
namespace Spine { namespace Spine {
static const float PI = 3.1415927f; static const float PI = 3.1415926535897932385f;
static const float PI_2 = PI * 2; static const float PI_2 = PI * 2;
static const float RAD_DEG = (180.0f / PI);
static const float DEG_RAD = (PI / 180.0f); static const float DEG_RAD = (PI / 180.0f);
static const float RAD_DEG = (180.0f / PI);
class MathUtil : public SpineObject { class MathUtil : public SpineObject {
public: public:
@ -52,8 +52,6 @@ namespace Spine {
static int sign(float val); static int sign(float val);
static bool areFloatsPracticallyEqual(float A, float B, float maxDiff = 0.0000000000000001f, float maxRelDiff = FLT_EPSILON);
static float clamp(float x, float lower, float upper); static float clamp(float x, float lower, float upper);
static float abs(float v); static float abs(float v);

View File

@ -68,11 +68,11 @@ namespace Spine {
_ashearX(0), _ashearX(0),
_ashearY(0), _ashearY(0),
_appliedValid(false), _appliedValid(false),
_a(0), _a(1),
_b(0), _b(0),
_worldX(0),
_c(0), _c(0),
_d(0), _d(1),
_worldX(0),
_worldY(0), _worldY(0),
_sorted(false) { _sorted(false) {
setToSetupPose(); setToSetupPose();
@ -87,6 +87,10 @@ namespace Spine {
} }
void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
float cosine, sine;
float pa, pb, pc, pd;
Bone* parent = _parent;
_ax = x; _ax = x;
_ay = y; _ay = y;
_arotation = rotation; _arotation = rotation;
@ -95,11 +99,8 @@ namespace Spine {
_ashearX = shearX; _ashearX = shearX;
_ashearY = shearY; _ashearY = shearY;
_appliedValid = true; _appliedValid = true;
Skeleton& skeleton = _skeleton;
Bone* parent = _parent; if (!parent) { /* Root bone. */
if (!parent) {
// Root bone.
float rotationY = rotation + 90 + shearY; float rotationY = rotation + 90 + shearY;
float la = MathUtil::cosDeg(rotation + shearX) * scaleX; float la = MathUtil::cosDeg(rotation + shearX) * scaleX;
float lb = MathUtil::cosDeg(rotationY) * scaleY; float lb = MathUtil::cosDeg(rotationY) * scaleY;
@ -110,27 +111,24 @@ namespace Spine {
la = -la; la = -la;
lb = -lb; lb = -lb;
} }
if (_skeleton.getFlipY() != yDown) {
if (_skeleton.getFlipY() != Bone::isYDown()) {
y = -y; y = -y;
lc = -lc; lc = -lc;
ld = -ld; ld = -ld;
} }
_a = la; _a = la;
_b = lb; _b = lb;
_c = lc; _c = lc;
_d = ld; _d = ld;
_worldX = x + _skeleton.getX(); _worldX = x + _skeleton.getX();
_worldY = y + _skeleton.getY(); _worldY = y + _skeleton.getY();
return; return;
} }
float pa = parent->_a; pa = parent->_a;
float pb = parent->_b; pb = parent->_b;
float pc = parent->_c; pc = parent->_c;
float pd = parent->_d; pd = parent->_d;
_worldX = pa * x + pb * y + parent->_worldX; _worldX = pa * x + pb * y + parent->_worldX;
_worldY = pc * x + pd * y + parent->_worldY; _worldY = pc * x + pd * y + parent->_worldY;
@ -146,7 +144,6 @@ namespace Spine {
_b = pa * lb + pb * ld; _b = pa * lb + pb * ld;
_c = pc * la + pd * lc; _c = pc * la + pd * lc;
_d = pc * lb + pd * ld; _d = pc * lb + pd * ld;
return; return;
} }
case TransformMode_OnlyTranslation: { case TransformMode_OnlyTranslation: {
@ -155,80 +152,70 @@ namespace Spine {
_b = MathUtil::cosDeg(rotationY) * scaleY; _b = MathUtil::cosDeg(rotationY) * scaleY;
_c = MathUtil::sinDeg(rotation + shearX) * scaleX; _c = MathUtil::sinDeg(rotation + shearX) * scaleX;
_d = MathUtil::sinDeg(rotationY) * scaleY; _d = MathUtil::sinDeg(rotationY) * scaleY;
break; break;
} }
case TransformMode_NoRotationOrReflection: { case TransformMode_NoRotationOrReflection: {
float s = pa * pa + pc * pc, prx; float s = pa * pa + pc * pc;
float prx, rx, ry, la, lb, lc, ld;
if (s > 0.0001f) { if (s > 0.0001f) {
s = MathUtil::abs(pa * pd - pb * pc) / s; s = MathUtil::abs(pa * pd - pb * pc) / s;
pb = pc * s; pb = pc * s;
pd = pa * s; pd = pa * s;
prx = MathUtil::atan2(pc, pa) * RAD_DEG; prx = MathUtil::atan2(pc, pa) * RAD_DEG;
} } else {
else {
pa = 0; pa = 0;
pc = 0; pc = 0;
prx = 90 - MathUtil::atan2(pd, pb) * RAD_DEG; prx = 90 - MathUtil::atan2(pd, pb) * RAD_DEG;
} }
float rx = rotation + shearX - prx; rx = rotation + shearX - prx;
float ry = rotation + shearY - prx + 90; ry = rotation + shearY - prx + 90;
float la = MathUtil::cosDeg(rx) * scaleX; la = MathUtil::cosDeg(rx) * scaleX;
float lb = MathUtil::cosDeg(ry) * scaleY; lb = MathUtil::cosDeg(ry) * scaleY;
float lc = MathUtil::sinDeg(rx) * scaleX; lc = MathUtil::sinDeg(rx) * scaleX;
float ld = MathUtil::sinDeg(ry) * scaleY; ld = MathUtil::sinDeg(ry) * scaleY;
_a = pa * la - pb * lc; _a = pa * la - pb * lc;
_b = pa * lb - pb * ld; _b = pa * lb - pb * ld;
_c = pc * la + pd * lc; _c = pc * la + pd * lc;
_d = pc * lb + pd * ld; _d = pc * lb + pd * ld;
break; break;
} }
case TransformMode_NoScale: case TransformMode_NoScale:
case TransformMode_NoScaleOrReflection: { case TransformMode_NoScaleOrReflection: {
float cos = MathUtil::cosDeg(rotation); float za, zc, s;
float sin = MathUtil::sinDeg(rotation); float r, zb, zd, la, lb, lc, ld;
float za = pa * cos + pb * sin; cosine = MathUtil::cosDeg(rotation); sine = MathUtil::sinDeg(rotation);
float zc = pc * cos + pd * sin; za = pa * cosine + pb * sine;
float s = MathUtil::sqrt(za * za + zc * zc); zc = pc * cosine + pd * sine;
if (s > 0.00001f) { s = MathUtil::sqrt(za * za + zc * zc);
s = 1 / s; if (s > 0.00001f) s = 1 / s;
}
za *= s; za *= s;
zc *= s; zc *= s;
s = MathUtil::sqrt(za * za + zc * zc); s = MathUtil::sqrt(za * za + zc * zc);
float r = PI / 2 + MathUtil::atan2(zc, za); r = PI / 2 + MathUtil::atan2(zc, za);
float zb = MathUtil::cos(r) * s; zb = MathUtil::cos(r) * s;
float zd = MathUtil::sin(r) * s; zd = MathUtil::sin(r) * s;
float la = MathUtil::cosDeg(shearX) * scaleX; la = MathUtil::cosDeg(shearX) * scaleX;
float lb = MathUtil::cosDeg(90 + shearY) * scaleY; lb = MathUtil::cosDeg(90 + shearY) * scaleY;
float lc = MathUtil::sinDeg(shearX) * scaleX; lc = MathUtil::sinDeg(shearX) * scaleX;
float ld = MathUtil::sinDeg(90 + shearY) * scaleY; ld = MathUtil::sinDeg(90 + shearY) * scaleY;
if (getData().getTransformMode() != TransformMode_NoScaleOrReflection ? pa * pd - pb * pc < 0 : _skeleton.getFlipX() != _skeleton.getFlipY()) {
if (_data.getTransformMode() != TransformMode_NoScaleOrReflection ? pa * pd - pb * pc < 0 : _skeleton.getFlipX() != _skeleton.getFlipY()) {
zb = -zb; zb = -zb;
zd = -zd; zd = -zd;
} }
_a = za * la + zb * lc; _a = za * la + zb * lc;
_b = za * lb + zb * ld; _b = za * lb + zb * ld;
_c = zc * la + zd * lc; _c = zc * la + zd * lc;
_d = zc * lb + zd * ld; _d = zc * lb + zd * ld;
return; return;
} }
} }
if (_skeleton.getFlipX()) { if (_skeleton.getFlipX()) {
_a = -_a; _a = -_a;
_b = -_b; _b = -_b;
} }
if (_skeleton.getFlipY() != yDown) {
if (skeleton.getFlipY() != Bone::isYDown()) { _c = -_c;
_c = -_c; _d = -_d;
_d = -_d;
} }
} }
@ -518,8 +505,8 @@ namespace Spine {
} }
void Bone::updateAppliedTransform() { void Bone::updateAppliedTransform() {
_appliedValid = true;
Bone* parent = _parent; Bone* parent = _parent;
_appliedValid = 1;
if (!parent) { if (!parent) {
_ax = _worldX; _ax = _worldX;
_ay = _worldY; _ay = _worldY;
@ -528,46 +515,33 @@ namespace Spine {
_ascaleY = MathUtil::sqrt(_b * _b + _d * _d); _ascaleY = MathUtil::sqrt(_b * _b + _d * _d);
_ashearX = 0; _ashearX = 0;
_ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * RAD_DEG; _ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * RAD_DEG;
} else {
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;
float pa = parent->_a; float ia = pid * pd;
float pb = parent->_b; float id = pid * pa;
float pc = parent->_c; float ib = pid * pb;
float pd = parent->_d; float ic = pid * pc;
float ra = ia * _a - ib * _c;
float pid = 1 / (pa * pd - pb * pc); float rb = ia * _b - ib * _d;
float dx = _worldX - parent->_worldX; float rc = id * _c - ic * _a;
float dy = _worldY - parent->_worldY; float rd = id * _d - ic * _b;
_ax = (dx * pd * pid - dy * pb * pid);
_ax = (dx * pd * pid - dy * pb * pid); _ay = (dy * pa * pid - dx * pc * pid);
_ay = (dy * pa * pid - dx * pc * pid); _ashearX = 0;
_ascaleX = MathUtil::sqrt(ra * ra + rc * rc);
float ia = pid * pd; if (_ascaleX > 0.0001f) {
float id = pid * pa; float det = ra * rd - rb * rc;
float ib = pid * pb; _ascaleY = det / _ascaleX;
float ic = pid * pc; _ashearY = MathUtil::atan2(ra * rb + rc * rd, det) * RAD_DEG;
_arotation = MathUtil::atan2(rc, ra) * RAD_DEG;
float ra = ia * _a - ib * _c; } else {
float rb = ia * _b - ib * _d; _ascaleX = 0;
float rc = id * _c - ic * _a; _ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
float rd = id * _d - ic * _b; _ashearY = 0;
_arotation = 90 - MathUtil::atan2(rd, rb) * RAD_DEG;
_ashearX = 0; }
_ascaleX = MathUtil::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) * RAD_DEG;
_arotation = MathUtil::atan2(rc, ra) * RAD_DEG;
}
else {
_ascaleX = 0;
_ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
_ashearY = 0;
_arotation = 90 - MathUtil::atan2(rd, rb) * RAD_DEG;
} }
} }

View File

@ -32,32 +32,31 @@
#include <math.h> #include <math.h>
namespace Spine { namespace Spine {
int MathUtil::sign(float val) { float MathUtil::abs(float v) {
return (0 < val) - (val < 0); return ((v) < 0? -(v): (v));
} }
bool MathUtil::areFloatsPracticallyEqual(float A, float B, float maxDiff, float maxRelDiff) { int MathUtil::sign(float v) {
// Check if the numbers are really close -- needed return ((v) < 0? -1: (v) > 0 ? 1 : 0);
// 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;
} }
float MathUtil::clamp(float x, float lower, float upper) { float MathUtil::clamp(float x, float min, float max) {
return fminf(upper, fmaxf(x, lower)); return((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)));
}
float MathUtil::fmod(float a, float b) {
return ::fmod(a, b);
}
/// 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) {
return ::atan2(y, x);
}
/// Returns the cosine in radians from a lookup table.
float MathUtil::cos(float radians) {
return ::cos(radians);
} }
/// Returns the sine in radians from a lookup table. /// Returns the sine in radians from a lookup table.
@ -65,9 +64,12 @@ namespace Spine {
return ::sin(radians); return ::sin(radians);
} }
/// Returns the cosine in radians from a lookup table. float MathUtil::sqrt(float v) {
float MathUtil::cos(float radians) { return ::sqrt(v);
return ::cos(radians); }
float MathUtil::acos(float v) {
return ::acos(v);
} }
/// Returns the sine in radians from a lookup table. /// Returns the sine in radians from a lookup table.
@ -80,28 +82,6 @@ namespace Spine {
return ::cos(degrees * DEG_RAD); return ::cos(degrees * DEG_RAD);
} }
/// 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) {
return ::atan2(y, x);
}
float MathUtil::acos(float v) {
return ::acos(v);
}
float MathUtil::sqrt(float v) {
return ::sqrt(v);
}
float MathUtil::fmod(float a, float b) {
return ::fmod(a, b);
}
float MathUtil::abs(float v) {
return ::fabs(v);
}
/* Need to pass 0 as an argument, so VC++ doesn't error with C2124 */ /* Need to pass 0 as an argument, so VC++ doesn't error with C2124 */
static bool _isNan(float value, float zero) { static bool _isNan(float value, float zero) {
float _nan = (float)0.0 / zero; float _nan = (float)0.0 / zero;