From da36386f4aa1853a0454571d27377c534f6a968e Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Thu, 12 Jun 2025 02:08:23 +0200 Subject: [PATCH] [cpp] 4.3 porting WIP --- .../spine-cpp/include/spine/PathConstraint.h | 91 ++-- .../include/spine/PathConstraintPose.h | 2 + spine-cpp/spine-cpp/include/spine/Skeleton.h | 6 +- spine-cpp/spine-cpp/include/spine/SlotData.h | 1 + .../spine-cpp/src/spine/PathConstraint.cpp | 465 +++++++++--------- 5 files changed, 264 insertions(+), 301 deletions(-) diff --git a/spine-cpp/spine-cpp/include/spine/PathConstraint.h b/spine-cpp/spine-cpp/include/spine/PathConstraint.h index 924b35483..3ba04bf48 100644 --- a/spine-cpp/spine-cpp/include/spine/PathConstraint.h +++ b/spine-cpp/spine-cpp/include/spine/PathConstraint.h @@ -30,84 +30,58 @@ #ifndef Spine_PathConstraint_h #define Spine_PathConstraint_h +#include #include - +#include +#include #include namespace spine { - class PathConstraintData; - class Skeleton; - class PathAttachment; - - class Bone; - + class BonePose; class Slot; + class Bone; + class Skin; + class Attachment; - class SP_API PathConstraint : public Updatable { + /// Stores the current pose for a path constraint. A path constraint adjusts the rotation, translation, and scale of the + /// constrained bones so they follow a PathAttachment. + /// + /// See https://esotericsoftware.com/spine-path-constraints Path constraints in the Spine User Guide. + class SP_API PathConstraint : public Constraint { friend class Skeleton; - friend class PathConstraintMixTimeline; - friend class PathConstraintPositionTimeline; - friend class PathConstraintSpacingTimeline; - RTTI_DECL + RTTI_DECL public: + static const float epsilon; + static const int NONE, BEFORE, AFTER; + PathConstraint(PathConstraintData &data, Skeleton &skeleton); - virtual void update(Physics physics); + virtual void update(Skeleton& skeleton, Physics physics); - virtual int getOrder(); + virtual void sort(Skeleton& skeleton); - PathConstraintData &getData(); + virtual bool isSourceActive(); - Vector &getBones(); + PathConstraintData &getData(); - Slot *getTarget(); + Vector &getBones(); - void setTarget(Slot *inValue); + Slot *getSlot(); - float getPosition(); + void setSlot(Slot *slot); - void setPosition(float inValue); - float getSpacing(); - - void setSpacing(float inValue); - - float getMixRotate(); - - void setMixRotate(float inValue); - - float getMixX(); - - void setMixX(float inValue); - - float getMixY(); - - void setMixY(float inValue); - - bool isActive(); - - void setActive(bool inValue); - - void setToSetupPose(); private: - static const float EPSILON; - static const int NONE; - static const int BEFORE; - static const int AFTER; - - PathConstraintData &_data; - Vector _bones; - Slot *_target; - float _position, _spacing; - float _mixRotate, _mixX, _mixY; + Vector _bones; + Slot *_slot; Vector _spaces; Vector _positions; @@ -116,17 +90,18 @@ namespace spine { Vector _lengths; Vector _segments; - bool _active; + Vector &computeWorldPositions(Skeleton& skeleton, PathAttachment &path, int spacesCount, bool tangents); - Vector &computeWorldPositions(PathAttachment &path, int spacesCount, bool tangents); + void addBeforePosition(float p, Vector &temp, int i, Vector &output, int o); - static void addBeforePosition(float p, Vector &temp, int i, Vector &output, int o); + void addAfterPosition(float p, Vector &temp, int i, Vector &output, int o); - static void addAfterPosition(float p, Vector &temp, int i, Vector &output, int o); - - static void - addCurvePosition(float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, + void 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); + + void sortPathSlot(Skeleton& skeleton, Skin& skin, int slotIndex, Bone& slotBone); + + void sortPath(Skeleton& skeleton, Attachment* attachment, Bone& slotBone); }; } diff --git a/spine-cpp/spine-cpp/include/spine/PathConstraintPose.h b/spine-cpp/spine-cpp/include/spine/PathConstraintPose.h index 2bc70e0aa..767156c99 100644 --- a/spine-cpp/spine-cpp/include/spine/PathConstraintPose.h +++ b/spine-cpp/spine-cpp/include/spine/PathConstraintPose.h @@ -36,6 +36,8 @@ namespace spine { /// Stores a pose for a path constraint. class SP_API PathConstraintPose : public Pose { + friend class PathConstraint; + RTTI_DECL private: diff --git a/spine-cpp/spine-cpp/include/spine/Skeleton.h b/spine-cpp/spine-cpp/include/spine/Skeleton.h index 603e3bebb..35026d25a 100644 --- a/spine-cpp/spine-cpp/include/spine/Skeleton.h +++ b/spine-cpp/spine-cpp/include/spine/Skeleton.h @@ -89,6 +89,8 @@ namespace spine { friend class IkConstraintTimeline; + friend class PathConstraint; + friend class PathConstraintMixTimeline; friend class PathConstraintPositionTimeline; @@ -206,7 +208,7 @@ namespace spine { Vector &getBones(); - Vector &getUpdateCacheList(); + Vector &getUpdateCacheList(); Vector &getSlots(); @@ -280,7 +282,7 @@ namespace spine { Vector _transformConstraints; Vector _pathConstraints; Vector _physicsConstraints; - Vector _updateCache; + Vector _updateCache; Skin *_skin; Color _color; float _scaleX, _scaleY; diff --git a/spine-cpp/spine-cpp/include/spine/SlotData.h b/spine-cpp/spine-cpp/include/spine/SlotData.h index 0bd918c06..890736779 100644 --- a/spine-cpp/spine-cpp/include/spine/SlotData.h +++ b/spine-cpp/spine-cpp/include/spine/SlotData.h @@ -45,6 +45,7 @@ namespace spine { friend class SkeletonBinary; friend class SkeletonJson; + friend class PathConstraint; friend class AttachmentTimeline; friend class RGBATimeline; friend class RGBTimeline; diff --git a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp index fb8683e7a..444effe38 100644 --- a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp @@ -30,259 +30,235 @@ #include #include +#include #include #include +#include #include #include +#include #include #include +#include using namespace spine; -RTTI_IMPL(PathConstraint, Updatable) +RTTI_IMPL_NOPARENT(PathConstraint) -const float PathConstraint::EPSILON = 0.00001f; +const float PathConstraint::epsilon = 0.00001f; const int PathConstraint::NONE = -1; const int PathConstraint::BEFORE = -2; const int PathConstraint::AFTER = -3; -PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) : Updatable(), - _data(data), - _target(skeleton.findSlot( - data.getTarget()->getName())), - _position(data.getPosition()), - _spacing(data.getSpacing()), - _mixRotate(data.getMixRotate()), - _mixX(data.getMixX()), - _mixY(data.getMixY()), - _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())); +PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) : + Constraint(data), + _slot(skeleton._slots.buffer()[data._slot->_index]) { + + _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()); } _segments.setSize(10, 0); } -void PathConstraint::update(Physics) { - Attachment *baseAttachment = _target->getAttachment(); +void PathConstraint::update(Skeleton& skeleton, Physics physics) { + Attachment *baseAttachment = _slot->getAppliedPose().getAttachment(); if (baseAttachment == NULL || !baseAttachment->getRTTI().instanceOf(PathAttachment::rtti)) { return; } - PathAttachment *attachment = static_cast(baseAttachment); + PathAttachment *pathAttachment = static_cast(baseAttachment); - float mixRotate = _mixRotate, mixX = _mixX, mixY = _mixY; + PathConstraintPose& p = *_applied; + float mixRotate = p._mixRotate, mixX = p._mixX, mixY = p._mixY; if (mixRotate == 0 && mixX == 0 && mixY == 0) return; - PathConstraintData &data = _data; - bool tangents = data._rotateMode == RotateMode_Tangent, scale = data._rotateMode == RotateMode_ChainScale; + PathConstraintData& data = _data; + bool tangents = data.getRotateMode() == RotateMode_Tangent, scale = data.getRotateMode() == RotateMode_ChainScale; size_t boneCount = _bones.size(); size_t spacesCount = tangents ? boneCount : boneCount + 1; + BonePose** bones = _bones.buffer(); _spaces.setSize(spacesCount, 0); - if (scale) _lengths.setSize(boneCount, 0); - float spacing = _spacing; + float* spaces = _spaces.buffer(); + float* lengths = NULL; + if (scale) { + _lengths.setSize(boneCount, 0); + lengths = _lengths.buffer(); + } + float spacing = p._spacing; - switch (data._spacingMode) { + switch (data.getSpacingMode()) { case SpacingMode_Percent: { if (scale) { for (size_t i = 0, n = spacesCount - 1; i < n; i++) { - Bone *boneP = _bones[i]; - Bone &bone = *boneP; - float setupLength = bone._data.getLength(); - float x = setupLength * bone._a; - float y = setupLength * bone._c; - _lengths[i] = MathUtil::sqrt(x * x + y * y); + BonePose* bone = bones[i]; + float setupLength = bone->_bone->getData().getLength(); + float x = setupLength * bone->_a; + float y = setupLength * bone->_c; + lengths[i] = MathUtil::sqrt(x * x + y * y); } } - for (size_t i = 1; i < spacesCount; ++i) { - _spaces[i] = spacing; + for (size_t i = 1; i < spacesCount; i++) { + spaces[i] = spacing; } break; } case SpacingMode_Proportional: { float sum = 0; for (size_t i = 0, n = spacesCount - 1; i < n;) { - Bone *boneP = _bones[i]; - Bone &bone = *boneP; - float setupLength = bone._data.getLength(); - if (setupLength < PathConstraint::EPSILON) { - if (scale) _lengths[i] = 0; - _spaces[++i] = spacing; + BonePose* bone = bones[i]; + float setupLength = bone->_bone->getData().getLength(); + if (setupLength < epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; } else { - float x = setupLength * bone._a, y = setupLength * bone._c; + float x = setupLength * bone->_a, y = setupLength * bone->_c; float length = MathUtil::sqrt(x * x + y * y); - if (scale) _lengths[i] = length; - _spaces[++i] = length; + if (scale) lengths[i] = length; + spaces[++i] = length; sum += length; } } if (sum > 0) { sum = spacesCount / sum * spacing; for (size_t i = 1; i < spacesCount; i++) { - _spaces[i] *= sum; + spaces[i] *= sum; } } break; } default: { - bool lengthSpacing = data._spacingMode == SpacingMode_Length; + bool lengthSpacing = data.getSpacingMode() == SpacingMode_Length; for (size_t i = 0, n = spacesCount - 1; i < n;) { - Bone *boneP = _bones[i]; - Bone &bone = *boneP; - float setupLength = bone._data.getLength(); - if (setupLength < PathConstraint::EPSILON) { - if (scale) _lengths[i] = 0; - _spaces[++i] = spacing; + BonePose* bone = bones[i]; + float setupLength = bone->_bone->getData().getLength(); + if (setupLength < epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; } else { - float x = setupLength * bone._a, y = setupLength * bone._c; + float x = setupLength * bone->_a, y = setupLength * bone->_c; float length = MathUtil::sqrt(x * x + y * y); - if (scale) _lengths[i] = length; - _spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; + if (scale) lengths[i] = length; + spaces[++i] = (lengthSpacing ? MathUtil::max(0.0f, setupLength + spacing) : spacing) * length / setupLength; } } } } - Vector &positions = computeWorldPositions(*attachment, (int) spacesCount, tangents); - float boneX = positions[0]; - float boneY = positions[1]; - float offsetRotation = data.getOffsetRotation(); + Vector &positions = computeWorldPositions(skeleton, *pathAttachment, (int) spacesCount, tangents); + float* positionsBuffer = positions.buffer(); + float boneX = positionsBuffer[0], boneY = positionsBuffer[1], offsetRotation = data.getOffsetRotation(); bool tip; - if (offsetRotation == 0) { - tip = data._rotateMode == RotateMode_Chain; - } else { + if (offsetRotation == 0) + tip = data.getRotateMode() == RotateMode_Chain; + else { tip = false; - Bone &p = _target->getBone(); - offsetRotation *= p.getA() * p.getD() - p.getB() * p.getC() > 0 ? MathUtil::Deg_Rad : -MathUtil::Deg_Rad; + BonePose& bone = _slot->getBone().getAppliedPose(); + offsetRotation *= bone._a * bone._d - bone._b * bone._c > 0 ? MathUtil::Deg_Rad : -MathUtil::Deg_Rad; } - - for (size_t i = 0, p = 3; i < boneCount; i++, p += 3) { - Bone *boneP = _bones[i]; - Bone &bone = *boneP; - bone._worldX += (boneX - bone._worldX) * mixX; - bone._worldY += (boneY - bone._worldY) * mixY; - float x = positions[p]; - float y = positions[p + 1]; - float dx = x - boneX; - float dy = y - boneY; + for (size_t i = 0, ip = 3; i < boneCount; i++, ip += 3) { + // int u = skeleton.update; // TODO: Add int update field to Skeleton class + int u = 1; // Temporary placeholder until Skeleton.update is implemented + BonePose* bone = bones[i]; + bone->_worldX += (boneX - bone->_worldX) * mixX; + bone->_worldY += (boneY - bone->_worldY) * mixY; + float x = positionsBuffer[ip], y = positionsBuffer[ip + 1], dx = x - boneX, dy = y - boneY; if (scale) { - float length = _lengths[i]; - if (length >= PathConstraint::EPSILON) { + float length = lengths[i]; + if (length >= epsilon) { float s = (MathUtil::sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1; - bone._a *= s; - bone._c *= s; + bone->_a *= s; + bone->_c *= s; } } - boneX = x; boneY = y; - if (mixRotate > 0) { - float a = bone._a, b = bone._b, c = bone._c, d = bone._d, r, cos, sin; + float a = bone->_a, b = bone->_b, c = bone->_c, d = bone->_d, r, cos, sin; if (tangents) - r = positions[p - 1]; - else if (_spaces[i + 1] < PathConstraint::EPSILON) - r = positions[p + 2]; + r = positionsBuffer[ip - 1]; + else if (spaces[i + 1] < epsilon) + r = positionsBuffer[ip + 2]; else r = MathUtil::atan2(dy, dx); - r -= MathUtil::atan2(c, a); - if (tip) { cos = MathUtil::cos(r); sin = MathUtil::sin(r); - float length = bone._data.getLength(); + float length = bone->_bone->getData().getLength(); boneX += (length * (cos * a - sin * c) - dx) * mixRotate; boneY += (length * (sin * a + cos * c) - dy) * mixRotate; } else r += offsetRotation; - if (r > MathUtil::Pi) r -= MathUtil::Pi_2; else if (r < -MathUtil::Pi) r += MathUtil::Pi_2; - r *= mixRotate; 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; + bone->_a = cos * a - sin * c; + bone->_b = cos * b - sin * d; + bone->_c = sin * a + cos * c; + bone->_d = sin * b + cos * d; } - - bone.updateAppliedTransform(); + bone->modifyWorld(u); } } -int PathConstraint::getOrder() { - return (int) _data.getOrder(); + +void PathConstraint::sort(Skeleton& skeleton) { + int slotIndex = _slot->getData().getIndex(); + Bone& slotBone = _slot->getBone(); + if (skeleton.getSkin() != NULL) sortPathSlot(skeleton, *skeleton.getSkin(), slotIndex, slotBone); + if (skeleton.getData()->getDefaultSkin() != NULL && skeleton.getData()->getDefaultSkin() != skeleton.getSkin()) + sortPathSlot(skeleton, *skeleton.getData()->getDefaultSkin(), slotIndex, slotBone); + sortPath(skeleton, _slot->getAppliedPose().getAttachment(), slotBone); + BonePose** bones = _bones.buffer(); + size_t boneCount = _bones.size(); + for (size_t i = 0; i < boneCount; i++) { + Bone* bone = bones[i]->_bone; + skeleton.sortBone(bone); + // skeleton.constrained(bone); // TODO: Add constrained() method to Skeleton class + } + skeleton._updateCache.add(this); + for (size_t i = 0; i < boneCount; i++) + skeleton.sortReset(bones[i]->_bone->getChildren()); + for (size_t i = 0; i < boneCount; i++) + bones[i]->_bone->_sorted = true; } -float PathConstraint::getPosition() { - return _position; -} - -void PathConstraint::setPosition(float inValue) { - _position = inValue; -} - -float PathConstraint::getSpacing() { - return _spacing; -} - -void PathConstraint::setSpacing(float inValue) { - _spacing = inValue; -} - -float PathConstraint::getMixRotate() { - return _mixRotate; -} - -void PathConstraint::setMixRotate(float inValue) { - _mixRotate = inValue; -} - -float PathConstraint::getMixX() { - return _mixX; -} - -void PathConstraint::setMixX(float inValue) { - _mixX = inValue; -} - -float PathConstraint::getMixY() { - return _mixY; -} - -void PathConstraint::setMixY(float inValue) { - _mixY = inValue; -} - -Vector &PathConstraint::getBones() { - return _bones; -} - -Slot *PathConstraint::getTarget() { - return _target; -} - -void PathConstraint::setTarget(Slot *inValue) { - _target = inValue; +bool PathConstraint::isSourceActive() { + return _slot->getBone().isActive(); } PathConstraintData &PathConstraint::getData() { return _data; } +Vector &PathConstraint::getBones() { + return _bones; +} + +Slot *PathConstraint::getSlot() { + return _slot; +} + +void PathConstraint::setSlot(Slot *slot) { + if (slot == NULL) throw; + _slot = slot; +} + Vector & -PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, bool tangents) { - Slot &target = *_target; - float position = _position; +PathConstraint::computeWorldPositions(Skeleton& skeleton, PathAttachment &path, int spacesCount, bool tangents) { + Slot &slot = *_slot; + float position = _applied->_position; + float* spaces = _spaces.buffer(); _positions.setSize(spacesCount * 3 + 2, 0); Vector &out = _positions; + float* outBuffer = out.buffer(); Vector &world = _world; bool closed = path.isClosed(); int verticesLength = (int) path.getWorldVerticesLength(); @@ -292,12 +268,13 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo float pathLength; if (!path.isConstantSpeed()) { Vector &lengths = path.getLengths(); + float* lengthsBuffer = lengths.buffer(); curveCount -= closed ? 1 : 2; - pathLength = lengths[curveCount]; - if (_data._positionMode == PositionMode_Percent) position *= pathLength; + pathLength = lengthsBuffer[curveCount]; + if (_data.getPositionMode() == PositionMode_Percent) position *= pathLength; float multiplier = 0; - switch (_data._spacingMode) { + switch (_data.getSpacingMode()) { case SpacingMode_Percent: multiplier = pathLength; break; @@ -309,8 +286,9 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo } world.setSize(8, 0); + float* worldBuffer = world.buffer(); for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { - float space = _spaces[i] * multiplier; + float space = spaces[i] * multiplier; position += space; float p = position; @@ -321,48 +299,41 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo } else if (p < 0) { if (prevCurve != BEFORE) { prevCurve = BEFORE; - path.computeWorldVertices(target, 2, 4, world, 0); + path.computeWorldVertices(skeleton, *_slot, 2, 4, world, 0, 2); } - addBeforePosition(p, world, 0, out, o); - continue; } else if (p > pathLength) { if (prevCurve != AFTER) { prevCurve = AFTER; - path.computeWorldVertices(target, verticesLength - 6, 4, world, 0); + path.computeWorldVertices(skeleton, *_slot, verticesLength - 6, 4, world, 0, 2); } - addAfterPosition(p - pathLength, world, 0, out, o); - continue; } // Determine curve containing position. for (;; curve++) { - float length = lengths[curve]; + float length = lengthsBuffer[curve]; if (p > length) continue; - if (curve == 0) p /= length; else { - float prev = lengths[curve - 1]; + float prev = lengthsBuffer[curve - 1]; p = (p - prev) / (length - prev); } break; } - if (curve != prevCurve) { prevCurve = curve; if (closed && curve == curveCount) { - path.computeWorldVertices(target, verticesLength - 4, 4, world, 0); - path.computeWorldVertices(target, 0, 4, world, 4); + path.computeWorldVertices(skeleton, *_slot, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(skeleton, *_slot, 0, 4, world, 4, 2); } else - path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0); + path.computeWorldVertices(skeleton, *_slot, curve * 6 + 2, 8, world, 0, 2); } - - addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], - out, o, tangents || (i > 0 && space < EPSILON)); + addCurvePosition(p, worldBuffer[0], worldBuffer[1], worldBuffer[2], worldBuffer[3], worldBuffer[4], worldBuffer[5], worldBuffer[6], worldBuffer[7], + out, o, tangents || (i > 0 && space < epsilon)); } return out; } @@ -371,29 +342,32 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo if (closed) { verticesLength += 2; world.setSize(verticesLength, 0); - path.computeWorldVertices(target, 2, verticesLength - 4, world, 0); - path.computeWorldVertices(target, 0, 2, world, verticesLength - 4); - world[verticesLength - 2] = world[0]; - world[verticesLength - 1] = world[1]; + float* worldBuffer = world.buffer(); + path.computeWorldVertices(skeleton, *_slot, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(skeleton, *_slot, 0, 2, world, verticesLength - 4, 2); + worldBuffer[verticesLength - 2] = worldBuffer[0]; + worldBuffer[verticesLength - 1] = worldBuffer[1]; } else { curveCount--; verticesLength -= 4; world.setSize(verticesLength, 0); - path.computeWorldVertices(target, 2, verticesLength, world, 0); + path.computeWorldVertices(skeleton, *_slot, 2, verticesLength, world, 0, 2); } + float* worldBuffer = world.buffer(); // Curve lengths. _curves.setSize(curveCount, 0); + float* curvesBuffer = _curves.buffer(); pathLength = 0; - float x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + float x1 = worldBuffer[0], y1 = worldBuffer[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy; for (int i = 0, w = 2; i < curveCount; i++, w += 6) { - cx1 = world[w]; - cy1 = world[w + 1]; - cx2 = world[w + 2]; - cy2 = world[w + 3]; - x2 = world[w + 4]; - y2 = world[w + 5]; + cx1 = worldBuffer[w]; + cy1 = worldBuffer[w + 1]; + cx2 = worldBuffer[w + 2]; + cy2 = worldBuffer[w + 3]; + x2 = worldBuffer[w + 4]; + y2 = worldBuffer[w + 5]; tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; @@ -414,15 +388,15 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo dfx += ddfx + dddfx; dfy += ddfy + dddfy; pathLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); - _curves[i] = pathLength; + curvesBuffer[i] = pathLength; x1 = x2; y1 = y2; } - if (_data._positionMode == PositionMode_Percent) position *= pathLength; + if (_data.getPositionMode() == PositionMode_Percent) position *= pathLength; float multiplier = 0; - switch (_data._spacingMode) { + switch (_data.getSpacingMode()) { case SpacingMode_Percent: multiplier = pathLength; break; @@ -432,10 +406,11 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo default: multiplier = 1; } + float* segmentsBuffer = _segments.buffer(); float curveLength = 0; for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { - float space = _spaces[i] * multiplier; + float space = spaces[i] * multiplier; position += space; float p = position; @@ -443,6 +418,7 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo p = MathUtil::fmod(p, pathLength); if (p < 0) p += pathLength; curve = 0; + segment = 0; } else if (p < 0) { addBeforePosition(p, world, 0, out, o); continue; @@ -453,12 +429,12 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo // Determine curve containing position. for (;; curve++) { - float length = _curves[curve]; + float length = curvesBuffer[curve]; if (p > length) continue; if (curve == 0) p /= length; else { - float prev = _curves[curve - 1]; + float prev = curvesBuffer[curve - 1]; p = (p - prev) / (length - prev); } break; @@ -468,14 +444,14 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo if (curve != prevCurve) { prevCurve = curve; int ii = curve * 6; - x1 = world[ii]; - y1 = world[ii + 1]; - cx1 = world[ii + 2]; - cy1 = world[ii + 3]; - cx2 = world[ii + 4]; - cy2 = world[ii + 5]; - x2 = world[ii + 6]; - y2 = world[ii + 7]; + x1 = worldBuffer[ii]; + y1 = worldBuffer[ii + 1]; + cx1 = worldBuffer[ii + 2]; + cy1 = worldBuffer[ii + 3]; + cx2 = worldBuffer[ii + 4]; + cy2 = worldBuffer[ii + 5]; + x2 = worldBuffer[ii + 6]; + y2 = worldBuffer[ii + 7]; tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; @@ -485,104 +461,111 @@ PathConstraint::computeWorldPositions(PathAttachment &path, int spacesCount, boo dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; curveLength = MathUtil::sqrt(dfx * dfx + dfy * dfy); - _segments[0] = curveLength; + segmentsBuffer[0] = curveLength; for (ii = 1; ii < 8; ii++) { dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); - _segments[ii] = curveLength; + segmentsBuffer[ii] = curveLength; } dfx += ddfx; dfy += ddfy; curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); - _segments[8] = curveLength; + segmentsBuffer[8] = curveLength; dfx += ddfx + dddfx; dfy += ddfy + dddfy; curveLength += MathUtil::sqrt(dfx * dfx + dfy * dfy); - _segments[9] = curveLength; + segmentsBuffer[9] = curveLength; segment = 0; } // Weight by segment length. p *= curveLength; for (;; segment++) { - float length = _segments[segment]; + float length = segmentsBuffer[segment]; if (p > length) continue; if (segment == 0) p /= length; else { - float prev = _segments[segment - 1]; + float prev = segmentsBuffer[segment - 1]; p = segment + (p - prev) / (length - prev); } break; } addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, - tangents || (i > 0 && space < EPSILON)); + tangents || (i > 0 && space < epsilon)); } return out; } void PathConstraint::addBeforePosition(float p, Vector &temp, int i, Vector &output, int o) { - float x1 = temp[i]; - float y1 = temp[i + 1]; - float dx = temp[i + 2] - x1; - float dy = temp[i + 3] - y1; - float r = MathUtil::atan2(dy, dx); - output[o] = x1 + p * MathUtil::cos(r); - output[o + 1] = y1 + p * MathUtil::sin(r); - output[o + 2] = r; + float* tempBuffer = temp.buffer(); + float* outBuffer = output.buffer(); + float x1 = tempBuffer[i], y1 = tempBuffer[i + 1], dx = tempBuffer[i + 2] - x1, dy = tempBuffer[i + 3] - y1, r = MathUtil::atan2(dy, dx); + outBuffer[o] = x1 + p * MathUtil::cos(r); + outBuffer[o + 1] = y1 + p * MathUtil::sin(r); + outBuffer[o + 2] = r; } void PathConstraint::addAfterPosition(float p, Vector &temp, int i, Vector &output, int o) { - float x1 = temp[i + 2]; - float y1 = temp[i + 3]; - float dx = x1 - temp[i]; - float dy = y1 - temp[i + 1]; - float r = MathUtil::atan2(dy, dx); - output[o] = x1 + p * MathUtil::cos(r); - output[o + 1] = y1 + p * MathUtil::sin(r); - output[o + 2] = r; + float* tempBuffer = temp.buffer(); + float* outBuffer = output.buffer(); + float x1 = tempBuffer[i + 2], y1 = tempBuffer[i + 3], dx = x1 - tempBuffer[i], dy = y1 - tempBuffer[i + 1], r = MathUtil::atan2(dy, dx); + outBuffer[o] = x1 + p * MathUtil::cos(r); + outBuffer[o + 1] = y1 + p * MathUtil::sin(r); + outBuffer[o + 2] = r; } 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 || MathUtil::isNan(p)) { - output[o] = x1; - output[o + 1] = y1; - output[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1); + float* outBuffer = output.buffer(); + if (p < epsilon || MathUtil::isNan(p)) { + outBuffer[o] = x1; + outBuffer[o + 1] = y1; + outBuffer[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1); return; } - float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; float ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; float x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; - output[o] = x; - output[o + 1] = y; + outBuffer[o] = x; + outBuffer[o + 1] = y; if (tangents) { - if (p < 0.001) - output[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1); + if (p < 0.001f) + outBuffer[o + 2] = MathUtil::atan2(cy1 - y1, cx1 - x1); else - output[o + 2] = MathUtil::atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), + outBuffer[o + 2] = MathUtil::atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); } } -bool PathConstraint::isActive() { - return _active; +void PathConstraint::sortPathSlot(Skeleton& skeleton, Skin& skin, int slotIndex, Bone& slotBone) { + // Object[] entries = skin.attachments.orderedItems().items; + // for (int i = 0, n = skin.attachments.size; i < n; i++) { + // var entry = (SkinEntry)entries[i]; + // if (entry.slotIndex == slotIndex) sortPath(skeleton, entry.attachment, slotBone); + // } + // TODO: Implement when Skin API is available } -void PathConstraint::setActive(bool inValue) { - _active = inValue; -} - -void PathConstraint::setToSetupPose() { - PathConstraintData &data = this->_data; - this->_position = data._position; - this->_spacing = data._spacing; - this->_mixRotate = data._mixRotate; - this->_mixX = data._mixX; - this->_mixY = data._mixY; -} +void PathConstraint::sortPath(Skeleton& skeleton, Attachment* attachment, Bone& slotBone) { + if (attachment == NULL || !attachment->getRTTI().instanceOf(PathAttachment::rtti)) return; + PathAttachment* pathAttachment = static_cast(attachment); + // int[] pathBones = pathAttachment.getBones(); + // if (pathBones == null) + // skeleton.sortBone(slotBone); + // else { + // Bone[] bones = skeleton.bones.items; + // for (int i = 0, n = pathBones.length; i < n;) { + // int nn = pathBones[i++]; + // nn += i; + // while (i < nn) + // skeleton.sortBone(bones[pathBones[i++]]); + // } + // } + // TODO: Implement when PathAttachment::getBones() API is available + skeleton.sortBone(&slotBone); +} \ No newline at end of file