123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- /******************************************************************************
- * Spine Runtimes License Agreement
- * Last updated January 1, 2020. Replaces all prior versions.
- *
- * Copyright (c) 2013-2020, Esoteric Software LLC
- *
- * Integration of the Spine Runtimes into software or otherwise creating
- * derivative works of the Spine Runtimes is permitted under the terms and
- * conditions of Section 2 of the Spine Editor License Agreement:
- * http://esotericsoftware.com/spine-editor-license
- *
- * Otherwise, it is permitted to integrate the Spine Runtimes into software
- * or otherwise create derivative works of the Spine Runtimes (collectively,
- * "Products"), provided that each user of the Products must obtain their own
- * Spine Editor license and redistribution of the Products in any form must
- * include this license and copyright notice.
- *
- * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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
- * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- #ifdef SPINE_UE4
- #include "SpinePluginPrivatePCH.h"
- #endif
- #include <spine/Bone.h>
- #include <spine/BoneData.h>
- #include <spine/Skeleton.h>
- using namespace spine;
- RTTI_IMPL(Bone, Updatable)
- bool Bone::yDown = false;
- void Bone::setYDown(bool inValue) {
- yDown = inValue;
- }
- bool Bone::isYDown() {
- return yDown;
- }
- 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(1),
- _b(0),
- _worldX(0),
- _c(0),
- _d(1),
- _worldY(0),
- _sorted(false),
- _active(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) {
- float cosine, sine;
- float pa, pb, pc, pd;
- Bone *parent = _parent;
- _ax = x;
- _ay = y;
- _arotation = rotation;
- _ascaleX = scaleX;
- _ascaleY = scaleY;
- _ashearX = shearX;
- _ashearY = shearY;
- _appliedValid = true;
- if (!parent) { /* Root bone. */
- float rotationY = rotation + 90 + shearY;
- float sx = _skeleton.getScaleX();
- float sy = _skeleton.getScaleY();
- _a = MathUtil::cosDeg(rotation + shearX) * scaleX * sx;
- _b = MathUtil::cosDeg(rotationY) * scaleY * sx;
- _c = MathUtil::sinDeg(rotation + shearX) * scaleX * sy;
- _d = MathUtil::sinDeg(rotationY) * scaleY * sy;
- _worldX = x * sx + _skeleton.getX();
- _worldY = y * sy + _skeleton.getY();
- return;
- }
- 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;
- 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;
- float prx, rx, ry, la, lb, lc, ld;
- if (s > 0.0001f) {
- s = MathUtil::abs(pa * pd - pb * pc) / s;
- pb = pc * s;
- pd = pa * s;
- prx = MathUtil::atan2(pc, pa) * MathUtil::Rad_Deg;
- } else {
- pa = 0;
- pc = 0;
- prx = 90 - MathUtil::atan2(pd, pb) * MathUtil::Rad_Deg;
- }
- rx = rotation + shearX - prx;
- ry = rotation + shearY - prx + 90;
- la = MathUtil::cosDeg(rx) * scaleX;
- lb = MathUtil::cosDeg(ry) * scaleY;
- lc = MathUtil::sinDeg(rx) * scaleX;
- 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 za, zc, s;
- float r, zb, zd, la, lb, lc, ld;
- cosine = MathUtil::cosDeg(rotation);
- sine = MathUtil::sinDeg(rotation);
- za = (pa * cosine + pb * sine) / _skeleton.getScaleX();
- zc = (pc * cosine + pd * sine) / _skeleton.getScaleY();
- s = MathUtil::sqrt(za * za + zc * zc);
- if (s > 0.00001f) s = 1 / s;
- za *= s;
- zc *= s;
- s = MathUtil::sqrt(za * za + zc * zc);
- if (_data.getTransformMode() == TransformMode_NoScale
- && (pa * pd - pb * pc < 0) != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
- s = -s;
- r = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
- zb = MathUtil::cos(r) * s;
- zd = MathUtil::sin(r) * s;
- la = MathUtil::cosDeg(shearX) * scaleX;
- lb = MathUtil::cosDeg(90 + shearY) * scaleY;
- lc = MathUtil::sinDeg(shearX) * scaleX;
- ld = MathUtil::sinDeg(90 + shearY) * scaleY;
- _a = za * la + zb * lc;
- _b = za * lb + zb * ld;
- _c = zc * la + zd * lc;
- _d = zc * lb + zd * ld;
- break;
- }
- }
- _a *= _skeleton.getScaleX();
- _b *= _skeleton.getScaleX();
- _c *= _skeleton.getScaleY();
- _d *= _skeleton.getScaleY();
- }
- 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) * MathUtil::Rad_Deg + this->_rotation - this->_shearX;
- }
- float Bone::localToWorldRotation(float localRotation) {
- localRotation -= this->_rotation - this->_shearX;
- float sin = MathUtil::sinDeg(localRotation);
- float cos = MathUtil::cosDeg(localRotation);
- return MathUtil::atan2(cos * _c + sin * _d, cos * _a + sin * _b) * MathUtil::Rad_Deg;
- }
- 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) * MathUtil::Rad_Deg;
- }
- 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) * MathUtil::Rad_Deg;
- }
- BoneData &Bone::getData() {
- return _data;
- }
- Skeleton &Bone::getSkeleton() {
- return _skeleton;
- }
- Bone *Bone::getParent() {
- return _parent;
- }
- Vector<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;
- }
- void Bone::setA(float inValue) {
- _a = inValue;
- }
- float Bone::getB() {
- return _b;
- }
- void Bone::setB(float inValue) {
- _b = inValue;
- }
- float Bone::getC() {
- return _c;
- }
- void Bone::setC(float inValue) {
- _c = inValue;
- }
- float Bone::getD() {
- return _d;
- }
- void Bone::setD(float inValue) {
- _d = inValue;
- }
- float Bone::getWorldX() {
- return _worldX;
- }
- void Bone::setWorldX(float inValue) {
- _worldX = inValue;
- }
- float Bone::getWorldY() {
- return _worldY;
- }
- void Bone::setWorldY(float inValue) {
- _worldY = inValue;
- }
- float Bone::getWorldRotationX() {
- return MathUtil::atan2(_c, _a) * MathUtil::MathUtil::Rad_Deg;
- }
- float Bone::getWorldRotationY() {
- return MathUtil::atan2(_d, _b) * MathUtil::Rad_Deg;
- }
- float Bone::getWorldScaleX() {
- return MathUtil::sqrt(_a * _a + _c * _c);
- }
- float Bone::getWorldScaleY() {
- return MathUtil::sqrt(_b * _b + _d * _d);
- }
- bool Bone::isAppliedValid() {
- return _appliedValid;
- }
- void Bone::setAppliedValid(bool valid) {
- _appliedValid = valid;
- }
- void Bone::updateAppliedTransform() {
- Bone *parent = _parent;
- _appliedValid = 1;
- if (!parent) {
- _ax = _worldX;
- _ay = _worldY;
- _arotation = MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
- _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) * MathUtil::Rad_Deg;
- } else {
- 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 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;
- _ax = (dx * pd * pid - dy * pb * pid);
- _ay = (dy * pa * pid - dx * pc * pid);
- _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) * MathUtil::Rad_Deg;
- _arotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
- } else {
- _ascaleX = 0;
- _ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
- _ashearY = 0;
- _arotation = 90 - MathUtil::atan2(rd, rb) * MathUtil::Rad_Deg;
- }
- }
- }
- bool Bone::isActive() {
- return _active;
- }
- void Bone::setActive(bool inValue) {
- _active = inValue;
- }
|