瀏覽代碼

Refactoring to make extension easier.

Much less weird OOP needed. Rendering is separate from data objects. cocos2d-iphone and cocos2d-x support for multi page atlases.
NathanSweet 12 年之前
父節點
當前提交
2bc3f511a1

+ 6 - 78
spine-c/example/main.c

@@ -7,86 +7,15 @@
 
 /**/
 
-typedef struct {
-	AtlasPage super;
-	int extraData;
-} ExampleAtlasPage;
-
-void _ExampleAtlasPage_dispose (AtlasPage* page) {
-	ExampleAtlasPage* self = SUB_CAST(ExampleAtlasPage, page);
-	_AtlasPage_deinit(SUPER(self));
-
-	self->extraData = 0;
-
-	FREE(self);
-}
-
-AtlasPage* AtlasPage_create (const char* name, const char* path) {
-	ExampleAtlasPage* self = NEW(ExampleAtlasPage);
-	_AtlasPage_init(SUPER(self), name, _ExampleAtlasPage_dispose);
-
-	self->extraData = 123;
-
-	return SUPER(self);
-}
-
-/**/
-
-typedef struct {
-	Skeleton super;
-	int extraData;
-} ExampleSkeleton;
-
-void _ExampleSkeleton_dispose (Skeleton* skeleton) {
-	ExampleSkeleton* self = SUB_CAST(ExampleSkeleton, skeleton);
-	_Skeleton_deinit(SUPER(self));
-
-	self->extraData = 0;
-
-	FREE(self);
+void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
+	self->texture = 0;
+	self->width = 123;
+	self->height = 456;
 }
 
-Skeleton* Skeleton_create (SkeletonData* data) {
-	ExampleSkeleton* self = NEW(ExampleSkeleton);
-	_Skeleton_init(SUPER(self), data, _ExampleSkeleton_dispose);
-
-	self->extraData = 789;
-
-	return SUPER(self);
+void _AtlasPage_disposeTexture (AtlasPage* self) {
 }
 
-/**/
-
-typedef struct {
-	RegionAttachment super;
-	int extraData;
-} ExampleRegionAttachment;
-
-void _ExampleRegionAttachment_dispose (Attachment* attachment) {
-	ExampleRegionAttachment* self = SUB_CAST(ExampleRegionAttachment, attachment);
-	_RegionAttachment_deinit(SUPER(self));
-
-	self->extraData = 0;
-
-	FREE(self);
-}
-
-void _ExampleRegionAttachment_draw (Attachment* attachment, Slot* slot) {
-	/*	ExampleRegionAttachment* self = (ExampleRegionAttachment*)attachment;
-	   Draw or queue region for drawing. */
-}
-
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
-	ExampleRegionAttachment* self = NEW(ExampleRegionAttachment);
-	_RegionAttachment_init(SUPER(self), name, _ExampleRegionAttachment_dispose, _ExampleRegionAttachment_draw);
-
-	self->extraData = 456;
-
-	return SUPER(self);
-}
-
-/**/
-
 char* _Util_readFile (const char* path, int* length) {
 	return _readFile(path, length);
 }
@@ -96,7 +25,7 @@ char* _Util_readFile (const char* path, int* length) {
 int main (void) {
 	Atlas* atlas = Atlas_readAtlasFile("data/spineboy.atlas");
 	printf("First region name: %s, x: %d, y: %d\n", atlas->regions->name, atlas->regions->x, atlas->regions->y);
-	printf("First page name: %s, extraData: %d\n", atlas->pages->name, ((ExampleAtlasPage*)atlas->pages)->extraData);
+	printf("First page name: %s, size: %d, %d\n", atlas->pages->name, atlas->pages->width, atlas->pages->height);
 
 	SkeletonJson* json = SkeletonJson_create(atlas);
 	SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/spineboy.json");
@@ -104,7 +33,6 @@ int main (void) {
 	printf("Default skin name: %s\n", skeletonData->defaultSkin->name);
 
 	Skeleton* skeleton = Skeleton_create(skeletonData);
-	printf("Skeleton extraData: %d\n", ((ExampleSkeleton*)skeleton)->extraData);
 
 	Animation* animation = SkeletonData_findAnimation(skeletonData, "walk");
 	if (!animation) printf("Error: %s\n", json->error);

+ 9 - 4
spine-c/include/spine/Atlas.h

@@ -55,12 +55,14 @@ struct AtlasPage {
 	AtlasFormat format;
 	AtlasFilter minFilter, magFilter;
 	AtlasWrap uWrap, vWrap;
-	AtlasPage* next;
 
-	const void* const vtable;
+	void* texture;
+	int width, height;
+
+	AtlasPage* next;
 };
 
-AtlasPage* AtlasPage_create (const char* name, const char* path);
+AtlasPage* AtlasPage_create (const char* name);
 void AtlasPage_dispose (AtlasPage* self);
 
 /**/
@@ -69,6 +71,7 @@ typedef struct AtlasRegion AtlasRegion;
 struct AtlasRegion {
 	const char* name;
 	int x, y, width, height;
+	float u, v, u2, v2;
 	float offsetX, offsetY;
 	int originalWidth, originalHeight;
 	int index;
@@ -76,7 +79,9 @@ struct AtlasRegion {
 	int/*bool*/flip;
 	int* splits;
 	int* pads;
+
 	AtlasPage* page;
+
 	AtlasRegion* next;
 };
 
@@ -90,7 +95,7 @@ typedef struct {
 	AtlasRegion* regions;
 } Atlas;
 
-/* Image files referenced in the atlas file will be prefixed dir. */
+/* Image files referenced in the atlas file will be prefixed with dir. */
 Atlas* Atlas_readAtlas (const char* data, int length, const char* dir);
 /* Image files referenced in the atlas file will be prefixed with the directory containing the atlas file. */
 Atlas* Atlas_readAtlasFile (const char* path);

+ 0 - 2
spine-c/include/spine/Attachment.h

@@ -47,8 +47,6 @@ struct Attachment {
 
 void Attachment_dispose (Attachment* self);
 
-void Attachment_draw (Attachment* self, struct Slot* slot);
-
 #ifdef __cplusplus
 }
 }

+ 10 - 1
spine-c/include/spine/RegionAttachment.h

@@ -28,22 +28,31 @@
 
 #include <spine/Attachment.h>
 #include <spine/Atlas.h>
+#include <spine/Slot.h>
 
 #ifdef __cplusplus
 namespace spine {
 extern "C" {
 #endif
 
+typedef enum {
+	VERTEX_X1 = 0, VERTEX_Y1, VERTEX_X2, VERTEX_Y2, VERTEX_X3, VERTEX_Y3, VERTEX_X4, VERTEX_Y4
+} VertexIndex;
+
 typedef struct RegionAttachment RegionAttachment;
 struct RegionAttachment {
 	Attachment super;
 	float x, y, scaleX, scaleY, rotation, width, height;
+	AtlasRegion* region;
 	float offset[8];
+	float vertices[8];
+	float uvs[8];
 };
 
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region);
+RegionAttachment* RegionAttachment_create (const char* name);
 
 void RegionAttachment_updateOffset (RegionAttachment* self);
+void RegionAttachment_updateVertices (RegionAttachment* self, Slot* slot);
 
 #ifdef __cplusplus
 }

+ 1 - 2
spine-c/include/spine/Skeleton.h

@@ -51,10 +51,9 @@ struct Skeleton {
 	float r, g, b, a;
 	float time;
 	int/*bool*/flipX, flipY;
-
-	const void* const vtable;
 };
 
+Skeleton* Skeleton_create (SkeletonData* data);
 void Skeleton_dispose (Skeleton* self);
 
 void Skeleton_updateWorldTransform (const Skeleton* self);

+ 14 - 35
spine-c/include/spine/extension.h

@@ -28,10 +28,11 @@
 
  - An OOP style is used where each "class" is made up of a struct and a number of functions prefixed with the struct name.
 
- - struct fields that are const are readonly. Either they are set in a constructor and can never be changed, or they can only be
- changed by calling a function.
+ - struct fields that are const are readonly. Either they are set in a create function and can never be changed, or they can only
+ be changed by calling a function.
 
  - Inheritance is done using a struct field named "super" as the first field, allowing the struct to be cast to its "super class".
+ This works because a pointer to a struct is guaranteed to be a pointer to the first struct field.
 
  - Classes intended for inheritance provide init/deinit functions which subclasses must call in their create/dispose functions.
 
@@ -73,10 +74,10 @@
 /* Gets the vtable for the specified type. Not type safe, use with care. */
 #define VTABLE(TYPE,VALUE) ((_##TYPE##Vtable*)((TYPE*)VALUE)->vtable)
 
-/* Frees memory. Can be used on const. */
+/* Frees memory. Can be used on const types. */
 #define FREE(VALUE) _free((void*)VALUE)
 
-/* Allocates a new char[], assigns it to TO, and copies FROM to it. Can be used on const. */
+/* Allocates a new char[], assigns it to TO, and copies FROM to it. Can be used on const types. */
 #define MALLOC_STR(TO,FROM) strcpy(CONST_CAST(char*, TO) = (char*)malloc(strlen(FROM) + 1), FROM)
 
 #include <stdlib.h>
@@ -96,10 +97,8 @@ extern "C" {
  * Functions that must be implemented:
  */
 
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region);
-
-AtlasPage* AtlasPage_create (const char* name, const char* path);
-
+void _AtlasPage_createTexture (AtlasPage* self, const char* path);
+void _AtlasPage_disposeTexture (AtlasPage* self);
 char* _Util_readFile (const char* path, int* length);
 
 /*
@@ -117,26 +116,21 @@ char* _readFile (const char* path, int* length);
 
 /**/
 
-void _Skeleton_init (Skeleton* self, SkeletonData* data, //
-		void (*dispose) (Skeleton* skeleton));
-void _Skeleton_deinit (Skeleton* self);
+void _AttachmentLoader_init (AttachmentLoader* self, //
+		void (*dispose) (AttachmentLoader* self), //
+		Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name));
+void _AttachmentLoader_deinit (AttachmentLoader* self);
+void _AttachmentLoader_setError (AttachmentLoader* self, const char* error1, const char* error2);
+void _AttachmentLoader_setUnknownTypeError (AttachmentLoader* self, AttachmentType type);
 
 /**/
 
 void _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
-		void (*dispose) (Attachment* self), //
-		void (*draw) (Attachment* self, struct Slot* slot));
+		void (*dispose) (Attachment* self));
 void _Attachment_deinit (Attachment* self);
 
 /**/
 
-void _RegionAttachment_init (RegionAttachment* self, const char* name, //
-		void (*dispose) (Attachment* self), //
-		void (*draw) (Attachment* self, struct Slot* slot));
-void _RegionAttachment_deinit (RegionAttachment* self);
-
-/**/
-
 void _Timeline_init (Timeline* self, //
 		void (*dispose) (Timeline* self), //
 		void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
@@ -149,21 +143,6 @@ void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
 		void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
 void _CurveTimeline_deinit (CurveTimeline* self);
 
-/**/
-
-void _AtlasPage_init (AtlasPage* self, const char* name, //
-		void (*dispose) (AtlasPage* self));
-void _AtlasPage_deinit (AtlasPage* self);
-
-/**/
-
-void _AttachmentLoader_init (AttachmentLoader* self, //
-		void (*dispose) (AttachmentLoader* self), //
-		Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name));
-void _AttachmentLoader_deinit (AttachmentLoader* self);
-void _AttachmentLoader_setError (AttachmentLoader* self, const char* error1, const char* error2);
-void _AttachmentLoader_setUnknownTypeError (AttachmentLoader* self, AttachmentType type);
-
 #ifdef __cplusplus
 }
 }

+ 5 - 5
spine-c/src/spine/Animation.c

@@ -70,8 +70,8 @@ typedef struct _TimelineVtable {
 	void (*dispose) (Timeline* self);
 } _TimelineVtable;
 
-void _Timeline_init (Timeline* self, /**/
-		void (*dispose) (Timeline* self), /**/
+void _Timeline_init (Timeline* self, //
+		void (*dispose) (Timeline* self), //
 		void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
 	CONST_CAST(_TimelineVtable*, self->vtable) = NEW(_TimelineVtable);
 	VTABLE(Timeline, self) ->dispose = dispose;
@@ -96,8 +96,8 @@ static const float CURVE_LINEAR = 0;
 static const float CURVE_STEPPED = -1;
 static const int CURVE_SEGMENTS = 10;
 
-void _CurveTimeline_init (CurveTimeline* self, int frameCount, /**/
-		void (*dispose) (Timeline* self), /**/
+void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
+		void (*dispose) (Timeline* self), //
 		void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
 	_Timeline_init(SUPER(self), dispose, apply);
 	self->curves = CALLOC(float, (frameCount - 1) * 6);
@@ -203,7 +203,7 @@ void _BaseTimeline_dispose (Timeline* timeline) {
 }
 
 /* Many timelines have structure identical to struct BaseTimeline and extend CurveTimeline. **/
-struct BaseTimeline* _BaseTimeline_create (int frameCount, int frameSize, /**/
+struct BaseTimeline* _BaseTimeline_create (int frameCount, int frameSize, //
 		void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
 
 	struct BaseTimeline* self = NEW(struct BaseTimeline);

+ 15 - 14
spine-c/src/spine/Atlas.c

@@ -35,20 +35,15 @@ typedef struct _AtlasPageVtable {
 	void (*dispose) (AtlasPage* self);
 } _AtlasPageVtable;
 
-void _AtlasPage_init (AtlasPage* self, const char* name, /**/
-		void (*dispose) (AtlasPage* self)) {
-	CONST_CAST(_AtlasPageVtable*, self->vtable) = NEW(_AtlasPageVtable);
-	VTABLE(AtlasPage, self) ->dispose = dispose;
+AtlasPage* AtlasPage_create (const char* name) {
+	AtlasPage* self = NEW(AtlasPage);
 	MALLOC_STR(self->name, name);
-}
-
-void _AtlasPage_deinit (AtlasPage* self) {
-	FREE(self->vtable);
-	FREE(self->name);
+	return self;
 }
 
 void AtlasPage_dispose (AtlasPage* self) {
-	VTABLE(AtlasPage, self) ->dispose(self);
+	FREE(self->name);
+	_AtlasPage_disposeTexture(self);
 }
 
 /**/
@@ -200,16 +195,14 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
 			if (needsSlash) path[dirLength] = '/';
 			strcpy(path + dirLength + needsSlash, name);
 
-			page = AtlasPage_create(name, path);
+			page = AtlasPage_create(name);
+			FREE(name);
 			if (lastPage)
 				lastPage->next = page;
 			else
 				self->pages = page;
 			lastPage = page;
 
-			FREE(name);
-			FREE(path);
-
 			if (!readValue(end, &str)) return abortAtlas(self);
 			page->format = (AtlasFormat)indexOf(formatNames, 7, &str);
 
@@ -222,6 +215,9 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
 				page->uWrap = *str.begin == 'x' ? ATLAS_REPEAT : (*str.begin == 'y' ? ATLAS_CLAMPTOEDGE : ATLAS_REPEAT);
 				page->vWrap = *str.begin == 'x' ? ATLAS_CLAMPTOEDGE : (*str.begin == 'y' ? ATLAS_REPEAT : ATLAS_REPEAT);
 			}
+
+			_AtlasPage_createTexture(page, path);
+			FREE(path);
 		} else {
 			AtlasRegion *region = AtlasRegion_create();
 			if (lastRegion)
@@ -244,6 +240,11 @@ Atlas* Atlas_readAtlas (const char* begin, int length, const char* dir) {
 			region->width = toInt(tuple);
 			region->height = toInt(tuple + 1);
 
+			region->u = region->x / (float)page->width;
+			region->v = region->y / (float)page->height;
+			region->u2 = (region->x + region->width) / (float)page->width;
+			region->v2 = (region->y + region->height) / (float)page->height;
+
 			int count;
 			if (!(count = readTuple(end, tuple))) return abortAtlas(self);
 			if (count == 4) { /* split is optional */

+ 3 - 1
spine-c/src/spine/AtlasAttachmentLoader.c

@@ -39,7 +39,9 @@ Attachment* _AtlasAttachmentLoader_newAttachment (AttachmentLoader* loader, Skin
 			_AttachmentLoader_setError(loader, "Region not found: ", name);
 			return 0;
 		}
-		return SUPER_CAST(Attachment, RegionAttachment_create(name, region)) ;
+		RegionAttachment* attachment = RegionAttachment_create(name);
+		attachment->region = region;
+		return SUPER(attachment);
 	}
 	default:
 		_AttachmentLoader_setUnknownTypeError(loader, type);

+ 2 - 9
spine-c/src/spine/Attachment.c

@@ -32,17 +32,14 @@ namespace spine {
 #endif
 
 typedef struct _AttachmentVtable {
-	void (*draw) (Attachment* self, struct Slot* slot);
 	void (*dispose) (Attachment* self);
 } _AttachmentVtable;
 
-void _Attachment_init (Attachment* self, const char* name, AttachmentType type, /**/
-		void (*dispose) (Attachment* self), /**/
-		void (*draw) (Attachment* self, struct Slot* slot)) {
+void _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
+		void (*dispose) (Attachment* self)) {
 
 	CONST_CAST(_AttachmentVtable*, self->vtable) = NEW(_AttachmentVtable);
 	VTABLE(Attachment, self) ->dispose = dispose;
-	VTABLE(Attachment, self) ->draw = draw;
 
 	MALLOC_STR(self->name, name);
 	self->type = type;
@@ -57,10 +54,6 @@ void Attachment_dispose (Attachment* self) {
 	VTABLE(Attachment, self) ->dispose(self);
 }
 
-void Attachment_draw (Attachment* self, Slot* slot) {
-	VTABLE(Attachment, self) ->draw(self, slot);
-}
-
 #ifdef __cplusplus
 }
 #endif

+ 2 - 2
spine-c/src/spine/AttachmentLoader.c

@@ -36,8 +36,8 @@ typedef struct _AttachmentLoaderVtable {
 	void (*dispose) (AttachmentLoader* self);
 } _AttachmentLoaderVtable;
 
-void _AttachmentLoader_init (AttachmentLoader* self, /**/
-		void (*dispose) (AttachmentLoader* self), /**/
+void _AttachmentLoader_init (AttachmentLoader* self, //
+		void (*dispose) (AttachmentLoader* self), //
 		Attachment* (*newAttachment) (AttachmentLoader* self, Skin* skin, AttachmentType type, const char* name)) {
 	CONST_CAST(_AttachmentLoaderVtable*, self->vtable) = NEW(_AttachmentLoaderVtable);
 	VTABLE(AttachmentLoader, self) ->dispose = dispose;

+ 25 - 16
spine-c/src/spine/RegionAttachment.c

@@ -31,16 +31,12 @@
 namespace spine {
 #endif
 
-void _RegionAttachment_init (RegionAttachment* self, const char* name, /**/
-		void (*dispose) (Attachment* self), /**/
-		void (*draw) (Attachment* self, struct Slot* slot)) {
+RegionAttachment* RegionAttachment_create (const char* name) {
+	RegionAttachment* self = NEW(RegionAttachment);
 	self->scaleX = 1;
 	self->scaleY = 1;
-	_Attachment_init(SUPER(self), name, ATTACHMENT_REGION, dispose, draw);
-}
-
-void _RegionAttachment_deinit (RegionAttachment* self) {
-	_Attachment_deinit(SUPER(self));
+	_Attachment_init(SUPER(self), name, ATTACHMENT_REGION, _Attachment_deinit);
+	return self;
 }
 
 void RegionAttachment_updateOffset (RegionAttachment* self) {
@@ -63,14 +59,27 @@ void RegionAttachment_updateOffset (RegionAttachment* self) {
 	float localX2Sin = localX2 * sine;
 	float localY2Cos = localY2 * cosine + self->y;
 	float localY2Sin = localY2 * sine;
-	self->offset[0] = localXCos - localYSin;
-	self->offset[1] = localYCos + localXSin;
-	self->offset[2] = localXCos - localY2Sin;
-	self->offset[3] = localY2Cos + localXSin;
-	self->offset[4] = localX2Cos - localY2Sin;
-	self->offset[5] = localY2Cos + localX2Sin;
-	self->offset[6] = localX2Cos - localYSin;
-	self->offset[7] = localYCos + localX2Sin;
+	self->offset[VERTEX_X1] = localXCos - localYSin;
+	self->offset[VERTEX_Y1] = localYCos + localXSin;
+	self->offset[VERTEX_X2] = localXCos - localY2Sin;
+	self->offset[VERTEX_Y2] = localY2Cos + localXSin;
+	self->offset[VERTEX_X3] = localX2Cos - localY2Sin;
+	self->offset[VERTEX_Y3] = localY2Cos + localX2Sin;
+	self->offset[VERTEX_X4] = localX2Cos - localYSin;
+	self->offset[VERTEX_Y4] = localYCos + localX2Sin;
+}
+
+void RegionAttachment_updateVertices (RegionAttachment* self, Slot* slot) {
+	float* offset = self->offset;
+	Bone* bone = slot->bone;
+	self->vertices[VERTEX_X1] = offset[VERTEX_X1] * bone->m00 + offset[VERTEX_Y1] * bone->m01 + bone->worldX;
+	self->vertices[VERTEX_Y1] = offset[VERTEX_X1] * bone->m10 + offset[VERTEX_Y1] * bone->m11 + bone->worldY;
+	self->vertices[VERTEX_X2] = offset[VERTEX_X2] * bone->m00 + offset[VERTEX_Y2] * bone->m01 + bone->worldX;
+	self->vertices[VERTEX_Y2] = offset[VERTEX_X2] * bone->m10 + offset[VERTEX_Y2] * bone->m11 + bone->worldY;
+	self->vertices[VERTEX_X3] = offset[VERTEX_X3] * bone->m00 + offset[VERTEX_Y3] * bone->m01 + bone->worldX;
+	self->vertices[VERTEX_Y3] = offset[VERTEX_X3] * bone->m10 + offset[VERTEX_Y3] * bone->m11 + bone->worldY;
+	self->vertices[VERTEX_X4] = offset[VERTEX_X4] * bone->m00 + offset[VERTEX_Y4] * bone->m01 + bone->worldX;
+	self->vertices[VERTEX_Y4] = offset[VERTEX_X4] * bone->m10 + offset[VERTEX_Y4] * bone->m11 + bone->worldY;
 }
 
 #ifdef __cplusplus

+ 5 - 15
spine-c/src/spine/Skeleton.c

@@ -31,16 +31,10 @@
 namespace spine {
 #endif
 
-typedef struct _SkeletonVtable {
-	void (*dispose) (Skeleton* skeleton);
-} _SkeletonVtable;
-
-void _Skeleton_init (Skeleton* self, SkeletonData* data, void (*dispose) (Skeleton* skeleton)) {
+Skeleton* Skeleton_create (SkeletonData* data) {
+	Skeleton* self = NEW(Skeleton);
 	CONST_CAST(SkeletonData*, self->data) = data;
 
-	CONST_CAST(_SkeletonVtable*, self->vtable) = NEW(_SkeletonVtable);
-	VTABLE(Skeleton, self) ->dispose = dispose;
-
 	self->boneCount = self->data->boneCount;
 	self->bones = MALLOC(Bone*, self->boneCount);
 	int i, ii;
@@ -84,11 +78,11 @@ void _Skeleton_init (Skeleton* self, SkeletonData* data, void (*dispose) (Skelet
 	self->g = 1;
 	self->b = 1;
 	self->a = 1;
-}
 
-void _Skeleton_deinit (Skeleton* self) {
-	FREE(self->vtable);
+	return self;
+}
 
+void Skeleton_dispose (Skeleton* self) {
 	int i;
 	for (i = 0; i < self->boneCount; ++i)
 		Bone_dispose(self->bones[i]);
@@ -101,10 +95,6 @@ void _Skeleton_deinit (Skeleton* self) {
 	FREE(self->drawOrder);
 }
 
-void Skeleton_dispose (Skeleton* self) {
-	VTABLE(Skeleton, self) ->dispose(self);
-}
-
 void Skeleton_updateWorldTransform (const Skeleton* self) {
 	int i;
 	for (i = 0; i < self->boneCount; ++i)

+ 15 - 19
spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.h

@@ -29,22 +29,6 @@
 #include <spine/spine.h>
 #include "cocos2d.h"
 
-#ifdef __cplusplus
-namespace spine {
-extern "C" {
-#endif
-
-ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* self, Slot* slot);
-ccV3F_C4B_T2F_Quad* RegionAttachment_getQuad (RegionAttachment* self);
-
-#ifdef __cplusplus
-}
-}
-using namespace spine;
-#endif
-
-/**/
-
 @interface CCSkeleton : CCNodeRGBA<CCBlendProtocol> {
 @private
 	bool ownsSkeleton;
@@ -58,9 +42,6 @@ using namespace spine;
 	bool debugSlots;
 	bool debugBones;
 
-	CCTextureAtlas* textureAtlas; // All region attachments for a skeleton must use the same texture.
-	unsigned int quadCount;
-
     ccBlendFunc blendFunc;
 }
 
@@ -109,4 +90,19 @@ using namespace spine;
 
 @end
 
+/**/
+
+#ifdef __cplusplus
+namespace spine {
+extern "C" {
+#endif
+
+void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad);
+
+#ifdef __cplusplus
+}
+}
+using namespace spine;
+#endif
+
 #endif /* SPINE_COCOS2D_H_ */

+ 104 - 169
spine-cocos2d-iphone/src/spine/spine-cocos2d-iphone.m

@@ -30,77 +30,33 @@
 namespace spine {
 #endif
 
-typedef struct {
-	AtlasPage super;
-	CCTexture2D* texture;
-	CCTextureAtlas* textureAtlas;
-} Cocos2dAtlasPage;
-
-void _Cocos2dAtlasPage_dispose (AtlasPage* page) {
-	Cocos2dAtlasPage* self = SUB_CAST(Cocos2dAtlasPage, page);
-	_AtlasPage_deinit(SUPER(self));
-
-	[self->texture release];
-	[self->textureAtlas release];
-
-	FREE(page);
+void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
+	CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:@(path)];
+	CCTextureAtlas* textureAtlas = [[CCTextureAtlas alloc] initWithTexture:texture capacity:4];
+	[textureAtlas retain];
+	self->texture = textureAtlas;
+	CGSize size = texture.contentSizeInPixels;
+	self->width = size.width;
+	self->height = size.height;
 }
 
-AtlasPage* AtlasPage_create (const char* name, const char* path) {
-	Cocos2dAtlasPage* self = NEW(Cocos2dAtlasPage);
-	_AtlasPage_init(SUPER(self), name, _Cocos2dAtlasPage_dispose);
-
-	self->texture = [[CCTextureCache sharedTextureCache] addImage:@(path)];
-	[self->texture retain];
-	self->textureAtlas = [[CCTextureAtlas alloc] initWithTexture:self->texture capacity:4];
-	[self->textureAtlas retain];
-
-	return SUPER(self);
+void _AtlasPage_disposeTexture (AtlasPage* self) {
+	[(CCTextureAtlas*)self->texture release];
 }
 
-/**/
-
-typedef struct {
-	Skeleton super;
-	CCSkeleton* node;
-} Cocos2dSkeleton;
-
-void _Cocos2dSkeleton_dispose (Skeleton* self) {
-	_Skeleton_deinit(self);
-	FREE(self);
-}
-
-Skeleton* _Cocos2dSkeleton_create (SkeletonData* data, CCSkeleton* node) {
-	Cocos2dSkeleton* self = NEW(Cocos2dSkeleton);
-	_Skeleton_init(SUPER(self), data, _Cocos2dSkeleton_dispose);
-
-	self->node = node;
-
-	return SUPER(self);
+char* _Util_readFile (const char* path, int* length) {
+	return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length);
 }
 
 /**/
 
-typedef struct {
-	RegionAttachment super;
-	ccV3F_C4B_T2F_Quad quad;
-	CCTextureAtlas* textureAtlas;
-} Cocos2dRegionAttachment;
-
-void _Cocos2dRegionAttachment_dispose (Attachment* self) {
-	_RegionAttachment_deinit(SUB_CAST(RegionAttachment, self) );
-	FREE(self);
-}
+void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad) {
+	RegionAttachment_updateVertices(self, slot);
 
-ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* attachment, Slot* slot) {
-	Cocos2dRegionAttachment* self = SUB_CAST(Cocos2dRegionAttachment, attachment);
-	Cocos2dSkeleton* skeleton = SUB_CAST(Cocos2dSkeleton, slot->skeleton);
-
-	GLubyte r = SUPER(skeleton)->r * slot->r * 255;
-	GLubyte g = SUPER(skeleton)->g * slot->g * 255;
-	GLubyte b = SUPER(skeleton)->b * slot->b * 255;
-	GLubyte a = SUPER(skeleton)->a * slot->a * 255;
-	ccV3F_C4B_T2F_Quad* quad = &self->quad;
+	GLubyte r = slot->skeleton->r * slot->r * 255;
+	GLubyte g = slot->skeleton->g * slot->g * 255;
+	GLubyte b = slot->skeleton->b * slot->b * 255;
+	GLubyte a = slot->skeleton->a * slot->a * 255;
 	quad->bl.colors.r = r;
 	quad->bl.colors.g = g;
 	quad->bl.colors.b = b;
@@ -118,82 +74,35 @@ ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* attachment, Slot* s
 	quad->br.colors.b = b;
 	quad->br.colors.a = a;
 
-	float* offset = SUPER(self)->offset;
-	quad->bl.vertices.x = offset[0] * slot->bone->m00 + offset[1] * slot->bone->m01 + slot->bone->worldX;
-	quad->bl.vertices.y = offset[0] * slot->bone->m10 + offset[1] * slot->bone->m11 + slot->bone->worldY;
-	quad->tl.vertices.x = offset[2] * slot->bone->m00 + offset[3] * slot->bone->m01 + slot->bone->worldX;
-	quad->tl.vertices.y = offset[2] * slot->bone->m10 + offset[3] * slot->bone->m11 + slot->bone->worldY;
-	quad->tr.vertices.x = offset[4] * slot->bone->m00 + offset[5] * slot->bone->m01 + slot->bone->worldX;
-	quad->tr.vertices.y = offset[4] * slot->bone->m10 + offset[5] * slot->bone->m11 + slot->bone->worldY;
-	quad->br.vertices.x = offset[6] * slot->bone->m00 + offset[7] * slot->bone->m01 + slot->bone->worldX;
-	quad->br.vertices.y = offset[6] * slot->bone->m10 + offset[7] * slot->bone->m11 + slot->bone->worldY;
-
-	return quad;
-}
-
-void _Cocos2dRegionAttachment_draw (Attachment* attachment, Slot* slot) {
-	RegionAttachment_updateQuad(attachment, slot);
-
-	Cocos2dRegionAttachment* self = SUB_CAST(Cocos2dRegionAttachment, attachment);
-	Cocos2dSkeleton* skeleton = SUB_CAST(Cocos2dSkeleton, slot->skeleton);
-
-	// Cocos2d doesn't handle batching for us, so we'll just force a single texture per skeleton.
-	skeleton->node->textureAtlas = self->textureAtlas;
-	while (self->textureAtlas.capacity <= skeleton->node->quadCount) {
-		if (![self->textureAtlas resizeCapacity:self->textureAtlas.capacity * 2]) return;
-	}
-	[self->textureAtlas updateQuad:&self->quad atIndex:skeleton->node->quadCount++];
-}
-
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
-	Cocos2dRegionAttachment* self = NEW(Cocos2dRegionAttachment);
-	_RegionAttachment_init(SUPER(self), name, _Cocos2dRegionAttachment_dispose, _Cocos2dRegionAttachment_draw);
-
-	Cocos2dAtlasPage* page = SUB_CAST(Cocos2dAtlasPage, region->page);
-	self->textureAtlas = page->textureAtlas;
-	CGSize size = page->texture.contentSizeInPixels;
-	float u = region->x / size.width;
-	float u2 = (region->x + region->width) / size.width;
-	float v = region->y / size.height;
-	float v2 = (region->y + region->height) / size.height;
-	ccV3F_C4B_T2F_Quad* quad = &self->quad;
-	if (region->rotate) {
-		quad->tl.texCoords.u = u;
-		quad->tl.texCoords.v = v2;
-		quad->tr.texCoords.u = u;
-		quad->tr.texCoords.v = v;
-		quad->br.texCoords.u = u2;
-		quad->br.texCoords.v = v;
-		quad->bl.texCoords.u = u2;
-		quad->bl.texCoords.v = v2;
+	float* offset = self->offset;
+	quad->bl.vertices.x = offset[VERTEX_X1] * slot->bone->m00 + offset[VERTEX_Y1] * slot->bone->m01 + slot->bone->worldX;
+	quad->bl.vertices.y = offset[VERTEX_X1] * slot->bone->m10 + offset[VERTEX_Y1] * slot->bone->m11 + slot->bone->worldY;
+	quad->tl.vertices.x = offset[VERTEX_X2] * slot->bone->m00 + offset[VERTEX_Y2] * slot->bone->m01 + slot->bone->worldX;
+	quad->tl.vertices.y = offset[VERTEX_X2] * slot->bone->m10 + offset[VERTEX_Y2] * slot->bone->m11 + slot->bone->worldY;
+	quad->tr.vertices.x = offset[VERTEX_X3] * slot->bone->m00 + offset[VERTEX_Y3] * slot->bone->m01 + slot->bone->worldX;
+	quad->tr.vertices.y = offset[VERTEX_X3] * slot->bone->m10 + offset[VERTEX_Y3] * slot->bone->m11 + slot->bone->worldY;
+	quad->br.vertices.x = offset[VERTEX_X4] * slot->bone->m00 + offset[VERTEX_Y4] * slot->bone->m01 + slot->bone->worldX;
+	quad->br.vertices.y = offset[VERTEX_X4] * slot->bone->m10 + offset[VERTEX_Y4] * slot->bone->m11 + slot->bone->worldY;
+
+	if (self->region->rotate) {
+		quad->tl.texCoords.u = self->region->u;
+		quad->tl.texCoords.v = self->region->v2;
+		quad->tr.texCoords.u = self->region->u;
+		quad->tr.texCoords.v = self->region->v;
+		quad->br.texCoords.u = self->region->u2;
+		quad->br.texCoords.v = self->region->v;
+		quad->bl.texCoords.u = self->region->u2;
+		quad->bl.texCoords.v = self->region->v2;
 	} else {
-		quad->bl.texCoords.u = u;
-		quad->bl.texCoords.v = v2;
-		quad->tl.texCoords.u = u;
-		quad->tl.texCoords.v = v;
-		quad->tr.texCoords.u = u2;
-		quad->tr.texCoords.v = v;
-		quad->br.texCoords.u = u2;
-		quad->br.texCoords.v = v2;
+		quad->bl.texCoords.u = self->region->u;
+		quad->bl.texCoords.v = self->region->v2;
+		quad->tl.texCoords.u = self->region->u;
+		quad->tl.texCoords.v = self->region->v;
+		quad->tr.texCoords.u = self->region->u2;
+		quad->tr.texCoords.v = self->region->v;
+		quad->br.texCoords.u = self->region->u2;
+		quad->br.texCoords.v = self->region->v2;
 	}
-
-	quad->bl.vertices.z = 0;
-	quad->tl.vertices.z = 0;
-	quad->tr.vertices.z = 0;
-	quad->br.vertices.z = 0;
-
-	return SUPER(self);
-}
-
-ccV3F_C4B_T2F_Quad* RegionAttachment_getQuad (RegionAttachment* attachment) {
-	Cocos2dRegionAttachment* self = SUB_CAST(Cocos2dRegionAttachment, attachment);
-	return &self->quad;
-}
-
-/**/
-
-char* _Util_readFile (const char* path, int* length) {
-	return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length);
 }
 
 #ifdef __cplusplus
@@ -211,11 +120,13 @@ char* _Util_readFile (const char* path, int* length) {
 + (CCSkeleton*) create:(NSString*)skeletonDataFile atlas:(Atlas*)atlas scale:(float)scale {
 	NSAssert(skeletonDataFile, @"skeletonDataFile cannot be nil.");
 	NSAssert(atlas, @"atlas cannot be nil.");
+
 	SkeletonJson* json = SkeletonJson_create(atlas);
 	json->scale = scale;
 	SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]);
 	NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error]));
 	SkeletonJson_dispose(json);
+
 	CCSkeleton* node = skeletonData ? [CCSkeleton create:skeletonData] : 0;
 	node->ownsSkeleton = true;
 	return node;
@@ -228,9 +139,11 @@ char* _Util_readFile (const char* path, int* length) {
 + (CCSkeleton*) create:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale {
 	NSAssert(skeletonDataFile, @"skeletonDataFile cannot be nil.");
 	NSAssert(atlasFile, @"atlasFile cannot be nil.");
+
 	Atlas* atlas = Atlas_readAtlasFile([atlasFile UTF8String]);
 	NSAssert(atlas, ([NSString stringWithFormat:@"Error reading atlas file: %@", atlasFile]));
 	if (!atlas) return 0;
+
 	SkeletonJson* json = SkeletonJson_create(atlas);
 	json->scale = scale;
 	SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]);
@@ -240,6 +153,7 @@ char* _Util_readFile (const char* path, int* length) {
 		Atlas_dispose(atlas);
 		return 0;
 	}
+
 	CCSkeleton* node = [CCSkeleton create:skeletonData];
 	node->ownsSkeleton = true;
 	node->atlas = atlas;
@@ -264,7 +178,7 @@ char* _Util_readFile (const char* path, int* length) {
 	self = [super init];
 	if (!self) return nil;
 
-	CONST_CAST(Skeleton*, skeleton) = _Cocos2dSkeleton_create(skeletonData, self);
+	CONST_CAST(Skeleton*, skeleton) = Skeleton_create(skeletonData);
 
 	if (!stateData) {
 		stateData = AnimationStateData_create(skeletonData);
@@ -308,23 +222,43 @@ char* _Util_readFile (const char* path, int* length) {
 	skeleton->b = color.b / (float)255;
 	skeleton->a = self.opacity / (float)255;
 
-	quadCount = 0;
-	for (int i = 0, n = skeleton->slotCount; i < n; ++i)
-		if (skeleton->slots[i]->attachment) Attachment_draw(skeleton->slots[i]->attachment, skeleton->slots[i]);
-	if (textureAtlas) [textureAtlas drawNumberOfQuads:quadCount];
+	CCTextureAtlas* textureAtlas = 0;
+	int quadCount = 0;
+	for (int i = 0, n = skeleton->slotCount; i < n; i++) {
+		Slot* slot = skeleton->slots[i];
+		if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+		RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+		CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->region->page->texture;
+		if (regionTextureAtlas != textureAtlas) {
+			if (textureAtlas) {
+				[textureAtlas drawNumberOfQuads:quadCount];
+				quadCount = 0;
+			}
+		}
+		textureAtlas = regionTextureAtlas;
+		if (textureAtlas.capacity == quadCount && ![textureAtlas resizeCapacity:quadCount * 2]) return;
+		RegionAttachment_updateQuad(attachment, slot, &textureAtlas.quads[quadCount++]);
+	}
+	if (textureAtlas) {
+		[textureAtlas drawNumberOfQuads:quadCount];
+		quadCount = 0;
+	}
 
 	if (debugSlots) {
 		// Slots.
 		ccDrawColor4B(0, 0, 255, 255);
 		glLineWidth(1);
 		CGPoint points[4];
-		for (int i = 0, n = skeleton->slotCount; i < n; ++i) {
-			if (!skeleton->slots[i]->attachment) continue;
-			ccV3F_C4B_T2F_Quad* quad = &((Cocos2dRegionAttachment*)skeleton->slots[i]->attachment)->quad;
-			points[0] = ccp(quad->bl.vertices.x, quad->bl.vertices.y);
-			points[1] = ccp(quad->br.vertices.x, quad->br.vertices.y);
-			points[2] = ccp(quad->tr.vertices.x, quad->tr.vertices.y);
-			points[3] = ccp(quad->tl.vertices.x, quad->tl.vertices.y);
+		ccV3F_C4B_T2F_Quad quad;
+		for (int i = 0, n = skeleton->slotCount; i < n; i++) {
+			Slot* slot = skeleton->slots[i];
+			if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+			RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+			RegionAttachment_updateQuad(attachment, slot, &quad);
+			points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y);
+			points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y);
+			points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y);
+			points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y);
 			ccDrawPoly(points, 4, true);
 		}
 	}
@@ -332,7 +266,7 @@ char* _Util_readFile (const char* path, int* length) {
 		// Bone lengths.
 		glLineWidth(2);
 		ccDrawColor4B(255, 0, 0, 255);
-		for (int i = 0, n = skeleton->boneCount; i < n; ++i) {
+		for (int i = 0, n = skeleton->boneCount; i < n; i++) {
 			Bone *bone = skeleton->bones[i];
 			float x = bone->data->length * bone->m00 + bone->worldX;
 			float y = bone->data->length * bone->m10 + bone->worldY;
@@ -341,7 +275,7 @@ char* _Util_readFile (const char* path, int* length) {
 		// Bone origins.
 		ccPointSize(4);
 		ccDrawColor4B(0, 0, 255, 255); // Root bone is blue.
-		for (int i = 0, n = skeleton->boneCount; i < n; ++i) {
+		for (int i = 0, n = skeleton->boneCount; i < n; i++) {
 			Bone *bone = skeleton->bones[i];
 			ccDrawPoint(ccp(bone->worldX, bone->worldY));
 			if (i == 0) ccDrawColor4B(0, 255, 0, 255);
@@ -353,27 +287,28 @@ char* _Util_readFile (const char* path, int* length) {
 	float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
 	float scaleX = self.scaleX;
 	float scaleY = self.scaleY;
+	ccV3F_C4B_T2F_Quad quad;
 	for (int i = 0; i < skeleton->slotCount; ++i) {
 		Slot* slot = skeleton->slots[i];
-		Attachment* attachment = slot->attachment;
-		if (!attachment || attachment->type != ATTACHMENT_REGION) continue;
-		Cocos2dRegionAttachment* regionAttachment = SUB_CAST(Cocos2dRegionAttachment, attachment);
-		minX = fmin(minX, regionAttachment->quad.bl.vertices.x * scaleX);
-		minY = fmin(minY, regionAttachment->quad.bl.vertices.y * scaleY);
-		maxX = fmax(maxX, regionAttachment->quad.bl.vertices.x * scaleX);
-		maxY = fmax(maxY, regionAttachment->quad.bl.vertices.y * scaleY);
-		minX = fmin(minX, regionAttachment->quad.br.vertices.x * scaleX);
-		minY = fmin(minY, regionAttachment->quad.br.vertices.y * scaleY);
-		maxX = fmax(maxX, regionAttachment->quad.br.vertices.x * scaleX);
-		maxY = fmax(maxY, regionAttachment->quad.br.vertices.y * scaleY);
-		minX = fmin(minX, regionAttachment->quad.tl.vertices.x * scaleX);
-		minY = fmin(minY, regionAttachment->quad.tl.vertices.y * scaleY);
-		maxX = fmax(maxX, regionAttachment->quad.tl.vertices.x * scaleX);
-		maxY = fmax(maxY, regionAttachment->quad.tl.vertices.y * scaleY);
-		minX = fmin(minX, regionAttachment->quad.tr.vertices.x * scaleX);
-		minY = fmin(minY, regionAttachment->quad.tr.vertices.y * scaleY);
-		maxX = fmax(maxX, regionAttachment->quad.tr.vertices.x * scaleX);
-		maxY = fmax(maxY, regionAttachment->quad.tr.vertices.y * scaleY);
+		if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+		RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+		RegionAttachment_updateQuad(attachment, slot, &quad);
+		minX = fmin(minX, quad.bl.vertices.x * scaleX);
+		minY = fmin(minY, quad.bl.vertices.y * scaleY);
+		maxX = fmax(maxX, quad.bl.vertices.x * scaleX);
+		maxY = fmax(maxY, quad.bl.vertices.y * scaleY);
+		minX = fmin(minX, quad.br.vertices.x * scaleX);
+		minY = fmin(minY, quad.br.vertices.y * scaleY);
+		maxX = fmax(maxX, quad.br.vertices.x * scaleX);
+		maxY = fmax(maxY, quad.br.vertices.y * scaleY);
+		minX = fmin(minX, quad.tl.vertices.x * scaleX);
+		minY = fmin(minY, quad.tl.vertices.y * scaleY);
+		maxX = fmax(maxX, quad.tl.vertices.x * scaleX);
+		maxY = fmax(maxY, quad.tl.vertices.y * scaleY);
+		minX = fmin(minX, quad.tr.vertices.x * scaleX);
+		minY = fmin(minY, quad.tr.vertices.y * scaleY);
+		maxX = fmax(maxX, quad.tr.vertices.x * scaleX);
+		maxY = fmax(maxY, quad.tr.vertices.y * scaleY);
 	}
 	minX = self.position.x + minX;
 	minY = self.position.y + minY;

+ 120 - 167
spine-cocos2dx/src/spine/spine-cocos2dx.cpp

@@ -31,44 +31,86 @@ using std::min;
 using std::max;
 namespace spine {
 
-void _Cocos2dxAtlasPage_dispose (AtlasPage* page) {
-	Cocos2dxAtlasPage* self = SUB_CAST(Cocos2dxAtlasPage, page);
-	_AtlasPage_deinit(SUPER(self));
-
-	CC_SAFE_RELEASE_NULL(self->texture);
-	CC_SAFE_RELEASE_NULL(self->textureAtlas);
-
-	FREE(page);
+void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
+	CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(path);
+	CCTextureAtlas* textureAtlas = CCTextureAtlas::createWithTexture(texture, 4);
+	textureAtlas->retain();
+	self->texture = textureAtlas;
+	self->width = texture->getPixelsWide();
+	self->height = texture->getPixelsHigh();
 }
 
-AtlasPage* AtlasPage_create (const char* name, const char* path) {
-	Cocos2dxAtlasPage* self = NEW(Cocos2dxAtlasPage);
-	_AtlasPage_init(SUPER(self), name, _Cocos2dxAtlasPage_dispose);
-
-	self->texture = CCTextureCache::sharedTextureCache()->addImage(path);
-	self->texture->retain();
-	self->textureAtlas = CCTextureAtlas::createWithTexture(self->texture, 4);
-	self->textureAtlas->retain();
+void _AtlasPage_disposeTexture (AtlasPage* self) {
+	((CCTextureAtlas*)self->texture)->release();
+}
 
-	return SUPER(self);
+char* _Util_readFile (const char* path, int* length) {
+	unsigned long size;
+    char* data = reinterpret_cast<char*>(CCFileUtils::sharedFileUtils()->getFileData(
+		CCFileUtils::sharedFileUtils()->fullPathForFilename(path).c_str(), "r", &size));
+	*length = size;
+	return data;
 }
 
 /**/
 
-void _Cocos2dxSkeleton_dispose (Skeleton* self) {
-	_Skeleton_deinit(self);
-	FREE(self);
-}
+void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad) {
+	RegionAttachment_updateVertices(self, slot);
 
-Skeleton* _Cocos2dxSkeleton_create (SkeletonData* data, CCSkeleton* node) {
-	Cocos2dxSkeleton* self = NEW(Cocos2dxSkeleton);
-	_Skeleton_init(SUPER(self), data, _Cocos2dxSkeleton_dispose);
-
-	self->node = node;
+	GLubyte r = slot->skeleton->r * slot->r * 255;
+	GLubyte g = slot->skeleton->g * slot->g * 255;
+	GLubyte b = slot->skeleton->b * slot->b * 255;
+	GLubyte a = slot->skeleton->a * slot->a * 255;
+	quad->bl.colors.r = r;
+	quad->bl.colors.g = g;
+	quad->bl.colors.b = b;
+	quad->bl.colors.a = a;
+	quad->tl.colors.r = r;
+	quad->tl.colors.g = g;
+	quad->tl.colors.b = b;
+	quad->tl.colors.a = a;
+	quad->tr.colors.r = r;
+	quad->tr.colors.g = g;
+	quad->tr.colors.b = b;
+	quad->tr.colors.a = a;
+	quad->br.colors.r = r;
+	quad->br.colors.g = g;
+	quad->br.colors.b = b;
+	quad->br.colors.a = a;
 
-	return SUPER(self);
+	float* offset = self->offset;
+	quad->bl.vertices.x = offset[VERTEX_X1] * slot->bone->m00 + offset[VERTEX_Y1] * slot->bone->m01 + slot->bone->worldX;
+	quad->bl.vertices.y = offset[VERTEX_X1] * slot->bone->m10 + offset[VERTEX_Y1] * slot->bone->m11 + slot->bone->worldY;
+	quad->tl.vertices.x = offset[VERTEX_X2] * slot->bone->m00 + offset[VERTEX_Y2] * slot->bone->m01 + slot->bone->worldX;
+	quad->tl.vertices.y = offset[VERTEX_X2] * slot->bone->m10 + offset[VERTEX_Y2] * slot->bone->m11 + slot->bone->worldY;
+	quad->tr.vertices.x = offset[VERTEX_X3] * slot->bone->m00 + offset[VERTEX_Y3] * slot->bone->m01 + slot->bone->worldX;
+	quad->tr.vertices.y = offset[VERTEX_X3] * slot->bone->m10 + offset[VERTEX_Y3] * slot->bone->m11 + slot->bone->worldY;
+	quad->br.vertices.x = offset[VERTEX_X4] * slot->bone->m00 + offset[VERTEX_Y4] * slot->bone->m01 + slot->bone->worldX;
+	quad->br.vertices.y = offset[VERTEX_X4] * slot->bone->m10 + offset[VERTEX_Y4] * slot->bone->m11 + slot->bone->worldY;
+
+	if (self->region->rotate) {
+		quad->tl.texCoords.u = self->region->u;
+		quad->tl.texCoords.v = self->region->v2;
+		quad->tr.texCoords.u = self->region->u;
+		quad->tr.texCoords.v = self->region->v;
+		quad->br.texCoords.u = self->region->u2;
+		quad->br.texCoords.v = self->region->v;
+		quad->bl.texCoords.u = self->region->u2;
+		quad->bl.texCoords.v = self->region->v2;
+	} else {
+		quad->bl.texCoords.u = self->region->u;
+		quad->bl.texCoords.v = self->region->v2;
+		quad->tl.texCoords.u = self->region->u;
+		quad->tl.texCoords.v = self->region->v;
+		quad->tr.texCoords.u = self->region->u2;
+		quad->tr.texCoords.v = self->region->v;
+		quad->br.texCoords.u = self->region->u2;
+		quad->br.texCoords.v = self->region->v2;
+	}
 }
 
+/**/
+
 CCSkeleton* CCSkeleton::create (const char* skeletonDataFile, Atlas* atlas, float scale) {
 	SkeletonJson* json = SkeletonJson_create(atlas);
 	json->scale = scale;
@@ -105,7 +147,7 @@ CCSkeleton* CCSkeleton::create (SkeletonData* skeletonData, AnimationStateData*
 CCSkeleton::CCSkeleton (SkeletonData *skeletonData, AnimationStateData *stateData) :
 				ownsSkeleton(false), ownsStateData(false), atlas(0),
 				skeleton(0), state(0), debugSlots(false), debugBones(false) {
-	CONST_CAST(Skeleton*, skeleton) = _Cocos2dxSkeleton_create(skeletonData, this);
+	CONST_CAST(Skeleton*, skeleton) = Skeleton_create(skeletonData);
 
 	if (!stateData) {
 		stateData = AnimationStateData_create(skeletonData);
@@ -146,23 +188,43 @@ void CCSkeleton::draw () {
 	skeleton->b = color.b / (float)255;
 	skeleton->a = getOpacity() / (float)255;
 
-	quadCount = 0;
-	for (int i = 0, n = skeleton->slotCount; i < n; i++)
-		if (skeleton->slots[i]->attachment) Attachment_draw(skeleton->slots[i]->attachment, skeleton->slots[i]);
-	if (textureAtlas) textureAtlas->drawNumberOfQuads(quadCount);
+	CCTextureAtlas* textureAtlas = 0;
+	int quadCount = 0;
+	for (int i = 0, n = skeleton->slotCount; i < n; i++) {
+		Slot* slot = skeleton->slots[i];
+		if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+		RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+		CCTextureAtlas* regionTextureAtlas = (CCTextureAtlas*)attachment->region->page->texture;
+		if (regionTextureAtlas != textureAtlas) {
+			if (textureAtlas) {
+				textureAtlas->drawNumberOfQuads(quadCount);
+				quadCount = 0;
+			}
+		}
+		textureAtlas = regionTextureAtlas;
+		if (textureAtlas->getCapacity() == quadCount && !textureAtlas->resizeCapacity(quadCount * 2)) return;
+		RegionAttachment_updateQuad(attachment, slot, &textureAtlas->getQuads()[quadCount++]);
+	}
+	if (textureAtlas) {
+		textureAtlas->drawNumberOfQuads(quadCount);
+		quadCount = 0;
+	}
 
 	if (debugSlots) {
 		// Slots.
 		ccDrawColor4B(0, 0, 255, 255);
 		glLineWidth(1);
 		CCPoint points[4];
+		ccV3F_C4B_T2F_Quad quad;
 		for (int i = 0, n = skeleton->slotCount; i < n; i++) {
-			if (!skeleton->slots[i]->attachment) continue;
-			ccV3F_C4B_T2F_Quad* quad = &((Cocos2dxRegionAttachment*)skeleton->slots[i]->attachment)->quad;
-			points[0] = ccp(quad->bl.vertices.x, quad->bl.vertices.y);
-			points[1] = ccp(quad->br.vertices.x, quad->br.vertices.y);
-			points[2] = ccp(quad->tr.vertices.x, quad->tr.vertices.y);
-			points[3] = ccp(quad->tl.vertices.x, quad->tl.vertices.y);
+			Slot* slot = skeleton->slots[i];
+			if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+			RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+			RegionAttachment_updateQuad(attachment, slot, &quad);
+			points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y);
+			points[1] = ccp(quad.br.vertices.x, quad.br.vertices.y);
+			points[2] = ccp(quad.tr.vertices.x, quad.tr.vertices.y);
+			points[3] = ccp(quad.tl.vertices.x, quad.tl.vertices.y);
 			ccDrawPoly(points, 4, true);
 		}
 	}
@@ -191,27 +253,28 @@ CCRect CCSkeleton::boundingBox () {
 	float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
 	float scaleX = getScaleX();
 	float scaleY = getScaleY();
+	ccV3F_C4B_T2F_Quad quad;
 	for (int i = 0; i < skeleton->slotCount; ++i) {
 		Slot* slot = skeleton->slots[i];
-		Attachment* attachment = slot->attachment;
-		if (!attachment || attachment->type != ATTACHMENT_REGION) continue;
-		Cocos2dxRegionAttachment* regionAttachment = SUB_CAST(Cocos2dxRegionAttachment, attachment);
-		minX = min(minX, regionAttachment->quad.bl.vertices.x * scaleX);
-		minY = min(minY, regionAttachment->quad.bl.vertices.y * scaleY);
-		maxX = max(maxX, regionAttachment->quad.bl.vertices.x * scaleX);
-		maxY = max(maxY, regionAttachment->quad.bl.vertices.y * scaleY);
-		minX = min(minX, regionAttachment->quad.br.vertices.x * scaleX);
-		minY = min(minY, regionAttachment->quad.br.vertices.y * scaleY);
-		maxX = max(maxX, regionAttachment->quad.br.vertices.x * scaleX);
-		maxY = max(maxY, regionAttachment->quad.br.vertices.y * scaleY);
-		minX = min(minX, regionAttachment->quad.tl.vertices.x * scaleX);
-		minY = min(minY, regionAttachment->quad.tl.vertices.y * scaleY);
-		maxX = max(maxX, regionAttachment->quad.tl.vertices.x * scaleX);
-		maxY = max(maxY, regionAttachment->quad.tl.vertices.y * scaleY);
-		minX = min(minX, regionAttachment->quad.tr.vertices.x * scaleX);
-		minY = min(minY, regionAttachment->quad.tr.vertices.y * scaleY);
-		maxX = max(maxX, regionAttachment->quad.tr.vertices.x * scaleX);
-		maxY = max(maxY, regionAttachment->quad.tr.vertices.y * scaleY);
+		if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
+		RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
+		RegionAttachment_updateQuad(attachment, slot, &quad);
+		minX = min(minX, quad.bl.vertices.x * scaleX);
+		minY = min(minY, quad.bl.vertices.y * scaleY);
+		maxX = max(maxX, quad.bl.vertices.x * scaleX);
+		maxY = max(maxY, quad.bl.vertices.y * scaleY);
+		minX = min(minX, quad.br.vertices.x * scaleX);
+		minY = min(minY, quad.br.vertices.y * scaleY);
+		maxX = max(maxX, quad.br.vertices.x * scaleX);
+		maxY = max(maxY, quad.br.vertices.y * scaleY);
+		minX = min(minX, quad.tl.vertices.x * scaleX);
+		minY = min(minY, quad.tl.vertices.y * scaleY);
+		maxX = max(maxX, quad.tl.vertices.x * scaleX);
+		maxY = max(maxY, quad.tl.vertices.y * scaleY);
+		minX = min(minX, quad.tr.vertices.x * scaleX);
+		minY = min(minY, quad.tr.vertices.y * scaleY);
+		maxX = max(maxX, quad.tr.vertices.x * scaleX);
+		maxY = max(maxY, quad.tr.vertices.y * scaleY);
 	}
 	CCPoint position = getPosition();
 	minX = position.x + minX;
@@ -283,114 +346,4 @@ void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) {
     this->blendFunc = blendFunc;
 }
 
-/**/
-
-void _Cocos2dxRegionAttachment_dispose (Attachment* self) {
-	_RegionAttachment_deinit(SUB_CAST(RegionAttachment, self) );
-	FREE(self);
-}
-
-ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* attachment, Slot* slot) {
-	Cocos2dxRegionAttachment* self = SUB_CAST(Cocos2dxRegionAttachment, attachment);
-	Cocos2dxSkeleton* skeleton = SUB_CAST(Cocos2dxSkeleton, slot->skeleton);
-
-	GLubyte r = SUPER(skeleton)->r * slot->r * 255;
-	GLubyte g = SUPER(skeleton)->g * slot->g * 255;
-	GLubyte b = SUPER(skeleton)->b * slot->b * 255;
-	GLubyte a = SUPER(skeleton)->a * slot->a * 255;
-	ccV3F_C4B_T2F_Quad* quad = &self->quad;
-	quad->bl.colors.r = r;
-	quad->bl.colors.g = g;
-	quad->bl.colors.b = b;
-	quad->bl.colors.a = a;
-	quad->tl.colors.r = r;
-	quad->tl.colors.g = g;
-	quad->tl.colors.b = b;
-	quad->tl.colors.a = a;
-	quad->tr.colors.r = r;
-	quad->tr.colors.g = g;
-	quad->tr.colors.b = b;
-	quad->tr.colors.a = a;
-	quad->br.colors.r = r;
-	quad->br.colors.g = g;
-	quad->br.colors.b = b;
-	quad->br.colors.a = a;
-
-	float* offset = SUPER(self)->offset;
-	quad->bl.vertices.x = offset[0] * slot->bone->m00 + offset[1] * slot->bone->m01 + slot->bone->worldX;
-	quad->bl.vertices.y = offset[0] * slot->bone->m10 + offset[1] * slot->bone->m11 + slot->bone->worldY;
-	quad->tl.vertices.x = offset[2] * slot->bone->m00 + offset[3] * slot->bone->m01 + slot->bone->worldX;
-	quad->tl.vertices.y = offset[2] * slot->bone->m10 + offset[3] * slot->bone->m11 + slot->bone->worldY;
-	quad->tr.vertices.x = offset[4] * slot->bone->m00 + offset[5] * slot->bone->m01 + slot->bone->worldX;
-	quad->tr.vertices.y = offset[4] * slot->bone->m10 + offset[5] * slot->bone->m11 + slot->bone->worldY;
-	quad->br.vertices.x = offset[6] * slot->bone->m00 + offset[7] * slot->bone->m01 + slot->bone->worldX;
-	quad->br.vertices.y = offset[6] * slot->bone->m10 + offset[7] * slot->bone->m11 + slot->bone->worldY;
-
-	return quad;
-}
-
-void _Cocos2dxRegionAttachment_draw (Attachment* attachment, Slot* slot) {
-	RegionAttachment_updateQuad(attachment, slot);
-
-	Cocos2dxRegionAttachment* self = SUB_CAST(Cocos2dxRegionAttachment, attachment);
-	Cocos2dxSkeleton* skeleton = SUB_CAST(Cocos2dxSkeleton, slot->skeleton);
-
-	// cocos2dx doesn't handle batching for us, so we force a single texture per skeleton.
-	skeleton->node->textureAtlas = self->textureAtlas;
-	while (self->textureAtlas->getCapacity() <= skeleton->node->quadCount) {
-		if (!self->textureAtlas->resizeCapacity(self->textureAtlas->getCapacity() * 2)) return;
-	}
-	self->textureAtlas->updateQuad(&self->quad, skeleton->node->quadCount++);
-}
-
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
-	Cocos2dxRegionAttachment* self = NEW(Cocos2dxRegionAttachment);
-	_RegionAttachment_init(SUPER(self), name, _Cocos2dxRegionAttachment_dispose, _Cocos2dxRegionAttachment_draw);
-
-	Cocos2dxAtlasPage* page = SUB_CAST(Cocos2dxAtlasPage, region->page);
-	self->textureAtlas = page->textureAtlas;
-	const CCSize& size = page->texture->getContentSizeInPixels();
-	float u = region->x / size.width;
-	float u2 = (region->x + region->width) / size.width;
-	float v = region->y / size.height;
-	float v2 = (region->y + region->height) / size.height;
-	ccV3F_C4B_T2F_Quad* quad = &self->quad;
-	if (region->rotate) {
-		quad->tl.texCoords.u = u;
-		quad->tl.texCoords.v = v2;
-		quad->tr.texCoords.u = u;
-		quad->tr.texCoords.v = v;
-		quad->br.texCoords.u = u2;
-		quad->br.texCoords.v = v;
-		quad->bl.texCoords.u = u2;
-		quad->bl.texCoords.v = v2;
-	} else {
-		quad->bl.texCoords.u = u;
-		quad->bl.texCoords.v = v2;
-		quad->tl.texCoords.u = u;
-		quad->tl.texCoords.v = v;
-		quad->tr.texCoords.u = u2;
-		quad->tr.texCoords.v = v;
-		quad->br.texCoords.u = u2;
-		quad->br.texCoords.v = v2;
-	}
-
-	quad->bl.vertices.z = 0;
-	quad->tl.vertices.z = 0;
-	quad->tr.vertices.z = 0;
-	quad->br.vertices.z = 0;
-
-	return SUPER(self);
-}
-
-/**/
-
-char* _Util_readFile (const char* path, int* length) {
-	unsigned long size;
-    char* data = reinterpret_cast<char*>(CCFileUtils::sharedFileUtils()->getFileData(
-		CCFileUtils::sharedFileUtils()->fullPathForFilename(path).c_str(), "r", &size));
-	*length = size;
-	return data;
-}
-
 }

+ 1 - 25
spine-cocos2dx/src/spine/spine-cocos2dx.h

@@ -31,21 +31,6 @@
 
 namespace spine {
 
-typedef struct {
-	AtlasPage super;
-	cocos2d::CCTexture2D* texture;
-	cocos2d::CCTextureAtlas* textureAtlas;
-} Cocos2dxAtlasPage;
-
-/**/
-
-class CCSkeleton;
-
-typedef struct {
-	Skeleton super;
-	CCSkeleton* node;
-} Cocos2dxSkeleton;
-
 class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol {
 private:
 	bool ownsSkeleton;
@@ -59,9 +44,6 @@ public:
 	bool debugSlots;
 	bool debugBones;
 
-	cocos2d::CCTextureAtlas* textureAtlas; // All region attachments for a skeleton must use the same texture.
-	unsigned int quadCount;
-
 	static CCSkeleton* create (const char* skeletonDataFile, Atlas* atlas, float scale = 1);
 	static CCSkeleton* create (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
 	static CCSkeleton* create (SkeletonData* skeletonData, AnimationStateData* stateData = 0);
@@ -110,13 +92,7 @@ public:
 
 /**/
 
-typedef struct {
-	RegionAttachment super;
-	cocos2d::ccV3F_C4B_T2F_Quad quad;
-	cocos2d::CCTextureAtlas* textureAtlas;
-} Cocos2dxRegionAttachment;
-
-cocos2d::ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* self, Slot* slot);
+void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, cocos2d::ccV3F_C4B_T2F_Quad* quad);
 
 }
 

+ 87 - 132
spine-sfml/src/spine/spine-sfml.cpp

@@ -31,58 +31,35 @@
 #include <SFML/Graphics/RenderTarget.hpp>
 #include <SFML/Graphics/RenderStates.hpp>
 
-using sf::Quads;
-using sf::RenderTarget;
-using sf::RenderStates;
-using sf::Texture;
-using sf::Uint8;
-using sf::Vertex;
-using sf::VertexArray;
+using namespace sf;
 
 namespace spine {
 
-void _SfmlAtlasPage_dispose (AtlasPage* page) {
-	SfmlAtlasPage* self = SUB_CAST(SfmlAtlasPage, page);
-	_AtlasPage_deinit(SUPER(self));
-
-	delete self->texture;
-
-	FREE(page);
+void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
+	Texture* texture = new Texture();
+	if (!texture->loadFromFile(path)) return;
+	self->texture = texture;
+	Vector2u size = texture->getSize();
+	self->width = size.x;
+	self->height = size.x;
 }
 
-AtlasPage* AtlasPage_create (const char* name, const char* path) {
-	SfmlAtlasPage* self = NEW(SfmlAtlasPage);
-	_AtlasPage_init(SUPER(self), name, _SfmlAtlasPage_dispose);
-
-	self->texture = new Texture();
-	self->texture->loadFromFile(path);
-
-	return SUPER(self);
+void _AtlasPage_disposeTexture (AtlasPage* self) {
+	delete (Texture*)self->texture;
 }
 
-/**/
-
-void _SfmlSkeleton_dispose (Skeleton* self) {
-	_Skeleton_deinit(self);
-	FREE(self);
+char* _Util_readFile (const char* path, int* length) {
+	return _readFile(path, length);
 }
 
-Skeleton* _SfmlSkeleton_create (SkeletonData* data, SkeletonDrawable* drawable) {
-	Bone_setYDown(1);
-
-	SfmlSkeleton* self = NEW(SfmlSkeleton);
-	_Skeleton_init(SUPER(self), data, _SfmlSkeleton_dispose);
-
-	CONST_CAST(SkeletonDrawable*, self->drawable) = drawable;
-
-	return SUPER(self);
-}
+/**/
 
 SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) :
 				timeScale(1),
-				vertexArray(new VertexArray(Quads, skeletonData->boneCount * 4)),
-				texture(0) {
-	skeleton = _SfmlSkeleton_create(skeletonData, this);
+				vertexArray(new VertexArray(Quads, skeletonData->boneCount * 4)) {
+	Bone_setYDown(true);
+
+	skeleton = Skeleton_create(skeletonData);
 	state = AnimationState_create(stateData);
 }
 
@@ -101,99 +78,77 @@ void SkeletonDrawable::update (float deltaTime) {
 
 void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 	vertexArray->clear();
-	for (int i = 0; i < skeleton->slotCount; ++i)
-		if (skeleton->slots[i]->attachment) Attachment_draw(skeleton->slots[i]->attachment, skeleton->slots[i]);
-	states.texture = texture;
-	target.draw(*vertexArray, states);
-}
-
-/**/
-
-void _SfmlRegionAttachment_dispose (Attachment* self) {
-	_RegionAttachment_deinit(SUB_CAST(RegionAttachment, self) );
-	FREE(self);
-}
-
-void _SfmlRegionAttachment_draw (Attachment* attachment, Slot* slot) {
-	SfmlRegionAttachment* self = SUB_CAST(SfmlRegionAttachment, attachment);
-	SfmlSkeleton* skeleton = (SfmlSkeleton*)slot->skeleton;
-	Uint8 r = SUPER(skeleton)->r * slot->r * 255;
-	Uint8 g = SUPER(skeleton)->g * slot->g * 255;
-	Uint8 b = SUPER(skeleton)->b * slot->b * 255;
-	Uint8 a = SUPER(skeleton)->a * slot->a * 255;
-	sf::Vertex* vertices = self->vertices;
-	vertices[0].color.r = r;
-	vertices[0].color.g = g;
-	vertices[0].color.b = b;
-	vertices[0].color.a = a;
-	vertices[1].color.r = r;
-	vertices[1].color.g = g;
-	vertices[1].color.b = b;
-	vertices[1].color.a = a;
-	vertices[2].color.r = r;
-	vertices[2].color.g = g;
-	vertices[2].color.b = b;
-	vertices[2].color.a = a;
-	vertices[3].color.r = r;
-	vertices[3].color.g = g;
-	vertices[3].color.b = b;
-	vertices[3].color.a = a;
-
-	float* offset = SUPER(self)->offset;
-	Bone* bone = slot->bone;
-	vertices[0].position.x = offset[0] * bone->m00 + offset[1] * bone->m01 + bone->worldX;
-	vertices[0].position.y = offset[0] * bone->m10 + offset[1] * bone->m11 + bone->worldY;
-	vertices[1].position.x = offset[2] * bone->m00 + offset[3] * bone->m01 + bone->worldX;
-	vertices[1].position.y = offset[2] * bone->m10 + offset[3] * bone->m11 + bone->worldY;
-	vertices[2].position.x = offset[4] * bone->m00 + offset[5] * bone->m01 + bone->worldX;
-	vertices[2].position.y = offset[4] * bone->m10 + offset[5] * bone->m11 + bone->worldY;
-	vertices[3].position.x = offset[6] * bone->m00 + offset[7] * bone->m01 + bone->worldX;
-	vertices[3].position.y = offset[6] * bone->m10 + offset[7] * bone->m11 + bone->worldY;
-
-	// SMFL doesn't handle batching for us, so we'll just force a single texture per skeleton.
-	skeleton->drawable->texture = self->texture;
-	skeleton->drawable->vertexArray->append(vertices[0]);
-	skeleton->drawable->vertexArray->append(vertices[1]);
-	skeleton->drawable->vertexArray->append(vertices[2]);
-	skeleton->drawable->vertexArray->append(vertices[3]);
-}
-
-RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
-	SfmlRegionAttachment* self = NEW(SfmlRegionAttachment);
-	_RegionAttachment_init(SUPER(self), name, _SfmlRegionAttachment_dispose, _SfmlRegionAttachment_draw);
-
-	self->texture = ((SfmlAtlasPage*)region->page)->texture;
-	int u = region->x;
-	int u2 = u + region->width;
-	int v = region->y;
-	int v2 = v + region->height;
-	if (region->rotate) {
-		self->vertices[1].texCoords.x = u;
-		self->vertices[1].texCoords.y = v2;
-		self->vertices[2].texCoords.x = u;
-		self->vertices[2].texCoords.y = v;
-		self->vertices[3].texCoords.x = u2;
-		self->vertices[3].texCoords.y = v;
-		self->vertices[0].texCoords.x = u2;
-		self->vertices[0].texCoords.y = v2;
-	} else {
-		self->vertices[0].texCoords.x = u;
-		self->vertices[0].texCoords.y = v2;
-		self->vertices[1].texCoords.x = u;
-		self->vertices[1].texCoords.y = v;
-		self->vertices[2].texCoords.x = u2;
-		self->vertices[2].texCoords.y = v;
-		self->vertices[3].texCoords.x = u2;
-		self->vertices[3].texCoords.y = v2;
+	for (int i = 0; i < skeleton->slotCount; ++i) {
+		Slot* slot = skeleton->slots[i];
+		Attachment* attachment = slot->attachment;
+		if (!attachment || attachment->type != ATTACHMENT_REGION) continue;
+		RegionAttachment* regionAttachment = (RegionAttachment*)attachment;
+		RegionAttachment_updateVertices(regionAttachment, slot);
+
+		Uint8 r = skeleton->r * slot->r * 255;
+		Uint8 g = skeleton->g * slot->g * 255;
+		Uint8 b = skeleton->b * slot->b * 255;
+		Uint8 a = skeleton->a * slot->a * 255;
+
+		sf::Vertex vertices[4];
+		vertices[0].color.r = r;
+		vertices[0].color.g = g;
+		vertices[0].color.b = b;
+		vertices[0].color.a = a;
+		vertices[1].color.r = r;
+		vertices[1].color.g = g;
+		vertices[1].color.b = b;
+		vertices[1].color.a = a;
+		vertices[2].color.r = r;
+		vertices[2].color.g = g;
+		vertices[2].color.b = b;
+		vertices[2].color.a = a;
+		vertices[3].color.r = r;
+		vertices[3].color.g = g;
+		vertices[3].color.b = b;
+		vertices[3].color.a = a;
+
+		vertices[0].position.x = regionAttachment->vertices[VERTEX_X1];
+		vertices[0].position.y = regionAttachment->vertices[VERTEX_Y1];
+		vertices[1].position.x = regionAttachment->vertices[VERTEX_X2];
+		vertices[1].position.y = regionAttachment->vertices[VERTEX_Y2];
+		vertices[2].position.x = regionAttachment->vertices[VERTEX_X3];
+		vertices[2].position.y = regionAttachment->vertices[VERTEX_Y3];
+		vertices[3].position.x = regionAttachment->vertices[VERTEX_X4];
+		vertices[3].position.y = regionAttachment->vertices[VERTEX_Y4];
+
+		int u = regionAttachment->region->x;
+		int u2 = u + regionAttachment->region->width;
+		int v = regionAttachment->region->y;
+		int v2 = v + regionAttachment->region->height;
+		if (regionAttachment->region->rotate) {
+			vertices[1].texCoords.x = u;
+			vertices[1].texCoords.y = v2;
+			vertices[2].texCoords.x = u;
+			vertices[2].texCoords.y = v;
+			vertices[3].texCoords.x = u2;
+			vertices[3].texCoords.y = v;
+			vertices[0].texCoords.x = u2;
+			vertices[0].texCoords.y = v2;
+		} else {
+			vertices[0].texCoords.x = u;
+			vertices[0].texCoords.y = v2;
+			vertices[1].texCoords.x = u;
+			vertices[1].texCoords.y = v;
+			vertices[2].texCoords.x = u2;
+			vertices[2].texCoords.y = v;
+			vertices[3].texCoords.x = u2;
+			vertices[3].texCoords.y = v2;
+		}
+
+		// SMFL doesn't handle batching for us, so we'll just force a single texture per skeleton.
+		states.texture = (Texture*)regionAttachment->region->page->texture;
+		vertexArray->append(vertices[0]);
+		vertexArray->append(vertices[1]);
+		vertexArray->append(vertices[2]);
+		vertexArray->append(vertices[3]);
 	}
-
-	return SUPER(self);
-}
-
-/**/
-
-char* _Util_readFile (const char* path, int* length) {
-	return _readFile(path, length);
+	target.draw(*vertexArray, states);
 }
 
 } /* namespace spine */

+ 0 - 1
spine-sfml/src/spine/spine-sfml.h

@@ -52,7 +52,6 @@ public:
 	AnimationState* state;
 	float timeScale;
 	sf::VertexArray* vertexArray;
-	sf::Texture* texture; // All region attachments must use the same texture.
 
 	SkeletonDrawable (SkeletonData* skeleton, AnimationStateData* stateData = 0);
 	~SkeletonDrawable ();