From d7a569d47d3f6613f360d3855698dedb4060ae3b Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Sun, 22 Oct 2017 21:08:29 -0400 Subject: [PATCH] wip --- .../spine-cpp/include/spine/Attachment.h | 4 + spine-cpp/spine-cpp/include/spine/Bone.h | 4 +- spine-cpp/spine-cpp/include/spine/BoneData.h | 6 +- .../spine-cpp/include/spine/ContainerUtil.h | 41 ++ .../spine-cpp/include/spine/IkConstraint.h | 50 +- .../include/spine/IkConstraintData.h | 4 +- spine-cpp/spine-cpp/include/spine/MathUtil.h | 2 +- .../spine-cpp/include/spine/PathConstraint.h | 67 +- spine-cpp/spine-cpp/include/spine/Skeleton.h | 4 +- spine-cpp/spine-cpp/include/spine/SlotData.h | 4 +- .../include/spine/TransformConstraint.h | 53 +- .../include/spine/TransformConstraintData.h | 2 + .../include/spine/VertexAttachment.h | 83 +++ spine-cpp/spine-cpp/src/spine/Attachment.cpp | 2 + spine-cpp/spine-cpp/src/spine/Bone.cpp | 14 +- spine-cpp/spine-cpp/src/spine/BoneData.cpp | 2 +- .../spine-cpp/src/spine/CurveTimeline.cpp | 2 +- .../spine-cpp/src/spine/IkConstraint.cpp | 328 +++++++++- .../spine-cpp/src/spine/IkConstraintData.cpp | 2 + .../spine-cpp/src/spine/PathConstraint.cpp | 601 +++++++++++++++++- spine-cpp/spine-cpp/src/spine/Skeleton.cpp | 77 ++- .../spine-cpp/src/spine/SkeletonData.cpp | 302 ++++----- spine-cpp/spine-cpp/src/spine/Skin.cpp | 2 +- .../src/spine/TransformConstraint.cpp | 416 +++++++++++- .../spine-cpp/src/spine/VertexAttachment.cpp | 163 +++++ 25 files changed, 2014 insertions(+), 221 deletions(-) create mode 100644 spine-cpp/spine-cpp/include/spine/VertexAttachment.h create mode 100644 spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp diff --git a/spine-cpp/spine-cpp/include/spine/Attachment.h b/spine-cpp/spine-cpp/include/spine/Attachment.h index 9f9f8460d..fdf5a1a58 100644 --- a/spine-cpp/spine-cpp/include/spine/Attachment.h +++ b/spine-cpp/spine-cpp/include/spine/Attachment.h @@ -31,12 +31,16 @@ #ifndef Spine_Attachment_h #define Spine_Attachment_h +#include + #include namespace Spine { class Attachment { + RTTI_DECL; + public: Attachment(std::string name); diff --git a/spine-cpp/spine-cpp/include/spine/Bone.h b/spine-cpp/spine-cpp/include/spine/Bone.h index e189750b2..46c04d3a5 100644 --- a/spine-cpp/spine-cpp/include/spine/Bone.h +++ b/spine-cpp/spine-cpp/include/spine/Bone.h @@ -48,6 +48,8 @@ namespace Spine class Bone : public Updatable { friend class RotateTimeline; + friend class IkConstraint; + friend class TransformConstraint; public: static void setYDown(bool inValue); @@ -55,7 +57,7 @@ namespace Spine static bool isYDown(); /// @param parent May be NULL. - Bone(BoneData& data, Skeleton& skeleton, Bone* parent); + Bone(BoneData& data, Skeleton& skeleton, Bone* parent = NULL); /// Same as updateWorldTransform. This method exists for Bone to implement Spine::Updatable. virtual void update(); diff --git a/spine-cpp/spine-cpp/include/spine/BoneData.h b/spine-cpp/spine-cpp/include/spine/BoneData.h index 292f4a4c4..9710eda27 100644 --- a/spine-cpp/spine-cpp/include/spine/BoneData.h +++ b/spine-cpp/spine-cpp/include/spine/BoneData.h @@ -40,7 +40,7 @@ namespace Spine class BoneData { public: - BoneData(int index, std::string name, BoneData* parent); + BoneData(int index, std::string name, BoneData* parent = NULL); /// The index of the bone in Skeleton.Bones const int getIndex(); @@ -49,7 +49,7 @@ namespace Spine const std::string& getName(); /// May be NULL. - const BoneData* getParent(); + BoneData* getParent(); float getLength(); void setLength(float inValue); @@ -89,7 +89,7 @@ namespace Spine private: const int _index; const std::string _name; - const BoneData* _parent; + BoneData* _parent; float _length; float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY; TransformMode _transformMode; diff --git a/spine-cpp/spine-cpp/include/spine/ContainerUtil.h b/spine-cpp/spine-cpp/include/spine/ContainerUtil.h index ecc52e168..11d8e34e6 100644 --- a/spine-cpp/spine-cpp/include/spine/ContainerUtil.h +++ b/spine-cpp/spine-cpp/include/spine/ContainerUtil.h @@ -34,11 +34,52 @@ #include #include +#include +#include + namespace Spine { class ContainerUtil { public: + /// Finds an item by comparing each item's name. + /// It is more efficient to cache the results of this method than to call it multiple times. + /// @return May be NULL. + template + static T* findWithName(Vector& items, std::string name) + { + assert(name.length() > 0); + + for (typename T* i = items.begin(); i != items.end(); ++i) + { + T* item = (*i); + if (item->getName() == name) + { + return item; + } + } + + return NULL; + } + + /// @return -1 if the item was not found. + template + static int findIndexWithName(Vector& items, std::string name) + { + assert(name.length() > 0); + + for (size_t i = 0, size_t len = items.size(); i < len; ++i) + { + T* item = items[i]; + if (item->getName() == name) + { + return i; + } + } + + return -1; + } + template static void cleanUpVectorOfPointers(Vector& items) { diff --git a/spine-cpp/spine-cpp/include/spine/IkConstraint.h b/spine-cpp/spine-cpp/include/spine/IkConstraint.h index c0acf47be..b7359ea7b 100644 --- a/spine-cpp/spine-cpp/include/spine/IkConstraint.h +++ b/spine-cpp/spine-cpp/include/spine/IkConstraint.h @@ -31,9 +31,57 @@ #ifndef Spine_IkConstraint_h #define Spine_IkConstraint_h +#include + +#include + namespace Spine { - // TODO + class IkConstraintData; + class Skeleton; + class Bone; + + class IkConstraint : public Constraint + { + public: + /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified + /// in the world coordinate system. + static void apply(Bone& bone, float targetX, float targetY, float alpha); + + /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as + /// possible. The target is specified in the world coordinate system. + /// @param child A direct descendant of the parent bone. + static void apply(Bone& parent, Bone& child, float targetX, float targetY, int bendDir, float alpha); + + IkConstraint(IkConstraintData& data, Skeleton& skeleton); + + /// Applies the constraint to the constrained bones. + void apply(); + + virtual void update(); + + virtual int getOrder(); + + IkConstraintData& getData(); + + Vector& getBones(); + + Bone* getTarget(); + void setTarget(Bone* inValue); + + int getBendDirection(); + void setBendDirection(int inValue); + + float getMix(); + void setMix(float inValue); + + private: + IkConstraintData& _data; + Vector _bones; + Bone* _target; + float _mix; + int _bendDirection; + }; } #endif /* Spine_IkConstraint_h */ diff --git a/spine-cpp/spine-cpp/include/spine/IkConstraintData.h b/spine-cpp/spine-cpp/include/spine/IkConstraintData.h index 4f231f711..521101734 100644 --- a/spine-cpp/spine-cpp/include/spine/IkConstraintData.h +++ b/spine-cpp/spine-cpp/include/spine/IkConstraintData.h @@ -35,10 +35,10 @@ #include -class BoneData; - namespace Spine { + class BoneData; + class IkConstraintData { public: diff --git a/spine-cpp/spine-cpp/include/spine/MathUtil.h b/spine-cpp/spine-cpp/include/spine/MathUtil.h index a87a42d04..bc9bc5851 100644 --- a/spine-cpp/spine-cpp/include/spine/MathUtil.h +++ b/spine-cpp/spine-cpp/include/spine/MathUtil.h @@ -35,7 +35,7 @@ #include #define SPINE_PI 3.1415927f -#define SPINE_PI_2 PI * 2 +#define SPINE_PI_2 SPINE_PI * 2 #define RadDeg 180.0f / SPINE_PI #define DegRad SPINE_PI / 180.0f #define SIN_BITS 14 // 16KB. Adjust for accuracy. diff --git a/spine-cpp/spine-cpp/include/spine/PathConstraint.h b/spine-cpp/spine-cpp/include/spine/PathConstraint.h index 374875876..464622a3d 100644 --- a/spine-cpp/spine-cpp/include/spine/PathConstraint.h +++ b/spine-cpp/spine-cpp/include/spine/PathConstraint.h @@ -31,9 +31,74 @@ #ifndef Spine_PathConstraint_h #define Spine_PathConstraint_h +#include + +#include + namespace Spine { - // TODO + class PathConstraintData; + class Skeleton; + class PathAttachment; + class Bone; + class Slot; + + class PathConstraint : public Constraint + { + PathConstraint(PathConstraintData& data, Skeleton& skeleton); + + /// Applies the constraint to the constrained bones. + void apply(); + + virtual void update(); + + virtual int getOrder(); + + float getPosition(); + void setPosition(float inValue); + + float getSpacing(); + void setSpacing(float inValue); + + float getRotateMix(); + void setRotateMix(float inValue); + + float getTranslateMix(); + void setTranslateMix(float inValue); + + Vector& getBones(); + + Slot* getTarget(); + void setTarget(Slot* inValue); + + PathConstraintData& getData(); + + 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, _rotateMix, _translateMix; + + Vector _spaces; + Vector _positions; + Vector _world; + Vector _curves; + Vector _lengths; + Vector _segments; + + Vector computeWorldPositions(PathAttachment& path, int spacesCount, bool tangents, bool percentPosition, bool percentSpacing); + + static void addBeforePosition(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, Vector& output, int o, bool tangents); + }; } #endif /* Spine_PathConstraint_h */ diff --git a/spine-cpp/spine-cpp/include/spine/Skeleton.h b/spine-cpp/spine-cpp/include/spine/Skeleton.h index cbc6cdfbd..5c4f3e782 100644 --- a/spine-cpp/spine-cpp/include/spine/Skeleton.h +++ b/spine-cpp/spine-cpp/include/spine/Skeleton.h @@ -54,6 +54,8 @@ namespace Spine public: Skeleton(SkeletonData& data); + ~Skeleton(); + /// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added /// or removed. void updateCache(); @@ -155,7 +157,7 @@ namespace Spine void setFlipY(float inValue); private: - const SkeletonData& _data; + SkeletonData& _data; Vector _bones; Vector _slots; Vector _drawOrder; diff --git a/spine-cpp/spine-cpp/include/spine/SlotData.h b/spine-cpp/spine-cpp/include/spine/SlotData.h index e843d545c..310cf1fd5 100644 --- a/spine-cpp/spine-cpp/include/spine/SlotData.h +++ b/spine-cpp/spine-cpp/include/spine/SlotData.h @@ -48,7 +48,7 @@ namespace Spine const std::string& getName(); - const BoneData& getBoneData(); + BoneData& getBoneData(); float getR(); void setR(float inValue); @@ -78,7 +78,7 @@ namespace Spine private: const int _index; const std::string _name; - const BoneData& _boneData; + BoneData& _boneData; float _r, _g, _b, _a; float _r2, _g2, _b2; bool _hasSecondColor; diff --git a/spine-cpp/spine-cpp/include/spine/TransformConstraint.h b/spine-cpp/spine-cpp/include/spine/TransformConstraint.h index 54a3585dd..550988911 100644 --- a/spine-cpp/spine-cpp/include/spine/TransformConstraint.h +++ b/spine-cpp/spine-cpp/include/spine/TransformConstraint.h @@ -31,9 +31,60 @@ #ifndef Spine_TransformConstraint_h #define Spine_TransformConstraint_h +#include + +#include + namespace Spine { - // TODO + class TransformConstraintData; + class Skeleton; + class Bone; + + class TransformConstraint : public Constraint + { + public: + TransformConstraint(TransformConstraintData& data, Skeleton& skeleton); + + void apply(); + + virtual void update(); + + virtual int getOrder(); + + TransformConstraintData& getData(); + + Vector& getBones(); + + Bone* getTarget(); + void setTarget(Bone* inValue); + + float getRotateMix(); + void setRotateMix(float inValue); + + float getTranslateMix(); + void setTranslateMix(float inValue); + + float getScaleMix(); + void setScaleMix(float inValue); + + float getShearMix(); + void setShearMix(float inValue); + + private: + TransformConstraintData& _data; + Vector _bones; + Bone* _target; + float _rotateMix, _translateMix, _scaleMix, _shearMix; + + void applyAbsoluteWorld(); + + void applyRelativeWorld(); + + void applyAbsoluteLocal(); + + void applyRelativeLocal(); + }; } #endif /* Spine_TransformConstraint_h */ diff --git a/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h b/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h index eb978ad6c..c74bc25bc 100644 --- a/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h +++ b/spine-cpp/spine-cpp/include/spine/TransformConstraintData.h @@ -41,6 +41,8 @@ namespace Spine class TransformConstraintData { + friend class TransformConstraint; + public: TransformConstraintData(std::string name); diff --git a/spine-cpp/spine-cpp/include/spine/VertexAttachment.h b/spine-cpp/spine-cpp/include/spine/VertexAttachment.h new file mode 100644 index 000000000..18b5fc81c --- /dev/null +++ b/spine-cpp/spine-cpp/include/spine/VertexAttachment.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef Spine_VertexAttachment_h +#define Spine_VertexAttachment_h + +#include + +#include + +namespace Spine +{ + class Slot; + + /// An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's vertices. + class VertexAttachment : Attachment + { + public: + VertexAttachment(std::string name); + + void computeWorldVertices(Slot& slot, Vector& worldVertices); + + /// Transforms local vertices to world coordinates. + /// @param start The index of the first Vertices value to transform. Each vertex has 2 values, x and y. + /// @param count The number of world vertex values to output. Must be less than or equal to WorldVerticesLength - start. + /// @param worldVertices The output world vertices. Must have a length greater than or equal to offset + count. + /// @param offset The worldVertices index to begin writing values. + /// @param stride The number of worldVertices entries between the value pairs written. + void computeWorldVertices(Slot& slot, int start, int count, Vector& worldVertices, int offset, int stride = 2); + + /// @return true if a deform originally applied to the specified attachment should be applied to this attachment. + virtual bool applyDeform(VertexAttachment* sourceAttachment); + + /// Gets a unique ID for this attachment. + int getId(); + + Vector getBones(); + void setBones(Vector inValue); + + Vector getVertices(); + void setVertices(Vector inValue); + + int getWorldVerticesLength(); + void setWorldVerticesLength(int inValue); + + private: + const int _id; + Vector _bones; + Vector _vertices; + int _worldVerticesLength; + + static int getNextID(); + }; +} + +#endif /* Spine_VertexAttachment_h */ diff --git a/spine-cpp/spine-cpp/src/spine/Attachment.cpp b/spine-cpp/spine-cpp/src/spine/Attachment.cpp index fdd42ea70..829f8c7d6 100644 --- a/spine-cpp/spine-cpp/src/spine/Attachment.cpp +++ b/spine-cpp/spine-cpp/src/spine/Attachment.cpp @@ -43,4 +43,6 @@ namespace Spine { return _name; } + + RTTI_IMPL_NOPARENT(Attachment); } diff --git a/spine-cpp/spine-cpp/src/spine/Bone.cpp b/spine-cpp/spine-cpp/src/spine/Bone.cpp index a2dacdbe8..f4fe9ed59 100644 --- a/spine-cpp/spine-cpp/src/spine/Bone.cpp +++ b/spine-cpp/spine-cpp/src/spine/Bone.cpp @@ -111,14 +111,14 @@ namespace Spine float lb = MathUtil::cosDeg(rotationY) * scaleY; float lc = MathUtil::sinDeg(rotation + shearX) * scaleX; float ld = MathUtil::sinDeg(rotationY) * scaleY; - if (_skeleton.isFlipX()) + if (_skeleton.getFlipX()) { x = -x; la = -la; lb = -lb; } - if (_skeleton.isFlipY() != Bone::isYDown()) + if (_skeleton.getFlipY() != Bone::isYDown()) { y = -y; lc = -lc; @@ -223,7 +223,7 @@ namespace Spine 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()) + if (_data.getTransformMode() != TransformMode_NoScaleOrReflection ? pa * pd - pb * pc < 0 : _skeleton.getFlipX() != _skeleton.getFlipY()) { zb = -zb; zd = -zd; @@ -238,16 +238,16 @@ namespace Spine } } - if (_skeleton.isFlipX()) + if (_skeleton.getFlipX()) { _a = -_a; _b = -_b; } - if (skeleton.isFlipY() != Bone::isYDown()) + if (skeleton.getFlipY() != Bone::isYDown()) { - c = -c; - d = -d; + _c = -_c; + _d = -_d; } } diff --git a/spine-cpp/spine-cpp/src/spine/BoneData.cpp b/spine-cpp/spine-cpp/src/spine/BoneData.cpp index ed87124ff..47278ea6e 100644 --- a/spine-cpp/spine-cpp/src/spine/BoneData.cpp +++ b/spine-cpp/spine-cpp/src/spine/BoneData.cpp @@ -62,7 +62,7 @@ namespace Spine return _name; } - const BoneData* BoneData::getParent() + BoneData* BoneData::getParent() { return _parent; } diff --git a/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp b/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp index de9f96e64..67c0435cf 100644 --- a/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp +++ b/spine-cpp/spine-cpp/src/spine/CurveTimeline.cpp @@ -48,7 +48,7 @@ namespace Spine int CurveTimeline::getFrameCount() { - return _curves.size() / BEZIER_SIZE + 1; + return static_cast(_curves.size() / BEZIER_SIZE + 1); } void CurveTimeline::setLinear(int frameIndex) diff --git a/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp b/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp index bb4d2ccfe..73e68082d 100644 --- a/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/IkConstraint.cpp @@ -28,7 +28,333 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#include + +#include +#include +#include + +#include +#include + namespace Spine { - // TODO + void IkConstraint::apply(Bone& bone, float targetX, float targetY, float alpha) + { + if (!bone._appliedValid) + { + bone.updateAppliedTransform(); + } + + Bone* parent = bone.getParent(); + Bone p = *parent; + + 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 = (float)atan2(ty, tx) * RadDeg - bone._ashearX - bone._arotation; + + if (bone._ascaleX < 0) + { + rotationIK += 180; + } + + if (rotationIK > 180) + { + rotationIK -= 360; + } + else if (rotationIK < -180) + { + rotationIK += 360; + } + + bone.updateWorldTransform(bone._ax, bone._ay, bone._arotation + rotationIK * alpha, bone._ascaleX, bone._ascaleY, bone._ashearX, bone._ashearY); + } + + void IkConstraint::apply(Bone& parent, Bone& child, float targetX, float targetY, int bendDir, float alpha) + { + if (areFloatsPracticallyEqual(alpha, 0)) + { + child.updateWorldTransform(); + + return; + } + + if (!parent._appliedValid) + { + parent.updateAppliedTransform(); + } + + if (!child._appliedValid) + { + child.updateAppliedTransform(); + } + + float px = parent._ax; + float py = parent._ay; + float psx = parent._ascaleX; + float psy = parent._ascaleY; + float csx = child._ascaleX; + + int os1, os2, s2; + if (psx < 0) + { + psx = -psx; + os1 = 180; + s2 = -1; + } + else + { + os1 = 0; + s2 = 1; + } + + if (psy < 0) + { + psy = -psy; + s2 = -s2; + } + + if (csx < 0) + { + csx = -csx; + os2 = 180; + } + else + { + os2 = 0; + } + + float cx = child._ax; + float cy; + float cwx; + float cwy; + float a = parent._a; + float b = parent._b; + float c = parent._c; + float d = parent._d; + + bool u = fabs(psx - psy) <= 0.0001f; + if (!u) + { + cy = 0; + cwx = a * cx + parent._worldX; + cwy = c * cx + parent._worldY; + } + else + { + cy = child._ay; + cwx = a * cx + b * cy + parent._worldX; + cwy = c * cx + d * cy + parent._worldY; + } + + Bone* parentparent = parent._parent; + Bone pp = *parentparent; + + a = pp._a; + b = pp._b; + c = pp._c; + d = pp._d; + + float id = 1 / (a * d - b * c), x = targetX - pp._worldX, y = targetY - pp._worldY; + float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + 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 = (float)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); + if (cos < -1) + { + cos = -1; + } + else if (cos > 1) + { + cos = 1; + } + + a2 = (float)acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * (float)sin(a2); + a1 = (float)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 = (float)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 = (float)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; + if (r * r <= dd) + { + y = (float)sqrt(dd - r * r) * bendDir; + a1 = ta - (float)atan2(y, r); + a2 = (float)atan2(y / psy, (r - l1) / psx); + + float os = (float)atan2(cy, cx) * s2; + float rotation = parent._arotation; + a1 = (a1 - os) * RadDeg + os1 - rotation; + if (a1 > 180) + { + a1 -= 360; + } + else if (a1 < -180) + { + a1 += 360; + } + + parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent._scaleX, parent._ascaleY, 0, 0); + rotation = child._arotation; + a2 = ((a2 + os) * RadDeg - child._ashearX) * s2 + os2 - rotation; + + if (a2 > 180) + { + a2 -= 360; + } + else if (a2 < -180) + { + a2 += 360; + } + + child.updateWorldTransform(cx, cy, rotation + a2 * alpha, child._ascaleX, child._ascaleY, child._ashearX, child._ashearY); + + return; + } + } + + float minAngle = SPINE_PI, minX = l1 - a, minDist = minX * minX, minY = 0; + float maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) + { + c = (float)acos(c); + x = a * (float)cos(c) + l1; + y = b * (float)sin(c); + d = x * x + y * y; + + if (d < minDist) + { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + + if (d > maxDist) + { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + + if (dd <= (minDist + maxDist) / 2) + { + a1 = ta - (float)atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } + else + { + a1 = ta - (float)atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + } + + IkConstraint::IkConstraint(IkConstraintData& data, Skeleton& skeleton) : Constraint(), + _data(data), + _mix(data.getMix()), + _bendDirection(data.getBendDirection()), + _target(skeleton.findBone(data.getTarget()->getName())) + { + _bones.reserve(_data.getBones().size()); + for (BoneData** i = _data.getBones().begin(); i != _data.getBones().end(); ++i) + { + BoneData* boneData = (*i); + + _bones.push_back(skeleton.findBone(boneData->getName())); + } + } + + /// Applies the constraint to the constrained bones. + void IkConstraint::apply() + { + update(); + } + + void IkConstraint::update() + { + switch (_bones.size()) + { + case 1: + { + Bone* bone0 = _bones[0]; + apply(*bone0, _target->getWorldX(), _target->getWorldY(), _mix); + } + break; + case 2: + { + Bone* bone0 = _bones[0]; + Bone* bone1 = _bones[1]; + apply(*bone0, *bone1, _target->getWorldX(), _target->getWorldY(), _bendDirection, _mix); + } + break; + } + } + + int IkConstraint::getOrder() + { + return _data.getOrder(); + } + + IkConstraintData& IkConstraint::getData() + { + return _data; + } + + Vector& IkConstraint::getBones() + { + return _bones; + } + + Bone* IkConstraint::getTarget() + { + return _target; + } + + void IkConstraint::setTarget(Bone* inValue) + { + _target = inValue; + } + + int IkConstraint::getBendDirection() + { + return _bendDirection; + } + + void IkConstraint::setBendDirection(int inValue) + { + _bendDirection = inValue; + } + + float IkConstraint::getMix() + { + return _mix; + } + + void IkConstraint::setMix(float inValue) + { + _mix = inValue; + } } diff --git a/spine-cpp/spine-cpp/src/spine/IkConstraintData.cpp b/spine-cpp/spine-cpp/src/spine/IkConstraintData.cpp index 4f84d1f83..13378993f 100644 --- a/spine-cpp/spine-cpp/src/spine/IkConstraintData.cpp +++ b/spine-cpp/spine-cpp/src/spine/IkConstraintData.cpp @@ -30,6 +30,8 @@ #include +#include + namespace Spine { IkConstraintData::IkConstraintData(std::string name) : diff --git a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp index bb4d2ccfe..32e688782 100644 --- a/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/PathConstraint.cpp @@ -28,7 +28,606 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + namespace Spine { - // TODO + 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) : Constraint(), + _data(data), + _position(data.getPosition()), + _spacing(data.getSpacing()), + _rotateMix(data.getRotateMix()), + _translateMix(data.getTranslateMix()), + _target(skeleton.findSlot(data.getTarget()->getName())) + { + _bones.reserve(_data.getBones().size()); + for (BoneData** i = _data.getBones().begin(); i != _data.getBones().end(); ++i) + { + BoneData* boneData = (*i); + + _bones.push_back(skeleton.findBone(boneData->getName())); + } + + _segments.reserve(10); + } + + void PathConstraint::apply() + { + update(); + } + + void PathConstraint::update() + { + Attachment* baseAttachment = _target->getAttachment(); + if (baseAttachment == NULL || !baseAttachment->getRTTI().derivesFrom(PathAttachment::rtti)) + { + return; + } + + PathAttachment* attachment = static_cast(baseAttachment); + + float rotateMix = _rotateMix; + float translateMix = _translateMix; + bool translate = translateMix > 0; + bool rotate = rotateMix > 0; + if (!translate && !rotate) + { + return; + } + + PathConstraintData data = _data; + SpacingMode spacingMode = data.spacingMode; + bool lengthSpacing = spacingMode == SpacingMode.Length; + RotateMode rotateMode = data.rotateMode; + bool tangents = rotateMode == RotateMode_Tangent, scale = rotateMode == RotateMode_ChainScale; + int boneCount = _bones.Count, spacesCount = tangents ? boneCount : boneCount + 1; + Bone[] bonesItems = _bones.Items; + Vector spaces = _spaces.Resize(spacesCount), lengths = NULL; + float spacing = _spacing; + if (scale || lengthSpacing) + { + if (scale) + { + lengths = _lengths.Resize(boneCount); + } + + for (int i = 0, n = spacesCount - 1; i < n;) + { + Bone bone = bonesItems[i]; + float setupLength = bone.data.length; + if (setupLength < PathConstraint.EPSILON) + { + if (scale) + { + lengths.Items[i] = 0; + } + spaces.Items[++i] = 0; + } + else + { + float x = setupLength * bone.a, y = setupLength * bone.c; + float length = (float)Math.Sqrt(x * x + y * y); + if (scale) + { + lengths.Items[i] = length; + } + spaces.Items[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; + } + } + } + else + { + for (int i = 1; i < spacesCount; ++i) + { + spaces.Items[i] = spacing; + } + } + + float[] positions = computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == PositionMode_Percent, spacingMode == SpacingMode_Percent); + float boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + bool tip; + if (offsetRotation == 0) + { + tip = rotateMode == RotateMode_Chain; + } + else + { + tip = false; + Bone p = target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? DegRad : -DegRad; + } + + for (int i = 0, p = 3; i < boneCount; i++, p += 3) + { + Bone bone = bonesItems[i]; + bone.worldX += (boneX - bone.worldX) * translateMix; + bone.worldY += (boneY - bone.worldY) * translateMix; + float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) + { + float length = lengths.Items[i]; + if (length >= PathConstraint.EPSILON) + { + float s = ((float)Math.Sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; + bone.a *= s; + bone.c *= s; + } + } + + boneX = x; + boneY = y; + + if (rotate) + { + 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.Items[i + 1] < PathConstraint.EPSILON) + { + r = positions[p + 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.length; + boneX += (length * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length * (sin * a + cos * c) - dy) * rotateMix; + } + else + { + r += offsetRotation; + } + + if (r > SPINE_PI) + { + r -= SPINE_PI_2; + } + else if (r < -SPINE_PI) + { + r += SPINE_PI_2; + } + + r *= rotateMix; + 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.appliedValid = false; + } + } + + int PathConstraint::getOrder() + { + return _data.getOrder(); + } + + 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::getRotateMix() + { + return _rotateMix; + } + + void PathConstraint::setRotateMix(float inValue) + { + _rotateMix = inValue; + } + + float PathConstraint::getTranslateMix() + { + return _translateMix; + } + + void PathConstraint::setTranslateMix(float inValue) + { + _translateMix = inValue; + } + + Vector& PathConstraint::getBones() + { + return _bones; + } + + Slot* PathConstraint::getTarget() + { + return _target; + } + + void PathConstraint::setTarget(Slot* inValue) + { + _target = inValue; + } + + PathConstraintData& PathConstraint::getData() + { + return _data; + } + + Vector PathConstraint::computeWorldPositions(PathAttachment& path, int spacesCount, bool tangents, bool percentPosition, bool percentSpacing) + { + Slot target = *_target; + float position = _position; + float[] spacesItems = _spaces.Items, output = _positions.Resize(spacesCount * 3 + 2).Items, world; + bool closed = path.Closed; + int verticesLength = path.WorldVerticesLength, curveCount = verticesLength / 6, prevCurve = NONE; + + float pathLength; + if (!path.ConstantSpeed) + { + float[] lengths = path.Lengths; + curveCount -= closed ? 1 : 2; + pathLength = lengths[curveCount]; + if (percentPosition) + { + position *= pathLength; + } + + if (percentSpacing) + { + for (int i = 0; i < spacesCount; ++i) + { + spacesItems[i] *= pathLength; + } + } + + world = _world.Resize(8).Items; + for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) + { + float space = spacesItems[i]; + position += space; + float p = position; + + if (closed) + { + p %= pathLength; + if (p < 0) + { + p += pathLength; + } + curve = 0; + } + else if (p < 0) + { + if (prevCurve != BEFORE) + { + prevCurve = BEFORE; + path.ComputeWorldVertices(target, 2, 4, world, 0); + } + + addBeforePosition(p, world, 0, output, o); + + continue; + } + else if (p > pathLength) + { + if (prevCurve != AFTER) + { + prevCurve = AFTER; + path.ComputeWorldVertices(target, verticesLength - 6, 4, world, 0); + } + + addAfterPosition(p - pathLength, world, 0, output, o); + + continue; + } + + // Determine curve containing position. + for (;; curve++) + { + float length = lengths[curve]; + if (p > length) + { + continue; + } + + if (curve == 0) + { + p /= length; + } + else + { + float prev = lengths[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); + } + else + { + path.ComputeWorldVertices(target, curve * 6 + 2, 8, world, 0); + } + } + + addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], output, o, tangents || (i > 0 && space < EPSILON)); + } + return output; + } + + // World vertices. + if (closed) + { + verticesLength += 2; + world = _world.Resize(verticesLength).Items; + 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]; + } + else + { + curveCount--; + verticesLength -= 4; + world = _world.Resize(verticesLength).Items; + path.ComputeWorldVertices(target, 2, verticesLength, world, 0); + } + + // Curve lengths. + float[] curves = _curves.Resize(curveCount).Items; + pathLength = 0; + float x1 = world[0], y1 = world[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]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; + dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; + pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + + if (percentPosition) + { + position *= pathLength; + } + + if (percentSpacing) + { + for (int i = 0; i < spacesCount; ++i) + { + spacesItems[i] *= pathLength; + } + } + + float[] segments = _segments; + float curveLength = 0; + for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) + { + float space = spacesItems[i]; + position += space; + float p = position; + + if (closed) + { + p %= pathLength; + if (p < 0) + { + p += pathLength; + } + curve = 0; + } + else if (p < 0) + { + addBeforePosition(p, world, 0, output, o); + continue; + } + else if (p > pathLength) + { + addAfterPosition(p - pathLength, world, verticesLength - 4, output, o); + continue; + } + + // Determine curve containing position. + for (;; curve++) + { + float length = curves[curve]; + if (p > length) + { + continue; + } + + if (curve == 0) + { + p /= length; + } + else + { + float prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + + // Curve segment lengths. + 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]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; + dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; + curveLength = (float)Math.Sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) + { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + + // Weight by segment length. + p *= curveLength; + for (;; segment++) + { + float length = segments[segment]; + if (p > length) + { + continue; + } + + if (segment == 0) + { + p /= length; + } + else + { + float prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, output, o, tangents || (i > 0 && space < EPSILON)); + } + + return output; + } + + 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; + } + + 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; + } + + 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 || float.IsNaN(p)) + { + p = EPSILON; + } + + 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; + if (tangents) + { + output[o + 2] = (float)Math.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/Skeleton.cpp b/spine-cpp/spine-cpp/src/spine/Skeleton.cpp index 88eefbd5a..aeae9606c 100644 --- a/spine-cpp/spine-cpp/src/spine/Skeleton.cpp +++ b/spine-cpp/spine-cpp/src/spine/Skeleton.cpp @@ -40,6 +40,14 @@ #include #include +#include +#include +#include +#include +#include + +#include + namespace Spine { Skeleton::Skeleton(SkeletonData& data) : @@ -56,61 +64,78 @@ namespace Spine _y(0) { _bones.reserve(_data.getBones().size()); - - foreach (BoneData boneData in _data.getBones()) + for (BoneData** i = _data.getBones().begin(); i != _data.getBones().end(); ++i) { - Bone bone; - if (boneData.parent == NULL) + BoneData* data = (*i); + + Bone* bone; + if (data->getParent() == NULL) { - bone = new Bone(boneData, this, NULL); + bone = new Bone(*data, *this, NULL); } else { - Bone parent = bones.Items[boneData.parent.index]; - bone = new Bone(boneData, this, parent); - parent.children.Add(bone); + Bone* parent = _bones[data->getParent()->getIndex()]; + bone = new Bone(*data, *this, parent); + parent->getChildren().push_back(bone); } - bones.Add(bone); + _bones.push_back(bone); } _slots.reserve(_data.getSlots().size()); _drawOrder.reserve(_data.getSlots().size()); - - foreach (SlotData slotData in data.slots) + for (SlotData** i = _data.getSlots().begin(); i != _data.getSlots().end(); ++i) { - Bone bone = bones.Items[slotData.boneData.index]; - Slot slot = new Slot(slotData, bone); - slots.Add(slot); - drawOrder.Add(slot); + SlotData* data = (*i); + + Bone* bone = _bones[data->getBoneData().getIndex()]; + Slot* slot = new Slot(*data, *bone); + + _slots.push_back(slot); + _drawOrder.push_back(slot); } - ikConstraints = new Vector(data.ikConstraints.Count); - - foreach (IkConstraintData ikConstraintData in data.ikConstraints) + _ikConstraints.reserve(_data.getIkConstraints().size()); + for (IkConstraintData** i = _data.getIkConstraints().begin(); i != _data.getIkConstraints().end(); ++i) { - ikConstraints.Add(new IkConstraint(ikConstraintData, this)); + IkConstraintData* data = (*i); + + _ikConstraints.push_back(new IkConstraint(*data, *this)); } - transformConstraints = new Vector(data.transformConstraints.Count); - foreach (TransformConstraintData transformConstraintData in data.transformConstraints) + _transformConstraints.reserve(_data.getTransformConstraints().size()); + for (TransformConstraintData** i = _data.getTransformConstraints().begin(); i != _data.getTransformConstraints().end(); ++i) { - transformConstraints.Add(new TransformConstraint(transformConstraintData, this)); + TransformConstraintData* data = (*i); + + _transformConstraints.push_back(new TransformConstraint(*data, *this)); } - pathConstraints = new Vector (data.pathConstraints.Count); - foreach (PathConstraintData pathConstraintData in data.pathConstraints) + _pathConstraints.reserve(_data.getPathConstraints().size()); + for (PathConstraintData** i = _data.getPathConstraints().begin(); i != _data.getPathConstraints().end(); ++i) { - pathConstraints.Add(new PathConstraint(pathConstraintData, this)); + PathConstraintData* data = (*i); + + _pathConstraints.push_back(new PathConstraint(*data, *this)); } updateCache(); updateWorldTransform(); } + Skeleton::~Skeleton() + { + ContainerUtil::cleanUpVectorOfPointers(_bones); + ContainerUtil::cleanUpVectorOfPointers(_slots); + ContainerUtil::cleanUpVectorOfPointers(_ikConstraints); + ContainerUtil::cleanUpVectorOfPointers(_transformConstraints); + ContainerUtil::cleanUpVectorOfPointers(_pathConstraints); + } + void Skeleton::updateCache() { - Vector updateCache = _updateCache; + Vector updateCache = _updateCache; updateCache.Clear(); _updateCacheReset.Clear(); diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonData.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonData.cpp index bd5cac04d..201359534 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonData.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonData.cpp @@ -39,6 +39,8 @@ #include #include +#include + #include namespace Spine @@ -54,244 +56,206 @@ namespace Spine BoneData* SkeletonData::findBone(std::string boneName) { - assert(boneName.length() > 0); - - for (BoneData** i = _bones.begin(); i != _bones.end(); ++i) - { - BoneData* boneData = (*i); - if (boneData->getName() == boneName) - { - return boneData; - } - } - - return NULL; + return ContainerUtil::findWithName(_bones, boneName); } int SkeletonData::findBoneIndex(std::string boneName) { - assert(boneName.length() > 0); - - var bones = this.bones; - var bonesItems = bones.Items; - for (int i = 0, n = bones.Count; i < n; ++i) - { - if (bonesItems[i].name == boneName) - { - return i; - } - } - - return -1; + return ContainerUtil::findIndexWithName(_bones, boneName); } - /// Use a template findWithName method instead to reduce redundant data container traversal code SlotData* SkeletonData::findSlot(std::string slotName) { - assert(slotName.length() > 0); - - Vector slots = this.slots; - for (int i = 0, n = slots.Count; i < n; ++i) - { - SlotData slot = slots.Items[i]; - if (slot.name == slotName) - { - return slot; - } - } - - return NULL; + return ContainerUtil::findWithName(_slots, slotName); } int SkeletonData::findSlotIndex(std::string slotName) { - assert(slotName.length() > 0); - - Vector slots = this.slots; - for (int i = 0, n = slots.Count; i < n; ++i) - { - if (slots.Items[i].name == slotName) - { - return i; - } - } - - return -1; + return ContainerUtil::findIndexWithName(_slots, slotName); } Skin* SkeletonData::findSkin(std::string skinName) { - assert(skinName.length() > 0); - - foreach (Skin skin in skins) - { - if (skin.name == skinName) - { - return skin; - } - } - - return NULL; + return ContainerUtil::findWithName(_skins, skinName); } EventData* SkeletonData::findEvent(std::string eventDataName) { - assert(eventDataName.length() > 0); - - foreach (EventData eventData in events) - { - if (eventData.name == eventDataName) - { - return eventData; - } - } - - return NULL; + return ContainerUtil::findWithName(_events, eventDataName); } Animation* SkeletonData::findAnimation(std::string animationName) { - assert(animationName.length() > 0); - - Vector animations = this.animations; - for (int i = 0, n = animations.Count; i < n; ++i) - { - Animation animation = animations.Items[i]; - if (animation.name == animationName) - { - return animation; - } - } - - return NULL; + return ContainerUtil::findWithName(_animations, animationName); } IkConstraintData* SkeletonData::findIkConstraint(std::string constraintName) { - assert(constraintName.length() > 0); - - Vector ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.Count; i < n; ++i) - { - IkConstraintData ikConstraint = ikConstraints.Items[i]; - if (ikConstraint.name == constraintName) - { - return ikConstraint; - } - } - - return NULL; + return ContainerUtil::findWithName(_ikConstraints, constraintName); } TransformConstraintData* SkeletonData::findTransformConstraint(std::string constraintName) { - assert(constraintName.length() > 0); - - Vector transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.Count; i < n; ++i) - { - TransformConstraintData transformConstraint = transformConstraints.Items[i]; - if (transformConstraint.name == constraintName) - { - return transformConstraint; - } - } - - return NULL; + return ContainerUtil::findWithName(_transformConstraints, constraintName); } PathConstraintData* SkeletonData::findPathConstraint(std::string constraintName) { - assert(constraintName.length() > 0); - - Vector pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; ++i) - { - PathConstraintData constraint = pathConstraints.Items[i]; - if (constraint.name.Equals(constraintName)) - { - return constraint; - } - } - - return NULL; + return ContainerUtil::findWithName(_pathConstraints, constraintName); } int SkeletonData::findPathConstraintIndex(std::string pathConstraintName) { - assert(pathConstraintName.length() > 0); - - Vector pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; ++i) - { - if (pathConstraints.Items[i].name.Equals(pathConstraintName)) - { - return i; - } - } - - return -1; + return ContainerUtil::findIndexWithName(_pathConstraints, pathConstraintName); } - std::string SkeletonData::getName() { return _name; } + std::string SkeletonData::getName() + { + return _name; + } - void SkeletonData::setName(std::string inValue) { _name = inValue; } + void SkeletonData::setName(std::string inValue) + { + _name = inValue; + } - Vector& SkeletonData::getBones() { return _bones; } + Vector& SkeletonData::getBones() + { + return _bones; + } - Vector& SkeletonData::getSlots() { return _slots; } + Vector& SkeletonData::getSlots() + { + return _slots; + } - Vector& SkeletonData::getSkins() { return _skins; } + Vector& SkeletonData::getSkins() + { + return _skins; + } - void SkeletonData::setSkins(Vector& inValue) { _skins = inValue; } + void SkeletonData::setSkins(Vector& inValue) + { + _skins = inValue; + } - Skin* SkeletonData::getDefaultSkin() { return _defaultSkin; } + Skin* SkeletonData::getDefaultSkin() + { + return _defaultSkin; + } - void SkeletonData::setDefaultSkin(Skin* inValue) { _defaultSkin = inValue; } + void SkeletonData::setDefaultSkin(Skin* inValue) + { + _defaultSkin = inValue; + } - Vector& SkeletonData::getEvents() { return _events; } + Vector& SkeletonData::getEvents() + { + return _events; + } - void SkeletonData::setEvents(Vector& inValue) { _events = inValue; } + void SkeletonData::setEvents(Vector& inValue) + { + _events = inValue; + } - Vector& SkeletonData::getAnimations() { return _animations; } + Vector& SkeletonData::getAnimations() + { + return _animations; + } - void SkeletonData::setAnimations(Vector& inValue) { _animations = inValue; } + void SkeletonData::setAnimations(Vector& inValue) + { + _animations = inValue; + } - Vector& SkeletonData::getIkConstraints() { return _ikConstraints; } + Vector& SkeletonData::getIkConstraints() + { + return _ikConstraints; + } - void SkeletonData::setIkConstraints(Vector& inValue) { _ikConstraints = inValue; } + void SkeletonData::setIkConstraints(Vector& inValue) + { + _ikConstraints = inValue; + } - Vector& SkeletonData::getTransformConstraints() { return _transformConstraints; } + Vector& SkeletonData::getTransformConstraints() + { + return _transformConstraints; + } - void SkeletonData::setTransformConstraints(Vector& inValue) { _transformConstraints = inValue; } + void SkeletonData::setTransformConstraints(Vector& inValue) + { + _transformConstraints = inValue; + } - Vector& SkeletonData::getPathConstraints() { return _pathConstraints; } + Vector& SkeletonData::getPathConstraints() + { + return _pathConstraints; + } - void SkeletonData::setPathConstraints(Vector& inValue) { _pathConstraints = inValue; } + void SkeletonData::setPathConstraints(Vector& inValue) + { + _pathConstraints = inValue; + } - float SkeletonData::getWidth() { return _width; } + float SkeletonData::getWidth() + { + return _width; + } - void SkeletonData::setWidth(float inValue) { _width = inValue; } + void SkeletonData::setWidth(float inValue) + { + _width = inValue; + } - float SkeletonData::getHeight() { return _height; } + float SkeletonData::getHeight() + { + return _height; + } - void SkeletonData::setHeight(float inValue) { _height = inValue; } + void SkeletonData::setHeight(float inValue) + { + _height = inValue; + } - /// The Spine version used to export this data, or NULL. - std::string SkeletonData::getVersion() { return _version; } + std::string SkeletonData::getVersion() + { + return _version; + } - void SkeletonData::setVersion(std::string inValue) { _version = inValue; } + void SkeletonData::setVersion(std::string inValue) + { + _version = inValue; + } - std::string SkeletonData::getHash() { return _hash; } + std::string SkeletonData::getHash() + { + return _hash; + } - void SkeletonData::setHash(std::string inValue) { _hash = inValue; } + void SkeletonData::setHash(std::string inValue) + { + _hash = inValue; + } - std::string SkeletonData::getImagesPath() { return _imagesPath; } + std::string SkeletonData::getImagesPath() + { + return _imagesPath; + } - void SkeletonData::setImagesPath(std::string inValue) { _imagesPath = inValue; } + void SkeletonData::setImagesPath(std::string inValue) + { + _imagesPath = inValue; + } - /// The dopesheet FPS in Spine. Available only when nonessential data was exported. - float SkeletonData::getFps { return _fps; } + float SkeletonData::getFps() + { + return _fps; + } - void SkeletonData::setFps(float inValue) { _fps = inValue; } + void SkeletonData::setFps(float inValue) + { + _fps = inValue; + } } diff --git a/spine-cpp/spine-cpp/src/spine/Skin.cpp b/spine-cpp/spine-cpp/src/spine/Skin.cpp index 291ded0bf..d2b8c7259 100644 --- a/spine-cpp/spine-cpp/src/spine/Skin.cpp +++ b/spine-cpp/spine-cpp/src/spine/Skin.cpp @@ -114,7 +114,7 @@ namespace Spine for (HashMap::Iterator i = oldSkin.getAttachments().begin(); i != oldSkin.getAttachments().end(); ++i) { int slotIndex = i.first()._slotIndex; - Slot* slot = skeleton.getSlots().at(slotIndex); + Slot* slot = skeleton.getSlots()[slotIndex]; if (slot->getAttachment() == i.second()) { diff --git a/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp b/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp index bb4d2ccfe..06669c000 100644 --- a/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp +++ b/spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp @@ -28,7 +28,421 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#include + +#include +#include +#include + +#include +#include + namespace Spine { - // TODO + TransformConstraint::TransformConstraint(TransformConstraintData& data, Skeleton& skeleton) : Constraint(), + _data(data), + _rotateMix(data.getRotateMix()), + _translateMix(data.getTranslateMix()), + _scaleMix(data.getScaleMix()), + _shearMix(data.getShearMix()), + _target(skeleton.findBone(data.getTarget()->getName())) + { + _bones.reserve(_data.getBones().size()); + for (BoneData** i = _data.getBones().begin(); i != _data.getBones().end(); ++i) + { + BoneData* boneData = (*i); + + _bones.push_back(skeleton.findBone(boneData->getName())); + } + } + + void TransformConstraint::apply() + { + update(); + } + + void TransformConstraint::update() + { + if (_data.isLocal()) + { + if (_data.isRelative()) + { + applyRelativeLocal(); + } + else + { + applyAbsoluteLocal(); + } + } + else + { + if (_data.isRelative()) + { + applyRelativeWorld(); + } + else + { + applyAbsoluteWorld(); + } + } + } + + int TransformConstraint::getOrder() + { + return _data.getOrder(); + } + + TransformConstraintData& TransformConstraint::getData() + { + return _data; + } + + Vector& TransformConstraint::getBones() + { + return _bones; + } + + Bone* TransformConstraint::getTarget() + { + return _target; + } + + void TransformConstraint::setTarget(Bone* inValue) + { + _target = inValue; + } + + float TransformConstraint::getRotateMix() + { + return _rotateMix; + } + + void TransformConstraint::setRotateMix(float inValue) + { + _rotateMix = inValue; + } + + float TransformConstraint::getTranslateMix() + { + return _translateMix; + } + + void TransformConstraint::setTranslateMix(float inValue) + { + _translateMix = inValue; + } + + float TransformConstraint::getScaleMix() + { + return _scaleMix; + } + + void TransformConstraint::setScaleMix(float inValue) + { + _scaleMix = inValue; + } + + float TransformConstraint::getShearMix() + { + return _shearMix; + } + + void TransformConstraint::setShearMix(float inValue) + { + _shearMix = inValue; + } + + void TransformConstraint::applyAbsoluteWorld() + { + float rotateMix = _rotateMix, translateMix = _translateMix, scaleMix = _scaleMix, shearMix = _shearMix; + Bone target = *_target; + float ta = target._a, tb = target._b, tc = target._c, td = target._d; + float degRadReflect = ta * td - tb * tc > 0 ? DegRad : -DegRad; + float offsetRotation = _data._offsetRotation * degRadReflect, offsetShearY = _data._offsetShearY * degRadReflect; + + for (Bone** i = _bones.begin(); i != _bones.end(); ++i) + { + Bone* item = (*i); + Bone& bone = *item; + + bool modified = false; + + if (rotateMix != 0) + { + float a = bone._a, b = bone._b, c = bone._c, d = bone._d; + float r = MathUtil::atan2(tc, ta) - MathUtil::atan2(c, a) + offsetRotation; + if (r > SPINE_PI) + { + r -= SPINE_PI_2; + } + else if (r < -SPINE_PI) + { + r += SPINE_PI_2; + } + + r *= rotateMix; + float 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; + modified = true; + } + + if (translateMix != 0) + { + float tx, ty; + target.localToWorld(_data._offsetX, _data._offsetY, tx, ty); + bone._worldX += (tx - bone._worldX) * translateMix; + bone._worldY += (ty - bone._worldY) * translateMix; + modified = true; + } + + if (scaleMix > 0) + { + float s = (float)sqrt(bone._a * bone._a + bone._c * bone._c); + + if (s > 0.00001f) + { + s = (s + ((float)sqrt(ta * ta + tc * tc) - s + _data._offsetScaleX) * scaleMix) / s; + } + bone._a *= s; + bone._c *= s; + s = (float)sqrt(bone._b * bone._b + bone._d * bone._d); + + if (s > 0.00001f) + { + s = (s + ((float)sqrt(tb * tb + td * td) - s + _data._offsetScaleY) * scaleMix) / s; + } + bone._b *= s; + bone._d *= s; + modified = true; + } + + if (shearMix > 0) + { + float b = bone._b, d = bone._d; + float by = MathUtil::atan2(d, b); + float r = MathUtil::atan2(td, tb) - MathUtil::atan2(tc, ta) - (by - MathUtil::atan2(bone._c, bone._a)); + if (r > SPINE_PI) + { + r -= SPINE_PI_2; + } + else if (r < -SPINE_PI) + { + r += SPINE_PI_2; + } + + r = by + (r + offsetShearY) * shearMix; + float s = (float)sqrt(b * b + d * d); + bone._b = MathUtil::cos(r) * s; + bone._d = MathUtil::sin(r) * s; + modified = true; + } + + if (modified) + { + bone._appliedValid = false; + } + } + } + + void TransformConstraint::applyRelativeWorld() + { + float rotateMix = _rotateMix, translateMix = _translateMix, scaleMix = _scaleMix, shearMix = _shearMix; + Bone target = *_target; + float ta = target._a, tb = target._b, tc = target._c, td = target._d; + float degRadReflect = ta * td - tb * tc > 0 ? DegRad : -DegRad; + float offsetRotation = _data._offsetRotation * degRadReflect, offsetShearY = _data._offsetShearY * degRadReflect; + for (Bone** i = _bones.begin(); i != _bones.end(); ++i) + { + Bone* item = (*i); + Bone& bone = *item; + + bool modified = false; + + if (rotateMix != 0) + { + float a = bone._a, b = bone._b, c = bone._c, d = bone._d; + float r = MathUtil::atan2(tc, ta) + offsetRotation; + if (r > SPINE_PI) + { + r -= SPINE_PI_2; + } + else if (r < -SPINE_PI) + { + r += SPINE_PI_2; + } + + r *= rotateMix; + float 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; + modified = true; + } + + if (translateMix != 0) + { + float tx, ty; + target.localToWorld(_data._offsetX, _data._offsetY, tx, ty); + bone._worldX += tx * translateMix; + bone._worldY += ty * translateMix; + modified = true; + } + + if (scaleMix > 0) + { + float s = ((float)sqrt(ta * ta + tc * tc) - 1 + _data._offsetScaleX) * scaleMix + 1; + bone._a *= s; + bone._c *= s; + s = ((float)sqrt(tb * tb + td * td) - 1 + _data._offsetScaleY) * scaleMix + 1; + bone._b *= s; + bone._d *= s; + modified = true; + } + + if (shearMix > 0) + { + float r = MathUtil::atan2(td, tb) - MathUtil::atan2(tc, ta); + if (r > SPINE_PI) + { + r -= SPINE_PI_2; + } + else if (r < -SPINE_PI) + { + r += SPINE_PI_2; + } + + float b = bone._b, d = bone._d; + r = MathUtil::atan2(d, b) + (r - SPINE_PI / 2 + offsetShearY) * shearMix; + float s = (float)sqrt(b * b + d * d); + bone._b = MathUtil::cos(r) * s; + bone._d = MathUtil::sin(r) * s; + modified = true; + } + + if (modified) + { + bone._appliedValid = false; + } + } + } + + void TransformConstraint::applyAbsoluteLocal() + { + float rotateMix = _rotateMix, translateMix = _translateMix, scaleMix = _scaleMix, shearMix = _shearMix; + Bone target = *_target; + if (!target._appliedValid) + { + target.updateAppliedTransform(); + } + + for (Bone** i = _bones.begin(); i != _bones.end(); ++i) + { + Bone* item = (*i); + Bone& bone = *item; + + if (!bone._appliedValid) + { + bone.updateAppliedTransform(); + } + + float rotation = bone._arotation; + if (rotateMix != 0) + { + float r = target._arotation - rotation + _data._offsetRotation; + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; + rotation += r * rotateMix; + } + + float x = bone._ax, y = bone._ay; + if (translateMix != 0) + { + x += (target._ax - x + _data._offsetX) * translateMix; + y += (target._ay - y + _data._offsetY) * translateMix; + } + + float scaleX = bone._ascaleX, scaleY = bone._ascaleY; + if (scaleMix > 0) + { + if (scaleX > 0.00001f) + { + scaleX = (scaleX + (target._ascaleX - scaleX + _data._offsetScaleX) * scaleMix) / scaleX; + } + + if (scaleY > 0.00001f) + { + scaleY = (scaleY + (target._ascaleY - scaleY + _data._offsetScaleY) * scaleMix) / scaleY; + } + } + + float shearY = bone._ashearY; + if (shearMix > 0) + { + float r = target._ashearY - shearY + _data._offsetShearY; + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; + bone._shearY += r * shearMix; + } + + bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone._ashearX, shearY); + } + } + + void TransformConstraint::applyRelativeLocal() + { + float rotateMix = _rotateMix, translateMix = _translateMix, scaleMix = _scaleMix, shearMix = _shearMix; + Bone target = *_target; + if (!target._appliedValid) + { + target.updateAppliedTransform(); + } + + for (Bone** i = _bones.begin(); i != _bones.end(); ++i) + { + Bone* item = (*i); + Bone& bone = *item; + + if (!bone._appliedValid) + { + bone.updateAppliedTransform(); + } + + float rotation = bone._arotation; + if (rotateMix != 0) + { + rotation += (target._arotation + _data._offsetRotation) * rotateMix; + } + + float x = bone._ax, y = bone._ay; + if (translateMix != 0) + { + x += (target._ax + _data._offsetX) * translateMix; + y += (target._ay + _data._offsetY) * translateMix; + } + + float scaleX = bone._ascaleX, scaleY = bone._ascaleY; + if (scaleMix > 0) + { + if (scaleX > 0.00001f) + { + scaleX *= ((target._ascaleX - 1 + data.offsetScaleX) * scaleMix) + 1; + } + + if (scaleY > 0.00001f) + { + scaleY *= ((target._ascaleY - 1 + data.offsetScaleY) * scaleMix) + 1; + } + } + + float shearY = bone._ashearY; + if (shearMix > 0) + { + shearY += (target._ashearY + data.offsetShearY) * shearMix; + } + + bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone._ashearX, shearY); + } + } } diff --git a/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp b/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp new file mode 100644 index 000000000..02819a18f --- /dev/null +++ b/spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp @@ -0,0 +1,163 @@ +/****************************************************************************** +* 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 + +#include + +namespace Spine +{ + VertexAttachment::VertexAttachment(std::string name) : Attachment(name), _id(getNextID()), _worldVerticesLength(0) + { + // Empty + } + + void VertexAttachment::computeWorldVertices(Slot& slot, Vector& worldVertices) + { + computeWorldVertices(slot, 0, _worldVerticesLength, worldVertices, 0); + } + + void VertexAttachment::computeWorldVertices(Slot& slot, int start, int count, Vector& worldVertices, int offset, int stride) + { + count = offset + (count >> 1) * stride; + Skeleton skeleton = slot.bone.skeleton; + var deformArray = slot.attachmentVertices; + Vector vertices = _vertices; + Vector bones = _bones; + if (bones == NULL) + { + if (deformArray.Count > 0) vertices = deformArray.Items; + Bone bone = slot.bone; + float x = bone.worldX, y = bone.worldY; + float a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (int vv = start, w = offset; w < count; vv += 2, w += stride) + { + float vx = vertices[vv], vy = vertices[vv + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + + int v = 0, skip = 0; + for (int i = 0; i < start; i += 2) + { + int n = bones[v]; + v += n + 1; + skip += n; + } + + var skeletonBones = skeleton.bones.Items; + if (deformArray.Count == 0) + { + for (int w = offset, b = skip * 3; w < count; w += stride) + { + float wx = 0, wy = 0; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) + { + Bone bone = skeletonBones[bones[v]]; + float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + else + { + Vector deform = deformArray.Items; + for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) + { + float wx = 0, wy = 0; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) + { + Bone bone = skeletonBones[bones[v]]; + float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } + + bool VertexAttachment::applyDeform(VertexAttachment* sourceAttachment) + { + return this == sourceAttachment; + } + + int VertexAttachment::getId() + { + return _id; + } + + Vector VertexAttachment::getBones() + { + return _bones; + } + + void VertexAttachment::setBones(Vector inValue) + { + _bones = inValue; + } + + Vector VertexAttachment::getVertices() + { + return _vertices; + } + + void VertexAttachment::setVertices(Vector inValue) + { + _vertices = inValue; + } + + int VertexAttachment::getWorldVerticesLength() + { + return _worldVerticesLength; + } + + void VertexAttachment::setWorldVerticesLength(int inValue) + { + _worldVerticesLength = inValue; + } + + int VertexAttachment::getNextID() + { + static int nextID = 0; + + return (nextID++ & 65535) << 11; + } +}