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 {
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);
void _AtlasPage_createTexture (AtlasPage* self, const char* path) {
self->texture = 0;
self->width = 123;
self->height = 456;
}
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);
void _AtlasPage_disposeTexture (AtlasPage* 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) {
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);

View File

@ -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);

View File

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

View File

@ -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
}

View File

@ -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);

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.
- 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
}
}

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
return self;
}
void _Skeleton_deinit (Skeleton* self) {
FREE(self->vtable);
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)

View File

@ -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_ */

View File

@ -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);
void _AtlasPage_disposeTexture (AtlasPage* self) {
[(CCTextureAtlas*)self->texture release];
}
self->texture = [[CCTextureCache sharedTextureCache] addImage:@(path)];
[self->texture retain];
self->textureAtlas = [[CCTextureAtlas alloc] initWithTexture:self->texture capacity:4];
[self->textureAtlas retain];
return SUPER(self);
char* _Util_readFile (const char* path, int* length) {
return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length);
}
/**/
typedef struct {
Skeleton super;
CCSkeleton* node;
} Cocos2dSkeleton;
void RegionAttachment_updateQuad (RegionAttachment* self, Slot* slot, ccV3F_C4B_T2F_Quad* quad) {
RegionAttachment_updateVertices(self, slot);
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);
}
/**/
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;
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;
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;
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;
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;

View File

@ -31,43 +31,85 @@ 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);
void _AtlasPage_disposeTexture (AtlasPage* self) {
((CCTextureAtlas*)self->texture)->release();
}
self->texture = CCTextureCache::sharedTextureCache()->addImage(path);
self->texture->retain();
self->textureAtlas = CCTextureAtlas::createWithTexture(self->texture, 4);
self->textureAtlas->retain();
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);
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) {
SkeletonJson* json = SkeletonJson_create(atlas);
@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
void _AtlasPage_disposeTexture (AtlasPage* self) {
delete (Texture*)self->texture;
}
self->texture = new Texture();
self->texture->loadFromFile(path);
return SUPER(self);
char* _Util_readFile (const char* path, int* length) {
return _readFile(path, length);
}
/**/
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) :
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;
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]);
}
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 */

View File

@ -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 ();