[cpp] Fix SkeletinBinary, fix memory leaks

This commit is contained in:
Mario Zechner 2024-04-01 13:29:26 +02:00
parent ff4cfbaa05
commit 2dc7335b4e
12 changed files with 393 additions and 176 deletions

View File

@ -37,6 +37,8 @@ namespace spine {
/// The interface for all constraints. /// The interface for all constraints.
class SP_API ConstraintData : public SpineObject { class SP_API ConstraintData : public SpineObject {
friend class SkeletonBinary;
RTTI_DECL RTTI_DECL
public: public:

View File

@ -42,12 +42,16 @@ namespace spine {
friend class SkeletonJson; friend class SkeletonJson;
public: public:
LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent, LinkedMesh(MeshAttachment *mesh, const int skinIndex, size_t slotIndex, const String &parent,
bool inheritTimeline); bool inheritTimeline);
LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
bool inheritTimeline);
private: private:
MeshAttachment *_mesh; MeshAttachment *_mesh;
String _skin; int _skinIndex;
String _skin;
size_t _slotIndex; size_t _slotIndex;
String _parent; String _parent;
bool _inheritTimeline; bool _inheritTimeline;

View File

@ -75,6 +75,7 @@ namespace spine {
static const int BONE_SHEAR = 7; static const int BONE_SHEAR = 7;
static const int BONE_SHEARX = 8; static const int BONE_SHEARX = 8;
static const int BONE_SHEARY = 9; static const int BONE_SHEARY = 9;
static const int BONE_INHERIT = 10;
static const int SLOT_ATTACHMENT = 0; static const int SLOT_ATTACHMENT = 0;
static const int SLOT_RGBA = 1; static const int SLOT_RGBA = 1;
@ -90,6 +91,15 @@ namespace spine {
static const int PATH_SPACING = 1; static const int PATH_SPACING = 1;
static const int PATH_MIX = 2; static const int PATH_MIX = 2;
static const int PHYSICS_INERTIA = 0;
static const int PHYSICS_STRENGTH = 1;
static const int PHYSICS_DAMPING = 2;
static const int PHYSICS_MASS = 4;
static const int PHYSICS_WIND = 5;
static const int PHYSICS_GRAVITY = 6;
static const int PHYSICS_MIX = 7;
static const int PHYSICS_RESET = 8;
static const int CURVE_LINEAR = 0; static const int CURVE_LINEAR = 0;
static const int CURVE_STEPPED = 1; static const int CURVE_STEPPED = 1;
static const int CURVE_BEZIER = 2; static const int CURVE_BEZIER = 2;
@ -147,11 +157,11 @@ namespace spine {
Attachment *readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName, Attachment *readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
SkeletonData *skeletonData, bool nonessential); SkeletonData *skeletonData, bool nonessential);
void readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, int vertexCount); int readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, bool weighted);
void readFloatArray(DataInput *input, int n, float scale, Vector<float> &array); void readFloatArray(DataInput *input, int n, float scale, Vector<float> &array);
void readShortArray(DataInput *input, Vector<unsigned short> &array); void readShortArray(DataInput *input, Vector<unsigned short> &array, int n);
Animation *readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData); Animation *readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData);
@ -159,9 +169,9 @@ namespace spine {
setBezier(DataInput *input, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2, setBezier(DataInput *input, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale); float value1, float value2, float scale);
Timeline *readTimeline(DataInput *input, CurveTimeline1 *timeline, float scale); void readTimeline(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline1 *timeline, float scale);
Timeline *readTimeline2(DataInput *input, CurveTimeline2 *timeline, float scale); void readTimeline2(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline2 *timeline, float scale);
}; };
} }

View File

@ -195,7 +195,7 @@ namespace spine {
} }
String substring(int startIndex, int length) const { String substring(int startIndex, int length) const {
if (startIndex < 0 || startIndex >= _length || length < 0 || startIndex + length > _length) { if (startIndex < 0 || startIndex >= (int)_length || length < 0 || startIndex + length > (int)_length) {
return String(); return String();
} }
char* subStr = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__); char* subStr = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
@ -205,7 +205,7 @@ namespace spine {
} }
String substring(int startIndex) const { String substring(int startIndex) const {
if (startIndex < 0 || startIndex >= _length) { if (startIndex < 0 || startIndex >= (int)_length) {
return String(); return String();
} }
int length = _length - startIndex; int length = _length - startIndex;

View File

@ -45,7 +45,7 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
float rotationIK = -bone._ashearX - bone._arotation; float rotationIK = -bone._ashearX - bone._arotation;
float tx = 0, ty = 0; float tx = 0, ty = 0;
switch (bone._data.getInherit()) { switch (bone._inherit) {
case Inherit_OnlyTranslation: case Inherit_OnlyTranslation:
tx = (targetX - bone._worldX) * MathUtil::sign(bone.getSkeleton().getScaleX()); tx = (targetX - bone._worldX) * MathUtil::sign(bone.getSkeleton().getScaleX());
ty = (targetY - bone._worldY) * MathUtil::sign(bone.getSkeleton().getScaleY()); ty = (targetY - bone._worldY) * MathUtil::sign(bone.getSkeleton().getScaleY());
@ -77,7 +77,7 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
float sx = bone._ascaleX; float sx = bone._ascaleX;
float sy = bone._ascaleY; float sy = bone._ascaleY;
if (compress || stretch) { if (compress || stretch) {
switch (bone._data.getInherit()) { switch (bone._inherit) {
case Inherit_NoScale: case Inherit_NoScale:
case Inherit_NoScaleOrReflection: case Inherit_NoScaleOrReflection:
tx = targetX - bone._worldX; tx = targetX - bone._worldX;
@ -109,7 +109,8 @@ void IkConstraint::apply(Bone &parent, Bone &child, float targetX, float targetY
Bone *pp = parent.getParent(); Bone *pp = parent.getParent();
float tx, ty, dx, dy, dd, l1, l2, a1, a2, r, td, sd, p; float tx, ty, dx, dy, dd, l1, l2, a1, a2, r, td, sd, p;
float id, x, y; float id, x, y;
px = parent._ax; if (parent._inherit != Inherit_Normal || child._inherit != Inherit_Normal) return;
px = parent._ax;
py = parent._ay; py = parent._ay;
psx = parent._ascaleX; psx = parent._ascaleX;
psy = parent._ascaleY; psy = parent._ascaleY;

View File

@ -37,11 +37,11 @@ RTTI_IMPL(IkConstraintData, ConstraintData)
IkConstraintData::IkConstraintData(const String &name) : ConstraintData(name), IkConstraintData::IkConstraintData(const String &name) : ConstraintData(name),
_target(NULL), _target(NULL),
_bendDirection(1), _bendDirection(0),
_compress(false), _compress(false),
_stretch(false), _stretch(false),
_uniform(false), _uniform(false),
_mix(1), _mix(0),
_softness(0) { _softness(0) {
} }

View File

@ -33,10 +33,20 @@
using namespace spine; using namespace spine;
LinkedMesh::LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent, LinkedMesh::LinkedMesh(MeshAttachment *mesh, const int skinIndex, size_t slotIndex, const String &parent,
bool inheritTimeline) : _mesh(mesh), bool inheritTimeline) : _mesh(mesh),
_skin(skin), _skinIndex(skinIndex),
_slotIndex(slotIndex), _skin(""),
_parent(parent), _slotIndex(slotIndex),
_inheritTimeline(inheritTimeline) { _parent(parent),
_inheritTimeline(inheritTimeline) {
}
LinkedMesh::LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
bool inheritTimeline) : _mesh(mesh),
_skinIndex(-1),
_skin(skin),
_slotIndex(slotIndex),
_parent(parent),
_inheritTimeline(inheritTimeline) {
} }

View File

@ -136,6 +136,7 @@ Skeleton::~Skeleton() {
ContainerUtil::cleanUpVectorOfPointers(_ikConstraints); ContainerUtil::cleanUpVectorOfPointers(_ikConstraints);
ContainerUtil::cleanUpVectorOfPointers(_transformConstraints); ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
ContainerUtil::cleanUpVectorOfPointers(_pathConstraints); ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
ContainerUtil::cleanUpVectorOfPointers(_physicsConstraints);
} }
void Skeleton::updateCache() { void Skeleton::updateCache() {
@ -195,7 +196,7 @@ continue_outer:
} }
} }
for (size_t ii = 0; ii < pathCount; ++ii) { for (size_t ii = 0; ii < physicsCount; ++ii) {
PhysicsConstraint *constraint = _physicsConstraints[ii]; PhysicsConstraint *constraint = _physicsConstraints[ii];
if (constraint->getData().getOrder() == i) { if (constraint->getData().getOrder() == i) {
sortPhysicsConstraint(constraint); sortPhysicsConstraint(constraint);
@ -222,7 +223,9 @@ void Skeleton::printUpdateCache() {
printf("ik constraint %s\n", ((IkConstraint *) updatable)->getData().getName().buffer()); printf("ik constraint %s\n", ((IkConstraint *) updatable)->getData().getName().buffer());
} else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) { } else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) {
printf("path constraint %s\n", ((PathConstraint *) updatable)->getData().getName().buffer()); printf("path constraint %s\n", ((PathConstraint *) updatable)->getData().getName().buffer());
} } else if (updatable->getRTTI().isExactly(PhysicsConstraint::rtti)) {
printf("physics constraint %s\n", ((PhysicsConstraint *) updatable)->getData().getName().buffer());
}
} }
} }

View File

@ -53,12 +53,15 @@
#include <spine/EventTimeline.h> #include <spine/EventTimeline.h>
#include <spine/IkConstraintData.h> #include <spine/IkConstraintData.h>
#include <spine/IkConstraintTimeline.h> #include <spine/IkConstraintTimeline.h>
#include <spine/InheritTimeline.h>
#include <spine/MeshAttachment.h> #include <spine/MeshAttachment.h>
#include <spine/PathAttachment.h> #include <spine/PathAttachment.h>
#include <spine/PathConstraintData.h> #include <spine/PathConstraintData.h>
#include <spine/PathConstraintMixTimeline.h> #include <spine/PathConstraintMixTimeline.h>
#include <spine/PathConstraintPositionTimeline.h> #include <spine/PathConstraintPositionTimeline.h>
#include <spine/PathConstraintSpacingTimeline.h> #include <spine/PathConstraintSpacingTimeline.h>
#include <spine/PhysicsConstraintData.h>
#include <spine/PhysicsConstraintTimeline.h>
#include <spine/PointAttachment.h> #include <spine/PointAttachment.h>
#include <spine/RegionAttachment.h> #include <spine/RegionAttachment.h>
#include <spine/RotateTimeline.h> #include <spine/RotateTimeline.h>
@ -129,6 +132,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
skeletonData->_y = readFloat(input); skeletonData->_y = readFloat(input);
skeletonData->_width = readFloat(input); skeletonData->_width = readFloat(input);
skeletonData->_height = readFloat(input); skeletonData->_height = readFloat(input);
skeletonData->_referenceScale = readFloat(input) * this->_scale;
nonessential = readBoolean(input); nonessential = readBoolean(input);
@ -161,6 +165,8 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
data->_skinRequired = readBoolean(input); data->_skinRequired = readBoolean(input);
if (nonessential) { if (nonessential) {
readColor(input, data->getColor()); readColor(input, data->getColor());
data->_icon.own(readString(input));
data->_visible = readBoolean(input);
} }
skeletonData->_bones[i] = data; skeletonData->_bones[i] = data;
} }
@ -169,9 +175,17 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
int slotsCount = readVarint(input, true); int slotsCount = readVarint(input, true);
skeletonData->_slots.setSize(slotsCount, 0); skeletonData->_slots.setSize(slotsCount, 0);
for (int i = 0; i < slotsCount; ++i) { for (int i = 0; i < slotsCount; ++i) {
const char *slotName = readString(input); String slotName = String(readString(input), true);
String pathName = "";
if (nonessential) {
int slash = slotName.lastIndexOf('/');
if (slash != -1) {
pathName = slotName.substring(0, slash);
slotName = slotName.substring(slash + 1);
}
}
BoneData *boneData = skeletonData->_bones[readVarint(input, true)]; BoneData *boneData = skeletonData->_bones[readVarint(input, true)];
SlotData *slotData = new (__FILE__, __LINE__) SlotData(i, String(slotName, true), *boneData); SlotData *slotData = new (__FILE__, __LINE__) SlotData(i, slotName, *boneData);
readColor(input, slotData->getColor()); readColor(input, slotData->getColor());
unsigned char a = readByte(input); unsigned char a = readByte(input);
@ -184,6 +198,10 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
} }
slotData->_attachmentName = readStringRef(input, skeletonData); slotData->_attachmentName = readStringRef(input, skeletonData);
slotData->_blendMode = static_cast<BlendMode>(readVarint(input, true)); slotData->_blendMode = static_cast<BlendMode>(readVarint(input, true));
if (nonessential) {
slotData->_visible = readBoolean(input);
slotData->_path = pathName;
}
skeletonData->_slots[i] = slotData; skeletonData->_slots[i] = slotData;
} }
@ -194,18 +212,20 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
const char *name = readString(input); const char *name = readString(input);
IkConstraintData *data = new (__FILE__, __LINE__) IkConstraintData(String(name, true)); IkConstraintData *data = new (__FILE__, __LINE__) IkConstraintData(String(name, true));
data->setOrder(readVarint(input, true)); data->setOrder(readVarint(input, true));
data->setSkinRequired(readBoolean(input));
int bonesCount = readVarint(input, true); int bonesCount = readVarint(input, true);
data->_bones.setSize(bonesCount, 0); data->_bones.setSize(bonesCount, 0);
for (int ii = 0; ii < bonesCount; ++ii) for (int ii = 0; ii < bonesCount; ++ii)
data->_bones[ii] = skeletonData->_bones[readVarint(input, true)]; data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
data->_target = skeletonData->_bones[readVarint(input, true)]; data->_target = skeletonData->_bones[readVarint(input, true)];
data->_mix = readFloat(input); int flags = readByte(input);
data->_softness = readFloat(input) * _scale; data->_skinRequired = (flags & 1) != 0;
data->_bendDirection = readSByte(input); data->_bendDirection = (flags & 2) != 0 ? 1 : -1;
data->_compress = readBoolean(input); data->_compress = (flags & 4) != 0;
data->_stretch = readBoolean(input); data->_stretch = (flags & 8) != 0;
data->_uniform = readBoolean(input); data->_uniform = (flags & 16) != 0;
if ((flags & 32) != 0) data->_mix = (flags & 64) != 0 ? readFloat(input) : 1;
if ((flags & 128) != 0) data->_softness = readFloat(input) * _scale;
skeletonData->_ikConstraints[i] = data; skeletonData->_ikConstraints[i] = data;
} }
@ -216,27 +236,30 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
const char *name = readString(input); const char *name = readString(input);
TransformConstraintData *data = new (__FILE__, __LINE__) TransformConstraintData(String(name, true)); TransformConstraintData *data = new (__FILE__, __LINE__) TransformConstraintData(String(name, true));
data->setOrder(readVarint(input, true)); data->setOrder(readVarint(input, true));
data->setSkinRequired(readBoolean(input));
int bonesCount = readVarint(input, true); int bonesCount = readVarint(input, true);
data->_bones.setSize(bonesCount, 0); data->_bones.setSize(bonesCount, 0);
for (int ii = 0; ii < bonesCount; ++ii) for (int ii = 0; ii < bonesCount; ++ii)
data->_bones[ii] = skeletonData->_bones[readVarint(input, true)]; data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
data->_target = skeletonData->_bones[readVarint(input, true)]; data->_target = skeletonData->_bones[readVarint(input, true)];
data->_local = readBoolean(input); int flags = readByte(input);
data->_relative = readBoolean(input); data->_skinRequired = (flags & 1) != 0;
data->_offsetRotation = readFloat(input); data->_local = (flags & 2) != 0;
data->_offsetX = readFloat(input) * _scale; data->_relative = (flags & 4) != 0;
data->_offsetY = readFloat(input) * _scale; if ((flags & 8) != 0) data->_offsetRotation = readFloat(input);
data->_offsetScaleX = readFloat(input); if ((flags & 16) != 0) data->_offsetX =readFloat(input) * _scale;
data->_offsetScaleY = readFloat(input); if ((flags & 32) != 0) data->_offsetY = readFloat(input) * _scale;
data->_offsetShearY = readFloat(input); if ((flags & 64) != 0) data->_offsetScaleX = readFloat(input);
data->_mixRotate = readFloat(input); if ((flags & 128) != 0) data->_offsetScaleY = readFloat(input);
data->_mixX = readFloat(input); flags = readByte(input);
data->_mixY = readFloat(input); if ((flags & 1) != 0) data->_offsetShearY = readFloat(input);
data->_mixScaleX = readFloat(input); if ((flags & 2) != 0) data->_mixRotate = readFloat(input);
data->_mixScaleY = readFloat(input); if ((flags & 4) != 0) data->_mixX = readFloat(input);
data->_mixShearY = readFloat(input); if ((flags & 8) != 0) data->_mixY = readFloat(input);
skeletonData->_transformConstraints[i] = data; if ((flags & 16) != 0) data->_mixScaleX = readFloat(input);
if ((flags & 32) != 0) data->_mixScaleY = readFloat(input);
if ((flags & 64) != 0) data->_mixShearY = readFloat(input);
skeletonData->_transformConstraints[i] = data;
} }
/* Path constraints */ /* Path constraints */
@ -252,10 +275,11 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
for (int ii = 0; ii < bonesCount; ++ii) for (int ii = 0; ii < bonesCount; ++ii)
data->_bones[ii] = skeletonData->_bones[readVarint(input, true)]; data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
data->_target = skeletonData->_slots[readVarint(input, true)]; data->_target = skeletonData->_slots[readVarint(input, true)];
data->_positionMode = static_cast<PositionMode>(readVarint(input, true)); int flags = readByte(input);
data->_spacingMode = static_cast<SpacingMode>(readVarint(input, true)); data->_positionMode = (PositionMode)(flags & 1);
data->_rotateMode = static_cast<RotateMode>(readVarint(input, true)); data->_spacingMode = (SpacingMode)((flags >> 1) & 3);
data->_offsetRotation = readFloat(input); data->_rotateMode = (RotateMode)((flags >> 3) & 3);
if ((flags & 128) != 0) data->_offsetRotation = readFloat(input);
data->_position = readFloat(input); data->_position = readFloat(input);
if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale; if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale;
data->_spacing = readFloat(input); data->_spacing = readFloat(input);
@ -267,6 +291,41 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
skeletonData->_pathConstraints[i] = data; skeletonData->_pathConstraints[i] = data;
} }
// Physics constraints.
int physicsConstraintsCount = readVarint(input, true);
skeletonData->_physicsConstraints.setSize(physicsConstraintsCount, 0);
for (int i = 0; i < physicsConstraintsCount; i++) {
const char *name = readString(input);
PhysicsConstraintData *data = new (__FILE__, __LINE__) PhysicsConstraintData(String(name, true));
data->_order = readVarint(input, true);
data->_bone = skeletonData->_bones[readVarint(input, true)];
int flags = readByte(input);
data->_skinRequired = (flags & 1) != 0;
if ((flags & 2) != 0) data->_x = readFloat(input);
if ((flags & 4) != 0) data->_y = readFloat(input);
if ((flags & 8) != 0) data->_rotate = readFloat(input);
if ((flags & 16) != 0) data->_scaleX = readFloat(input);
if ((flags & 32) != 0) data->_shearX = readFloat(input);
data->_limit = ((flags & 64) != 0 ? readFloat(input) : 5000) * _scale;
data->_step = 1.f / readByte(input);
data->_inertia = readFloat(input);
data->_strength = readFloat(input);
data->_damping = readFloat(input);
data->_massInverse = (flags & 128) != 0 ? readFloat(input) : 1;
data->_wind = readFloat(input);
data->_gravity = readFloat(input);
flags = readByte(input);
if ((flags & 1) != 0) data->_inertiaGlobal = true;
if ((flags & 2) != 0) data->_strengthGlobal = true;
if ((flags & 4) != 0) data->_dampingGlobal = true;
if ((flags & 8) != 0) data->_massGlobal = true;
if ((flags & 16) != 0) data->_windGlobal = true;
if ((flags & 32) != 0) data->_gravityGlobal = true;
if ((flags & 64) != 0) data->_mixGlobal = true;
data->_mix = (flags & 128) != 0 ? readFloat(input) : 1;
skeletonData->_physicsConstraints[i] = data;
}
/* Default skin. */ /* Default skin. */
Skin *defaultSkin = readSkin(input, true, skeletonData, nonessential); Skin *defaultSkin = readSkin(input, true, skeletonData, nonessential);
if (defaultSkin) { if (defaultSkin) {
@ -289,13 +348,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
/* Linked meshes. */ /* Linked meshes. */
for (int i = 0, n = (int) _linkedMeshes.size(); i < n; ++i) { for (int i = 0, n = (int) _linkedMeshes.size(); i < n; ++i) {
LinkedMesh *linkedMesh = _linkedMeshes[i]; LinkedMesh *linkedMesh = _linkedMeshes[i];
Skin *skin = linkedMesh->_skin.length() == 0 ? skeletonData->getDefaultSkin() : skeletonData->findSkin(linkedMesh->_skin); Skin *skin = skeletonData->_skins[linkedMesh->_skinIndex];
if (skin == NULL) {
delete input;
delete skeletonData;
setError("Skin not found: ", linkedMesh->_skin.buffer());
return NULL;
}
Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent); Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent);
if (parent == NULL) { if (parent == NULL) {
delete input; delete input;
@ -316,8 +369,8 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
int eventsCount = readVarint(input, true); int eventsCount = readVarint(input, true);
skeletonData->_events.setSize(eventsCount, 0); skeletonData->_events.setSize(eventsCount, 0);
for (int i = 0; i < eventsCount; ++i) { for (int i = 0; i < eventsCount; ++i) {
const char *name = readStringRef(input, skeletonData); const char *name = readString(input);
EventData *eventData = new (__FILE__, __LINE__) EventData(String(name)); EventData *eventData = new (__FILE__, __LINE__) EventData(String(name, true));
eventData->_intValue = readVarint(input, false); eventData->_intValue = readVarint(input, false);
eventData->_floatValue = readFloat(input); eventData->_floatValue = readFloat(input);
eventData->_stringValue.own(readString(input)); eventData->_stringValue.own(readString(input));
@ -452,7 +505,10 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
if (slotCount == 0) return NULL; if (slotCount == 0) return NULL;
skin = new (__FILE__, __LINE__) Skin("default"); skin = new (__FILE__, __LINE__) Skin("default");
} else { } else {
skin = new (__FILE__, __LINE__) Skin(readStringRef(input, skeletonData)); skin = new (__FILE__, __LINE__) Skin(String(readString(input), true));
if (nonessential) readColor(input, skin->getColor());
for (int i = 0, n = readVarint(input, true); i < n; i++) { for (int i = 0, n = readVarint(input, true); i < n; i++) {
int boneIndex = readVarint(input, true); int boneIndex = readVarint(input, true);
if (boneIndex >= (int) skeletonData->_bones.size()) return NULL; if (boneIndex >= (int) skeletonData->_bones.size()) return NULL;
@ -476,6 +532,12 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
if (pathIndex >= (int) skeletonData->_pathConstraints.size()) return NULL; if (pathIndex >= (int) skeletonData->_pathConstraints.size()) return NULL;
skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]); skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]);
} }
for (int i = 0, n = readVarint(input, true); i < n; i++) {
int physicsIndex = readVarint(input, true);
if (physicsIndex >= (int) skeletonData->_physicsConstraints.size()) return NULL;
skin->getConstraints().add(skeletonData->_physicsConstraints[physicsIndex]);
}
slotCount = readVarint(input, true); slotCount = readVarint(input, true);
} }
@ -496,7 +558,6 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
} }
Sequence *SkeletonBinary::readSequence(DataInput *input) { Sequence *SkeletonBinary::readSequence(DataInput *input) {
if (!readBoolean(input)) return NULL;
Sequence *sequence = new (__FILE__, __LINE__) Sequence(readVarint(input, true)); Sequence *sequence = new (__FILE__, __LINE__) Sequence(readVarint(input, true));
sequence->_start = readVarint(input, true); sequence->_start = readVarint(input, true);
sequence->_digits = readVarint(input, true); sequence->_digits = readVarint(input, true);
@ -506,24 +567,23 @@ Sequence *SkeletonBinary::readSequence(DataInput *input) {
Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName, Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
SkeletonData *skeletonData, bool nonessential) { SkeletonData *skeletonData, bool nonessential) {
String name(readStringRef(input, skeletonData));
if (name.isEmpty()) name = attachmentName;
AttachmentType type = static_cast<AttachmentType>(readByte(input)); int flags = readByte(input);
String name = (flags & 8) != 0 ? readStringRef(input, skeletonData) : attachmentName;
AttachmentType type = static_cast<AttachmentType>(flags & 0x7);
switch (type) { switch (type) {
case AttachmentType_Region: { case AttachmentType_Region: {
String path(readStringRef(input, skeletonData)); String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
if (path.isEmpty()) path = name; Color color(1, 1, 1, 1);
float rotation = readFloat(input); if ((flags & 32) != 0) readColor(input, color);
Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
float rotation = (flags & 128) != 0 ? readFloat(input) : 0;
float x = readFloat(input) * _scale; float x = readFloat(input) * _scale;
float y = readFloat(input) * _scale; float y = readFloat(input) * _scale;
float scaleX = readFloat(input); float scaleX = readFloat(input);
float scaleY = readFloat(input); float scaleY = readFloat(input);
float width = readFloat(input) * _scale; float width = readFloat(input) * _scale;
float height = readFloat(input) * _scale; float height = readFloat(input) * _scale;
Color color;
readColor(input, color);
Sequence *sequence = readSequence(input);
RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence); RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence);
if (!region) { if (!region) {
setError("Error reading attachment: ", name.buffer()); setError("Error reading attachment: ", name.buffer());
@ -544,14 +604,13 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
return region; return region;
} }
case AttachmentType_Boundingbox: { case AttachmentType_Boundingbox: {
int vertexCount = readVarint(input, true);
BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name)); BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
if (!box) { if (!box) {
setError("Error reading attachment: ", name.buffer()); setError("Error reading attachment: ", name.buffer());
return NULL; return NULL;
} }
readVertices(input, box->getVertices(), box->getBones(), vertexCount); readVertices(input, box->getVertices(), box->getBones(), (flags & 16) != 0);
box->setWorldVerticesLength(vertexCount << 1); box->setWorldVerticesLength(box->getVertices().size());
if (nonessential) { if (nonessential) {
readColor(input, box->getColor()); readColor(input, box->getColor());
} }
@ -559,31 +618,28 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
return box; return box;
} }
case AttachmentType_Mesh: { case AttachmentType_Mesh: {
Color color;
int vertexCount;
Vector<float> uvs; Vector<float> uvs;
Vector<unsigned short> triangles; Vector<unsigned short> triangles;
Vector<float> vertices; Vector<float> vertices;
Vector<int> bones; Vector<int> bones;
int hullLength; int hullLength;
Sequence *sequence;
float width = 0; float width = 0;
float height = 0; float height = 0;
Vector<unsigned short> edges; Vector<unsigned short> edges;
String path(readStringRef(input, skeletonData)); String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
if (path.isEmpty()) path = name; Color color(1, 1, 1, 1);
readColor(input, color); if ((flags & 32) != 0) readColor(input, color);
vertexCount = readVarint(input, true); Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
readFloatArray(input, vertexCount << 1, 1, uvs); hullLength = readVarint(input, true);
readShortArray(input, triangles); int verticesLength = readVertices(input, vertices, bones, (flags & 128) != 0);
readVertices(input, vertices, bones, vertexCount); readFloatArray(input, verticesLength, 1, uvs);
hullLength = readVarint(input, true) << 1; readShortArray(input, triangles, (verticesLength - hullLength - 2) * 3);
sequence = readSequence(input);
if (nonessential) { if (nonessential) {
readShortArray(input, edges); readShortArray(input, edges, readVarint(input, true));
width = readFloat(input) * _scale; width = readFloat(input);
height = readFloat(input) * _scale; height = readFloat(input);
} }
MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence); MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence);
@ -595,7 +651,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
mesh->_color.set(color); mesh->_color.set(color);
mesh->_bones.addAll(bones); mesh->_bones.addAll(bones);
mesh->_vertices.addAll(vertices); mesh->_vertices.addAll(vertices);
mesh->setWorldVerticesLength(vertexCount << 1); mesh->setWorldVerticesLength(verticesLength);
mesh->_triangles.addAll(triangles); mesh->_triangles.addAll(triangles);
mesh->_regionUVs.addAll(uvs); mesh->_regionUVs.addAll(uvs);
if (sequence == NULL) mesh->updateRegion(); if (sequence == NULL) mesh->updateRegion();
@ -610,16 +666,14 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
return mesh; return mesh;
} }
case AttachmentType_Linkedmesh: { case AttachmentType_Linkedmesh: {
String path(readStringRef(input, skeletonData)); String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
if (path.isEmpty()) path = name; Color color(1, 1, 1, 1);
if ((flags & 32) != 0) readColor(input, color);
Color color; Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
float width = 0, height = 0; bool inheritTimelines = (flags & 128) != 0;
readColor(input, color); int skinIndex = readVarint(input, true);
String skinName(readStringRef(input, skeletonData));
String parent(readStringRef(input, skeletonData)); String parent(readStringRef(input, skeletonData));
bool inheritTimelines = readBoolean(input); float width = 0, height = 0;
Sequence *sequence = readSequence(input);
if (nonessential) { if (nonessential) {
width = readFloat(input) * _scale; width = readFloat(input) * _scale;
height = readFloat(input) * _scale; height = readFloat(input) * _scale;
@ -638,7 +692,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
mesh->_height = height; mesh->_height = height;
} }
LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, String(skinName), slotIndex, LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, skinIndex, slotIndex,
String(parent), inheritTimelines); String(parent), inheritTimelines);
_linkedMeshes.add(linkedMesh); _linkedMeshes.add(linkedMesh);
return mesh; return mesh;
@ -649,12 +703,11 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
setError("Error reading attachment: ", name.buffer()); setError("Error reading attachment: ", name.buffer());
return NULL; return NULL;
} }
path->_closed = readBoolean(input); path->_closed = (flags & 16) != 0;
path->_constantSpeed = readBoolean(input); path->_constantSpeed = (flags & 32) != 0;
int vertexCount = readVarint(input, true); int verticesLength = readVertices(input, path->getVertices(), path->getBones(), (flags & 64) != 0);
readVertices(input, path->getVertices(), path->getBones(), vertexCount); path->setWorldVerticesLength(verticesLength);
path->setWorldVerticesLength(vertexCount << 1); int lengthsLength = verticesLength / 6;
int lengthsLength = vertexCount / 3;
path->_lengths.setSize(lengthsLength, 0); path->_lengths.setSize(lengthsLength, 0);
for (int i = 0; i < lengthsLength; ++i) { for (int i = 0; i < lengthsLength; ++i) {
path->_lengths[i] = readFloat(input) * _scale; path->_lengths[i] = readFloat(input) * _scale;
@ -683,14 +736,13 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
} }
case AttachmentType_Clipping: { case AttachmentType_Clipping: {
int endSlotIndex = readVarint(input, true); int endSlotIndex = readVarint(input, true);
int vertexCount = readVarint(input, true);
ClippingAttachment *clip = _attachmentLoader->newClippingAttachment(*skin, name); ClippingAttachment *clip = _attachmentLoader->newClippingAttachment(*skin, name);
if (!clip) { if (!clip) {
setError("Error reading attachment: ", name.buffer()); setError("Error reading attachment: ", name.buffer());
return NULL; return NULL;
} }
readVertices(input, clip->getVertices(), clip->getBones(), vertexCount); int verticesLength = readVertices(input, clip->getVertices(), clip->getBones(), (flags & 16) != 0);
clip->setWorldVerticesLength(vertexCount << 1); clip->setWorldVerticesLength(verticesLength);
clip->_endSlot = skeletonData->_slots[endSlotIndex]; clip->_endSlot = skeletonData->_slots[endSlotIndex];
if (nonessential) { if (nonessential) {
readColor(input, clip->getColor()); readColor(input, clip->getColor());
@ -702,18 +754,16 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
return NULL; return NULL;
} }
void SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, int vertexCount) { int SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, bool weighted) {
float scale = _scale; float scale = _scale;
int vertexCount = readVarint(input, true);
int verticesLength = vertexCount << 1; int verticesLength = vertexCount << 1;
if (!weighted) {
if (!readBoolean(input)) { readFloatArray(input, verticesLength, scale, vertices);
readFloatArray(input, verticesLength, scale, vertices); return verticesLength;
return; }
} vertices.ensureCapacity(verticesLength * 3 * 3);
bones.ensureCapacity(verticesLength * 3);
vertices.ensureCapacity(verticesLength * 3 * 3);
bones.ensureCapacity(verticesLength * 3);
for (int i = 0; i < vertexCount; ++i) { for (int i = 0; i < vertexCount; ++i) {
int boneCount = readVarint(input, true); int boneCount = readVarint(input, true);
bones.add(boneCount); bones.add(boneCount);
@ -724,6 +774,7 @@ void SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vec
vertices.add(readFloat(input)); vertices.add(readFloat(input));
} }
} }
return verticesLength;
} }
void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector<float> &array) { void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector<float> &array) {
@ -741,14 +792,10 @@ void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector
} }
} }
void SkeletonBinary::readShortArray(DataInput *input, Vector<unsigned short> &array) { void SkeletonBinary::readShortArray(DataInput *input, Vector<unsigned short> &array, int n) {
int n = readVarint(input, true);
array.setSize(n, 0); array.setSize(n, 0);
for (int i = 0; i < n; ++i) {
int i; array[i] = (short)readVarint(input, true);
for (i = 0; i < n; ++i) {
array[i] = readByte(input) << 8;
array[i] |= readByte(input);
} }
} }
@ -762,7 +809,7 @@ void SkeletonBinary::setBezier(DataInput *input, CurveTimeline *timeline, int be
timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1 * scale, cx2, cy2 * scale, time2, value2); timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1 * scale, cx2, cy2 * scale, time2, value2);
} }
Timeline *SkeletonBinary::readTimeline(DataInput *input, CurveTimeline1 *timeline, float scale) { void SkeletonBinary::readTimeline(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline1 *timeline, float scale) {
float time = readFloat(input); float time = readFloat(input);
float value = readFloat(input) * scale; float value = readFloat(input) * scale;
for (int frame = 0, bezier = 0, frameLast = (int) timeline->getFrameCount() - 1;; frame++) { for (int frame = 0, bezier = 0, frameLast = (int) timeline->getFrameCount() - 1;; frame++) {
@ -780,10 +827,10 @@ Timeline *SkeletonBinary::readTimeline(DataInput *input, CurveTimeline1 *timelin
time = time2; time = time2;
value = value2; value = value2;
} }
return timeline; timelines.add(timeline);
} }
Timeline *SkeletonBinary::readTimeline2(DataInput *input, CurveTimeline2 *timeline, float scale) { void SkeletonBinary::readTimeline2(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline2 *timeline, float scale) {
float time = readFloat(input); float time = readFloat(input);
float value1 = readFloat(input) * scale; float value1 = readFloat(input) * scale;
float value2 = readFloat(input) * scale; float value2 = readFloat(input) * scale;
@ -805,7 +852,7 @@ Timeline *SkeletonBinary::readTimeline2(DataInput *input, CurveTimeline2 *timeli
value1 = nvalue1; value1 = nvalue1;
value2 = nvalue2; value2 = nvalue2;
} }
return timeline; timelines.add(timeline);
} }
Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData) { Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData) {
@ -1039,50 +1086,59 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) { for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
unsigned char timelineType = readByte(input); unsigned char timelineType = readByte(input);
int frameCount = readVarint(input, true); int frameCount = readVarint(input, true);
int bezierCount = readVarint(input, true); if (timelineType == BONE_INHERIT) {
Timeline *timeline = NULL; InheritTimeline *timeline = new (__FILE__, __LINE__) InheritTimeline(frameCount, boneIndex);
for (int frame = 0; frame < frameCount; frame++) {
float time = readFloat(input);
Inherit inherit = (Inherit)readByte(input);
timeline->setFrame(frame, time, inherit);
}
timelines.add(timeline);
continue;
}
int bezierCount = readVarint(input, true);
switch (timelineType) { switch (timelineType) {
case BONE_ROTATE: case BONE_ROTATE:
timeline = readTimeline(input, readTimeline(input, timelines,
new (__FILE__, __LINE__) RotateTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) RotateTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_TRANSLATE: case BONE_TRANSLATE:
timeline = readTimeline2(input, new (__FILE__, __LINE__) TranslateTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline2(input, timelines,new (__FILE__, __LINE__) TranslateTimeline(frameCount, bezierCount, boneIndex), scale);
break; break;
case BONE_TRANSLATEX: case BONE_TRANSLATEX:
timeline = readTimeline(input, new (__FILE__, __LINE__) TranslateXTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline(input, timelines, new (__FILE__, __LINE__) TranslateXTimeline(frameCount, bezierCount, boneIndex), scale);
break; break;
case BONE_TRANSLATEY: case BONE_TRANSLATEY:
timeline = readTimeline(input, new (__FILE__, __LINE__) TranslateYTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline(input, timelines, new (__FILE__, __LINE__) TranslateYTimeline(frameCount, bezierCount, boneIndex), scale);
break; break;
case BONE_SCALE: case BONE_SCALE:
timeline = readTimeline2(input, readTimeline2(input, timelines,
new (__FILE__, __LINE__) ScaleTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ScaleTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_SCALEX: case BONE_SCALEX:
timeline = readTimeline(input, readTimeline(input, timelines,
new (__FILE__, __LINE__) ScaleXTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ScaleXTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_SCALEY: case BONE_SCALEY:
timeline = readTimeline(input, readTimeline(input, timelines,
new (__FILE__, __LINE__) ScaleYTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ScaleYTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_SHEAR: case BONE_SHEAR:
timeline = readTimeline2(input, readTimeline2(input, timelines,
new (__FILE__, __LINE__) ShearTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ShearTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_SHEARX: case BONE_SHEARX:
timeline = readTimeline(input, readTimeline(input, timelines,
new (__FILE__, __LINE__) ShearXTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ShearXTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
case BONE_SHEARY: case BONE_SHEARY:
timeline = readTimeline(input, readTimeline(input, timelines,
new (__FILE__, __LINE__) ShearYTimeline(frameCount, bezierCount, boneIndex), new (__FILE__, __LINE__) ShearYTimeline(frameCount, bezierCount, boneIndex),
1); 1);
break; break;
@ -1092,7 +1148,6 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
return NULL; return NULL;
} }
} }
timelines.add(timeline);
} }
} }
@ -1103,25 +1158,20 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
int frameLast = frameCount - 1; int frameLast = frameCount - 1;
int bezierCount = readVarint(input, true); int bezierCount = readVarint(input, true);
IkConstraintTimeline *timeline = new (__FILE__, __LINE__) IkConstraintTimeline(frameCount, bezierCount, index); IkConstraintTimeline *timeline = new (__FILE__, __LINE__) IkConstraintTimeline(frameCount, bezierCount, index);
float time = readFloat(input); int flags = readByte(input);
float mix = readFloat(input); float time = readFloat(input), mix = (flags & 1) != 0 ? ((flags & 2) != 0 ? readFloat(input) : 1) : 0;
float softness = readFloat(input) * scale; float softness = (flags & 4) != 0 ? readFloat(input) * scale : 0;
for (int frame = 0, bezier = 0;; frame++) { for (int frame = 0, bezier = 0;; frame++) {
int bendDirection = readSByte(input); timeline->setFrame(frame, time, mix, softness, (flags & 8) != 0 ? 1 : -1, (flags & 16) != 0, (flags & 32) != 0);
bool compress = readBoolean(input);
bool stretch = readBoolean(input);
timeline->setFrame(frame, time, mix, softness, bendDirection, compress, stretch);
if (frame == frameLast) break; if (frame == frameLast) break;
float time2 = readFloat(input); flags = readByte(input);
float mix2 = readFloat(input); float time2 = readFloat(input), mix2 = (flags & 1) != 0 ? ((flags & 2) != 0 ? readFloat(input) : 1) : 0;
float softness2 = readFloat(input) * scale; float softness2 = (flags & 4) != 0 ? readFloat(input) * scale : 0;
switch (readSByte(input)) { if ((flags & 64) != 0)
case CURVE_STEPPED: timeline->setStepped(frame);
timeline->setStepped(frame); else if ((flags & 128) != 0) {
break; setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1);
case CURVE_BEZIER: setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale);
setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1);
setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale);
} }
time = time2; time = time2;
mix = mix2; mix = mix2;
@ -1182,26 +1232,24 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
int index = readVarint(input, true); int index = readVarint(input, true);
PathConstraintData *data = skeletonData->_pathConstraints[index]; PathConstraintData *data = skeletonData->_pathConstraints[index];
for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) { for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) {
int type = readSByte(input); int type = readByte(input);
int frameCount = readVarint(input, true); int frameCount = readVarint(input, true);
int bezierCount = readVarint(input, true); int bezierCount = readVarint(input, true);
switch (type) { switch (type) {
case PATH_POSITION: { case PATH_POSITION: {
timelines readTimeline(input, timelines, new PathConstraintPositionTimeline(frameCount, bezierCount, index),
.add(readTimeline(input, new PathConstraintPositionTimeline(frameCount, bezierCount, index), data->_positionMode == PositionMode_Fixed ? scale : 1);
data->_positionMode == PositionMode_Fixed ? scale : 1));
break; break;
} }
case PATH_SPACING: { case PATH_SPACING: {
timelines readTimeline(input, timelines,
.add(readTimeline(input,
new PathConstraintSpacingTimeline(frameCount, new PathConstraintSpacingTimeline(frameCount,
bezierCount, bezierCount,
index), index),
data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Length ||
data->_spacingMode == SpacingMode_Fixed data->_spacingMode == SpacingMode_Fixed
? scale ? scale
: 1)); : 1);
break; break;
} }
case PATH_MIX: case PATH_MIX:
@ -1236,7 +1284,46 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
} }
} }
// Deform timelines. // Physics timelines.
for (int i = 0, n = readVarint(input, true); i < n; i++) {
int index = readVarint(input, true) - 1;
for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) {
int type = readByte(input);
int frameCount = readVarint(input, true);
if (type == PHYSICS_RESET) {
PhysicsConstraintResetTimeline *timeline = new (__FILE__, __LINE__) PhysicsConstraintResetTimeline(frameCount, index);
for (int frame = 0; frame < frameCount; frame++)
timeline->setFrame(frame, readFloat(input));
timelines.add(timeline);
continue;
}
int bezierCount = readVarint(input, true);
switch (type) {
case PHYSICS_INERTIA:
readTimeline(input, timelines, new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_STRENGTH:
readTimeline(input, timelines, new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_DAMPING:
readTimeline(input, timelines, new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_MASS:
readTimeline(input, timelines, new PhysicsConstraintMassTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_WIND:
readTimeline(input, timelines, new PhysicsConstraintWindTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_GRAVITY:
readTimeline(input, timelines, new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index), 1);
break;
case PHYSICS_MIX:
readTimeline(input, timelines, new PhysicsConstraintMixTimeline(frameCount, bezierCount, index), 1);
}
}
}
// Attachment timelines.
for (int i = 0, n = readVarint(input, true); i < n; ++i) { for (int i = 0, n = readVarint(input, true); i < n; ++i) {
Skin *skin = skeletonData->_skins[readVarint(input, true)]; Skin *skin = skeletonData->_skins[readVarint(input, true)];
for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) { for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
@ -1379,10 +1466,13 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
event->_intValue = readVarint(input, false); event->_intValue = readVarint(input, false);
event->_floatValue = readFloat(input); event->_floatValue = readFloat(input);
bool freeString = readBoolean(input); const char *event_stringValue = readString(input);
const char *event_stringValue = freeString ? readString(input) : eventData->_stringValue.buffer(); if (event_stringValue == nullptr) {
event->_stringValue = String(event_stringValue); event->_stringValue = eventData->_stringValue;
if (freeString) SpineExtension::free(event_stringValue, __FILE__, __LINE__); } else {
event->_stringValue = String(event_stringValue);
SpineExtension::free(event_stringValue, __FILE__, __LINE__);
}
if (!eventData->_audioPath.isEmpty()) { if (!eventData->_audioPath.isEmpty()) {
event->_volume = readFloat(input); event->_volume = readFloat(input);

View File

@ -58,6 +58,7 @@
#include <spine/PathConstraintMixTimeline.h> #include <spine/PathConstraintMixTimeline.h>
#include <spine/PathConstraintPositionTimeline.h> #include <spine/PathConstraintPositionTimeline.h>
#include <spine/PathConstraintSpacingTimeline.h> #include <spine/PathConstraintSpacingTimeline.h>
#include <spine/PhysicsConstraintData.h>
#include <spine/PointAttachment.h> #include <spine/PointAttachment.h>
#include <spine/RegionAttachment.h> #include <spine/RegionAttachment.h>
#include <spine/RotateTimeline.h> #include <spine/RotateTimeline.h>
@ -133,7 +134,7 @@ SkeletonData *SkeletonJson::readSkeletonDataFile(const String &path) {
SkeletonData *SkeletonJson::readSkeletonData(const char *json) { SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
int i, ii; int i, ii;
SkeletonData *skeletonData; SkeletonData *skeletonData;
Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events; Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *physics, *slots, *skins, *animations, *events;
_error = ""; _error = "";
_linkedMeshes.clear(); _linkedMeshes.clear();
@ -455,6 +456,54 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
} }
} }
/* Physics constraints */
physics = Json::getItem(root, "physics");
if (physics) {
Json *constraintMap;
skeletonData->_physicsConstraints.ensureCapacity(physics->_size);
skeletonData->_physicsConstraints.setSize(physics->_size, 0);
for (constraintMap = physics->_child, i = 0; constraintMap; constraintMap = constraintMap->_next, ++i) {
const char *name;
PhysicsConstraintData *data = new (__FILE__, __LINE__) PhysicsConstraintData(
Json::getString(constraintMap, "name", 0));
data->setOrder(Json::getInt(constraintMap, "order", 0));
data->setSkinRequired(Json::getBoolean(constraintMap, "skin", false));
name = Json::getString(constraintMap, "bone", 0);
data->_bone = skeletonData->findBone(name);
if (!data->_bone) {
delete skeletonData;
setError(root, "Physics bone not found: ", name);
return NULL;
}
data->_x = Json::getFloat(constraintMap, "x", 0);
data->_y = Json::getFloat(constraintMap, "y", 0);
data->_rotate = Json::getFloat(constraintMap, "rotate", 0);
data->_scaleX = Json::getFloat(constraintMap, "scaleX", 0);
data->_shearX = Json::getFloat(constraintMap, "shearX", 0);
data->_limit = Json::getFloat(constraintMap, "limit", 5000) * _scale;
data->_step = 1.0f / Json::getInt(constraintMap, "fps", 60);
data->_inertia = Json::getFloat(constraintMap, "inertia", 1);
data->_strength = Json::getFloat(constraintMap, "strength", 100);
data->_damping = Json::getFloat(constraintMap, "damping", 1);
data->_massInverse = 1 / Json::getFloat(constraintMap, "mass", 1);
data->_wind = Json::getFloat(constraintMap, "wind", 0);
data->_gravity = Json::getFloat(constraintMap, "gravity", 0);
data->_mix = Json::getFloat(constraintMap, "mix", 1);
data->_inertiaGlobal = Json::getBoolean(constraintMap, "inertiaGlobal", false);
data->_strengthGlobal = Json::getBoolean(constraintMap, "strengthGlobal", false);
data->_dampingGlobal = Json::getBoolean(constraintMap, "dampingGlobal", false);
data->_massGlobal = Json::getBoolean(constraintMap, "massGlobal", false);
data->_windGlobal = Json::getBoolean(constraintMap, "windGlobal", false);
data->_gravityGlobal = Json::getBoolean(constraintMap, "gravityGlobal", false);
data->_mixGlobal = Json::getBoolean(constraintMap, "mixGlobal", false);
skeletonData->_physicsConstraints[i] = data;
}
}
/* Skins. */ /* Skins. */
skins = Json::getItem(root, "skins"); skins = Json::getItem(root, "skins");
if (skins) { if (skins) {
@ -520,6 +569,19 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
} }
} }
item = Json::getItem(skinMap, "physics");
if (item) {
for (item = item->_child; item; item = item->_next) {
PhysicsConstraintData *data = skeletonData->findPhysicsConstraint(item->_valueString);
if (!data) {
delete skeletonData;
setError(root, String("Skin physics constraint not found: "), item->_valueString);
return NULL;
}
skin->getConstraints().add(data);
}
}
skeletonData->_skins[skinsIndex++] = skin; skeletonData->_skins[skinsIndex++] = skin;
if (strcmp(Json::getString(skinMap, "name", ""), "default") == 0) { if (strcmp(Json::getString(skinMap, "name", ""), "default") == 0) {
skeletonData->_defaultSkin = skin; skeletonData->_defaultSkin = skin;

View File

@ -611,6 +611,40 @@ void mixAndMatch(SkeletonData *skeletonData, Atlas *atlas) {
} }
} }
void celestialCircus(SkeletonData *skeletonData, Atlas *atlas) {
SP_UNUSED(atlas);
SkeletonDrawable drawable(skeletonData);
drawable.timeScale = 1;
drawable.setUsePremultipliedAlpha(true);
Skeleton *skeleton = drawable.skeleton;
skeleton->setPosition(320, 480);
skeleton->updateWorldTransform(Physics_Update);
drawable.state->setAnimation(0, "swing", true);
sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - celestial circus");
window.setFramerateLimit(60);
sf::Event event;
sf::Clock deltaClock;
while (window.isOpen()) {
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
float delta = deltaClock.getElapsedTime().asSeconds();
deltaClock.restart();
drawable.update(delta);
window.clear();
window.draw(drawable);
window.display();
}
}
/** /**
* Used for debugging purposes during runtime development * Used for debugging purposes during runtime development
*/ */
@ -636,11 +670,11 @@ DebugExtension dbgExtension(SpineExtension::getInstance());
int main() { int main() {
SpineExtension::setInstance(&dbgExtension); SpineExtension::setInstance(&dbgExtension);
testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);
testcase(celestialCircus, "data/celestial-circus-pro.json", "data/celestial-circus-pro.skel", "data/celestial-circus-pma.atlas", 0.2f);
testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f); testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f);
testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f); testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f);
testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f);
testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f); testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f);
testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);
testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f); testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f);
testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f); testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f);
testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f); testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);

View File

@ -79,6 +79,7 @@ namespace spine {
void SkeletonDrawable::update(float deltaTime, Physics physics) { void SkeletonDrawable::update(float deltaTime, Physics physics) {
state->update(deltaTime * timeScale); state->update(deltaTime * timeScale);
state->apply(*skeleton); state->apply(*skeleton);
skeleton->update(deltaTime * timeScale);
skeleton->updateWorldTransform(physics); skeleton->updateWorldTransform(physics);
} }