mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
wip
This commit is contained in:
parent
9129d64100
commit
d7a569d47d
@ -31,12 +31,16 @@
|
|||||||
#ifndef Spine_Attachment_h
|
#ifndef Spine_Attachment_h
|
||||||
#define Spine_Attachment_h
|
#define Spine_Attachment_h
|
||||||
|
|
||||||
|
#include <spine/RTTI.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
class Attachment
|
class Attachment
|
||||||
{
|
{
|
||||||
|
RTTI_DECL;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Attachment(std::string name);
|
Attachment(std::string name);
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,8 @@ namespace Spine
|
|||||||
class Bone : public Updatable
|
class Bone : public Updatable
|
||||||
{
|
{
|
||||||
friend class RotateTimeline;
|
friend class RotateTimeline;
|
||||||
|
friend class IkConstraint;
|
||||||
|
friend class TransformConstraint;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void setYDown(bool inValue);
|
static void setYDown(bool inValue);
|
||||||
@ -55,7 +57,7 @@ namespace Spine
|
|||||||
static bool isYDown();
|
static bool isYDown();
|
||||||
|
|
||||||
/// @param parent May be NULL.
|
/// @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.
|
/// Same as updateWorldTransform. This method exists for Bone to implement Spine::Updatable.
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
|||||||
@ -40,7 +40,7 @@ namespace Spine
|
|||||||
class BoneData
|
class BoneData
|
||||||
{
|
{
|
||||||
public:
|
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
|
/// The index of the bone in Skeleton.Bones
|
||||||
const int getIndex();
|
const int getIndex();
|
||||||
@ -49,7 +49,7 @@ namespace Spine
|
|||||||
const std::string& getName();
|
const std::string& getName();
|
||||||
|
|
||||||
/// May be NULL.
|
/// May be NULL.
|
||||||
const BoneData* getParent();
|
BoneData* getParent();
|
||||||
|
|
||||||
float getLength();
|
float getLength();
|
||||||
void setLength(float inValue);
|
void setLength(float inValue);
|
||||||
@ -89,7 +89,7 @@ namespace Spine
|
|||||||
private:
|
private:
|
||||||
const int _index;
|
const int _index;
|
||||||
const std::string _name;
|
const std::string _name;
|
||||||
const BoneData* _parent;
|
BoneData* _parent;
|
||||||
float _length;
|
float _length;
|
||||||
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
|
float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
|
||||||
TransformMode _transformMode;
|
TransformMode _transformMode;
|
||||||
|
|||||||
@ -34,11 +34,52 @@
|
|||||||
#include <spine/Vector.h>
|
#include <spine/Vector.h>
|
||||||
#include <spine/HashMap.h>
|
#include <spine/HashMap.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
class ContainerUtil
|
class ContainerUtil
|
||||||
{
|
{
|
||||||
public:
|
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>
|
template<typename T>
|
||||||
static void cleanUpVectorOfPointers(Vector<T*>& items)
|
static void cleanUpVectorOfPointers(Vector<T*>& items)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -31,9 +31,57 @@
|
|||||||
#ifndef Spine_IkConstraint_h
|
#ifndef Spine_IkConstraint_h
|
||||||
#define Spine_IkConstraint_h
|
#define Spine_IkConstraint_h
|
||||||
|
|
||||||
|
#include <spine/Constraint.h>
|
||||||
|
|
||||||
|
#include <spine/Vector.h>
|
||||||
|
|
||||||
namespace Spine
|
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 */
|
#endif /* Spine_IkConstraint_h */
|
||||||
|
|||||||
@ -35,10 +35,10 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class BoneData;
|
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
|
class BoneData;
|
||||||
|
|
||||||
class IkConstraintData
|
class IkConstraintData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#define SPINE_PI 3.1415927f
|
#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 RadDeg 180.0f / SPINE_PI
|
||||||
#define DegRad SPINE_PI / 180.0f
|
#define DegRad SPINE_PI / 180.0f
|
||||||
#define SIN_BITS 14 // 16KB. Adjust for accuracy.
|
#define SIN_BITS 14 // 16KB. Adjust for accuracy.
|
||||||
|
|||||||
@ -31,9 +31,74 @@
|
|||||||
#ifndef Spine_PathConstraint_h
|
#ifndef Spine_PathConstraint_h
|
||||||
#define Spine_PathConstraint_h
|
#define Spine_PathConstraint_h
|
||||||
|
|
||||||
|
#include <spine/Constraint.h>
|
||||||
|
|
||||||
|
#include <spine/Vector.h>
|
||||||
|
|
||||||
namespace Spine
|
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 */
|
#endif /* Spine_PathConstraint_h */
|
||||||
|
|||||||
@ -54,6 +54,8 @@ namespace Spine
|
|||||||
public:
|
public:
|
||||||
Skeleton(SkeletonData& data);
|
Skeleton(SkeletonData& data);
|
||||||
|
|
||||||
|
~Skeleton();
|
||||||
|
|
||||||
/// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added
|
/// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added
|
||||||
/// or removed.
|
/// or removed.
|
||||||
void updateCache();
|
void updateCache();
|
||||||
@ -155,7 +157,7 @@ namespace Spine
|
|||||||
void setFlipY(float inValue);
|
void setFlipY(float inValue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SkeletonData& _data;
|
SkeletonData& _data;
|
||||||
Vector<Bone*> _bones;
|
Vector<Bone*> _bones;
|
||||||
Vector<Slot*> _slots;
|
Vector<Slot*> _slots;
|
||||||
Vector<Slot*> _drawOrder;
|
Vector<Slot*> _drawOrder;
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace Spine
|
|||||||
|
|
||||||
const std::string& getName();
|
const std::string& getName();
|
||||||
|
|
||||||
const BoneData& getBoneData();
|
BoneData& getBoneData();
|
||||||
|
|
||||||
float getR();
|
float getR();
|
||||||
void setR(float inValue);
|
void setR(float inValue);
|
||||||
@ -78,7 +78,7 @@ namespace Spine
|
|||||||
private:
|
private:
|
||||||
const int _index;
|
const int _index;
|
||||||
const std::string _name;
|
const std::string _name;
|
||||||
const BoneData& _boneData;
|
BoneData& _boneData;
|
||||||
float _r, _g, _b, _a;
|
float _r, _g, _b, _a;
|
||||||
float _r2, _g2, _b2;
|
float _r2, _g2, _b2;
|
||||||
bool _hasSecondColor;
|
bool _hasSecondColor;
|
||||||
|
|||||||
@ -31,9 +31,60 @@
|
|||||||
#ifndef Spine_TransformConstraint_h
|
#ifndef Spine_TransformConstraint_h
|
||||||
#define Spine_TransformConstraint_h
|
#define Spine_TransformConstraint_h
|
||||||
|
|
||||||
|
#include <spine/Constraint.h>
|
||||||
|
|
||||||
|
#include <spine/Vector.h>
|
||||||
|
|
||||||
namespace Spine
|
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 */
|
#endif /* Spine_TransformConstraint_h */
|
||||||
|
|||||||
@ -41,6 +41,8 @@ namespace Spine
|
|||||||
|
|
||||||
class TransformConstraintData
|
class TransformConstraintData
|
||||||
{
|
{
|
||||||
|
friend class TransformConstraint;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransformConstraintData(std::string name);
|
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;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTTI_IMPL_NOPARENT(Attachment);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,14 +111,14 @@ namespace Spine
|
|||||||
float lb = MathUtil::cosDeg(rotationY) * scaleY;
|
float lb = MathUtil::cosDeg(rotationY) * scaleY;
|
||||||
float lc = MathUtil::sinDeg(rotation + shearX) * scaleX;
|
float lc = MathUtil::sinDeg(rotation + shearX) * scaleX;
|
||||||
float ld = MathUtil::sinDeg(rotationY) * scaleY;
|
float ld = MathUtil::sinDeg(rotationY) * scaleY;
|
||||||
if (_skeleton.isFlipX())
|
if (_skeleton.getFlipX())
|
||||||
{
|
{
|
||||||
x = -x;
|
x = -x;
|
||||||
la = -la;
|
la = -la;
|
||||||
lb = -lb;
|
lb = -lb;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_skeleton.isFlipY() != Bone::isYDown())
|
if (_skeleton.getFlipY() != Bone::isYDown())
|
||||||
{
|
{
|
||||||
y = -y;
|
y = -y;
|
||||||
lc = -lc;
|
lc = -lc;
|
||||||
@ -223,7 +223,7 @@ namespace Spine
|
|||||||
float lc = MathUtil::sinDeg(shearX) * scaleX;
|
float lc = MathUtil::sinDeg(shearX) * scaleX;
|
||||||
float ld = MathUtil::sinDeg(90 + shearY) * scaleY;
|
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;
|
zb = -zb;
|
||||||
zd = -zd;
|
zd = -zd;
|
||||||
@ -238,16 +238,16 @@ namespace Spine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_skeleton.isFlipX())
|
if (_skeleton.getFlipX())
|
||||||
{
|
{
|
||||||
_a = -_a;
|
_a = -_a;
|
||||||
_b = -_b;
|
_b = -_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skeleton.isFlipY() != Bone::isYDown())
|
if (skeleton.getFlipY() != Bone::isYDown())
|
||||||
{
|
{
|
||||||
c = -c;
|
_c = -_c;
|
||||||
d = -d;
|
_d = -_d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@ namespace Spine
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoneData* BoneData::getParent()
|
BoneData* BoneData::getParent()
|
||||||
{
|
{
|
||||||
return _parent;
|
return _parent;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace Spine
|
|||||||
|
|
||||||
int CurveTimeline::getFrameCount()
|
int CurveTimeline::getFrameCount()
|
||||||
{
|
{
|
||||||
return _curves.size() / BEZIER_SIZE + 1;
|
return static_cast<int>(_curves.size() / BEZIER_SIZE + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CurveTimeline::setLinear(int frameIndex)
|
void CurveTimeline::setLinear(int frameIndex)
|
||||||
|
|||||||
@ -28,7 +28,333 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* 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
|
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/IkConstraintData.h>
|
||||||
|
|
||||||
|
#include <spine/BoneData.h>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
{
|
{
|
||||||
IkConstraintData::IkConstraintData(std::string name) :
|
IkConstraintData::IkConstraintData(std::string name) :
|
||||||
|
|||||||
@ -28,7 +28,606 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* 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
|
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/Skin.h>
|
||||||
#include <spine/Attachment.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
|
namespace Spine
|
||||||
{
|
{
|
||||||
Skeleton::Skeleton(SkeletonData& data) :
|
Skeleton::Skeleton(SkeletonData& data) :
|
||||||
@ -56,61 +64,78 @@ namespace Spine
|
|||||||
_y(0)
|
_y(0)
|
||||||
{
|
{
|
||||||
_bones.reserve(_data.getBones().size());
|
_bones.reserve(_data.getBones().size());
|
||||||
|
for (BoneData** i = _data.getBones().begin(); i != _data.getBones().end(); ++i)
|
||||||
foreach (BoneData boneData in _data.getBones())
|
|
||||||
{
|
{
|
||||||
Bone bone;
|
BoneData* data = (*i);
|
||||||
if (boneData.parent == NULL)
|
|
||||||
|
Bone* bone;
|
||||||
|
if (data->getParent() == NULL)
|
||||||
{
|
{
|
||||||
bone = new Bone(boneData, this, NULL);
|
bone = new Bone(*data, *this, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Bone parent = bones.Items[boneData.parent.index];
|
Bone* parent = _bones[data->getParent()->getIndex()];
|
||||||
bone = new Bone(boneData, this, parent);
|
bone = new Bone(*data, *this, parent);
|
||||||
parent.children.Add(bone);
|
parent->getChildren().push_back(bone);
|
||||||
}
|
}
|
||||||
|
|
||||||
bones.Add(bone);
|
_bones.push_back(bone);
|
||||||
}
|
}
|
||||||
|
|
||||||
_slots.reserve(_data.getSlots().size());
|
_slots.reserve(_data.getSlots().size());
|
||||||
_drawOrder.reserve(_data.getSlots().size());
|
_drawOrder.reserve(_data.getSlots().size());
|
||||||
|
for (SlotData** i = _data.getSlots().begin(); i != _data.getSlots().end(); ++i)
|
||||||
foreach (SlotData slotData in data.slots)
|
|
||||||
{
|
{
|
||||||
Bone bone = bones.Items[slotData.boneData.index];
|
SlotData* data = (*i);
|
||||||
Slot slot = new Slot(slotData, bone);
|
|
||||||
slots.Add(slot);
|
Bone* bone = _bones[data->getBoneData().getIndex()];
|
||||||
drawOrder.Add(slot);
|
Slot* slot = new Slot(*data, *bone);
|
||||||
|
|
||||||
|
_slots.push_back(slot);
|
||||||
|
_drawOrder.push_back(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
ikConstraints = new Vector<IkConstraint>(data.ikConstraints.Count);
|
_ikConstraints.reserve(_data.getIkConstraints().size());
|
||||||
|
for (IkConstraintData** i = _data.getIkConstraints().begin(); i != _data.getIkConstraints().end(); ++i)
|
||||||
foreach (IkConstraintData ikConstraintData in data.ikConstraints)
|
|
||||||
{
|
{
|
||||||
ikConstraints.Add(new IkConstraint(ikConstraintData, this));
|
IkConstraintData* data = (*i);
|
||||||
|
|
||||||
|
_ikConstraints.push_back(new IkConstraint(*data, *this));
|
||||||
}
|
}
|
||||||
|
|
||||||
transformConstraints = new Vector<TransformConstraint>(data.transformConstraints.Count);
|
_transformConstraints.reserve(_data.getTransformConstraints().size());
|
||||||
foreach (TransformConstraintData transformConstraintData in data.transformConstraints)
|
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);
|
_pathConstraints.reserve(_data.getPathConstraints().size());
|
||||||
foreach (PathConstraintData pathConstraintData in data.pathConstraints)
|
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();
|
updateCache();
|
||||||
updateWorldTransform();
|
updateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Skeleton::~Skeleton()
|
||||||
|
{
|
||||||
|
ContainerUtil::cleanUpVectorOfPointers(_bones);
|
||||||
|
ContainerUtil::cleanUpVectorOfPointers(_slots);
|
||||||
|
ContainerUtil::cleanUpVectorOfPointers(_ikConstraints);
|
||||||
|
ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
|
||||||
|
ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
void Skeleton::updateCache()
|
void Skeleton::updateCache()
|
||||||
{
|
{
|
||||||
Vector<IUpdatable> updateCache = _updateCache;
|
Vector<Updatable> updateCache = _updateCache;
|
||||||
updateCache.Clear();
|
updateCache.Clear();
|
||||||
_updateCacheReset.Clear();
|
_updateCacheReset.Clear();
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,8 @@
|
|||||||
#include <spine/TransformConstraintData.h>
|
#include <spine/TransformConstraintData.h>
|
||||||
#include <spine/PathConstraintData.h>
|
#include <spine/PathConstraintData.h>
|
||||||
|
|
||||||
|
#include <spine/ContainerUtil.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
namespace Spine
|
namespace Spine
|
||||||
@ -54,244 +56,206 @@ namespace Spine
|
|||||||
|
|
||||||
BoneData* SkeletonData::findBone(std::string boneName)
|
BoneData* SkeletonData::findBone(std::string boneName)
|
||||||
{
|
{
|
||||||
assert(boneName.length() > 0);
|
return ContainerUtil::findWithName(_bones, boneName);
|
||||||
|
|
||||||
for (BoneData** i = _bones.begin(); i != _bones.end(); ++i)
|
|
||||||
{
|
|
||||||
BoneData* boneData = (*i);
|
|
||||||
if (boneData->getName() == boneName)
|
|
||||||
{
|
|
||||||
return boneData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkeletonData::findBoneIndex(std::string boneName)
|
int SkeletonData::findBoneIndex(std::string boneName)
|
||||||
{
|
{
|
||||||
assert(boneName.length() > 0);
|
return ContainerUtil::findIndexWithName(_bones, boneName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a template findWithName method instead to reduce redundant data container traversal code
|
|
||||||
SlotData* SkeletonData::findSlot(std::string slotName)
|
SlotData* SkeletonData::findSlot(std::string slotName)
|
||||||
{
|
{
|
||||||
assert(slotName.length() > 0);
|
return ContainerUtil::findWithName(_slots, slotName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkeletonData::findSlotIndex(std::string slotName)
|
int SkeletonData::findSlotIndex(std::string slotName)
|
||||||
{
|
{
|
||||||
assert(slotName.length() > 0);
|
return ContainerUtil::findIndexWithName(_slots, slotName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Skin* SkeletonData::findSkin(std::string skinName)
|
Skin* SkeletonData::findSkin(std::string skinName)
|
||||||
{
|
{
|
||||||
assert(skinName.length() > 0);
|
return ContainerUtil::findWithName(_skins, skinName);
|
||||||
|
|
||||||
foreach (Skin skin in skins)
|
|
||||||
{
|
|
||||||
if (skin.name == skinName)
|
|
||||||
{
|
|
||||||
return skin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventData* SkeletonData::findEvent(std::string eventDataName)
|
EventData* SkeletonData::findEvent(std::string eventDataName)
|
||||||
{
|
{
|
||||||
assert(eventDataName.length() > 0);
|
return ContainerUtil::findWithName(_events, eventDataName);
|
||||||
|
|
||||||
foreach (EventData eventData in events)
|
|
||||||
{
|
|
||||||
if (eventData.name == eventDataName)
|
|
||||||
{
|
|
||||||
return eventData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation* SkeletonData::findAnimation(std::string animationName)
|
Animation* SkeletonData::findAnimation(std::string animationName)
|
||||||
{
|
{
|
||||||
assert(animationName.length() > 0);
|
return ContainerUtil::findWithName(_animations, animationName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IkConstraintData* SkeletonData::findIkConstraint(std::string constraintName)
|
IkConstraintData* SkeletonData::findIkConstraint(std::string constraintName)
|
||||||
{
|
{
|
||||||
assert(constraintName.length() > 0);
|
return ContainerUtil::findWithName(_ikConstraints, constraintName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TransformConstraintData* SkeletonData::findTransformConstraint(std::string constraintName)
|
TransformConstraintData* SkeletonData::findTransformConstraint(std::string constraintName)
|
||||||
{
|
{
|
||||||
assert(constraintName.length() > 0);
|
return ContainerUtil::findWithName(_transformConstraints, constraintName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PathConstraintData* SkeletonData::findPathConstraint(std::string constraintName)
|
PathConstraintData* SkeletonData::findPathConstraint(std::string constraintName)
|
||||||
{
|
{
|
||||||
assert(constraintName.length() > 0);
|
return ContainerUtil::findWithName(_pathConstraints, constraintName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkeletonData::findPathConstraintIndex(std::string pathConstraintName)
|
int SkeletonData::findPathConstraintIndex(std::string pathConstraintName)
|
||||||
{
|
{
|
||||||
assert(pathConstraintName.length() > 0);
|
return ContainerUtil::findIndexWithName(_pathConstraints, pathConstraintName);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
std::string SkeletonData::getVersion() { return _version; }
|
{
|
||||||
|
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()
|
||||||
float SkeletonData::getFps { return _fps; }
|
{
|
||||||
|
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)
|
for (HashMap<AttachmentKey, Attachment*, HashAttachmentKey>::Iterator i = oldSkin.getAttachments().begin(); i != oldSkin.getAttachments().end(); ++i)
|
||||||
{
|
{
|
||||||
int slotIndex = i.first()._slotIndex;
|
int slotIndex = i.first()._slotIndex;
|
||||||
Slot* slot = skeleton.getSlots().at(slotIndex);
|
Slot* slot = skeleton.getSlots()[slotIndex];
|
||||||
|
|
||||||
if (slot->getAttachment() == i.second())
|
if (slot->getAttachment() == i.second())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -28,7 +28,421 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* 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
|
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