Ver Fonte

Almost done with SkeletonBinary

Stephen Gowen há 7 anos atrás
pai
commit
8f28ae1c2d

+ 2 - 2
spine-cpp/spine-cpp/include/spine/Bone.h

@@ -47,8 +47,6 @@ namespace Spine
     /// constraint or application code modifies the world transform after it was computed from the local transform.
     class Bone : public Updatable
     {
-        RTTI_DECL;
-        
         friend class AnimationState;
         
         friend class RotateTimeline;
@@ -63,6 +61,8 @@ namespace Spine
         friend class ShearTimeline;
         friend class TranslateTimeline;
         
+        RTTI_DECL;
+        
     public:
         static void setYDown(bool inValue);
         

+ 2 - 0
spine-cpp/spine-cpp/include/spine/BoneData.h

@@ -40,6 +40,8 @@ namespace Spine
     class BoneData
     {
         friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         friend class AnimationState;
         
         friend class RotateTimeline;

+ 4 - 1
spine-cpp/spine-cpp/include/spine/ClippingAttachment.h

@@ -39,10 +39,13 @@ namespace Spine
     
     class ClippingAttachment : public VertexAttachment
     {
-        RTTI_DECL;
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
         
         friend class SkeletonClipping;
         
+        RTTI_DECL;
+        
     public:
         ClippingAttachment(std::string name);
         

+ 2 - 0
spine-cpp/spine-cpp/include/spine/EventData.h

@@ -38,6 +38,8 @@ namespace Spine
     /// Stores the setup pose values for an Event.
     class EventData
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
         friend class Event;
         
     public:

+ 2 - 0
spine-cpp/spine-cpp/include/spine/IkConstraintData.h

@@ -41,6 +41,8 @@ namespace Spine
     
     class IkConstraintData
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
         friend class IkConstraint;
         friend class Skeleton;
         friend class IkConstraintTimeline;

+ 3 - 0
spine-cpp/spine-cpp/include/spine/LinkedMesh.h

@@ -39,6 +39,9 @@ namespace Spine
     
     class LinkedMesh
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
     public:
         LinkedMesh(MeshAttachment* mesh, std::string skin, int slotIndex, std::string parent);
         

+ 10 - 8
spine-cpp/spine-cpp/include/spine/MeshAttachment.h

@@ -42,10 +42,12 @@ namespace Spine
     /// Attachment that displays a texture region using a mesh.
     class MeshAttachment : public VertexAttachment
     {
-        RTTI_DECL;
-        
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
         friend class AtlasAttachmentLoader;
         
+        RTTI_DECL;
+        
     public:
         MeshAttachment(std::string name);
 
@@ -63,8 +65,8 @@ namespace Spine
         Vector<float>& getUVs();
         void setUVs(Vector<float>& inValue);
         
-        Vector<int>& getTriangles();
-        void setTriangles(Vector<int>& inValue);
+        Vector<short>& getTriangles();
+        void setTriangles(Vector<short>& inValue);
         
         float getR();
         void setR(float inValue);
@@ -123,8 +125,8 @@ namespace Spine
         void setParentMesh(MeshAttachment* inValue);
         
         // Nonessential.
-        Vector<int>& getEdges();
-        void setEdges(Vector<int>& inValue);
+        Vector<short>& getEdges();
+        void setEdges(Vector<short>& inValue);
         float getWidth();
         void setWidth(float inValue);
         float getHeight();
@@ -135,8 +137,8 @@ namespace Spine
         MeshAttachment* _parentMesh;
         Vector<float> _uvs;
         Vector<float> _regionUVs;
-        Vector<int> _triangles;
-        Vector<int> _edges;
+        Vector<short> _triangles;
+        Vector<short> _edges;
         void* _rendererObject;
         std::string _path;
         float _regionU;

+ 3 - 0
spine-cpp/spine-cpp/include/spine/PathAttachment.h

@@ -37,6 +37,9 @@ namespace Spine
 {
     class PathAttachment : public VertexAttachment
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         RTTI_DECL;
         
     public:

+ 3 - 0
spine-cpp/spine-cpp/include/spine/PathConstraintData.h

@@ -45,6 +45,9 @@ namespace Spine
     
     class PathConstraintData
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         friend class PathConstraint;
         friend class Skeleton;
         friend class PathConstraintMixTimeline;

+ 3 - 0
spine-cpp/spine-cpp/include/spine/PointAttachment.h

@@ -46,6 +46,9 @@ namespace Spine
     /// 
     class PointAttachment : public Attachment
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         RTTI_DECL;
         
     public:

+ 4 - 2
spine-cpp/spine-cpp/include/spine/RegionAttachment.h

@@ -46,10 +46,12 @@ namespace Spine
     /// Attachment that displays a texture region.
     class RegionAttachment : public Attachment
     {
-        RTTI_DECL;
-        
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
         friend class AtlasAttachmentLoader;
         
+        RTTI_DECL;
+        
     public:
         RegionAttachment(std::string name);
 

+ 23 - 5
spine-cpp/spine-cpp/include/spine/SkeletonBinary.h

@@ -42,6 +42,10 @@ namespace Spine
     class Atlas;
     class AttachmentLoader;
     class LinkedMesh;
+    class Skin;
+    class Attachment;
+    class VertexAttachment;
+    class Animation;
     
     class SkeletonBinary
     {
@@ -101,15 +105,29 @@ namespace Spine
         
         float readFloat(DataInput* input);
         
-        static unsigned char readByte(DataInput* input);
+        unsigned char readByte(DataInput* input);
         
-        static signed char readSByte(DataInput* input);
+        signed char readSByte(DataInput* input);
         
-        static int readBoolean(DataInput* input);
+        int readBoolean(DataInput* input);
         
-        static int readInt(DataInput* input);
+        int readInt(DataInput* input);
         
-        static int readVarint(DataInput* input, bool optimizePositive);
+        void readColor(DataInput* input, float *r, float *g, float *b, float *a);
+        
+        int readVarint(DataInput* input, bool optimizePositive);
+        
+        Skin* readSkin(DataInput* input, const char* skinName, SkeletonData* skeletonData, bool nonessential);
+        
+        Attachment* readAttachment(DataInput* input, Skin* skin, int slotIndex, const char* attachmentName, SkeletonData* skeletonData, bool nonessential);
+        
+        void readVertices(DataInput* input, VertexAttachment* attachment, int vertexCount);
+        
+        Vector<float> readFloatArray(DataInput *input, int n, float scale);
+        
+        Vector<short> readShortArray(DataInput *input);
+        
+        Animation* readAnimation(const char* name, DataInput* input, SkeletonData *skeletonData);
     };
 }
 

+ 4 - 1
spine-cpp/spine-cpp/include/spine/SlotData.h

@@ -41,6 +41,9 @@ namespace Spine
     
     class SlotData
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         friend class AttachmentTimeline;
         friend class ColorTimeline;
         friend class DeformTimeline;
@@ -95,7 +98,7 @@ namespace Spine
         const std::string _name;
         BoneData& _boneData;
         float _r, _g, _b, _a;
-        float _r2, _g2, _b2;
+        float _r2, _g2, _b2, _a2;
         bool _hasSecondColor;
         std::string _attachmentName;
         BlendMode _blendMode;

+ 3 - 0
spine-cpp/spine-cpp/include/spine/TransformConstraintData.h

@@ -41,6 +41,9 @@ namespace Spine
     
     class TransformConstraintData
     {
+        friend class SkeletonBinary;
+        friend class SkeletonJson;
+        
         friend class TransformConstraint;
         friend class Skeleton;
         friend class TransformConstraintTimeline;

+ 2 - 2
spine-cpp/spine-cpp/include/spine/VertexAttachment.h

@@ -42,10 +42,10 @@ namespace Spine
     /// An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's vertices.
     class VertexAttachment : public Attachment
     {
-        RTTI_DECL;
-        
         friend class DeformTimeline;
         
+        RTTI_DECL;
+        
     public:
         VertexAttachment(std::string name);
         

+ 4 - 4
spine-cpp/spine-cpp/src/spine/MeshAttachment.cpp

@@ -123,12 +123,12 @@ namespace Spine
         _uvs = inValue;
     }
     
-    Vector<int>& MeshAttachment::getTriangles()
+    Vector<short>& MeshAttachment::getTriangles()
     {
         return _triangles;
     }
     
-    void MeshAttachment::setTriangles(Vector<int>& inValue)
+    void MeshAttachment::setTriangles(Vector<short>& inValue)
     {
         _triangles = inValue;
     }
@@ -335,12 +335,12 @@ namespace Spine
         }
     }
     
-    Vector<int>& MeshAttachment::getEdges()
+    Vector<short>& MeshAttachment::getEdges()
     {
         return _edges;
     }
     
-    void MeshAttachment::setEdges(Vector<int>& inValue)
+    void MeshAttachment::setEdges(Vector<short>& inValue)
     {
         _edges = inValue;
     }

+ 949 - 191
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -34,10 +34,29 @@
 #include <spine/Atlas.h>
 #include <spine/AtlasAttachmentLoader.h>
 #include <spine/LinkedMesh.h>
+#include <spine/Skin.h>
+#include <spine/Attachment.h>
+#include <spine/VertexAttachment.h>
+#include <spine/Animation.h>
 
 #include <spine/Extension.h>
 #include <spine/ContainerUtil.h>
 #include <spine/BoneData.h>
+#include <spine/SlotData.h>
+#include <spine/IkConstraintData.h>
+#include <spine/TransformConstraintData.h>
+#include <spine/PathConstraintData.h>
+#include <spine/PositionMode.h>
+#include <spine/SpacingMode.h>
+#include <spine/RotateMode.h>
+#include <spine/AttachmentType.h>
+#include <spine/RegionAttachment.h>
+#include <spine/BoundingBoxAttachment.h>
+#include <spine/MeshAttachment.h>
+#include <spine/PathAttachment.h>
+#include <spine/PointAttachment.h>
+#include <spine/ClippingAttachment.h>
+#include <spine/EventData.h>
 
 namespace Spine
 {
@@ -170,199 +189,223 @@ namespace Spine
                 readInt(input);
             }
             
-            skeletonData->_bones.push_back(data);
+            skeletonData->_bones[i] = data;
         }
 
         /* Slots. */
-//        skeletonData->slotsCount = readVarint(input, 1);
-//        skeletonData->slots = MALLOC(spSlotData*, skeletonData->slotsCount);
-//        for (i = 0; i < skeletonData->slotsCount; ++i)
-//        {
-//            int r, g, b, a;
-//            const char* slotName = readString(input);
-//            spBoneData* boneData = skeletonData->bones[readVarint(input, 1)];
-//            /* TODO Avoid copying of slotName */
-//            spSlotData* slotData = spSlotData_create(i, slotName, boneData);
-//            FREE(slotName);
-//            readColor(input, &slotData->color.r, &slotData->color.g, &slotData->color.b, &slotData->color.a);
-//            r = readByte(input);
-//            g = readByte(input);
-//            b = readByte(input);
-//            a = readByte(input);
-//            if (!(r == 0xff && g == 0xff && b == 0xff && a == 0xff))
-//            {
-//                slotData->darkColor = spColor_create();
-//                spColor_setFromFloats(slotData->darkColor, r / 255.0f, g / 255.0f, b / 255.0f, 1);
-//            }
-//            slotData->attachmentName = readString(input);
-//            slotData->blendMode = (spBlendMode)readVarint(input, 1);
-//            skeletonData->slots[i] = slotData;
-//        }
-//
-//        /* IK constraints. */
-//        skeletonData->ikConstraintsCount = readVarint(input, 1);
-//        skeletonData->ikConstraints = MALLOC(spIkConstraintData*, skeletonData->ikConstraintsCount);
-//        for (i = 0; i < skeletonData->ikConstraintsCount; ++i)
-//        {
-//            const char* name = readString(input);
-//            /* TODO Avoid copying of name */
-//            spIkConstraintData* data = spIkConstraintData_create(name);
-//            data->order = readVarint(input, 1);
-//            FREE(name);
-//            data->bonesCount = readVarint(input, 1);
-//            data->bones = MALLOC(spBoneData*, data->bonesCount);
-//            for (ii = 0; ii < data->bonesCount; ++ii)
-//                data->bones[ii] = skeletonData->bones[readVarint(input, 1)];
-//            data->target = skeletonData->bones[readVarint(input, 1)];
-//            data->mix = readFloat(input);
-//            data->bendDirection = readSByte(input);
-//            skeletonData->ikConstraints[i] = data;
-//        }
-//
-//        /* Transform constraints. */
-//        skeletonData->transformConstraintsCount = readVarint(input, 1);
-//        skeletonData->transformConstraints = MALLOC(spTransformConstraintData*, skeletonData->transformConstraintsCount);
-//        for (i = 0; i < skeletonData->transformConstraintsCount; ++i)
-//        {
-//            const char* name = readString(input);
-//            /* TODO Avoid copying of name */
-//            spTransformConstraintData* data = spTransformConstraintData_create(name);
-//            data->order = readVarint(input, 1);
-//            FREE(name);
-//            data->bonesCount = readVarint(input, 1);
-//            CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
-//            for (ii = 0; ii < data->bonesCount; ++ii)
-//            {
-//                data->bones[ii] = skeletonData->bones[readVarint(input, 1)];
-//            }
-//            data->target = skeletonData->bones[readVarint(input, 1)];
-//            data->local = readBoolean(input);
-//            data->relative = readBoolean(input);
-//            data->offsetRotation = readFloat(input);
-//            data->offsetX = readFloat(input) * _scale;
-//            data->offsetY = readFloat(input) * _scale;
-//            data->offsetScaleX = readFloat(input);
-//            data->offsetScaleY = readFloat(input);
-//            data->offsetShearY = readFloat(input);
-//            data->rotateMix = readFloat(input);
-//            data->translateMix = readFloat(input);
-//            data->scaleMix = readFloat(input);
-//            data->shearMix = readFloat(input);
-//            skeletonData->transformConstraints[i] = data;
-//        }
-//
-//        /* Path constraints */
-//        skeletonData->pathConstraintsCount = readVarint(input, 1);
-//        skeletonData->pathConstraints = MALLOC(spPathConstraintData*, skeletonData->pathConstraintsCount);
-//        for (i = 0; i < skeletonData->pathConstraintsCount; ++i)
-//        {
-//            const char* name = readString(input);
-//            /* TODO Avoid copying of name */
-//            spPathConstraintData* data = spPathConstraintData_create(name);
-//            data->order = readVarint(input, 1);
-//            FREE(name);
-//            data->bonesCount = readVarint(input, 1);
-//            CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
-//            for (ii = 0; ii < data->bonesCount; ++ii)
-//            {
-//                data->bones[ii] = skeletonData->bones[readVarint(input, 1)];
-//            }
-//            data->target = skeletonData->slots[readVarint(input, 1)];
-//            data->positionMode = (spPositionMode)readVarint(input, 1);
-//            data->spacingMode = (spSpacingMode)readVarint(input, 1);
-//            data->rotateMode = (spRotateMode)readVarint(input, 1);
-//            data->offsetRotation = readFloat(input);
-//            data->position = readFloat(input);
-//            if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= _scale;
-//            data->spacing = readFloat(input);
-//            if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= _scale;
-//            data->rotateMix = readFloat(input);
-//            data->translateMix = readFloat(input);
-//            skeletonData->pathConstraints[i] = data;
-//        }
-//
-//        /* Default skin. */
-//        skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, "default", skeletonData, nonessential);
-//        skeletonData->skinsCount = readVarint(input, 1);
-//
-//        if (skeletonData->defaultSkin)
-//        {
-//            ++skeletonData->skinsCount;
-//        }
-//
-//        skeletonData->skins = MALLOC(spSkin*, skeletonData->skinsCount);
-//
-//        if (skeletonData->defaultSkin)
-//        {
-//            skeletonData->skins[0] = skeletonData->defaultSkin;
-//        }
-//
-//        /* Skins. */
-//        for (i = skeletonData->defaultSkin ? 1 : 0; i < skeletonData->skinsCount; ++i)
-//        {
-//            const char* skinName = readString(input);
-//            /* TODO Avoid copying of skinName */
-//            skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, skinName, skeletonData, nonessential);
-//            FREE(skinName);
-//        }
-//
-//        /* Linked meshes. */
-//        for (i = 0; i < internal->linkedMeshCount; ++i)
-//        {
-//            _spLinkedMesh* linkedMesh = internal->linkedMeshes + i;
-//            spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin);
-//            spAttachment* parent;
-//            if (!skin)
-//            {
-//                FREE(input);
-//                spSkeletonData_dispose(skeletonData);
-//                _spSkeletonBinary_setError(self, "Skin not found: ", linkedMesh->skin);
-//                return 0;
-//            }
-//            parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent);
-//            if (!parent)
-//            {
-//                FREE(input);
-//                spSkeletonData_dispose(skeletonData);
-//                _spSkeletonBinary_setError(self, "Parent mesh not found: ", linkedMesh->parent);
-//                return 0;
-//            }
-//            spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent));
-//            spMeshAttachment_updateUVs(linkedMesh->mesh);
-//            spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh)));
-//        }
-//
-//        /* Events. */
-//        skeletonData->eventsCount = readVarint(input, 1);
-//        skeletonData->events = MALLOC(spEventData*, skeletonData->eventsCount);
-//        for (i = 0; i < skeletonData->eventsCount; ++i)
-//        {
-//            const char* name = readString(input);
-//            /* TODO Avoid copying of skinName */
-//            spEventData* eventData = spEventData_create(name);
-//            FREE(name);
-//            eventData->intValue = readVarint(input, 0);
-//            eventData->floatValue = readFloat(input);
-//            eventData->stringValue = readString(input);
-//            skeletonData->events[i] = eventData;
-//        }
-//
-//        /* Animations. */
-//        skeletonData->animationsCount = readVarint(input, 1);
-//        skeletonData->animations = MALLOC(spAnimation*, skeletonData->animationsCount);
-//        for (i = 0; i < skeletonData->animationsCount; ++i)
-//        {
-//            const char* name = readString(input);
-//            spAnimation* animation = _spSkeletonBinary_readAnimation(self, name, input, skeletonData);
-//            FREE(name);
-//            if (!animation)
-//            {
-//                FREE(input);
-//                spSkeletonData_dispose(skeletonData);
-//                return 0;
-//            }
-//            skeletonData->animations[i] = animation;
-//        }
+        int slotsCount = readVarint(input, 1);
+        skeletonData->_slots.reserve(slotsCount);
+        for (i = 0; i < slotsCount; ++i)
+        {
+            int r, g, b, a;
+            const char* slotName = readString(input);
+            BoneData* boneData = skeletonData->_bones[readVarint(input, 1)];
+            
+            SlotData* slotData = NEW(SlotData);
+            new (slotData) SlotData(i, std::string(slotName), *boneData);
+            
+            FREE(slotName);
+            readColor(input, &slotData->_r, &slotData->_g, &slotData->_b, &slotData->_a);
+            r = readByte(input);
+            g = readByte(input);
+            b = readByte(input);
+            a = readByte(input);
+            if (!(r == 0xff && g == 0xff && b == 0xff && a == 0xff))
+            {
+                slotData->_r2 = r / 255.0f;
+                slotData->_g2 = g / 255.0f;
+                slotData->_b2 = b / 255.0f;
+            }
+            char* slotData_attachmentName = readString(input);
+            slotData->_attachmentName = std::string(slotData_attachmentName);
+            FREE(slotData_attachmentName);
+            slotData->_blendMode = static_cast<BlendMode>(readVarint(input, 1));
+            
+            skeletonData->_slots[i] = slotData;
+        }
+
+        /* IK constraints. */
+        int ikConstraintsCount = readVarint(input, 1);
+        skeletonData->_ikConstraints.reserve(ikConstraintsCount);
+        for (i = 0; i < ikConstraintsCount; ++i)
+        {
+            const char* name = readString(input);
+            
+            IkConstraintData* data = NEW(IkConstraintData);
+            new (data) IkConstraintData(std::string(name));
+            
+            data->_order = readVarint(input, 1);
+            
+            FREE(name);
+            int bonesCount = readVarint(input, 1);
+            data->_bones.reserve(bonesCount);
+            for (ii = 0; ii < bonesCount; ++ii)
+            {
+                data->_bones[ii] = skeletonData->_bones[readVarint(input, 1)];
+            }
+            data->_target = skeletonData->_bones[readVarint(input, 1)];
+            data->_mix = readFloat(input);
+            data->_bendDirection = readSByte(input);
+            
+            skeletonData->_ikConstraints[i] = data;
+        }
+
+        /* Transform constraints. */
+        int transformConstraintsCount = readVarint(input, 1);
+        skeletonData->_transformConstraints.reserve(transformConstraintsCount);
+        for (i = 0; i < transformConstraintsCount; ++i)
+        {
+            const char* name = readString(input);
+            
+            TransformConstraintData* data = NEW(TransformConstraintData);
+            new (data) TransformConstraintData(std::string(name));
+            
+            data->_order = readVarint(input, 1);
+            FREE(name);
+            int bonesCount = readVarint(input, 1);
+            data->_bones.reserve(bonesCount);
+            for (ii = 0; ii < bonesCount; ++ii)
+            {
+                data->_bones[ii] = skeletonData->_bones[readVarint(input, 1)];
+            }
+            data->_target = skeletonData->_bones[readVarint(input, 1)];
+            data->_local = readBoolean(input);
+            data->_relative = readBoolean(input);
+            data->_offsetRotation = readFloat(input);
+            data->_offsetX = readFloat(input) * _scale;
+            data->_offsetY = readFloat(input) * _scale;
+            data->_offsetScaleX = readFloat(input);
+            data->_offsetScaleY = readFloat(input);
+            data->_offsetShearY = readFloat(input);
+            data->_rotateMix = readFloat(input);
+            data->_translateMix = readFloat(input);
+            data->_scaleMix = readFloat(input);
+            data->_shearMix = readFloat(input);
+            
+            skeletonData->_transformConstraints[i] = data;
+        }
+
+        /* Path constraints */
+        int pathConstraintsCount = readVarint(input, 1);
+        skeletonData->_pathConstraints.reserve(pathConstraintsCount);
+        for (i = 0; i < pathConstraintsCount; ++i)
+        {
+            const char* name = readString(input);
+            
+            PathConstraintData* data = NEW(PathConstraintData);
+            new (data) PathConstraintData(std::string(name));
+            
+            data->_order = readVarint(input, 1);
+            FREE(name);
+            
+            int bonesCount = readVarint(input, 1);
+            data->_bones.reserve(bonesCount);
+            for (ii = 0; ii < bonesCount; ++ii)
+            {
+                data->_bones[ii] = skeletonData->_bones[readVarint(input, 1)];
+            }
+            data->_target = skeletonData->_slots[readVarint(input, 1)];
+            data->_positionMode = static_cast<PositionMode>(readVarint(input, 1));
+            data->_spacingMode = static_cast<SpacingMode>(readVarint(input, 1));
+            data->_rotateMode = static_cast<RotateMode>(readVarint(input, 1));
+            data->_offsetRotation = readFloat(input);
+            data->_position = readFloat(input);
+            if (data->_positionMode == PositionMode_Fixed)
+            {
+                data->_position *= _scale;
+            }
+            
+            data->_spacing = readFloat(input);
+            if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed)
+            {
+                data->_spacing *= _scale;
+            }
+            data->_rotateMix = readFloat(input);
+            data->_translateMix = readFloat(input);
+            
+            skeletonData->_pathConstraints[i] = data;
+        }
+
+        /* Default skin. */
+        skeletonData->_defaultSkin = readSkin(input, "default", skeletonData, nonessential);
+        int skinsCount = readVarint(input, 1);
+
+        if (skeletonData->_defaultSkin)
+        {
+            ++skinsCount;
+        }
+
+        skeletonData->_skins.reserve(skinsCount);
+
+        if (skeletonData->_defaultSkin)
+        {
+            skeletonData->_skins[0] = skeletonData->_defaultSkin;
+        }
+
+        /* Skins. */
+        for (i = skeletonData->_defaultSkin ? 1 : 0; i < skeletonData->_skins.size(); ++i)
+        {
+            const char* skinName = readString(input);
+            skeletonData->_skins[i] = readSkin(input, skinName, skeletonData, nonessential);
+            FREE(skinName);
+        }
+
+        /* Linked meshes. */
+        for (int i = 0, n = static_cast<int>(_linkedMeshes.size()); i < n; i++)
+        {
+            LinkedMesh* linkedMesh = _linkedMeshes[i];
+            Skin* skin = linkedMesh->_skin.length() == 0 ? skeletonData->getDefaultSkin() : skeletonData->findSkin(linkedMesh->_skin);
+            if (skin == NULL)
+            {
+                FREE(input);
+                DESTROY(SkeletonData, skeletonData);
+                setError("Skin not found: ", linkedMesh->_skin.c_str());
+                return NULL;
+            }
+            Attachment* parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent);
+            if (parent == NULL)
+            {
+                FREE(input);
+                DESTROY(SkeletonData, skeletonData);
+                setError("Parent mesh not found: ", linkedMesh->_parent.c_str());
+                return NULL;
+            }
+            linkedMesh->_mesh->_parentMesh = static_cast<MeshAttachment*>(parent);
+            linkedMesh->_mesh->updateUVs();
+        }
+        _linkedMeshes.clear();
+
+        /* Events. */
+        int eventsCount = readVarint(input, 1);
+        skeletonData->_events.reserve(eventsCount);
+        for (i = 0; i < eventsCount; ++i)
+        {
+            const char* name = readString(input);
+            EventData* eventData = NEW(EventData);
+            new (eventData) EventData(std::string(name));
+            FREE(name);
+            eventData->_intValue = readVarint(input, 0);
+            eventData->_floatValue = readFloat(input);
+            eventData->_stringValue = readString(input);
+            skeletonData->_events[i] = eventData;
+        }
+
+        /* Animations. */
+        int animationsCount = readVarint(input, 1);
+        skeletonData->_animations.reserve(animationsCount);
+        for (i = 0; i < animationsCount; ++i)
+        {
+            const char* name = readString(input);
+            Animation* animation = readAnimation(name, input, skeletonData);
+            FREE(name);
+            if (!animation)
+            {
+                FREE(input);
+                DESTROY(SkeletonData, skeletonData);
+                return NULL;
+            }
+            skeletonData->_animations[i] = animation;
+        }
 
         FREE(input);
         
@@ -403,7 +446,7 @@ namespace Spine
         int length = readVarint(input, 1);
         char* string;
         if (length == 0) {
-            return 0;
+            return NULL;
         }
         string = MALLOC(char, length);
         memcpy(string, input->cursor, length - 1);
@@ -452,6 +495,14 @@ namespace Spine
         return result;
     }
     
+    void SkeletonBinary::readColor(DataInput* input, float *r, float *g, float *b, float *a)
+    {
+        *r = readByte(input) / 255.0f;
+        *g = readByte(input) / 255.0f;
+        *b = readByte(input) / 255.0f;
+        *a = readByte(input) / 255.0f;
+    }
+    
     int SkeletonBinary::readVarint(DataInput* input, bool optimizePositive)
     {
         unsigned char b = readByte(input);
@@ -480,4 +531,711 @@ namespace Spine
         
         return value;
     }
+    
+    Skin* SkeletonBinary::readSkin(DataInput* input, const char* skinName, SkeletonData* skeletonData, bool nonessential)
+    {
+        Skin* skin = NULL;
+        int slotCount = readVarint(input, 1);
+        int i, ii, nn;
+        if (slotCount == 0)
+        {
+            return 0;
+        }
+        
+        skin = NEW(Skin);
+        new (skin) Skin(std::string(skinName));
+        
+        for (i = 0; i < slotCount; ++i)
+        {
+            int slotIndex = readVarint(input, 1);
+            for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii)
+            {
+                const char* name = readString(input);
+                Attachment* attachment = readAttachment(input, skin, slotIndex, name, skeletonData, nonessential);
+                if (attachment)
+                {
+                    skin->addAttachment(slotIndex, std::string(name), attachment);
+                }
+                FREE(name);
+            }
+        }
+        
+        return skin;
+    }
+    
+    Attachment* SkeletonBinary::readAttachment(DataInput* input, Skin* skin, int slotIndex, const char* attachmentName, SkeletonData* skeletonData, bool nonessential)
+    {
+        int i;
+        AttachmentType type;
+        const char* name = readString(input);
+        int freeName = name != 0;
+        if (!name)
+        {
+            freeName = 0;
+            name = attachmentName;
+        }
+        
+        type = static_cast<AttachmentType>(readByte(input));
+        
+        switch (type)
+        {
+            case AttachmentType_Region:
+            {
+                const char* path = readString(input);
+                RegionAttachment* region;
+                if (!path)
+                {
+                    path = name;
+                }
+                region = _attachmentLoader->newRegionAttachment(*skin, std::string(name), std::string(path));
+                region->_path = std::string(path);
+                region->_rotation = readFloat(input);
+                region->_x = readFloat(input) * _scale;
+                region->_y = readFloat(input) * _scale;
+                region->_scaleX = readFloat(input);
+                region->_scaleY = readFloat(input);
+                region->_width = readFloat(input) * _scale;
+                region->_height = readFloat(input) * _scale;
+                readColor(input, &region->_r, &region->_g, &region->_b, &region->_a);
+                region->updateOffset();
+                
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return region;
+            }
+            case AttachmentType_Boundingbox:
+            {
+                int vertexCount = readVarint(input, 1);
+                BoundingBoxAttachment* box = _attachmentLoader->newBoundingBoxAttachment(*skin, std::string(name));
+                readVertices(input, static_cast<VertexAttachment*>(box), vertexCount);
+                if (nonessential)
+                {
+                    /* Skip color. */
+                    readInt(input);
+                }
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return box;
+            }
+            case AttachmentType_Mesh:
+            {
+                int vertexCount;
+                MeshAttachment* mesh;
+                const char* path = readString(input);
+                if (!path)
+                {
+                    path = name;
+                }
+                mesh = _attachmentLoader->newMeshAttachment(*skin, std::string(name), std::string(path));
+                mesh->_path = std::string(path);
+                readColor(input, &mesh->_r, &mesh->_g, &mesh->_b, &mesh->_a);
+                vertexCount = readVarint(input, 1);
+                Vector<float> float_array = readFloatArray(input, vertexCount << 1, 1);
+                mesh->setRegionUVs(float_array);
+                Vector<short> triangles = readShortArray(input);
+                mesh->setTriangles(triangles);
+                readVertices(input, static_cast<VertexAttachment*>(mesh), vertexCount);
+                mesh->updateUVs();
+                mesh->_hullLength = readVarint(input, 1) << 1;
+                if (nonessential)
+                {
+                    Vector<short> edges = readShortArray(input);
+                    mesh->setEdges(edges);
+                    mesh->_width = readFloat(input) * _scale;
+                    mesh->_height = readFloat(input) * _scale;
+                }
+                else
+                {
+                    mesh->_width = 0;
+                    mesh->_height = 0;
+                }
+                
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return mesh;
+            }
+            case AttachmentType_Linkedmesh:
+            {
+                const char* skinName;
+                const char* parent;
+                MeshAttachment* mesh;
+                const char* path = readString(input);
+                if (!path)
+                {
+                    path = name;
+                }
+                
+                mesh = _attachmentLoader->newMeshAttachment(*skin, std::string(name), std::string(path));
+                mesh->_path = path;
+                readColor(input, &mesh->_r, &mesh->_g, &mesh->_b, &mesh->_a);
+                skinName = readString(input);
+                parent = readString(input);
+                mesh->_inheritDeform = readBoolean(input);
+                if (nonessential)
+                {
+                    mesh->_width = readFloat(input) * _scale;
+                    mesh->_height = readFloat(input) * _scale;
+                }
+                
+                LinkedMesh* linkedMesh = NEW(LinkedMesh);
+                new (linkedMesh) LinkedMesh(mesh, std::string(skinName), slotIndex, std::string(parent));
+                _linkedMeshes.push_back(linkedMesh);
+                
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return mesh;
+            }
+            case AttachmentType_Path:
+            {
+                PathAttachment* path = _attachmentLoader->newPathAttachment(*skin, std::string(name));
+                int vertexCount = 0;
+                path->_closed = readBoolean(input);
+                path->_constantSpeed = readBoolean(input);
+                vertexCount = readVarint(input, 1);
+                readVertices(input, static_cast<VertexAttachment*>(path), vertexCount);
+                int lengthsLength = vertexCount / 3;
+                path->_lengths.reserve(lengthsLength);
+                for (i = 0; i < lengthsLength; ++i)
+                {
+                    path->_lengths[i] = readFloat(input) * _scale;
+                }
+                
+                if (nonessential)
+                {
+                    /* Skip color. */
+                    readInt(input);
+                }
+                
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return path;
+            }
+            case AttachmentType_Point:
+            {
+                PointAttachment* point = _attachmentLoader->newPointAttachment(*skin, std::string(name));
+                point->_rotation = readFloat(input);
+                point->_x = readFloat(input) * _scale;
+                point->_y = readFloat(input) * _scale;
+                
+                if (nonessential)
+                {
+                    /* Skip color. */
+                    readInt(input);
+                }
+                
+                return point;
+            }
+            case AttachmentType_Clipping:
+            {
+                int endSlotIndex = readVarint(input, 1);
+                int vertexCount = readVarint(input, 1);
+                ClippingAttachment* clip = _attachmentLoader->newClippingAttachment(*skin, name);
+                readVertices(input, static_cast<VertexAttachment*>(clip), vertexCount);
+                
+                if (nonessential)
+                {
+                    /* Skip color. */
+                    readInt(input);
+                }
+                
+                clip->_endSlot = skeletonData->_slots[endSlotIndex];
+                
+                if (freeName)
+                {
+                    FREE(name);
+                }
+                
+                return clip;
+            }
+        }
+        
+        if (freeName)
+        {
+            FREE(name);
+        }
+        
+        return NULL;
+    }
+    
+    void SkeletonBinary::readVertices(DataInput* input, VertexAttachment* attachment, int vertexCount)
+    {
+        float scale = _scale;
+        int verticesLength = vertexCount << 1;
+        
+        if (!readBoolean(input))
+        {
+            attachment->setVertices(readFloatArray(input, verticesLength, scale));
+            return;
+        }
+        
+        Vertices vertices;
+        vertices._bones.reserve(verticesLength * 3);
+        vertices._vertices.reserve(verticesLength * 3 * 3);
+        
+        for (int i = 0; i < vertexCount; ++i)
+        {
+            int boneCount = readVarint(input, true);
+            vertices._bones.push_back(boneCount);
+            for (int ii = 0; ii < boneCount; ++ii)
+            {
+                vertices._bones.push_back(readVarint(input, true));
+                vertices._vertices.push_back(readFloat(input) * scale);
+                vertices._vertices.push_back(readFloat(input) * scale);
+                vertices._vertices.push_back(readFloat(input));
+            }
+        }
+        
+        attachment->setVertices(vertices._vertices);
+        attachment->setBones(vertices._bones);
+    }
+    
+    Vector<float> SkeletonBinary::readFloatArray(DataInput *input, int n, float scale)
+    {
+        Vector<float> array;
+        array.reserve(n);
+        
+        int i;
+        if (scale == 1)
+        {
+            for (i = 0; i < n; ++i)
+            {
+                array[i] = readFloat(input);
+            }
+        }
+        else
+        {
+            for (i = 0; i < n; ++i)
+            {
+                array[i] = readFloat(input) * scale;
+            }
+        }
+        
+        return array;
+    }
+    
+    Vector<short> SkeletonBinary::readShortArray(DataInput *input)
+    {
+        int n = readVarint(input, 1);
+        
+        Vector<short> array;
+        array.reserve(n);
+        
+        int i;
+        for (i = 0; i < n; ++i)
+        {
+            array[i] = readByte(input) << 8;
+            array[i] |= readByte(input);
+        }
+        
+        return array;
+    }
+    
+    Animation* SkeletonBinary::readAnimation(const char* name, DataInput* input, SkeletonData *skeletonData)
+    {
+//        var timelines = new ExposedList<Timeline>();
+//        float scale = Scale;
+//        float duration = 0;
+//
+//        // Slot timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            int slotIndex = ReadVarint(input, true);
+//            for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
+//            {
+//                int timelineType = input.ReadByte();
+//                int frameCount = ReadVarint(input, true);
+//                switch (timelineType)
+//                {
+//                    case SLOT_ATTACHMENT:
+//                    {
+//                        AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
+//                        timeline.slotIndex = slotIndex;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input));
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[frameCount - 1]);
+//                        break;
+//                    }
+//                    case SLOT_COLOR:
+//                    {
+//                        ColorTimeline timeline = new ColorTimeline(frameCount);
+//                        timeline.slotIndex = slotIndex;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)\
+//                        {
+//                            float time = ReadFloat(input);
+//                            int color = ReadInt(input);
+//                            float r = ((color & 0xff000000) >> 24) / 255f;
+//                            float g = ((color & 0x00ff0000) >> 16) / 255f;
+//                            float b = ((color & 0x0000ff00) >> 8) / 255f;
+//                            float a = ((color & 0x000000ff)) / 255f;
+//                            timeline.SetFrame(frameIndex, time, r, g, b, a);
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                    case SLOT_TWO_COLOR:
+//                    {
+//                        TwoColorTimeline timeline = new TwoColorTimeline(frameCount);
+//                        timeline.slotIndex = slotIndex;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            float time = ReadFloat(input);
+//                            int color = ReadInt(input);
+//                            float r = ((color & 0xff000000) >> 24) / 255f;
+//                            float g = ((color & 0x00ff0000) >> 16) / 255f;
+//                            float b = ((color & 0x0000ff00) >> 8) / 255f;
+//                            float a = ((color & 0x000000ff)) / 255f;
+//                            int color2 = ReadInt(input); // 0x00rrggbb
+//                            float r2 = ((color2 & 0x00ff0000) >> 16) / 255f;
+//                            float g2 = ((color2 & 0x0000ff00) >> 8) / 255f;
+//                            float b2 = ((color2 & 0x000000ff)) / 255f;
+//
+//                            timeline.SetFrame(frameIndex, time, r, g, b, a, r2, g2, b2);
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TwoColorTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                }
+//            }
+//        }
+//
+//        // Bone timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            int boneIndex = ReadVarint(input, true);
+//            for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
+//            {
+//                int timelineType = input.ReadByte();
+//                int frameCount = ReadVarint(input, true);
+//                switch (timelineType)
+//                {
+//                    case BONE_ROTATE:
+//                    {
+//                        RotateTimeline timeline = new RotateTimeline(frameCount);
+//                        timeline.boneIndex = boneIndex;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input));
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * RotateTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                    case BONE_TRANSLATE:
+//                    case BONE_SCALE:
+//                    case BONE_SHEAR:
+//                    {
+//                        TranslateTimeline timeline;
+//                        float timelineScale = 1;
+//                        if (timelineType == BONE_SCALE)
+//                        {
+//                            timeline = new ScaleTimeline(frameCount);
+//                        }
+//                        else if (timelineType == BONE_SHEAR)
+//                        {
+//                            timeline = new ShearTimeline(frameCount);
+//                        }
+//                        else
+//                        {
+//                            timeline = new TranslateTimeline(frameCount);
+//                            timelineScale = scale;
+//                        }
+//                        timeline.boneIndex = boneIndex;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale, ReadFloat(input)
+//                                              * timelineScale);
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TranslateTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                }
+//            }
+//        }
+//
+//        // IK timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            int index = ReadVarint(input, true);
+//            int frameCount = ReadVarint(input, true);
+//            IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
+//            timeline.ikConstraintIndex = index;
+//            for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//            {
+//                timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input));
+//                if (frameIndex < frameCount - 1)
+//                {
+//                    ReadCurve(input, frameIndex, timeline);
+//                }
+//            }
+//            timelines.Add(timeline);
+//            duration = Math.Max(duration, timeline.frames[(frameCount - 1) * IkConstraintTimeline.ENTRIES]);
+//        }
+//
+//        // Transform constraint timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            int index = ReadVarint(input, true);
+//            int frameCount = ReadVarint(input, true);
+//            TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount);
+//            timeline.transformConstraintIndex = index;
+//            for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//            {
+//                timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input));
+//                if (frameIndex < frameCount - 1)
+//                {
+//                    ReadCurve(input, frameIndex, timeline);
+//                }
+//            }
+//            timelines.Add(timeline);
+//            duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]);
+//        }
+//
+//        // Path constraint timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            int index = ReadVarint(input, true);
+//            PathConstraintData data = skeletonData.pathConstraints.Items[index];
+//            for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
+//            {
+//                int timelineType = ReadSByte(input);
+//                int frameCount = ReadVarint(input, true);
+//                switch(timelineType)
+//                {
+//                    case PATH_POSITION:
+//                    case PATH_SPACING:
+//                    {
+//                        PathConstraintPositionTimeline timeline;
+//                        float timelineScale = 1;
+//                        if (timelineType == PATH_SPACING)
+//                        {
+//                            timeline = new PathConstraintSpacingTimeline(frameCount);
+//                            if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed)
+//                            {
+//                                timelineScale = scale;
+//                            }
+//                        }
+//                        else
+//                        {
+//                            timeline = new PathConstraintPositionTimeline(frameCount);
+//                            if (data.positionMode == PositionMode.Fixed)
+//                            {
+//                                timelineScale = scale;
+//                            }
+//                        }
+//                        timeline.pathConstraintIndex = index;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale);
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                    case PATH_MIX:
+//                    {
+//                        PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount);
+//                        timeline.pathConstraintIndex = index;
+//                        for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                        {
+//                            timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input));
+//                            if (frameIndex < frameCount - 1)
+//                            {
+//                                ReadCurve(input, frameIndex, timeline);
+//                            }
+//                        }
+//                        timelines.Add(timeline);
+//                        duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]);
+//                        break;
+//                    }
+//                }
+//            }
+//        }
+//
+//        // Deform timelines.
+//        for (int i = 0, n = ReadVarint(input, true); i < n; i++)
+//        {
+//            Skin skin = skeletonData.skins.Items[ReadVarint(input, true)];
+//            for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++)
+//            {
+//                int slotIndex = ReadVarint(input, true);
+//                for (int iii = 0, nnn = ReadVarint(input, true); iii < nnn; iii++)
+//                {
+//                    VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, ReadString(input));
+//                    bool weighted = attachment.bones != null;
+//                    float[] vertices = attachment.vertices;
+//                    int deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length;
+//
+//                    int frameCount = ReadVarint(input, true);
+//                    DeformTimeline timeline = new DeformTimeline(frameCount);
+//                    timeline.slotIndex = slotIndex;
+//                    timeline.attachment = attachment;
+//
+//                    for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
+//                    {
+//                        float time = ReadFloat(input);
+//                        float[] deform;
+//                        int end = ReadVarint(input, true);
+//                        if (end == 0)
+//                        {
+//                            deform = weighted ? new float[deformLength] : vertices;
+//                        }
+//                        else
+//                        {
+//                            deform = new float[deformLength];
+//                            int start = ReadVarint(input, true);
+//                            end += start;
+//                            if (scale == 1)
+//                            {
+//                                for (int v = start; v < end; v++)
+//                                {
+//                                    deform[v] = ReadFloat(input);
+//                                }
+//                            }
+//                            else
+//                            {
+//                                for (int v = start; v < end; v++)
+//                                {
+//                                    deform[v] = ReadFloat(input) * scale;
+//                                }
+//                            }
+//
+//                            if (!weighted)
+//                            {
+//                                for (int v = 0, vn = deform.Length; v < vn; v++)
+//                                {
+//                                    deform[v] += vertices[v];
+//                                }
+//                            }
+//                        }
+//
+//                        timeline.SetFrame(frameIndex, time, deform);
+//                        if (frameIndex < frameCount - 1)
+//                        {
+//                            ReadCurve(input, frameIndex, timeline);
+//                        }
+//                    }
+//
+//                    timelines.Add(timeline);
+//                    duration = Math.Max(duration, timeline.frames[frameCount - 1]);
+//                }
+//            }
+//        }
+//
+//        // Draw order timeline.
+//        int drawOrderCount = ReadVarint(input, true);
+//        if (drawOrderCount > 0)
+//        {
+//            DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount);
+//            int slotCount = skeletonData.slots.Count;
+//            for (int i = 0; i < drawOrderCount; i++)
+//            {
+//                float time = ReadFloat(input);
+//                int offsetCount = ReadVarint(input, true);
+//                int[] drawOrder = new int[slotCount];
+//                for (int ii = slotCount - 1; ii >= 0; ii--)
+//                {
+//                    drawOrder[ii] = -1;
+//                }
+//                int[] unchanged = new int[slotCount - offsetCount];
+//                int originalIndex = 0, unchangedIndex = 0;
+//                for (int ii = 0; ii < offsetCount; ii++)
+//                {
+//                    int slotIndex = ReadVarint(input, true);
+//                    // Collect unchanged items.
+//                    while (originalIndex != slotIndex)
+//                    {
+//                        unchanged[unchangedIndex++] = originalIndex++;
+//                    }
+//                    // Set changed items.
+//                    drawOrder[originalIndex + ReadVarint(input, true)] = originalIndex++;
+//                }
+//
+//                // Collect remaining unchanged items.
+//                while (originalIndex < slotCount)
+//                {
+//                    unchanged[unchangedIndex++] = originalIndex++;
+//                }
+//
+//                // Fill in unchanged items.
+//                for (int ii = slotCount - 1; ii >= 0; ii--)
+//                {
+//                    if (drawOrder[ii] == -1)
+//                    {
+//                        drawOrder[ii] = unchanged[--unchangedIndex];
+//                    }
+//                }
+//                timeline.SetFrame(i, time, drawOrder);
+//            }
+//            timelines.Add(timeline);
+//            duration = Math.Max(duration, timeline.frames[drawOrderCount - 1]);
+//        }
+//
+//        // Event timeline.
+//        int eventCount = ReadVarint(input, true);
+//        if (eventCount > 0)
+//        {
+//            EventTimeline timeline = new EventTimeline(eventCount);
+//            for (int i = 0; i < eventCount; i++)
+//            {
+//                float time = ReadFloat(input);
+//                EventData eventData = skeletonData.events.Items[ReadVarint(input, true)];
+//                Event e = new Event(time, eventData);
+//                e.Int = ReadVarint(input, false);
+//                e.Float = ReadFloat(input);
+//                e.String = ReadBoolean(input) ? ReadString(input) : eventData.String;
+//                timeline.SetFrame(i, e);
+//            }
+//
+//            timelines.Add(timeline);
+//            duration = Math.Max(duration, timeline.frames[eventCount - 1]);
+//        }
+//
+//        timelines.TrimExcess();
+//
+        Animation* ret = NEW(Animation);
+//        new (ret) Animation(std::string(name), timelines, duration);
+        
+        return ret;
+    }
 }

+ 1 - 0
spine-cpp/spine-cpp/src/spine/SlotData.cpp

@@ -45,6 +45,7 @@ namespace Spine
     _r2(0),
     _g2(0),
     _b2(0),
+    _a2(1),
     _hasSecondColor(false),
     _attachmentName(),
     _blendMode(BlendMode_Normal)