diff --git a/spine-cpp/spine-cpp/include/spine/MathUtil.h b/spine-cpp/spine-cpp/include/spine/MathUtil.h index 645294509..17a49daab 100644 --- a/spine-cpp/spine-cpp/include/spine/MathUtil.h +++ b/spine-cpp/spine-cpp/include/spine/MathUtil.h @@ -33,8 +33,8 @@ #include -#include #include +#include #define SPINE_PI 3.1415927f #define SPINE_PI_2 (SPINE_PI * 2) @@ -50,39 +50,20 @@ #define MAX(a, b) ((((a) > (b)) ? (a) : (b))) #define MIN(a, b) ((((a) < (b)) ? (a) : (b))) + namespace Spine { - template - int sign(T val) { - return (T(0) < val) - (val < T(0)); - } - - 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; - } - - inline float clamp(float x, float lower, float upper) { - return fminf(upper, fmaxf(x, lower)); - } class MathUtil : public SpineObject { public: MathUtil(); + + 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 abs(float v); /// Returns the sine in radians from a lookup table. static float sin(float radians); @@ -99,6 +80,14 @@ namespace Spine { /// 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); + + static float acos(float v); + + static float sqrt(float v); + + static float fmod(float a, float b); + + static bool isNan(float v); private: static float SIN_TABLE[SIN_COUNT]; diff --git a/spine-cpp/spine-cpp/src/spine/Animation.cpp b/spine-cpp/spine-cpp/src/spine/Animation.cpp index fabee44a1..501b994fc 100644 --- a/spine-cpp/spine-cpp/src/spine/Animation.cpp +++ b/spine-cpp/spine-cpp/src/spine/Animation.cpp @@ -37,7 +37,6 @@ #include #include -#include /* fmod */ namespace Spine { Animation::Animation(const String& name, Vector& timelines, float duration) : @@ -53,9 +52,9 @@ namespace Spine { void Animation::apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector* pEvents, float alpha, MixPose pose, MixDirection direction) { if (loop && _duration != 0) { - time = fmod(time, _duration); + time = MathUtil::fmod(time, _duration); if (lastTime > 0) { - lastTime = fmod(lastTime, _duration); + lastTime = MathUtil::fmod(lastTime, _duration); } } diff --git a/spine-cpp/spine-cpp/src/spine/AnimationState.cpp b/spine-cpp/spine-cpp/src/spine/AnimationState.cpp index d5ccf90e3..b7759c40c 100644 --- a/spine-cpp/spine-cpp/src/spine/AnimationState.cpp +++ b/spine-cpp/spine-cpp/src/spine/AnimationState.cpp @@ -90,7 +90,7 @@ namespace Spine { return _animationStart; } - return fmodf(_trackTime, duration) + _animationStart; + return MathUtil::fmod(_trackTime, duration) + _animationStart; } return MIN(_trackTime + _animationStart, _animationEnd); @@ -705,17 +705,17 @@ namespace Spine { bool current = diff > 0, dir = lastTotal >= 0; // Detect cross at 0 (not 180). - if (sign(lastDiff) != sign(diff) && fabs(lastDiff) <= 90) { + if (MathUtil::sign(lastDiff) != MathUtil::sign(diff) && MathUtil::abs(lastDiff) <= 90) { // A cross after a 360 rotation is a loop. - if (fabs(lastTotal) > 180) { - lastTotal += 360 * sign(lastTotal); + if (MathUtil::abs(lastTotal) > 180) { + lastTotal += 360 * MathUtil::sign(lastTotal); } dir = current; } - total = diff + lastTotal - fmod(lastTotal, 360); // Store loops as part of lastTotal. + total = diff + lastTotal - MathUtil::fmod(lastTotal, 360); // Store loops as part of lastTotal. if (dir != current) { - total += 360 * sign(lastTotal); + total += 360 * MathUtil::sign(lastTotal); } timelinesRotation[i] = total; } @@ -847,7 +847,7 @@ namespace Spine { void AnimationState::queueEvents(TrackEntry* entry, float animationTime) { float animationStart = entry->_animationStart, animationEnd = entry->_animationEnd; float duration = animationEnd - animationStart; - float trackLastWrapped = fmodf(entry->_trackLast, duration); + float trackLastWrapped = MathUtil::fmod(entry->_trackLast, duration); // Queue events before complete. int i = 0, n = static_cast(_events.size()); @@ -864,7 +864,7 @@ namespace Spine { } // Queue complete if completed a loop iteration or the animation. - if (entry->_loop ? (trackLastWrapped > fmod(entry->_trackTime, duration)) : (animationTime >= animationEnd && entry->_animationLast < animationEnd)) { + if (entry->_loop ? (trackLastWrapped > MathUtil::fmod(entry->_trackTime, duration)) : (animationTime >= animationEnd && entry->_animationLast < animationEnd)) { _queue->complete(entry); } diff --git a/spine-cpp/spine-cpp/src/spine/Bone.cpp b/spine-cpp/spine-cpp/src/spine/Bone.cpp index 184b1c0e1..9b33d7d1f 100644 --- a/spine-cpp/spine-cpp/src/spine/Bone.cpp +++ b/spine-cpp/spine-cpp/src/spine/Bone.cpp @@ -161,7 +161,7 @@ namespace Spine { case TransformMode_NoRotationOrReflection: { float s = pa * pa + pc * pc, prx; if (s > 0.0001f) { - s = fabs(pa * pd - pb * pc) / s; + s = MathUtil::abs(pa * pd - pb * pc) / s; pb = pc * s; pd = pa * s; prx = MathUtil::atan2(pc, pa) * RadDeg; @@ -191,14 +191,14 @@ namespace Spine { float sin = MathUtil::sinDeg(rotation); float za = pa * cos + pb * sin; float zc = pc * cos + pd * sin; - float s = sqrt(za * za + zc * zc); + float s = MathUtil::sqrt(za * za + zc * zc); if (s > 0.00001f) { s = 1 / s; } za *= s; zc *= s; - s = sqrt(za * za + zc * zc); + s = MathUtil::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; @@ -510,11 +510,11 @@ namespace Spine { } float Bone::getWorldScaleX() { - return sqrt(_a * _a + _c * _c); + return MathUtil::sqrt(_a * _a + _c * _c); } float Bone::getWorldScaleY() { - return sqrt(_b * _b + _d * _d); + return MathUtil::sqrt(_b * _b + _d * _d); } void Bone::updateAppliedTransform() { @@ -524,8 +524,8 @@ namespace Spine { _ax = _worldX; _ay = _worldY; _arotation = MathUtil::atan2(_c, _a) * RadDeg; - _ascaleX = sqrt(_a * _a + _c * _c); - _ascaleY = sqrt(_b * _b + _d * _d); + _ascaleX = MathUtil::sqrt(_a * _a + _c * _c); + _ascaleY = MathUtil::sqrt(_b * _b + _d * _d); _ashearX = 0; _ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * RadDeg; @@ -555,7 +555,7 @@ namespace Spine { float rd = id * _d - ic * _b; _ashearX = 0; - _ascaleX = sqrt(ra * ra + rc * rc); + _ascaleX = MathUtil::sqrt(ra * ra + rc * rc); if (_ascaleX > 0.0001f) { float det = ra * rd - rb * rc; @@ -565,7 +565,7 @@ namespace Spine { } else { _ascaleX = 0; - _ascaleY = sqrt(rb * rb + rd * rd); + _ascaleY = MathUtil::sqrt(rb * rb + rd * rd); _ashearY = 0; _arotation = 90 - MathUtil::atan2(rd, rb) * RadDeg; } diff --git a/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp b/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp index 10ff0ce37..431cf372a 100644 --- a/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp +++ b/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp @@ -85,7 +85,7 @@ namespace Spine { } float CurveTimeline::getCurvePercent(int frameIndex, float percent) { - percent = clamp(percent, 0, 1); + percent = MathUtil::clamp(percent, 0, 1); int i = frameIndex * BEZIER_SIZE; float type = _curves[i]; diff --git a/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp b/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp index 9973a2865..753ac6848 100644 --- a/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp @@ -51,7 +51,7 @@ namespace Spine { float id = 1 / (p._a * p._d - p._b * p._c); float x = targetX - p._worldX, y = targetY - p._worldY; float tx = (x * p._d - y * p._b) * id - bone._ax, ty = (y * p._a - x * p._c) * id - bone._ay; - float rotationIK = atan2(ty, tx) * RadDeg - bone._ashearX - bone._arotation; + float rotationIK = MathUtil::atan2(ty, tx) * RadDeg - bone._ashearX - bone._arotation; if (bone._ascaleX < 0) { rotationIK += 180; @@ -68,7 +68,7 @@ namespace Spine { } void IkConstraint::apply(Bone& parent, Bone& child, float targetX, float targetY, int bendDir, float alpha) { - if (areFloatsPracticallyEqual(alpha, 0)) { + if (MathUtil::areFloatsPracticallyEqual(alpha, 0)) { child.updateWorldTransform(); return; @@ -121,7 +121,7 @@ namespace Spine { float c = parent._c; float d = parent._d; - bool u = fabs(psx - psy) <= 0.0001f; + bool u = MathUtil::abs(psx - psy) <= 0.0001f; if (!u) { cy = 0; cwx = a * cx + parent._worldX; @@ -146,7 +146,7 @@ namespace Spine { x = cwx - pp._worldX; y = cwy - pp._worldY; float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; - float l1 = sqrt(dx * dx + dy * dy), l2 = child._data.getLength() * csx, a1, a2; + float l1 = MathUtil::sqrt(dx * dx + dy * dy), l2 = child._data.getLength() * csx, a1, a2; if (u) { l2 *= psx; float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); @@ -157,30 +157,30 @@ namespace Spine { cos = 1; } - a2 = acos(cos) * bendDir; + a2 = MathUtil::acos(cos) * bendDir; a = l1 + l2 * cos; - b = l2 * sin(a2); - a1 = atan2(ty * a - tx * b, tx * a + ty * b); + b = l2 * MathUtil::sin(a2); + a1 = MathUtil::atan2(ty * a - tx * b, tx * a + ty * b); } else { a = psx * l2; b = psy * l2; - float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = atan2(ty, tx); + float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = MathUtil::atan2(ty, tx); c = bb * l1 * l1 + aa * dd - aa * bb; float c1 = -2 * bb * l1, c2 = bb - aa; d = c1 * c1 - 4 * c2 * c; if (d >= 0) { - float q = sqrt(d); + float q = MathUtil::sqrt(d); if (c1 < 0) q = -q; q = -(c1 + q) / 2; float r0 = q / c2, r1 = c / q; - float r = fabs(r0) < fabs(r1) ? r0 : r1; + float r = MathUtil::abs(r0) < MathUtil::abs(r1) ? r0 : r1; if (r * r <= dd) { - y = sqrt(dd - r * r) * bendDir; - a1 = ta - atan2(y, r); - a2 = atan2(y / psy, (r - l1) / psx); + y = MathUtil::sqrt(dd - r * r) * bendDir; + a1 = ta - MathUtil::atan2(y, r); + a2 = MathUtil::atan2(y / psy, (r - l1) / psx); - float os = atan2(cy, cx) * s2; + float os = MathUtil::atan2(cy, cx) * s2; float rotation = parent._arotation; a1 = (a1 - os) * RadDeg + os1 - rotation; if (a1 > 180) { @@ -211,9 +211,9 @@ namespace Spine { float maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; c = -a * l1 / (aa - bb); if (c >= -1 && c <= 1) { - c = acos(c); - x = a * cos(c) + l1; - y = b * (float)sin(c); + c = MathUtil::acos(c); + x = a * MathUtil::cos(c) + l1; + y = b * (float)MathUtil::sin(c); d = x * x + y * y; if (d < minDist) { @@ -232,11 +232,11 @@ namespace Spine { } if (dd <= (minDist + maxDist) / 2) { - a1 = ta - atan2(minY * bendDir, minX); + a1 = ta - MathUtil::atan2(minY * bendDir, minX); a2 = minAngle * bendDir; } else { - a1 = ta - atan2(maxY * bendDir, maxX); + a1 = ta - MathUtil::atan2(maxY * bendDir, maxX); a2 = maxAngle * bendDir; } } diff --git a/spine-cpp/spine-cpp/src/spine/MathUtil.cpp b/spine-cpp/spine-cpp/src/spine/MathUtil.cpp index 452e61328..d98ddf13e 100644 --- a/spine-cpp/spine-cpp/src/spine/MathUtil.cpp +++ b/spine-cpp/spine-cpp/src/spine/MathUtil.cpp @@ -29,6 +29,7 @@ *****************************************************************************/ #include +#include namespace Spine { float MathUtil::SIN_TABLE[SIN_COUNT] = {0.0f}; @@ -42,6 +43,34 @@ namespace Spine { SIN_TABLE[i * DegToIndex & SIN_MASK] = sin(i * DegRad); } } + + int MathUtil::sign(float val) { + return (0 < val) - (val < 0); + } + + bool MathUtil::areFloatsPracticallyEqual(float A, float B, float maxDiff, float maxRelDiff) { + // 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; + } + + float MathUtil::clamp(float x, float lower, float upper) { + return fminf(upper, fmaxf(x, lower)); + } /// Returns the sine in radians from a lookup table. float MathUtil::sin(float radians) { @@ -93,4 +122,30 @@ namespace Spine { return y < 0.0f ? atan - SPINE_PI : atan; } + + 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 */ + static bool _isNan(float value, float zero) { + float _nan = (float)0.0 / zero; + return 0 == memcmp((void*)&value, (void*)&_nan, sizeof(value)); + } + + bool MathUtil::isNan(float v) { + return _isNan(v, 0); + } } diff --git a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp index 5cbb85ebb..aa333302e 100644 --- a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp @@ -118,7 +118,7 @@ namespace Spine { else { float x = setupLength * bone._a; float y = setupLength * bone._c; - float length = sqrt(x * x + y * y); + float length = MathUtil::sqrt(x * x + y * y); if (scale) { _lengths[i] = length; } @@ -159,7 +159,7 @@ namespace Spine { if (scale) { float length = _lengths[i]; if (length >= PathConstraint::EPSILON) { - float s = (sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; + float s = (MathUtil::sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; bone._a *= s; bone._c *= s; } @@ -298,7 +298,7 @@ namespace Spine { float p = position; if (closed) { - p = fmod(p, pathLength); + p = MathUtil::fmod(p, pathLength); if (p < 0) { p += pathLength; @@ -398,18 +398,18 @@ namespace Spine { ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; - pathLength += sqrt(dfx * dfx + dfy * dfy); + pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; - pathLength += sqrt(dfx * dfx + dfy * dfy); + pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; - pathLength += sqrt(dfx * dfx + dfy * dfy); + pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); dfx += ddfx + dddfx; dfy += ddfy + dddfy; - pathLength += sqrt(dfx * dfx + dfy * dfy); + pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); _curves[i] = pathLength; x1 = x2; y1 = y2; @@ -432,7 +432,7 @@ namespace Spine { float p = position; if (closed) { - p = fmod(p, pathLength); + p = MathUtil::fmod(p, pathLength); if (p < 0) { p += pathLength; @@ -485,23 +485,23 @@ namespace Spine { ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; - curveLength = sqrt(dfx * dfx + dfy * dfy); + curveLength = MathUtil::sqrt(dfx * dfx + dfy * dfy); _segments[0] = curveLength; for (ii = 1; ii < 8; ii++) { dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; - curveLength += sqrt(dfx * dfx + dfy * dfy); + curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); _segments[ii] = curveLength; } dfx += ddfx; dfy += ddfy; - curveLength += sqrt(dfx * dfx + dfy * dfy); + curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); _segments[8] = curveLength; dfx += ddfx + dddfx; dfy += ddfy + dddfy; - curveLength += sqrt(dfx * dfx + dfy * dfy); + curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); _segments[9] = curveLength; segment = 0; } @@ -553,7 +553,7 @@ namespace Spine { } void PathConstraint::addCurvePosition(float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, Vector& output, int o, bool tangents) { - if (p < EPSILON || isnan(p)) { + if (p < EPSILON || MathUtil::isNan(p)) { p = EPSILON; } @@ -563,7 +563,7 @@ namespace Spine { output[o] = x; output[o + 1] = y; if (tangents) { - output[o + 2] = atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + output[o + 2] = MathUtil::atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); } } } diff --git a/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp b/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp index 80ef42a4a..40061cf49 100644 --- a/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp @@ -171,17 +171,17 @@ namespace Spine { } if (scaleMix > 0) { - float s = sqrt(bone._a * bone._a + bone._c * bone._c); + float s = MathUtil::sqrt(bone._a * bone._a + bone._c * bone._c); if (s > 0.00001f) { - s = (s + (sqrt(ta * ta + tc * tc) - s + _data._offsetScaleX) * scaleMix) / s; + s = (s + (MathUtil::sqrt(ta * ta + tc * tc) - s + _data._offsetScaleX) * scaleMix) / s; } bone._a *= s; bone._c *= s; - s = sqrt(bone._b * bone._b + bone._d * bone._d); + s = MathUtil::sqrt(bone._b * bone._b + bone._d * bone._d); if (s > 0.00001f) { - s = (s + (sqrt(tb * tb + td * td) - s + _data._offsetScaleY) * scaleMix) / s; + s = (s + (MathUtil::sqrt(tb * tb + td * td) - s + _data._offsetScaleY) * scaleMix) / s; } bone._b *= s; bone._d *= s; @@ -200,7 +200,7 @@ namespace Spine { } r = by + (r + offsetShearY) * shearMix; - float s = sqrt(b * b + d * d); + float s = MathUtil::sqrt(b * b + d * d); bone._b = MathUtil::cos(r) * s; bone._d = MathUtil::sin(r) * s; modified = true; @@ -252,10 +252,10 @@ namespace Spine { } if (scaleMix > 0) { - float s = (sqrt(ta * ta + tc * tc) - 1 + _data._offsetScaleX) * scaleMix + 1; + float s = (MathUtil::sqrt(ta * ta + tc * tc) - 1 + _data._offsetScaleX) * scaleMix + 1; bone._a *= s; bone._c *= s; - s = (sqrt(tb * tb + td * td) - 1 + _data._offsetScaleY) * scaleMix + 1; + s = (MathUtil::sqrt(tb * tb + td * td) - 1 + _data._offsetScaleY) * scaleMix + 1; bone._b *= s; bone._d *= s; modified = true; @@ -272,7 +272,7 @@ namespace Spine { float b = bone._b, d = bone._d; r = MathUtil::atan2(d, b) + (r - SPINE_PI / 2 + offsetShearY) * shearMix; - float s = sqrt(b * b + d * d); + float s = MathUtil::sqrt(b * b + d * d); bone._b = MathUtil::cos(r) * s; bone._d = MathUtil::sin(r) * s; modified = true;