This commit is contained in:
Stephen Gowen 2017-10-22 21:08:29 -04:00
parent 9129d64100
commit d7a569d47d
25 changed files with 2014 additions and 221 deletions

View File

@ -31,12 +31,16 @@
#ifndef Spine_Attachment_h
#define Spine_Attachment_h
#include <spine/RTTI.h>
#include <string>
namespace Spine
{
class Attachment
{
RTTI_DECL;
public:
Attachment(std::string name);

View File

@ -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();

View File

@ -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;

View File

@ -34,11 +34,52 @@
#include <spine/Vector.h>
#include <spine/HashMap.h>
#include <string>
#include <assert.h>
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<typename T>
static T* findWithName(Vector<T*>& 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<typename T>
static int findIndexWithName(Vector<T*>& 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<typename T>
static void cleanUpVectorOfPointers(Vector<T*>& items)
{

View File

@ -31,9 +31,57 @@
#ifndef Spine_IkConstraint_h
#define Spine_IkConstraint_h
#include <spine/Constraint.h>
#include <spine/Vector.h>
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<Bone*>& getBones();
Bone* getTarget();
void setTarget(Bone* inValue);
int getBendDirection();
void setBendDirection(int inValue);
float getMix();
void setMix(float inValue);
private:
IkConstraintData& _data;
Vector<Bone*> _bones;
Bone* _target;
float _mix;
int _bendDirection;
};
}
#endif /* Spine_IkConstraint_h */

View File

@ -35,10 +35,10 @@
#include <string>
class BoneData;
namespace Spine
{
class BoneData;
class IkConstraintData
{
public:

View File

@ -35,7 +35,7 @@
#include <float.h>
#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.

View File

@ -31,9 +31,74 @@
#ifndef Spine_PathConstraint_h
#define Spine_PathConstraint_h
#include <spine/Constraint.h>
#include <spine/Vector.h>
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<Bone*>& 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<Bone*> _bones;
Slot* _target;
float _position, _spacing, _rotateMix, _translateMix;
Vector<float> _spaces;
Vector<float> _positions;
Vector<float> _world;
Vector<float> _curves;
Vector<float> _lengths;
Vector<float> _segments;
Vector<float> computeWorldPositions(PathAttachment& path, int spacesCount, bool tangents, bool percentPosition, bool percentSpacing);
static void addBeforePosition(float p, Vector<float>& temp, int i, Vector<float>& output, int o);
static void addAfterPosition(float p, Vector<float>& temp, int i, Vector<float>& 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<float>& output, int o, bool tangents);
};
}
#endif /* Spine_PathConstraint_h */

View File

@ -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<Bone*> _bones;
Vector<Slot*> _slots;
Vector<Slot*> _drawOrder;

View File

@ -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;

View File

@ -31,9 +31,60 @@
#ifndef Spine_TransformConstraint_h
#define Spine_TransformConstraint_h
#include <spine/Constraint.h>
#include <spine/Vector.h>
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<Bone*>& 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<Bone*> _bones;
Bone* _target;
float _rotateMix, _translateMix, _scaleMix, _shearMix;
void applyAbsoluteWorld();
void applyRelativeWorld();
void applyAbsoluteLocal();
void applyRelativeLocal();
};
}
#endif /* Spine_TransformConstraint_h */

View File

@ -41,6 +41,8 @@ namespace Spine
class TransformConstraintData
{
friend class TransformConstraint;
public:
TransformConstraintData(std::string name);

View File

@ -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 <spine/Attachment.h>
#include <spine/Vector.h>
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<float>& 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<float>& 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<int> getBones();
void setBones(Vector<int> inValue);
Vector<float> getVertices();
void setVertices(Vector<float> inValue);
int getWorldVerticesLength();
void setWorldVerticesLength(int inValue);
private:
const int _id;
Vector<int> _bones;
Vector<float> _vertices;
int _worldVerticesLength;
static int getNextID();
};
}
#endif /* Spine_VertexAttachment_h */

View File

@ -43,4 +43,6 @@ namespace Spine
{
return _name;
}
RTTI_IMPL_NOPARENT(Attachment);
}

View File

@ -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;
}
}

View File

@ -62,7 +62,7 @@ namespace Spine
return _name;
}
const BoneData* BoneData::getParent()
BoneData* BoneData::getParent()
{
return _parent;
}

View File

@ -48,7 +48,7 @@ namespace Spine
int CurveTimeline::getFrameCount()
{
return _curves.size() / BEZIER_SIZE + 1;
return static_cast<int>(_curves.size() / BEZIER_SIZE + 1);
}
void CurveTimeline::setLinear(int frameIndex)

View File

@ -28,7 +28,333 @@
* POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <spine/IkConstraint.h>
#include <spine/IkConstraintData.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/MathUtil.h>
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<Bone*>& 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;
}
}

View File

@ -30,6 +30,8 @@
#include <spine/IkConstraintData.h>
#include <spine/BoneData.h>
namespace Spine
{
IkConstraintData::IkConstraintData(std::string name) :

View File

@ -28,7 +28,606 @@
* POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <spine/PathConstraint.h>
#include <spine/PathConstraintData.h>
#include <spine/Skeleton.h>
#include <spine/PathAttachment.h>
#include <spine/Bone.h>
#include <spine/Slot.h>
#include <spine/SlotData.h>
#include <spine/BoneData.h>
#include <spine/SpacingMode.h>
#include <spine/PositionMode.h>
#include <spine/RotateMode.h>
#include <spine/MathUtil.h>
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<PathAttachment*>(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<float> 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<Bone*>& PathConstraint::getBones()
{
return _bones;
}
Slot* PathConstraint::getTarget()
{
return _target;
}
void PathConstraint::setTarget(Slot* inValue)
{
_target = inValue;
}
PathConstraintData& PathConstraint::getData()
{
return _data;
}
Vector<float> 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<float>& temp, int i, Vector<float>& 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<float>& temp, int i, Vector<float>& 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<float>& 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));
}
}
}

View File

@ -40,6 +40,14 @@
#include <spine/Skin.h>
#include <spine/Attachment.h>
#include <spine/BoneData.h>
#include <spine/SlotData.h>
#include <spine/IkConstraintData.h>
#include <spine/TransformConstraintData.h>
#include <spine/PathConstraintData.h>
#include <spine/ContainerUtil.h>
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<IkConstraint>(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<TransformConstraint>(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<PathConstraint> (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<IUpdatable> updateCache = _updateCache;
Vector<Updatable> updateCache = _updateCache;
updateCache.Clear();
_updateCacheReset.Clear();

View File

@ -39,6 +39,8 @@
#include <spine/TransformConstraintData.h>
#include <spine/PathConstraintData.h>
#include <spine/ContainerUtil.h>
#include <assert.h>
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<SlotData> 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<SlotData> 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<Animation*> 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<IkConstraintData> 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<TransformConstraintData> 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<PathConstraintData> 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<PathConstraintData> 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<BoneData*>& SkeletonData::getBones() { return _bones; }
Vector<BoneData*>& SkeletonData::getBones()
{
return _bones;
}
Vector<SlotData*>& SkeletonData::getSlots() { return _slots; }
Vector<SlotData*>& SkeletonData::getSlots()
{
return _slots;
}
Vector<Skin*>& SkeletonData::getSkins() { return _skins; }
Vector<Skin*>& SkeletonData::getSkins()
{
return _skins;
}
void SkeletonData::setSkins(Vector<Skin*>& inValue) { _skins = inValue; }
void SkeletonData::setSkins(Vector<Skin*>& 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<EventData*>& SkeletonData::getEvents() { return _events; }
Vector<EventData*>& SkeletonData::getEvents()
{
return _events;
}
void SkeletonData::setEvents(Vector<EventData*>& inValue) { _events = inValue; }
void SkeletonData::setEvents(Vector<EventData*>& inValue)
{
_events = inValue;
}
Vector<Animation*>& SkeletonData::getAnimations() { return _animations; }
Vector<Animation*>& SkeletonData::getAnimations()
{
return _animations;
}
void SkeletonData::setAnimations(Vector<Animation*>& inValue) { _animations = inValue; }
void SkeletonData::setAnimations(Vector<Animation*>& inValue)
{
_animations = inValue;
}
Vector<IkConstraintData*>& SkeletonData::getIkConstraints() { return _ikConstraints; }
Vector<IkConstraintData*>& SkeletonData::getIkConstraints()
{
return _ikConstraints;
}
void SkeletonData::setIkConstraints(Vector<IkConstraintData*>& inValue) { _ikConstraints = inValue; }
void SkeletonData::setIkConstraints(Vector<IkConstraintData*>& inValue)
{
_ikConstraints = inValue;
}
Vector<TransformConstraintData*>& SkeletonData::getTransformConstraints() { return _transformConstraints; }
Vector<TransformConstraintData*>& SkeletonData::getTransformConstraints()
{
return _transformConstraints;
}
void SkeletonData::setTransformConstraints(Vector<TransformConstraintData*>& inValue) { _transformConstraints = inValue; }
void SkeletonData::setTransformConstraints(Vector<TransformConstraintData*>& inValue)
{
_transformConstraints = inValue;
}
Vector<PathConstraintData*>& SkeletonData::getPathConstraints() { return _pathConstraints; }
Vector<PathConstraintData*>& SkeletonData::getPathConstraints()
{
return _pathConstraints;
}
void SkeletonData::setPathConstraints(Vector<PathConstraintData*>& inValue) { _pathConstraints = inValue; }
void SkeletonData::setPathConstraints(Vector<PathConstraintData*>& 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;
}
}

View File

@ -114,7 +114,7 @@ namespace Spine
for (HashMap<AttachmentKey, Attachment*, HashAttachmentKey>::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())
{

View File

@ -28,7 +28,421 @@
* POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <spine/TransformConstraint.h>
#include <spine/TransformConstraintData.h>
#include <spine/Skeleton.h>
#include <spine/Bone.h>
#include <spine/BoneData.h>
#include <spine/MathUtil.h>
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<Bone*>& 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);
}
}
}

View File

@ -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 <spine/VertexAttachment.h>
#include <spine/Slot.h>
namespace Spine
{
VertexAttachment::VertexAttachment(std::string name) : Attachment(name), _id(getNextID()), _worldVerticesLength(0)
{
// Empty
}
void VertexAttachment::computeWorldVertices(Slot& slot, Vector<float>& worldVertices)
{
computeWorldVertices(slot, 0, _worldVerticesLength, worldVertices, 0);
}
void VertexAttachment::computeWorldVertices(Slot& slot, int start, int count, Vector<float>& worldVertices, int offset, int stride)
{
count = offset + (count >> 1) * stride;
Skeleton skeleton = slot.bone.skeleton;
var deformArray = slot.attachmentVertices;
Vector<float> vertices = _vertices;
Vector<int> 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<float> 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<int> VertexAttachment::getBones()
{
return _bones;
}
void VertexAttachment::setBones(Vector<int> inValue)
{
_bones = inValue;
}
Vector<float> VertexAttachment::getVertices()
{
return _vertices;
}
void VertexAttachment::setVertices(Vector<float> 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;
}
}