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.
This commit is contained in:
NathanSweet 2013-04-17 22:06:36 +02:00
parent 3defbc4132
commit 2bc3f511a1
19 changed files with 425 additions and 698 deletions

View File

@ -7,86 +7,15 @@
/**/ /**/
typedef struct { void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
AtlasPage super; self->texture = 0;
int extraData; self->width = 123;
} ExampleAtlasPage; self->height = 456;
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) { void _AtlasPage_disposeTexture (AtlasPage* self) {
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);
}
Skeleton* Skeleton_create (SkeletonData* data) {
ExampleSkeleton* self = NEW(ExampleSkeleton);
_Skeleton_init(SUPER(self), data, _ExampleSkeleton_dispose);
self->extraData = 789;
return SUPER(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) { char* _Util_readFile (const char* path, int* length) {
return _readFile(path, length); return _readFile(path, length);
} }
@ -96,7 +25,7 @@ char* _Util_readFile (const char* path, int* length) {
int main (void) { int main (void) {
Atlas* atlas = Atlas_readAtlasFile("data/spineboy.atlas"); 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 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); SkeletonJson* json = SkeletonJson_create(atlas);
SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/spineboy.json"); SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "data/spineboy.json");
@ -104,7 +33,6 @@ int main (void) {
printf("Default skin name: %s\n", skeletonData->defaultSkin->name); printf("Default skin name: %s\n", skeletonData->defaultSkin->name);
Skeleton* skeleton = Skeleton_create(skeletonData); Skeleton* skeleton = Skeleton_create(skeletonData);
printf("Skeleton extraData: %d\n", ((ExampleSkeleton*)skeleton)->extraData);
Animation* animation = SkeletonData_findAnimation(skeletonData, "walk"); Animation* animation = SkeletonData_findAnimation(skeletonData, "walk");
if (!animation) printf("Error: %s\n", json->error); if (!animation) printf("Error: %s\n", json->error);

View File

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

View File

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

View File

@ -28,22 +28,31 @@
#include <spine/Attachment.h> #include <spine/Attachment.h>
#include <spine/Atlas.h> #include <spine/Atlas.h>
#include <spine/Slot.h>
#ifdef __cplusplus #ifdef __cplusplus
namespace spine { namespace spine {
extern "C" { extern "C" {
#endif #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; typedef struct RegionAttachment RegionAttachment;
struct RegionAttachment { struct RegionAttachment {
Attachment super; Attachment super;
float x, y, scaleX, scaleY, rotation, width, height; float x, y, scaleX, scaleY, rotation, width, height;
AtlasRegion* region;
float offset[8]; 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_updateOffset (RegionAttachment* self);
void RegionAttachment_updateVertices (RegionAttachment* self, Slot* slot);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

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

View File

@ -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. - 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 - struct fields that are const are readonly. Either they are set in a create function and can never be changed, or they can only
changed by calling a function. 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". - 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. - 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. */ /* Gets the vtable for the specified type. Not type safe, use with care. */
#define VTABLE(TYPE,VALUE) ((_##TYPE##Vtable*)((TYPE*)VALUE)->vtable) #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) #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) #define MALLOC_STR(TO,FROM) strcpy(CONST_CAST(char*, TO) = (char*)malloc(strlen(FROM) + 1), FROM)
#include <stdlib.h> #include <stdlib.h>
@ -96,10 +97,8 @@ extern "C" {
* Functions that must be implemented: * Functions that must be implemented:
*/ */
RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region); void _AtlasPage_createTexture (AtlasPage* self, const char* path);
void _AtlasPage_disposeTexture (AtlasPage* self);
AtlasPage* AtlasPage_create (const char* name, const char* path);
char* _Util_readFile (const char* path, int* length); 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 _AttachmentLoader_init (AttachmentLoader* self, //
void (*dispose) (Skeleton* skeleton)); void (*dispose) (AttachmentLoader* self), //
void _Skeleton_deinit (Skeleton* 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 _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
void (*dispose) (Attachment* self), // void (*dispose) (Attachment* self));
void (*draw) (Attachment* self, struct Slot* slot));
void _Attachment_deinit (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 _Timeline_init (Timeline* self, //
void (*dispose) (Timeline* self), // void (*dispose) (Timeline* self), //
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)); 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 (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
void _CurveTimeline_deinit (CurveTimeline* self); 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 #ifdef __cplusplus
} }
} }

View File

@ -70,8 +70,8 @@ typedef struct _TimelineVtable {
void (*dispose) (Timeline* self); void (*dispose) (Timeline* self);
} _TimelineVtable; } _TimelineVtable;
void _Timeline_init (Timeline* self, /**/ void _Timeline_init (Timeline* self, //
void (*dispose) (Timeline* self), /**/ void (*dispose) (Timeline* self), //
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) { void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
CONST_CAST(_TimelineVtable*, self->vtable) = NEW(_TimelineVtable); CONST_CAST(_TimelineVtable*, self->vtable) = NEW(_TimelineVtable);
VTABLE(Timeline, self) ->dispose = dispose; VTABLE(Timeline, self) ->dispose = dispose;
@ -96,8 +96,8 @@ static const float CURVE_LINEAR = 0;
static const float CURVE_STEPPED = -1; static const float CURVE_STEPPED = -1;
static const int CURVE_SEGMENTS = 10; static const int CURVE_SEGMENTS = 10;
void _CurveTimeline_init (CurveTimeline* self, int frameCount, /**/ void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
void (*dispose) (Timeline* self), /**/ void (*dispose) (Timeline* self), //
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) { void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
_Timeline_init(SUPER(self), dispose, apply); _Timeline_init(SUPER(self), dispose, apply);
self->curves = CALLOC(float, (frameCount - 1) * 6); 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. **/ /* 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)) { void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha)) {
struct BaseTimeline* self = NEW(struct BaseTimeline); struct BaseTimeline* self = NEW(struct BaseTimeline);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,22 +29,6 @@
#include <spine/spine.h> #include <spine/spine.h>
#include "cocos2d.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> { @interface CCSkeleton : CCNodeRGBA<CCBlendProtocol> {
@private @private
bool ownsSkeleton; bool ownsSkeleton;
@ -58,9 +42,6 @@ using namespace spine;
bool debugSlots; bool debugSlots;
bool debugBones; bool debugBones;
CCTextureAtlas* textureAtlas; // All region attachments for a skeleton must use the same texture.
unsigned int quadCount;
ccBlendFunc blendFunc; ccBlendFunc blendFunc;
} }
@ -109,4 +90,19 @@ using namespace spine;
@end @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_ */ #endif /* SPINE_COCOS2D_H_ */

View File

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

View File

@ -31,43 +31,85 @@ using std::min;
using std::max; using std::max;
namespace spine { namespace spine {
void _Cocos2dxAtlasPage_dispose (AtlasPage* page) { void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
Cocos2dxAtlasPage* self = SUB_CAST(Cocos2dxAtlasPage, page); CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(path);
_AtlasPage_deinit(SUPER(self)); CCTextureAtlas* textureAtlas = CCTextureAtlas::createWithTexture(texture, 4);
textureAtlas->retain();
CC_SAFE_RELEASE_NULL(self->texture); self->texture = textureAtlas;
CC_SAFE_RELEASE_NULL(self->textureAtlas); self->width = texture->getPixelsWide();
self->height = texture->getPixelsHigh();
FREE(page);
} }
AtlasPage* AtlasPage_create (const char* name, const char* path) { void _AtlasPage_disposeTexture (AtlasPage* self) {
Cocos2dxAtlasPage* self = NEW(Cocos2dxAtlasPage); ((CCTextureAtlas*)self->texture)->release();
_AtlasPage_init(SUPER(self), name, _Cocos2dxAtlasPage_dispose); }
self->texture = CCTextureCache::sharedTextureCache()->addImage(path); char* _Util_readFile (const char* path, int* length) {
self->texture->retain(); unsigned long size;
self->textureAtlas = CCTextureAtlas::createWithTexture(self->texture, 4); char* data = reinterpret_cast<char*>(CCFileUtils::sharedFileUtils()->getFileData(
self->textureAtlas->retain(); CCFileUtils::sharedFileUtils()->fullPathForFilename(path).c_str(), "r", &size));
*length = size;
return SUPER(self); return data;
} }
/**/ /**/
void _Cocos2dxSkeleton_dispose (Skeleton* self) { void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad) {
_Skeleton_deinit(self); RegionAttachment_updateVertices(self, slot);
FREE(self);
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;
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;
}
} }
Skeleton* _Cocos2dxSkeleton_create (SkeletonData* data, CCSkeleton* node) { /**/
Cocos2dxSkeleton* self = NEW(Cocos2dxSkeleton);
_Skeleton_init(SUPER(self), data, _Cocos2dxSkeleton_dispose);
self->node = node;
return SUPER(self);
}
CCSkeleton* CCSkeleton::create (const char* skeletonDataFile, Atlas* atlas, float scale) { CCSkeleton* CCSkeleton::create (const char* skeletonDataFile, Atlas* atlas, float scale) {
SkeletonJson* json = SkeletonJson_create(atlas); SkeletonJson* json = SkeletonJson_create(atlas);
@ -105,7 +147,7 @@ CCSkeleton* CCSkeleton::create (SkeletonData* skeletonData, AnimationStateData*
CCSkeleton::CCSkeleton (SkeletonData *skeletonData, AnimationStateData *stateData) : CCSkeleton::CCSkeleton (SkeletonData *skeletonData, AnimationStateData *stateData) :
ownsSkeleton(false), ownsStateData(false), atlas(0), ownsSkeleton(false), ownsStateData(false), atlas(0),
skeleton(0), state(0), debugSlots(false), debugBones(false) { 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) { if (!stateData) {
stateData = AnimationStateData_create(skeletonData); stateData = AnimationStateData_create(skeletonData);
@ -146,23 +188,43 @@ void CCSkeleton::draw () {
skeleton->b = color.b / (float)255; skeleton->b = color.b / (float)255;
skeleton->a = getOpacity() / (float)255; skeleton->a = getOpacity() / (float)255;
quadCount = 0; CCTextureAtlas* textureAtlas = 0;
for (int i = 0, n = skeleton->slotCount; i < n; i++) int quadCount = 0;
if (skeleton->slots[i]->attachment) Attachment_draw(skeleton->slots[i]->attachment, skeleton->slots[i]); for (int i = 0, n = skeleton->slotCount; i < n; i++) {
if (textureAtlas) textureAtlas->drawNumberOfQuads(quadCount); 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) { if (debugSlots) {
// Slots. // Slots.
ccDrawColor4B(0, 0, 255, 255); ccDrawColor4B(0, 0, 255, 255);
glLineWidth(1); glLineWidth(1);
CCPoint points[4]; CCPoint points[4];
ccV3F_C4B_T2F_Quad quad;
for (int i = 0, n = skeleton->slotCount; i < n; i++) { for (int i = 0, n = skeleton->slotCount; i < n; i++) {
if (!skeleton->slots[i]->attachment) continue; Slot* slot = skeleton->slots[i];
ccV3F_C4B_T2F_Quad* quad = &((Cocos2dxRegionAttachment*)skeleton->slots[i]->attachment)->quad; if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
points[0] = ccp(quad->bl.vertices.x, quad->bl.vertices.y); RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
points[1] = ccp(quad->br.vertices.x, quad->br.vertices.y); RegionAttachment_updateQuad(attachment, slot, &quad);
points[2] = ccp(quad->tr.vertices.x, quad->tr.vertices.y); points[0] = ccp(quad.bl.vertices.x, quad.bl.vertices.y);
points[3] = ccp(quad->tl.vertices.x, quad->tl.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); 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 minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
float scaleX = getScaleX(); float scaleX = getScaleX();
float scaleY = getScaleY(); float scaleY = getScaleY();
ccV3F_C4B_T2F_Quad quad;
for (int i = 0; i < skeleton->slotCount; ++i) { for (int i = 0; i < skeleton->slotCount; ++i) {
Slot* slot = skeleton->slots[i]; Slot* slot = skeleton->slots[i];
Attachment* attachment = slot->attachment; if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
if (!attachment || attachment->type != ATTACHMENT_REGION) continue; RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
Cocos2dxRegionAttachment* regionAttachment = SUB_CAST(Cocos2dxRegionAttachment, attachment); RegionAttachment_updateQuad(attachment, slot, &quad);
minX = min(minX, regionAttachment->quad.bl.vertices.x * scaleX); minX = min(minX, quad.bl.vertices.x * scaleX);
minY = min(minY, regionAttachment->quad.bl.vertices.y * scaleY); minY = min(minY, quad.bl.vertices.y * scaleY);
maxX = max(maxX, regionAttachment->quad.bl.vertices.x * scaleX); maxX = max(maxX, quad.bl.vertices.x * scaleX);
maxY = max(maxY, regionAttachment->quad.bl.vertices.y * scaleY); maxY = max(maxY, quad.bl.vertices.y * scaleY);
minX = min(minX, regionAttachment->quad.br.vertices.x * scaleX); minX = min(minX, quad.br.vertices.x * scaleX);
minY = min(minY, regionAttachment->quad.br.vertices.y * scaleY); minY = min(minY, quad.br.vertices.y * scaleY);
maxX = max(maxX, regionAttachment->quad.br.vertices.x * scaleX); maxX = max(maxX, quad.br.vertices.x * scaleX);
maxY = max(maxY, regionAttachment->quad.br.vertices.y * scaleY); maxY = max(maxY, quad.br.vertices.y * scaleY);
minX = min(minX, regionAttachment->quad.tl.vertices.x * scaleX); minX = min(minX, quad.tl.vertices.x * scaleX);
minY = min(minY, regionAttachment->quad.tl.vertices.y * scaleY); minY = min(minY, quad.tl.vertices.y * scaleY);
maxX = max(maxX, regionAttachment->quad.tl.vertices.x * scaleX); maxX = max(maxX, quad.tl.vertices.x * scaleX);
maxY = max(maxY, regionAttachment->quad.tl.vertices.y * scaleY); maxY = max(maxY, quad.tl.vertices.y * scaleY);
minX = min(minX, regionAttachment->quad.tr.vertices.x * scaleX); minX = min(minX, quad.tr.vertices.x * scaleX);
minY = min(minY, regionAttachment->quad.tr.vertices.y * scaleY); minY = min(minY, quad.tr.vertices.y * scaleY);
maxX = max(maxX, regionAttachment->quad.tr.vertices.x * scaleX); maxX = max(maxX, quad.tr.vertices.x * scaleX);
maxY = max(maxY, regionAttachment->quad.tr.vertices.y * scaleY); maxY = max(maxY, quad.tr.vertices.y * scaleY);
} }
CCPoint position = getPosition(); CCPoint position = getPosition();
minX = position.x + minX; minX = position.x + minX;
@ -283,114 +346,4 @@ void CCSkeleton::setBlendFunc (ccBlendFunc blendFunc) {
this->blendFunc = 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;
}
} }

View File

@ -31,21 +31,6 @@
namespace spine { 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 { class CCSkeleton: public cocos2d::CCNodeRGBA, public cocos2d::CCBlendProtocol {
private: private:
bool ownsSkeleton; bool ownsSkeleton;
@ -59,9 +44,6 @@ public:
bool debugSlots; bool debugSlots;
bool debugBones; 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, Atlas* atlas, float scale = 1);
static CCSkeleton* create (const char* skeletonDataFile, const char* atlasFile, float scale = 1); static CCSkeleton* create (const char* skeletonDataFile, const char* atlasFile, float scale = 1);
static CCSkeleton* create (SkeletonData* skeletonData, AnimationStateData* stateData = 0); static CCSkeleton* create (SkeletonData* skeletonData, AnimationStateData* stateData = 0);
@ -110,13 +92,7 @@ public:
/**/ /**/
typedef struct { void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, cocos2d::ccV3F_C4B_T2F_Quad* quad);
RegionAttachment super;
cocos2d::ccV3F_C4B_T2F_Quad quad;
cocos2d::CCTextureAtlas* textureAtlas;
} Cocos2dxRegionAttachment;
cocos2d::ccV3F_C4B_T2F_Quad* RegionAttachment_updateQuad (Attachment* self, Slot* slot);
} }

View File

@ -31,58 +31,35 @@
#include <SFML/Graphics/RenderTarget.hpp> #include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderStates.hpp> #include <SFML/Graphics/RenderStates.hpp>
using sf::Quads; using namespace sf;
using sf::RenderTarget;
using sf::RenderStates;
using sf::Texture;
using sf::Uint8;
using sf::Vertex;
using sf::VertexArray;
namespace spine { namespace spine {
void _SfmlAtlasPage_dispose (AtlasPage* page) { void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
SfmlAtlasPage* self = SUB_CAST(SfmlAtlasPage, page); Texture* texture = new Texture();
_AtlasPage_deinit(SUPER(self)); if (!texture->loadFromFile(path)) return;
self->texture = texture;
delete self->texture; Vector2u size = texture->getSize();
self->width = size.x;
FREE(page); self->height = size.x;
} }
AtlasPage* AtlasPage_create (const char* name, const char* path) { void _AtlasPage_disposeTexture (AtlasPage* self) {
SfmlAtlasPage* self = NEW(SfmlAtlasPage); delete (Texture*)self->texture;
_AtlasPage_init(SUPER(self), name, _SfmlAtlasPage_dispose); }
self->texture = new Texture(); char* _Util_readFile (const char* path, int* length) {
self->texture->loadFromFile(path); return _readFile(path, length);
return SUPER(self);
} }
/**/ /**/
void _SfmlSkeleton_dispose (Skeleton* self) {
_Skeleton_deinit(self);
FREE(self);
}
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) : SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) :
timeScale(1), timeScale(1),
vertexArray(new VertexArray(Quads, skeletonData->boneCount * 4)), vertexArray(new VertexArray(Quads, skeletonData->boneCount * 4)) {
texture(0) { Bone_setYDown(true);
skeleton = _SfmlSkeleton_create(skeletonData, this);
skeleton = Skeleton_create(skeletonData);
state = AnimationState_create(stateData); state = AnimationState_create(stateData);
} }
@ -101,99 +78,77 @@ void SkeletonDrawable::update (float deltaTime) {
void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
vertexArray->clear(); vertexArray->clear();
for (int i = 0; i < skeleton->slotCount; ++i) for (int i = 0; i < skeleton->slotCount; ++i) {
if (skeleton->slots[i]->attachment) Attachment_draw(skeleton->slots[i]->attachment, skeleton->slots[i]); Slot* slot = skeleton->slots[i];
states.texture = texture; 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]);
}
target.draw(*vertexArray, states); 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;
}
return SUPER(self);
}
/**/
char* _Util_readFile (const char* path, int* length) {
return _readFile(path, length);
}
} /* namespace spine */ } /* namespace spine */

View File

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