mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
wip
This commit is contained in:
parent
9129d64100
commit
d7a569d47d
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -35,10 +35,10 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
class BoneData;
|
||||
|
||||
namespace Spine
|
||||
{
|
||||
class BoneData;
|
||||
|
||||
class IkConstraintData
|
||||
{
|
||||
public:
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -41,6 +41,8 @@ namespace Spine
|
||||
|
||||
class TransformConstraintData
|
||||
{
|
||||
friend class TransformConstraint;
|
||||
|
||||
public:
|
||||
TransformConstraintData(std::string name);
|
||||
|
||||
|
||||
83
spine-cpp/spine-cpp/include/spine/VertexAttachment.h
Normal file
83
spine-cpp/spine-cpp/include/spine/VertexAttachment.h
Normal 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 */
|
||||
@ -43,4 +43,6 @@ namespace Spine
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
RTTI_IMPL_NOPARENT(Attachment);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ namespace Spine
|
||||
return _name;
|
||||
}
|
||||
|
||||
const BoneData* BoneData::getParent()
|
||||
BoneData* BoneData::getParent()
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
|
||||
#include <spine/IkConstraintData.h>
|
||||
|
||||
#include <spine/BoneData.h>
|
||||
|
||||
namespace Spine
|
||||
{
|
||||
IkConstraintData::IkConstraintData(std::string name) :
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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())
|
||||
{
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
163
spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp
Normal file
163
spine-cpp/spine-cpp/src/spine/VertexAttachment.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user