Better class extension.

This commit is contained in:
NathanSweet 2013-04-11 06:06:09 +02:00
parent 4f971f30fb
commit e56050e3a7
12 changed files with 113 additions and 103 deletions

View File

@ -23,8 +23,7 @@ void _ExampleAtlasPage_dispose (AtlasPage* page) {
AtlasPage* AtlasPage_create (const char* name, const char* path) {
ExampleAtlasPage* self = NEW(ExampleAtlasPage);
_AtlasPage_init(SUPER(self), name);
VTABLE(AtlasPage, self) ->dispose = _ExampleAtlasPage_dispose;
_AtlasPage_init(SUPER(self), name, _ExampleAtlasPage_dispose);
self->extraData = 123;
@ -49,8 +48,7 @@ void _ExampleSkeleton_dispose (Skeleton* skeleton) {
Skeleton* Skeleton_create (SkeletonData* data) {
ExampleSkeleton* self = NEW(ExampleSkeleton);
_Skeleton_init(SUPER(self), data);
VTABLE(Skeleton, self) ->dispose = _ExampleSkeleton_dispose;
_Skeleton_init(SUPER(self), data, _ExampleSkeleton_dispose);
self->extraData = 789;
@ -80,9 +78,7 @@ void _ExampleRegionAttachment_draw (Attachment* attachment, Slot* slot) {
RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
ExampleRegionAttachment* self = NEW(ExampleRegionAttachment);
_RegionAttachment_init(SUPER(self), name);
VTABLE(Attachment, self) ->dispose = _ExampleRegionAttachment_dispose;
VTABLE(Attachment, self) ->draw = _ExampleRegionAttachment_draw;
_RegionAttachment_init(SUPER(self), name, _ExampleRegionAttachment_dispose, _ExampleRegionAttachment_draw);
self->extraData = 456;

View File

@ -35,17 +35,17 @@
- Classes intended for inheritance provide init/deinit functions which subclasses must call in their create/dispose functions.
- Polymorphism is done by a base class providing a "vtable" pointer to a struct containing function pointers. The public API
delegates to the appropriate vtable function. Subclasses may change the vtable pointers.
- Polymorphism is done by a base class providing function pointers in its init function. The public API delegates to this
function.
- Subclasses do not provide a dispose function, instead the base class' dispose function should be used, which will delegate to
a dispose function in its vtable.
a dispose function.
- Classes not designed for inheritance cannot be extended. They may use an internal subclass to hide private data and don't
expose a vtable.
expose function pointers.
- The public API hides implementation details such as vtable structs and init/deinit functions. An internal API is exposed in
extension.h to allow classes to be extended. Internal structs and functions begin with underscore (_).
- The public API hides implementation details such init/deinit functions. An internal API is exposed in extension.h to allow
classes to be extended. Internal functions begin with underscore (_).
- OOP in C tends to lose type safety. Macros are provided in extension.h to give context for why a cast is being done.
*/
@ -108,62 +108,52 @@ char* _Util_readFile (const char* path, int* length);
char* _readFile (const char* path, int* length);
typedef struct _SkeletonVtable {
void (*dispose) (Skeleton* skeleton);
} _SkeletonVtable;
void _Skeleton_init (Skeleton* self, SkeletonData* data);
void _Skeleton_init (Skeleton* self, SkeletonData* data, //
void (*dispose) (Skeleton* skeleton));
void _Skeleton_deinit (Skeleton* self);
/**/
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 _Attachment_init (Attachment* self, const char* name, AttachmentType type, //
void (*dispose) (Attachment* self), //
void (*draw) (Attachment* self, struct Slot* slot));
void _Attachment_deinit (Attachment* self);
/**/
void _RegionAttachment_init (RegionAttachment* self, const char* name);
void _RegionAttachment_init (RegionAttachment* self, const char* name, //
void (*dispose) (Attachment* self), //
void (*draw) (Attachment* self, struct Slot* slot));
void _RegionAttachment_deinit (RegionAttachment* self);
/**/
typedef struct _TimelineVtable {
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha);
void (*dispose) (Timeline* self);
} _TimelineVtable;
void _Timeline_init (Timeline* self);
void _Timeline_init (Timeline* self, //
void (*dispose) (Timeline* self), //
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
void _Timeline_deinit (Timeline* self);
/**/
void _CurveTimeline_init (CurveTimeline* self, int frameCount);
void _CurveTimeline_init (CurveTimeline* self, int frameCount, //
void (*dispose) (Timeline* self), //
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha));
void _CurveTimeline_deinit (CurveTimeline* self);
/**/
typedef struct _AtlasPageVtable {
void (*dispose) (AtlasPage* self);
} _AtlasPageVtable;
void _AtlasPage_init (AtlasPage* self, const char* name);
void _AtlasPage_init (AtlasPage* self, const char* name, //
void (*dispose) (AtlasPage* self));
void _AtlasPage_deinit (AtlasPage* self);
/**/
typedef struct _AttachmentLoaderVtable {
Attachment* (*newAttachment) (AttachmentLoader* self, AttachmentType type, const char* name);
void (*dispose) (AttachmentLoader* self);
} _AttachmentLoaderVtable;
void _AttachmentLoader_init (AttachmentLoader* self);
void _AttachmentLoader_init (AttachmentLoader* self, //
void (*dispose) (AttachmentLoader* self), //
Attachment* (*newAttachment) (AttachmentLoader* self, 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

@ -65,8 +65,17 @@ void Animation_mix (const Animation* self, Skeleton* skeleton, float time, int/*
/**/
void _Timeline_init (Timeline* self) {
typedef struct _TimelineVtable {
void (*apply) (const Timeline* self, Skeleton* skeleton, float time, float alpha);
void (*dispose) (Timeline* self);
} _TimelineVtable;
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;
VTABLE(Timeline, self) ->apply = apply;
}
void _Timeline_deinit (Timeline* self) {
@ -87,8 +96,10 @@ 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) {
_Timeline_init(SUPER(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);
}
@ -192,10 +203,11 @@ 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);
_CurveTimeline_init(SUPER(self), frameCount);
VTABLE(Timeline, self) ->dispose = _BaseTimeline_dispose;
_CurveTimeline_init(SUPER(self), frameCount, _BaseTimeline_dispose, apply);
CONST_CAST(int, self->framesLength) = frameCount * frameSize;
CONST_CAST(float*, self->frames) = CALLOC(float, self->framesLength);
@ -246,9 +258,7 @@ void _RotateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float
}
RotateTimeline* RotateTimeline_create (int frameCount) {
RotateTimeline* self = _BaseTimeline_create(frameCount, 2);
VTABLE(Timeline, self) ->apply = _RotateTimeline_apply;
return self;
return _BaseTimeline_create(frameCount, 2, _RotateTimeline_apply);
}
void RotateTimeline_setFrame (RotateTimeline* self, int frameIndex, float time, float angle) {
@ -291,9 +301,7 @@ void _TranslateTimeline_apply (const Timeline* timeline, Skeleton* skeleton, flo
}
TranslateTimeline* TranslateTimeline_create (int frameCount) {
TranslateTimeline* self = _BaseTimeline_create(frameCount, 3);
VTABLE(Timeline, self) ->apply = _TranslateTimeline_apply;
return self;
return _BaseTimeline_create(frameCount, 3, _TranslateTimeline_apply);
}
void TranslateTimeline_setFrame (TranslateTimeline* self, int frameIndex, float time, float x, float y) {
@ -332,9 +340,7 @@ void _ScaleTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float t
}
ScaleTimeline* ScaleTimeline_create (int frameCount) {
ScaleTimeline* self = _BaseTimeline_create(frameCount, 3);
VTABLE(Timeline, self) ->apply = _ScaleTimeline_apply;
return self;
return _BaseTimeline_create(frameCount, 3, _ScaleTimeline_apply);
}
void ScaleTimeline_setFrame (ScaleTimeline* self, int frameIndex, float time, float x, float y) {
@ -393,9 +399,7 @@ void _ColorTimeline_apply (const Timeline* timeline, Skeleton* skeleton, float t
}
ColorTimeline* ColorTimeline_create (int frameCount) {
ColorTimeline* self = (ColorTimeline*)_BaseTimeline_create(frameCount, 5);
VTABLE(Timeline, self) ->apply = _ColorTimeline_apply;
return self;
return (ColorTimeline*)_BaseTimeline_create(frameCount, 5, _ColorTimeline_apply);
}
void ColorTimeline_setFrame (ColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a) {
@ -439,11 +443,9 @@ void _AttachmentTimeline_dispose (Timeline* timeline) {
AttachmentTimeline* AttachmentTimeline_create (int frameCount) {
AttachmentTimeline* self = NEW(AttachmentTimeline);
_Timeline_init(SUPER(self));
VTABLE(Timeline, self) ->dispose = _AttachmentTimeline_dispose;
VTABLE(Timeline, self) ->apply = _AttachmentTimeline_apply;
CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, frameCount);
_Timeline_init(SUPER(self), _AttachmentTimeline_dispose, _AttachmentTimeline_apply);
CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, frameCount);
CONST_CAST(int, self->framesLength) = frameCount;
CONST_CAST(float*, self->frames) = CALLOC(float, frameCount);

View File

@ -31,8 +31,14 @@
namespace spine {
#endif
void _AtlasPage_init (AtlasPage* self, const char* name) {
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;
MALLOC_STR(self->name, name);
}

View File

@ -24,7 +24,6 @@
******************************************************************************/
#include <spine/AtlasAttachmentLoader.h>
#include <stdio.h>
#include <spine/extension.h>
#ifdef __cplusplus
@ -46,21 +45,16 @@ Attachment* _AtlasAttachmentLoader_newAttachment (AttachmentLoader* loader, Atta
}
return SUPER_CAST(Attachment, RegionAttachment_create(name, region)) ;
}
default: {
char buffer[16];
sprintf(buffer, "%d", type);
_AttachmentLoader_setError(loader, "Unknown attachment type: ", buffer);
default:
_AttachmentLoader_setUnknownTypeError(loader, type);
return 0;
}
}
}
AtlasAttachmentLoader* AtlasAttachmentLoader_create (Atlas* atlas) {
AtlasAttachmentLoader* self = NEW(AtlasAttachmentLoader);
_AttachmentLoader_init(SUPER(self));
_AttachmentLoader_init(SUPER(self), _AtlasAttachmentLoader_dispose, _AtlasAttachmentLoader_newAttachment);
self->atlas = atlas;
VTABLE(AttachmentLoader, self) ->newAttachment = _AtlasAttachmentLoader_newAttachment;
VTABLE(AttachmentLoader, self) ->dispose = _AtlasAttachmentLoader_dispose;
return self;
}

View File

@ -31,8 +31,19 @@
namespace spine {
#endif
void _Attachment_init (Attachment* self, const char* name, AttachmentType type) {
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)) {
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;
}

View File

@ -24,14 +24,24 @@
******************************************************************************/
#include <spine/AttachmentLoader.h>
#include <stdio.h>
#include <spine/extension.h>
#ifdef __cplusplus
namespace spine {
#endif
void _AttachmentLoader_init (AttachmentLoader* self) {
typedef struct _AttachmentLoaderVtable {
Attachment* (*newAttachment) (AttachmentLoader* self, AttachmentType type, const char* name);
void (*dispose) (AttachmentLoader* self);
} _AttachmentLoaderVtable;
void _AttachmentLoader_init (AttachmentLoader* self, //
void (*dispose) (AttachmentLoader* self), //
Attachment* (*newAttachment) (AttachmentLoader* self, AttachmentType type, const char* name)) {
CONST_CAST(_AttachmentLoaderVtable*, self->vtable) = NEW(_AttachmentLoaderVtable);
VTABLE(AttachmentLoader, self) ->dispose = dispose;
VTABLE(AttachmentLoader, self) ->newAttachment = newAttachment;
}
void _AttachmentLoader_deinit (AttachmentLoader* self) {
@ -59,6 +69,12 @@ void _AttachmentLoader_setError (AttachmentLoader* self, const char* error1, con
MALLOC_STR(self->error2, error2);
}
void _AttachmentLoader_setUnknownTypeError (AttachmentLoader* self, AttachmentType type) {
char buffer[16];
sprintf(buffer, "%d", type);
_AttachmentLoader_setError(self, "Unknown attachment type: ", buffer);
}
#ifdef __cplusplus
}
#endif

View File

@ -31,10 +31,12 @@
namespace spine {
#endif
void _RegionAttachment_init (RegionAttachment* self, const char* name) {
void _RegionAttachment_init (RegionAttachment* self, const char* name, //
void (*dispose) (Attachment* self), //
void (*draw) (Attachment* self, struct Slot* slot)) {
self->scaleX = 1;
self->scaleY = 1;
_Attachment_init(SUPER(self), name, ATTACHMENT_REGION);
_Attachment_init(SUPER(self), name, ATTACHMENT_REGION, dispose, draw);
}
void _RegionAttachment_deinit (RegionAttachment* self) {

View File

@ -31,10 +31,15 @@
namespace spine {
#endif
void _Skeleton_init (Skeleton* self, SkeletonData* data) {
typedef struct _SkeletonVtable {
void (*dispose) (Skeleton* skeleton);
} _SkeletonVtable;
void _Skeleton_init (Skeleton* self, SkeletonData* data, void (*dispose) (Skeleton* 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);

View File

@ -48,8 +48,7 @@ void _Cocos2dAtlasPage_dispose (AtlasPage* page) {
AtlasPage* AtlasPage_create (const char* name, const char* path) {
Cocos2dAtlasPage* self = NEW(Cocos2dAtlasPage);
_AtlasPage_init(SUPER(self), name);
VTABLE(AtlasPage, self) ->dispose = _Cocos2dAtlasPage_dispose;
_AtlasPage_init(SUPER(self), name, _Cocos2dAtlasPage_dispose);
self->texture = [[CCTextureCache sharedTextureCache] addImage:@(path)];
[self->texture retain];
@ -73,8 +72,7 @@ void _Cocos2dSkeleton_dispose (Skeleton* self) {
Skeleton* _Cocos2dSkeleton_create (SkeletonData* data, CCSkeleton* node) {
Cocos2dSkeleton* self = NEW(Cocos2dSkeleton);
_Skeleton_init(SUPER(self), data);
VTABLE(Skeleton, self) ->dispose = _Cocos2dSkeleton_dispose;
_Skeleton_init(SUPER(self), data, _Cocos2dSkeleton_dispose);
self->node = node;
@ -149,9 +147,7 @@ void _Cocos2dRegionAttachment_draw (Attachment* attachment, Slot* slot) {
RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
Cocos2dRegionAttachment* self = NEW(Cocos2dRegionAttachment);
_RegionAttachment_init(SUPER(self), name);
VTABLE(Attachment, self) ->dispose = _Cocos2dRegionAttachment_dispose;
VTABLE(Attachment, self) ->draw = _Cocos2dRegionAttachment_draw;
_RegionAttachment_init(SUPER(self), name, _Cocos2dRegionAttachment_dispose, _Cocos2dRegionAttachment_draw);
Cocos2dAtlasPage* page = SUB_CAST(Cocos2dAtlasPage, region->page);
self->textureAtlas = page->textureAtlas;

View File

@ -43,8 +43,7 @@ void _Cocos2dxAtlasPage_dispose (AtlasPage* page) {
AtlasPage* AtlasPage_create (const char* name, const char* path) {
Cocos2dxAtlasPage* self = NEW(Cocos2dxAtlasPage);
_AtlasPage_init(SUPER(self), name);
VTABLE(AtlasPage, self) ->dispose = _Cocos2dxAtlasPage_dispose;
_AtlasPage_init(SUPER(self), name, _Cocos2dxAtlasPage_dispose);
self->texture = CCTextureCache::sharedTextureCache()->addImage(path);
self->texture->retain();
@ -63,8 +62,7 @@ void _Cocos2dxSkeleton_dispose (Skeleton* self) {
Skeleton* _Cocos2dxSkeleton_create (SkeletonData* data, CCSkeleton* node) {
Cocos2dxSkeleton* self = NEW(Cocos2dxSkeleton);
_Skeleton_init(SUPER(self), data);
VTABLE(Skeleton, self) ->dispose = _Cocos2dxSkeleton_dispose;
_Skeleton_init(SUPER(self), data, _Cocos2dxSkeleton_dispose);
self->node = node;
@ -340,9 +338,7 @@ void _Cocos2dxRegionAttachment_draw (Attachment* attachment, Slot* slot) {
RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
Cocos2dxRegionAttachment* self = NEW(Cocos2dxRegionAttachment);
_RegionAttachment_init(SUPER(self), name);
VTABLE(Attachment, self) ->dispose = _Cocos2dxRegionAttachment_dispose;
VTABLE(Attachment, self) ->draw = _Cocos2dxRegionAttachment_draw;
_RegionAttachment_init(SUPER(self), name, _Cocos2dxRegionAttachment_dispose, _Cocos2dxRegionAttachment_draw);
Cocos2dxAtlasPage* page = SUB_CAST(Cocos2dxAtlasPage, region->page);
self->textureAtlas = page->textureAtlas;

View File

@ -52,8 +52,7 @@ void _SfmlAtlasPage_dispose (AtlasPage* page) {
AtlasPage* AtlasPage_create (const char* name, const char* path) {
SfmlAtlasPage* self = NEW(SfmlAtlasPage);
_AtlasPage_init(SUPER(self), name);
VTABLE(AtlasPage, self) ->dispose = _SfmlAtlasPage_dispose;
_AtlasPage_init(SUPER(self), name, _SfmlAtlasPage_dispose);
self->texture = new Texture();
self->texture->loadFromFile(path);
@ -72,8 +71,7 @@ Skeleton* _SfmlSkeleton_create (SkeletonData* data, SkeletonDrawable* drawable)
Bone_setYDown(1);
SfmlSkeleton* self = NEW(SfmlSkeleton);
_Skeleton_init(SUPER(self), data);
VTABLE(Skeleton, self) ->dispose = _SfmlSkeleton_dispose;
_Skeleton_init(SUPER(self), data, _SfmlSkeleton_dispose);
CONST_CAST(SkeletonDrawable*, self->drawable) = drawable;
@ -162,9 +160,7 @@ void _SfmlRegionAttachment_draw (Attachment* attachment, Slot* slot) {
RegionAttachment* RegionAttachment_create (const char* name, AtlasRegion* region) {
SfmlRegionAttachment* self = NEW(SfmlRegionAttachment);
_RegionAttachment_init(SUPER(self), name);
VTABLE(Attachment, self) ->dispose = _SfmlRegionAttachment_dispose;
VTABLE(Attachment, self) ->draw = _SfmlRegionAttachment_draw;
_RegionAttachment_init(SUPER(self), name, _SfmlRegionAttachment_dispose, _SfmlRegionAttachment_draw);
self->texture = ((SfmlAtlasPage*)region->page)->texture;
int u = region->x;