Explorar el Código

[cpp] Fixed up binary reader, added debug extension for memory profiling, fixed up RTTI usage, fixed update cache sorting.

badlogic hace 7 años
padre
commit
a8fd3e14be

+ 0 - 1
spine-cpp/spine-cpp-unit-tests/CMakeLists.txt

@@ -10,7 +10,6 @@ include_directories(../spine-cpp/include teamcity minicppunit tests memory)
 
 set(SRC
 	src/main.cpp
-	src/TestHarness.cpp
 )
 
 add_executable(spine_cpp_unit_test ${SRC})

+ 0 - 91
spine-cpp/spine-cpp-unit-tests/src/TestHarness.cpp

@@ -1,91 +0,0 @@
-/******************************************************************************
- * Spine Runtimes Software License v2.5
- *
- * Copyright (c) 2013-2016, Esoteric Software
- * All rights reserved.
- *
- * You are granted a perpetual, non-exclusive, non-sublicensable, and
- * non-transferable license to use, install, execute, and perform the Spine
- * Runtimes software and derivative works solely for personal or internal
- * use. Without the written permission of Esoteric Software (see Section 2 of
- * the Spine Software License Agreement), you may not (a) modify, translate,
- * adapt, or develop new applications using the Spine Runtimes or otherwise
- * create derivative works or improvements of the Spine Runtimes or (b) remove,
- * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
- * or other intellectual property or proprietary rights notices on or in the
- * Software, including any copy thereof. Redistributions in binary or source
- * form must include this license and terms.
- *
- * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
- * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-
-#include "TestHarness.h"
-
-void *Spine::TestSpineExtension::_alloc(size_t size, const char *file, int line) {
-	void* result = DefaultSpineExtension::_alloc(size, file, line);
-	_allocated.push_back(Allocation(result, size, file, line));
-	_allocations++;
-	return result;
-}
-
-void *Spine::TestSpineExtension::_calloc(size_t size, const char *file, int line) {
-	void* result = DefaultSpineExtension::_calloc(size, file, line);
-	_allocated.push_back(Allocation(result, size, file, line));
-	_allocations++;
-	return result;
-}
-
-void *Spine::TestSpineExtension::_realloc(void *ptr, size_t size, const char *file, int line) {
-	void* result = DefaultSpineExtension::_realloc(ptr, size, file, line);
-	_reallocations++;
-
-	for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
-		if (it->address == ptr) {
-			it->address = result;
-			it->size = size;
-			it->fileName = file;
-			it->line = line;
-			return result;
-		}
-	}
-
-	_allocated.push_back(Allocation(result, size, file, line));
-	return result;
-}
-
-void Spine::TestSpineExtension::_free(void *mem, const char *file, int line) {
-
-	for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
-		if (it->address == mem) {
-			DefaultSpineExtension::_free(mem, file, line);
-			_frees++;
-			_allocated.erase(it);
-			return;
-		}
-	}
-
-	printf("%s:%i (address %p): Double free or not allocated through SpineExtension\n", file, line, mem);
-	DefaultSpineExtension::_free(mem, file, line);
-}
-
-void Spine::TestSpineExtension::reportLeaks() {
-	for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
-		printf("\"%s:%i (%zu bytes at %p)\n", it->fileName, it->line, it->size, it->address);
-	}
-	printf("allocations: %lu, reallocations: %lu, frees: %lu\n", _allocations, _reallocations, _frees);
-	if (_allocated.empty()) printf("No leaks detected");
-}
-
-void Spine::TestSpineExtension::clearAllocations() {
-	_allocated.resize(0);
-}

+ 2 - 3
spine-cpp/spine-cpp-unit-tests/src/main.cpp

@@ -30,8 +30,7 @@
 
 #include <stdio.h>
 #include <spine/spine.h>
-
-#include "TestHarness.h"
+#include <spine/Debug.h>
 
 using namespace Spine;
 
@@ -115,7 +114,7 @@ void testLoading() {
 }
 
 int main (int argc, char** argv) {
-	TestSpineExtension* ext = new TestSpineExtension();
+	DebugExtension* ext = new DebugExtension();
 	SpineExtension::setInstance(ext);
 
  	testLoading();

+ 29 - 4
spine-cpp/spine-cpp/include/spine/Color.h

@@ -1,7 +1,32 @@
-//
-// Created by Mario Zechner on 2/20/18.
-//
-
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
 #ifndef SPINE_COLOR_H
 #define SPINE_COLOR_H
 

+ 68 - 21
spine-cpp/spine-cpp-unit-tests/src/TestHarness.h → spine-cpp/spine-cpp/include/spine/Debug.h

@@ -28,40 +28,87 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
-
-#ifndef SPINE_TESTHARNESS_H
-#define SPINE_TESTHARNESS_H
+#ifndef SPINE_DEBUG_H
+#define SPINE_DEBUG_H
 
 #include <spine/Extension.h>
+
 #include <vector>
 
 namespace Spine {
-	struct Allocation {
-		void* address;
-		size_t size;
-		const char* fileName;
-		int line;
+	class DebugExtension: public DefaultSpineExtension {
+		struct Allocation {
+			void* address;
+			size_t size;
+			const char* fileName;
+			int line;
 
-		Allocation() : address(NULL), size(0), fileName(NULL), line(0) {
-		}
+			Allocation() : address(NULL), size(0), fileName(NULL), line(0) {
+			}
 
-		Allocation(void* a, size_t s, const char* f, int l) : address(a), size(s), fileName(f), line(l) {
-		}
-	};
+			Allocation(void* a, size_t s, const char* f, int l) : address(a), size(s), fileName(f), line(l) {
+			}
+		};
 
-	class TestSpineExtension: public DefaultSpineExtension {
 	public:
-		void reportLeaks ();
-		void clearAllocations();
+		void reportLeaks () {
+			for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
+				printf("\"%s:%i (%zu bytes at %p)\n", it->fileName, it->line, it->size, it->address);
+			}
+			printf("allocations: %lu, reallocations: %lu, frees: %lu\n", _allocations, _reallocations, _frees);
+			if (_allocated.empty()) printf("No leaks detected");
+		}
+
+		void clearAllocations() {
+			_allocated.resize(0);
+		}
 
 	protected:
-		virtual void* _alloc(size_t size, const char* file, int line);
+		virtual void* _alloc(size_t size, const char* file, int line) {
+			void* result = DefaultSpineExtension::_alloc(size, file, line);
+			_allocated.push_back(Allocation(result, size, file, line));
+			_allocations++;
+			return result;
+		}
+
+		virtual void* _calloc(size_t size, const char* file, int line) {
+			void* result = DefaultSpineExtension::_calloc(size, file, line);
+			_allocated.push_back(Allocation(result, size, file, line));
+			_allocations++;
+			return result;
+		}
 
-		virtual void* _calloc(size_t size, const char* file, int line);
+		virtual void* _realloc(void* ptr, size_t size, const char* file, int line) {
+			void* result = DefaultSpineExtension::_realloc(ptr, size, file, line);
+			_reallocations++;
 
-		virtual void* _realloc(void* ptr, size_t size, const char* file, int line);
+			for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
+				if (it->address == ptr) {
+					it->address = result;
+					it->size = size;
+					it->fileName = file;
+					it->line = line;
+					return result;
+				}
+			}
 
-		virtual void _free(void* mem, const char* file, int line);
+			_allocated.push_back(Allocation(result, size, file, line));
+			return result;
+		}
+
+		virtual void _free(void* mem, const char* file, int line) {
+			for (std::vector<Allocation>::iterator it = _allocated.begin(); it != _allocated.end(); it++) {
+				if (it->address == mem) {
+					DefaultSpineExtension::_free(mem, file, line);
+					_frees++;
+					_allocated.erase(it);
+					return;
+				}
+			}
+
+			printf("%s:%i (address %p): Double free or not allocated through SpineExtension\n", file, line, mem);
+			DefaultSpineExtension::_free(mem, file, line);
+		}
 
 	private:
 		std::vector<Allocation> _allocated;
@@ -72,4 +119,4 @@ namespace Spine {
 }
 
 
-#endif //SPINE_TESTHARNESS_H
+#endif //SPINE_DEBUG_H

+ 13 - 0
spine-cpp/spine-cpp/include/spine/Extension.h

@@ -99,6 +99,19 @@ namespace Spine {
 
         virtual char* _readFile(const String& path, int* length);
     };
+
+    struct Allocation {
+        void* address;
+        size_t size;
+        const char* fileName;
+        int line;
+
+        Allocation() : address(NULL), size(0), fileName(NULL), line(0) {
+        }
+
+        Allocation(void* a, size_t s, const char* f, int l) : address(a), size(s), fileName(f), line(l) {
+        }
+    };
 }
 
 #endif /* Spine_Extension_h */

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

@@ -45,8 +45,8 @@ namespace Spine {
         const std::string& getClassName() const;
         
         bool isExactly(const RTTI& rtti) const;
-        
-        bool derivesFrom(const RTTI& rtti) const;
+
+        bool instanceOf(const RTTI &rtti) const;
         
     private:
         // Prevent copying

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

@@ -78,6 +78,8 @@ namespace Spine {
         /// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added
         /// or removed.
         void updateCache();
+
+        void printUpdateCache ();
         
         /// Updates the world transform for each bone and applies constraints.
         void updateWorldTransform();

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

@@ -113,9 +113,9 @@ namespace Spine {
         
         int readVarint(DataInput* input, bool optimizePositive);
         
-        Skin* readSkin(DataInput* input, const char* skinName, SkeletonData* skeletonData, bool nonessential);
+        Skin* readSkin(DataInput* input, const String& skinName, SkeletonData* skeletonData, bool nonessential);
         
-        Attachment* readAttachment(DataInput* input, Skin* skin, int slotIndex, const char* attachmentName, SkeletonData* skeletonData, bool nonessential);
+        Attachment* readAttachment(DataInput* input, Skin* skin, int slotIndex, const String& attachmentName, SkeletonData* skeletonData, bool nonessential);
         
         void readVertices(DataInput* input, VertexAttachment* attachment, int vertexCount);
         

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

@@ -61,7 +61,7 @@ namespace Spine {
     public:
         SlotData(int index, const String& name, BoneData& boneData);
         
-        const int getIndex();
+        int getIndex();
         
         const String& getName();
         

+ 4 - 0
spine-cpp/spine-cpp/include/spine/String.h

@@ -72,6 +72,10 @@ namespace Spine {
 			return _length;
 		}
 
+		bool isEmpty () const {
+			return _length == 0;
+		}
+
 		const char* buffer () const {
 			return _buffer;
 		}

+ 12 - 12
spine-cpp/spine-cpp/include/spine/Vector.h

@@ -80,7 +80,7 @@ namespace Spine {
             deallocate(_buffer);
         }
 
-        void clear () {
+        inline void clear () {
             for (size_t i = 0; i < _size; ++i) {
                 destroy(_buffer + (_size - 1 - i));
             }
@@ -88,11 +88,11 @@ namespace Spine {
             _size = 0;
         }
 
-        size_t size() const {
+        inline size_t size() const {
             return _size;
         }
 
-        void setSize(size_t newSize) {
+        inline void setSize(size_t newSize) {
             assert(newSize >= 0);
             _size = newSize;
             if (_capacity < newSize) {
@@ -102,13 +102,13 @@ namespace Spine {
             }
         }
 
-        void ensureCapacity(size_t newCapacity = 0) {
+        inline void ensureCapacity(size_t newCapacity = 0) {
             if (_capacity >= newCapacity) return;
             _capacity = newCapacity;
             _buffer = SpineExtension::realloc<T>(_buffer, newCapacity, __FILE__, __LINE__);
         }
 
-		void add(const T &inValue) {
+		inline void add(const T &inValue) {
 			if (_size == _capacity) {
                 _capacity = (int)(_size  * 1.75f);
                 if (_capacity < 8) _capacity = 8;
@@ -117,7 +117,7 @@ namespace Spine {
 			construct(_buffer + _size++, inValue);
 		}
 
-        void removeAt(size_t inIndex) {
+        inline void removeAt(size_t inIndex) {
             assert(inIndex < _size);
 
             --_size;
@@ -131,7 +131,7 @@ namespace Spine {
             destroy(_buffer + _size);
         }
 
-        bool contains(const T& inValue) {
+        inline bool contains(const T& inValue) {
             for (size_t i = 0; i < _size; ++i) {
                 if (_buffer[i] == inValue) {
                     return true;
@@ -141,7 +141,7 @@ namespace Spine {
             return false;
         }
 
-        int indexOf(const T& inValue) {
+        inline int indexOf(const T& inValue) {
             for (size_t i = 0; i < _size; ++i) {
                 if (_buffer[i] == inValue) {
                     return static_cast<int>(i);
@@ -151,13 +151,13 @@ namespace Spine {
             return -1;
         }
 
-        T& operator[](size_t inIndex) {
+        inline T& operator[](size_t inIndex) {
             assert(inIndex < _size);
 
             return _buffer[inIndex];
         }
 
-        friend bool operator==(Vector<T>& lhs, Vector<T>& rhs) {
+        inline friend bool operator==(Vector<T>& lhs, Vector<T>& rhs) {
             if (lhs.size() != rhs.size()) {
                 return false;
             }
@@ -171,11 +171,11 @@ namespace Spine {
             return true;
         }
 
-        friend bool operator!=(Vector<T>& lhs, Vector<T>& rhs) {
+        inline friend bool operator!=(Vector<T>& lhs, Vector<T>& rhs) {
             return !(lhs == rhs);
         }
 
-		T* buffer() {
+		inline T* buffer() {
 			return _buffer;
 		}
 

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

@@ -428,7 +428,7 @@ namespace Spine {
                     MixPose pose = timelineData[ii] >= AnimationState::First ? MixPose_Setup : currentPose;
                     
                     RotateTimeline* rotateTimeline = NULL;
-                    if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti)) {
+                    if (timeline->getRTTI().isExactly(RotateTimeline::rtti)) {
                         rotateTimeline = static_cast<RotateTimeline*>(timeline);
                     }
                     
@@ -784,10 +784,10 @@ namespace Spine {
             Timeline* timeline = timelines[i];
             switch (timelineData[i]) {
                 case Subsequent:
-                    if (!attachments && timeline->getRTTI().derivesFrom(AttachmentTimeline::rtti)) {
+                    if (!attachments && timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) {
                         continue;
                     }
-                    if (!drawOrder && timeline->getRTTI().derivesFrom(DrawOrderTimeline::rtti)) {
+                    if (!drawOrder && timeline->getRTTI().isExactly(DrawOrderTimeline::rtti)) {
                         continue;
                     }
                     
@@ -811,7 +811,7 @@ namespace Spine {
             from->_totalAlpha += alpha;
             
             RotateTimeline* rotateTimeline = NULL;
-            if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti)) {
+            if (timeline->getRTTI().isExactly(RotateTimeline::rtti)) {
                 rotateTimeline = static_cast<RotateTimeline*>(timeline);
             }
             

+ 1 - 1
spine-cpp/spine-cpp/src/spine/DeformTimeline.cpp

@@ -59,7 +59,7 @@ namespace Spine {
         Slot* slotP = skeleton._slots[_slotIndex];
         Slot& slot = *slotP;
         
-        if (slot._attachment == NULL || !slot._attachment->getRTTI().derivesFrom(VertexAttachment::rtti)) {
+        if (slot._attachment == NULL || !slot._attachment->getRTTI().instanceOf(VertexAttachment::rtti)) {
             return;
         }
         

+ 1 - 1
spine-cpp/spine-cpp/src/spine/PathConstraint.cpp

@@ -73,7 +73,7 @@ namespace Spine {
     
     void PathConstraint::update() {
         Attachment* baseAttachment = _target->getAttachment();
-        if (baseAttachment == NULL || !baseAttachment->getRTTI().derivesFrom(PathAttachment::rtti)) {
+        if (baseAttachment == NULL || !baseAttachment->getRTTI().instanceOf(PathAttachment::rtti)) {
             return;
         }
         

+ 5 - 5
spine-cpp/spine-cpp/src/spine/RTTI.cpp

@@ -45,18 +45,18 @@ namespace Spine {
     bool RTTI::isExactly(const RTTI& rtti) const {
         return (this == &rtti);
     }
-    
-    bool RTTI::derivesFrom(const RTTI& rtti) const {
+
+    bool RTTI::instanceOf(const RTTI &rtti) const {
         const RTTI * pCompare = this;
-        
+
         while (pCompare) {
             if (pCompare == &rtti) {
                 return true;
             }
-            
+
             pCompare = pCompare->_pBaseRTTI;
         }
-        
+
         return false;
     }
 }

+ 53 - 90
spine-cpp/spine-cpp/src/spine/Skeleton.cpp

@@ -142,57 +142,57 @@ namespace Spine {
         int pathCount = static_cast<int>(_pathConstraints.size());
         
         int constraintCount = ikCount + transformCount + pathCount;
-        
-        for (int i = 0; i < constraintCount; ++i) {
-            bool gotoNextConstraintCount = false;
-            
+
+        int i = 0;
+        continue_outer:
+        for (; i < constraintCount; ++i) {
             for (int ii = 0; ii < ikCount; ++ii) {
                 IkConstraint* constraint = _ikConstraints[ii];
                 if (constraint->getData().getOrder() == i) {
                     sortIkConstraint(constraint);
-                    
-                    gotoNextConstraintCount = true;
-                    break;
+                    i++;
+                    goto continue_outer;
                 }
             }
             
-            if (gotoNextConstraintCount) {
-                break;
-            }
-            
             for (int ii = 0; ii < transformCount; ++ii) {
                 TransformConstraint* constraint = _transformConstraints[ii];
                 if (constraint->getData().getOrder() == i) {
                     sortTransformConstraint(constraint);
-                    
-                    gotoNextConstraintCount = true;
-                    break;
+                    i++;
+                    goto continue_outer;
                 }
             }
             
-            if (gotoNextConstraintCount) {
-                break;
-            }
-            
             for (int ii = 0; ii < pathCount; ++ii) {
                 PathConstraint* constraint = _pathConstraints[ii];
                 if (constraint->getData().getOrder() == i) {
                     sortPathConstraint(constraint);
-                    
-                    gotoNextConstraintCount = true;
-                    break;
+                    i++;
+                    goto continue_outer;
                 }
             }
-            
-            if (gotoNextConstraintCount) {
-                break;
-            }
         }
         
         for (int i = 0, n = static_cast<int>(_bones.size()); i < n; ++i) {
             sortBone(_bones[i]);
         }
     }
+
+    void Skeleton::printUpdateCache () {
+        for (size_t i = 0; i < _updateCache.size(); i++) {
+            Updatable* updatable = _updateCache[i];
+            if (updatable->getRTTI().isExactly(Bone::rtti)) {
+                printf("bone %s\n", ((Bone*)updatable)->getData().getName().buffer());
+            } else if (updatable->getRTTI().isExactly(TransformConstraint::rtti)) {
+                printf("transform constraint %s\n", ((TransformConstraint*)updatable)->getData().getName().buffer());
+            } else if (updatable->getRTTI().isExactly(IkConstraint::rtti)) {
+                printf("ik constraint %s\n", ((IkConstraint*)updatable)->getData().getName().buffer());
+            } else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) {
+                printf("path constraint %s\n", ((PathConstraint*)updatable)->getData().getName().buffer());
+            }
+        }
+    }
     
     void Skeleton::updateWorldTransform() {
         for (int i = 0, n = static_cast<int>(_updateCacheReset.size()); i < n; ++i) {
@@ -407,7 +407,7 @@ namespace Spine {
             int verticesLength = 0;
             Attachment* attachment = slot->getAttachment();
             
-            if (attachment != NULL && attachment->getRTTI().derivesFrom(RegionAttachment::rtti)) {
+            if (attachment != NULL && attachment->getRTTI().instanceOf(RegionAttachment::rtti)) {
                 RegionAttachment* regionAttachment = static_cast<RegionAttachment*>(attachment);
 
                 verticesLength = 8;
@@ -416,7 +416,7 @@ namespace Spine {
                 }
                 regionAttachment->computeWorldVertices(slot->getBone(), outVertexBuffer, 0);
             }
-            else if (attachment != NULL && attachment->getRTTI().derivesFrom(MeshAttachment::rtti)) {
+            else if (attachment != NULL && attachment->getRTTI().instanceOf(MeshAttachment::rtti)) {
                 MeshAttachment* mesh = static_cast<MeshAttachment*>(attachment);
 
                 verticesLength = mesh->getWorldVerticesLength();
@@ -543,9 +543,7 @@ namespace Spine {
         
         if (constrained.size() > 1) {
             Bone* child = constrained[constrained.size() - 1];
-            if (!_updateCache.contains(child)) {
-				_updateCacheReset.add(child);
-            }
+            if (!_updateCache.contains(child)) _updateCacheReset.add(child);
         }
 
 		_updateCache.add(constraint);
@@ -556,72 +554,55 @@ namespace Spine {
     
     void Skeleton::sortPathConstraint(PathConstraint* constraint) {
         Slot* slot = constraint->getTarget();
-        int slotIndex = slot->_data.getIndex();
-        Bone& slotBone = slot->_bone;
-        
-        if (_skin != NULL) {
-            sortPathConstraintAttachment(_skin, slotIndex, slotBone);
-        }
-        
-        if (_data->_defaultSkin != NULL && _data->_defaultSkin != _skin) {
+        int slotIndex = slot->getData().getIndex();
+        Bone& slotBone = slot->getBone();
+        if (_skin != NULL) sortPathConstraintAttachment(_skin, slotIndex, slotBone);
+        if (_data->_defaultSkin != NULL && _data->_defaultSkin != _skin)
             sortPathConstraintAttachment(_data->_defaultSkin, slotIndex, slotBone);
-        }
-        
-        for (int ii = 0, nn = static_cast<int>(_data->_skins.size()); ii < nn; ++ii) {
+        for (size_t ii = 0, nn = _data->_skins.size(); ii < nn; ii++)
             sortPathConstraintAttachment(_data->_skins[ii], slotIndex, slotBone);
-        }
         
         Attachment* attachment = slot->_attachment;
-        if (attachment != NULL && attachment->getRTTI().derivesFrom(PathAttachment::rtti)) {
+        if (attachment != NULL && attachment->getRTTI().instanceOf(PathAttachment::rtti))
             sortPathConstraintAttachment(attachment, slotBone);
-        }
         
         Vector<Bone*>& constrained = constraint->getBones();
-        int boneCount = static_cast<int>(constrained.size());
-        for (int i = 0; i < boneCount; ++i) {
+        size_t boneCount = constrained.size();
+        for (size_t i = 0; i < boneCount; ++i) {
             sortBone(constrained[i]);
         }
 
 		_updateCache.add(constraint);
         
-        for (int i = 0; i < boneCount; ++i) {
+        for (int i = 0; i < boneCount; i++)
             sortReset(constrained[i]->getChildren());
-        }
-        
-        for (int i = 0; i < boneCount; ++i) {
+        for (int i = 0; i < boneCount; i++)
             constrained[i]->_sorted = true;
-        }
     }
     
     void Skeleton::sortTransformConstraint(TransformConstraint* constraint) {
         sortBone(constraint->getTarget());
         
         Vector<Bone*>& constrained = constraint->getBones();
-        int boneCount = static_cast<int>(constrained.size());
+        size_t boneCount = constrained.size();
         if (constraint->_data.isLocal()) {
-            for (int i = 0; i < boneCount; ++i) {
+            for (size_t i = 0; i < boneCount; i++) {
                 Bone* child = constrained[i];
                 sortBone(child->getParent());
-                if (!_updateCache.contains(child)) {
-					_updateCacheReset.add(child);
-                }
+                if (!_updateCache.contains(child)) _updateCacheReset.add(child);
             }
-        }
-        else {
-            for (int i = 0; i < boneCount; ++i) {
+        } else {
+            for (size_t i = 0; i < boneCount; ++i) {
                 sortBone(constrained[i]);
             }
         }
 
 		_updateCache.add(constraint);
         
-        for (int i = 0; i < boneCount; ++i) {
+        for (size_t i = 0; i < boneCount; ++i)
             sortReset(constrained[i]->getChildren());
-        }
-        
-        for (int i = 0; i < boneCount; ++i) {
+        for (size_t i = 0; i < boneCount; ++i)
             constrained[i]->_sorted = true;
-        }
     }
     
     void Skeleton::sortPathConstraintAttachment(Skin* skin, int slotIndex, Bone& slotBone) {
@@ -638,18 +619,12 @@ namespace Spine {
     }
     
     void Skeleton::sortPathConstraintAttachment(Attachment* attachment, Bone& slotBone) {
-        if (attachment == NULL || attachment->getRTTI().derivesFrom(PathAttachment::rtti)) {
-            return;
-        }
-        
-        PathAttachment* pathAttachment = static_cast<PathAttachment*>(attachment);
-        Vector<int>& pathBonesRef = pathAttachment->getBones();
-        Vector<int> pathBones = pathBonesRef;
-        if (pathBones.size() == 0) {
+        if (attachment == NULL || !attachment->getRTTI().instanceOf(PathAttachment::rtti)) return;
+        Vector<int>& pathBones = static_cast<PathAttachment*>(attachment)->getBones();
+        if (pathBones.size() == 0)
             sortBone(&slotBone);
-        }
         else {
-            for (int i = 0, n = static_cast<int>(pathBones.size()); i < n;) {
+            for (size_t i = 0, n = pathBones.size(); i < n;) {
                 int nn = pathBones[i++];
                 nn += i;
                 while (i < nn) {
@@ -660,29 +635,17 @@ namespace Spine {
     }
     
     void Skeleton::sortBone(Bone* bone) {
-        assert(bone != NULL);
-        
-        if (bone->_sorted) {
-            return;
-        }
-        
+        if (bone->_sorted) return;
         Bone* parent = bone->_parent;
-        if (parent != NULL) {
-            sortBone(parent);
-        }
-        
+        if (parent != NULL) sortBone(parent);
         bone->_sorted = true;
-
 		_updateCache.add(bone);
     }
     
     void Skeleton::sortReset(Vector<Bone*>& bones) {
-        for (size_t i = 0; i < bones.size(); ++i) {
+        for (size_t i = 0, n = bones.size(); i < n; ++i) {
             Bone* bone = bones[i];
-            if (bone->_sorted) {
-                sortReset(bone->getChildren());
-            }
-            
+            if (bone->_sorted) sortReset(bone->getChildren());
             bone->_sorted = false;
         }
     }

+ 54 - 101
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -492,7 +492,7 @@ namespace Spine {
         return value;
     }
     
-    Skin* SkeletonBinary::readSkin(DataInput* input, const char* skinName, SkeletonData* skeletonData, bool nonessential) {
+    Skin* SkeletonBinary::readSkin(DataInput* input, const String& skinName, SkeletonData* skeletonData, bool nonessential) {
         Skin* skin = NULL;
         int slotCount = readVarint(input, true);
         int i, ii, nn;
@@ -500,7 +500,7 @@ namespace Spine {
             return NULL;
         }
         
-        skin = new (__FILE__, __LINE__) Skin(String(skinName));
+        skin = new (__FILE__, __LINE__) Skin(skinName);
         
         for (i = 0; i < slotCount; ++i) {
             int slotIndex = readVarint(input, true);
@@ -517,27 +517,17 @@ namespace Spine {
         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));
-        
+    Attachment* SkeletonBinary::readAttachment(DataInput* input, Skin* skin, int slotIndex, const String& attachmentName, SkeletonData* skeletonData, bool nonessential) {
+        String name(readString(input), true);
+        if (name.isEmpty()) name = attachmentName;
+
+        AttachmentType 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, String(name), String(path));
-                region->_path = String(path);
+                String path(readString(input), true);
+                if (path.isEmpty()) path = name;
+                RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path));
+                region->_path = path;
                 region->_rotation = readFloat(input);
                 region->_x = readFloat(input) * _scale;
                 region->_y = readFloat(input) * _scale;
@@ -547,68 +537,50 @@ namespace Spine {
                 region->_height = readFloat(input) * _scale;
                 readColor(input, region->getColor());
                 region->updateOffset();
-                
-                if (freeName) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
                 return region;
             }
             case AttachmentType_Boundingbox: {
                 int vertexCount = readVarint(input, true);
-                BoundingBoxAttachment* box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
-                readVertices(input, static_cast<VertexAttachment*>(box), vertexCount);
+                BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
+                readVertices(input, static_cast<VertexAttachment *>(box), vertexCount);
                 if (nonessential) {
                     /* Skip color. */
                     readInt(input);
                 }
-                if (freeName) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
                 return box;
             }
             case AttachmentType_Mesh: {
                 int vertexCount;
-                MeshAttachment* mesh;
-                const char* path = readString(input);
-                if (!path) {
-                    path = name;
-                }
+                MeshAttachment *mesh;
+                String path(readString(input), true);
+                if (path.isEmpty()) path = name;
+
                 mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path));
                 mesh->_path = String(path);
                 readColor(input, mesh->getColor());
                 vertexCount = readVarint(input, true);
                 readFloatArray(input, vertexCount << 1, 1, mesh->getRegionUVs());
                 readShortArray(input, mesh->getTriangles());
-                readVertices(input, static_cast<VertexAttachment*>(mesh), vertexCount);
+                readVertices(input, static_cast<VertexAttachment *>(mesh), vertexCount);
                 mesh->updateUVs();
                 mesh->_hullLength = readVarint(input, true) << 1;
                 if (nonessential) {
                     readShortArray(input, mesh->getEdges());
                     mesh->_width = readFloat(input) * _scale;
                     mesh->_height = readFloat(input) * _scale;
-                }
-                else {
+                } else {
                     mesh->_width = 0;
                     mesh->_height = 0;
                 }
-                
-                if (freeName) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
                 return mesh;
             }
             case AttachmentType_Linkedmesh: {
-                const char* skinName;
-                const char* parent;
-                MeshAttachment* mesh;
-                const char* path = readString(input);
-                if (!path) {
-                    path = name;
-                }
-                
+                const char *skinName;
+                const char *parent;
+                MeshAttachment *mesh;
+                String path(readString(input), true);
+                if (path.isEmpty()) path = name;
+
                 mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path));
                 mesh->_path = path;
                 readColor(input, mesh->getColor());
@@ -619,110 +591,91 @@ namespace Spine {
                     mesh->_width = readFloat(input) * _scale;
                     mesh->_height = readFloat(input) * _scale;
                 }
-                
-                LinkedMesh* linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, String(skinName), slotIndex, String(parent));
-				_linkedMeshes.add(linkedMesh);
-                
-                if (freeName) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
+
+                LinkedMesh *linkedMesh = new(__FILE__, __LINE__) LinkedMesh(mesh, String(skinName), slotIndex,
+                                                                            String(parent));
+                _linkedMeshes.add(linkedMesh);
+
                 SpineExtension::free(skinName, __FILE__, __LINE__);
                 SpineExtension::free(parent, __FILE__, __LINE__);
-                
+
                 return mesh;
             }
             case AttachmentType_Path: {
-                PathAttachment* path = _attachmentLoader->newPathAttachment(*skin, String(name));
+                PathAttachment *path = _attachmentLoader->newPathAttachment(*skin, String(name));
                 int vertexCount = 0;
                 path->_closed = readBoolean(input);
                 path->_constantSpeed = readBoolean(input);
                 vertexCount = readVarint(input, true);
-                readVertices(input, static_cast<VertexAttachment*>(path), vertexCount);
+                readVertices(input, static_cast<VertexAttachment *>(path), vertexCount);
                 int lengthsLength = vertexCount / 3;
                 path->_lengths.setSize(lengthsLength);
-                for (i = 0; i < lengthsLength; ++i) {
+                for (int i = 0; i < lengthsLength; ++i) {
                     path->_lengths[i] = readFloat(input) * _scale;
                 }
-                
+
                 if (nonessential) {
                     /* Skip color. */
                     readInt(input);
                 }
-                
-                if (freeName) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
                 return path;
             }
             case AttachmentType_Point: {
-                PointAttachment* point = _attachmentLoader->newPointAttachment(*skin, String(name));
+                PointAttachment *point = _attachmentLoader->newPointAttachment(*skin, 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, true);
                 int vertexCount = readVarint(input, true);
-                ClippingAttachment* clip = _attachmentLoader->newClippingAttachment(*skin, name);
-                readVertices(input, static_cast<VertexAttachment*>(clip), vertexCount);
-                
+                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) {
-                    SpineExtension::free(name, __FILE__, __LINE__);
-                }
-                
                 return clip;
             }
         }
-        
-        if (freeName) {
-            SpineExtension::free(name, __FILE__, __LINE__);
-        }
-        
         return NULL;
     }
     
     void SkeletonBinary::readVertices(DataInput* input, VertexAttachment* attachment, int vertexCount) {
         float scale = _scale;
         int verticesLength = vertexCount << 1;
-        
+        attachment->setWorldVerticesLength(vertexCount << 1);
+
         if (!readBoolean(input)) {
             readFloatArray(input, verticesLength, scale, attachment->getVertices());
             return;
         }
-        
-        Vertices vertices;
-        vertices._bones.ensureCapacity(verticesLength * 3);
-        vertices._vertices.ensureCapacity(verticesLength * 3 * 3);
+
+        Vector<float>& vertices = attachment->getVertices();
+        Vector<int>& bones = attachment->getBones();
+        vertices.ensureCapacity(verticesLength * 3 * 3);
+        bones.ensureCapacity(verticesLength * 3);
         
         for (int i = 0; i < vertexCount; ++i) {
             int boneCount = readVarint(input, true);
-			vertices._bones.add(boneCount);
+			bones.add(boneCount);
             for (int ii = 0; ii < boneCount; ++ii) {
-				vertices._bones.add(readVarint(input, true));
-				vertices._vertices.add(readFloat(input) * scale);
-				vertices._vertices.add(readFloat(input) * scale);
-				vertices._vertices.add(readFloat(input));
+				bones.add(readVarint(input, true));
+				vertices.add(readFloat(input) * scale);
+				vertices.add(readFloat(input) * scale);
+				vertices.add(readFloat(input));
             }
         }
-        
-        attachment->setVertices(vertices._vertices);
-        attachment->setBones(vertices._bones);
     }
     
     void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector<float>& array) {

+ 1 - 1
spine-cpp/spine-cpp/src/spine/SkeletonBounds.cpp

@@ -54,7 +54,7 @@ namespace Spine {
         for (int i = 0; i < slotCount; i++) {
             Slot* slot = slots[i];
             Attachment* attachment = slot->_attachment;
-            if (attachment == NULL || !attachment->getRTTI().derivesFrom(BoundingBoxAttachment::rtti)) {
+            if (attachment == NULL || !attachment->getRTTI().instanceOf(BoundingBoxAttachment::rtti)) {
                 continue;
             }
             BoundingBoxAttachment* boundingBox = static_cast<BoundingBoxAttachment*>(attachment);

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

@@ -49,7 +49,6 @@ namespace Spine {
     
     std::size_t Skin::HashAttachmentKey::operator()(const Spine::Skin::AttachmentKey& val) const {
         std::size_t h1 = val._slotIndex;
-        
         return h1;
     }
     

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

@@ -46,7 +46,7 @@ namespace Spine {
         assert(_name.length() > 0);
     }
     
-    const int SlotData::getIndex() {
+    int SlotData::getIndex() {
         return _index;
     }
     

+ 1 - 0
spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java

@@ -208,6 +208,7 @@ public class SkeletonViewer extends ApplicationAdapter {
 		}
 
 		skeleton = new Skeleton(skeletonData);
+		skeleton.updateWorldTransform();
 		skeleton.setToSetupPose();
 		skeleton = new Skeleton(skeleton); // Tests copy constructors.
 		skeleton.updateWorldTransform();

+ 44 - 0
spine-sfml/c/CMakeLists.txt

@@ -1,5 +1,49 @@
 cmake_minimum_required(VERSION 2.8.9)
 
+#
+# First download and extract SFML 2.3.2 for the respective OS we are on
+#
+set(DEPS_DIR "${CMAKE_CURRENT_LIST_DIR}/dependencies/")
+if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+	set(SFML_URL "http://www.sfml-dev.org/files/SFML-2.4.1-osx-clang.tar.gz")
+	set(SFML_DIR ${DEPS_DIR}/SFML-2.4.1-osx-clang)
+	if (NOT EXISTS "${SFML_DIR}")
+		message("Downloading SFML for Mac OS X")
+		file(DOWNLOAD "${SFML_URL}" "${DEPS_DIR}/sfml.tar.gz")
+		execute_process(
+				COMMAND ${CMAKE_COMMAND} -E tar xzf  ${DEPS_DIR}/sfml.tar.gz
+				WORKING_DIRECTORY ${DEPS_DIR}
+		)
+		# copy freetype over to Frameworks/ so rpath resoultion works
+		execute_process(
+				COMMAND ${CMAKE_COMMAND} -E copy_directory ${SFML_DIR}/extlibs/freetype.framework ${SFML_DIR}/Frameworks/freetype.framework
+				WORKING_DIRECTORY ${SFML_DIR}
+		)
+	endif()
+elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+	set(SFML_URL "http://www.sfml-dev.org/files/SFML-2.4.1-linux-gcc-64-bit.tar.gz")
+	set(SFML_DIR ${DEPS_DIR}/SFML-2.4.1)
+	if (NOT EXISTS ${SFML_DIR})
+		message("Downloading SFML for Linux 64-bit")
+		file(DOWNLOAD "${SFML_URL}" "${DEPS_DIR}/sfml.tar.gz")
+		execute_process(
+				COMMAND ${CMAKE_COMMAND} -E tar xzf  ${DEPS_DIR}/sfml.tar.gz
+				WORKING_DIRECTORY ${DEPS_DIR}
+		)
+	endif()
+else()
+	set(SFML_URL "http://www.sfml-dev.org/files/SFML-2.4.1-windows-vc14-32-bit.zip")
+	set(SFML_DIR ${DEPS_DIR}/SFML-2.4.1)
+	if (NOT EXISTS ${SFML_DIR})
+		message("Downloading SFML for Windows 32-bit")
+		file(DOWNLOAD "${SFML_URL}" "${DEPS_DIR}/sfml.zip")
+		execute_process(
+				COMMAND ${CMAKE_COMMAND} -E tar x  ${DEPS_DIR}/sfml.zip
+				WORKING_DIRECTORY ${DEPS_DIR}
+		)
+	endif()
+endif()
+
 # Define spine-sfml library
 include_directories(src ${SFML_DIR}/include)
 file(GLOB INCLUDES "src/**/*.h")

+ 8 - 5
spine-sfml/cpp/example/main.cpp

@@ -30,8 +30,8 @@
 
 #include <iostream>
 #include <string.h>
-#define SPINE_SHORT_NAMES
 #include <spine/spine-sfml.h>
+#include <spine/Debug.h>
 #include <SFML/Graphics.hpp>
 #include <SFML/Window/Mouse.hpp>
 
@@ -94,7 +94,8 @@ SkeletonData* readSkeletonBinaryData (const char* filename, Atlas* atlas, float
 void testcase (void func(SkeletonData* skeletonData, Atlas* atlas),
 		const char* jsonName, const char* binaryName, const char* atlasName,
 		float scale) {
-	Atlas* atlas = new (__FILE__, __LINE__) Atlas(atlasName, 0);
+	SFMLTextureLoader textureLoader;
+	Atlas* atlas = new (__FILE__, __LINE__) Atlas(atlasName, &textureLoader);
 
 	SkeletonData* skeletonData = readSkeletonJsonData(jsonName, atlas, scale);
 	func(skeletonData, atlas);
@@ -440,15 +441,17 @@ void test (SkeletonData* skeletonData, Atlas* atlas) {
 }
 
 int main () {
+	DebugExtension dbgExtension;
+	SpineExtension::setInstance(&dbgExtension);
 	testcase(test, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 1.0f);
 	testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f);
-	/*testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl.atlas", 0.5f);
+	testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl.atlas", 0.5f);
 	testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin.atlas", 0.5f);
 	testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine.atlas", 0.5f);
 	testcase(tank, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 0.2f);
 	testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor.atlas", 0.5f);
-	testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f);
 	testcase(goblins, "data/goblins-pro.json", "data/goblins-pro.skel", "data/goblins.atlas", 1.4f);
-	testcase(stretchyman, "data/stretchyman-pro.json", "data/stretchyman-pro.skel", "data/stretchyman.atlas", 0.6f);*/
+	testcase(stretchyman, "data/stretchyman-pro.json", "data/stretchyman-pro.skel", "data/stretchyman.atlas", 0.6f);
+	dbgExtension.reportLeaks();
 	return 0;
 }

+ 19 - 3
spine-sfml/cpp/src/spine/spine-sfml.cpp

@@ -130,7 +130,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 		int indicesCount = 0;
 		Color* attachmentColor;
 
-		if (attachment->rtti.derivesFrom(RegionAttachment::rtti)) {
+		if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
 			RegionAttachment* regionAttachment = (RegionAttachment*)attachment;
 			regionAttachment->computeWorldVertices(slot.getBone(), worldVertices, 0, 2);
 			verticesCount = 4;
@@ -140,7 +140,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 			texture = (Texture*)((AtlasRegion*)regionAttachment->getRendererObject())->page->rendererObject;
 			attachmentColor = &regionAttachment->getColor();
 
-		} else if (attachment->rtti.derivesFrom(MeshAttachment::rtti)) {
+		} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
 			MeshAttachment* mesh = (MeshAttachment*)attachment;
 			if (mesh->getWorldVerticesLength() > worldVertices.size()) worldVertices.setSize(mesh->getWorldVerticesLength());
 			texture = (Texture*)((AtlasRegion*)mesh->getRendererObject())->page->rendererObject;
@@ -150,7 +150,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 			indices = &mesh->getTriangles();
 			indicesCount = mesh->getTriangles().size();
 			attachmentColor = &mesh->getColor();
-		} else if (attachment->rtti.derivesFrom(ClippingAttachment::rtti)) {
+		} else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) {
 			ClippingAttachment* clip = (ClippingAttachment*)slot.getAttachment();
 			clipper.clipStart(slot, clip);
 			continue;
@@ -280,4 +280,20 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 	// BOZO if (vertexEffect != 0) vertexEffect->end(vertexEffect);
 }
 
+void SFMLTextureLoader::load(AtlasPage &page, const String &path) {
+	Texture* texture = new Texture();
+	if (!texture->loadFromFile(path.buffer())) return;
+
+	if (page.magFilter == TextureFilter_Linear) texture->setSmooth(true);
+	if (page.uWrap == TextureWrap_Repeat && page.vWrap == TextureWrap_Repeat) texture->setRepeated(true);
+
+	page.rendererObject = texture;
+	Vector2u size = texture->getSize();
+	page.width = size.x;
+	page.height = size.y;
+}
+
+void SFMLTextureLoader::unload(void *texture) {
+	delete (Texture*)texture;
+}
 } /* namespace spine */

+ 7 - 0
spine-sfml/cpp/src/spine/spine-sfml.h

@@ -66,5 +66,12 @@ private:
 	mutable bool usePremultipliedAlpha;
 };
 
+class SFMLTextureLoader: public TextureLoader {
+public:
+	virtual void load(AtlasPage& page, const String& path);
+
+	virtual void unload(void* texture);
+};
+
 } /* namespace spine */
 #endif /* SPINE_SFML_H_ */