diff --git a/src/animation.c b/src/animation.c index 068d7c6..f5c3d83 100644 --- a/src/animation.c +++ b/src/animation.c @@ -3,6 +3,8 @@ #include #include "private.h" +#include "world.h" +#include "sprite.h" static HeliArray cache; @@ -27,8 +29,8 @@ static cairo_surface_t* loadFrame(const char *path) { return NULL; } -static HeliAnimation* load(const char *path) { - HeliAnimation *a = calloc(1, sizeof(*a)); +static HeliAnimationInstance* load(const char *path) { + HeliAnimationInstance *a = calloc(1, sizeof(*a)); a->path = heliStringCopy(path); GDir *dir = g_dir_open(path, 0, NULL); @@ -53,23 +55,32 @@ static HeliAnimation* load(const char *path) { return a; } -static void unload(HeliAnimation *a) { +static void unload(HeliAnimationInstance *a) { assert(!a->refcount); free(a->path); heliArrayDestroy(&a->frames); free(a); } -HeliAnimation *heliCreateAnimation(const char *path) { +Animation createAnimation(const char *path) { HeliPair *item = heliStringmapGet(&cache, path); if (!item) item = heliStringmapAdd(&cache, path, load(path), (HeliFreeCallback)&unload); - HeliAnimation *a = (HeliAnimation*)item->value; + HeliAnimationInstance *a = (HeliAnimationInstance*)item->value; ++a->refcount; - return a; + + Animation animation = calloc(1, sizeof(*animation)); + animation->instance = a; + ++animation->refcount; + return animation; } -void heliAnimationUnref(HeliAnimation *a) - { if (--a->refcount <= 0) heliStringmapRemove(&cache, a->path); } +void animationDestroy(Animation animation) { + if (--animation->refcount <= 0) { + if (--animation->instance->refcount <= 0) + heliStringmapRemove(&cache, animation->instance->path); + free(animation); + } +} void heliAnimationFinish() { heliArrayDestroy(&cache); } diff --git a/src/group.c b/src/group.c index 400bffd..e9c4b2c 100644 --- a/src/group.c +++ b/src/group.c @@ -47,6 +47,7 @@ void groupDestroyEx(Group group, int destroySprites) { } void groupAdd(Group group, Sprite sprite) { + if (!sprite) return; if (groupContains(group, sprite)) return; heliArrayInsert(&group->sprites, -1, sprite, NULL); heliArrayInsert(heliSpriteGetGroups(sprite), -1, sprite, NULL); @@ -175,13 +176,25 @@ void groupSetMirrorXEach(Group group, int mirrorX) { foreachInt(group, mirrorX, &spriteSetMirrorX); } void groupSetMirrorYEach(Group group, int mirrorY) { foreachInt(group, mirrorY, &spriteSetMirrorY); } -void groupSetAnimationEach(Group group, const char *path) - { foreachString(group, path, &spriteSetAnimation); } +void groupSetTagEach(Group group, int tag) + { foreachInt(group, tag, &spriteSetTag); } +void groupSetAnimationPathEach(Group group, const char *path) + { foreachString(group, path, &spriteSetAnimationPath); } void groupSetShapeColorEach(Group group, const char *color) { foreachString(group, color, &spriteSetShapeColor); } void groupSetTintColorEach(Group group, const char *color) { foreachString(group, color, &spriteSetTintColor); } +void groupSetAnimationEach(Group group, Animation animation) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteSetAnimation(groupGet(group, i), animation); +} + +void groupSetNoAnimationEach(Group group) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteSetNoAnimation(groupGet(group, i)); +} + void groupPointToEach(Group group, double x, double y) { for(int i = 0; i < groupGetCount(group); ++i) spritePointTo(groupGet(group, i), x, y); diff --git a/src/group.h b/src/group.h index 241577c..84fe917 100644 --- a/src/group.h +++ b/src/group.h @@ -55,9 +55,12 @@ void groupSetRotationSpeedEach(Group group, double rotationSpeed); void groupSetScaleEach(Group group, double scale); void groupSetMirrorXEach(Group group, int mirrorX); void groupSetMirrorYEach(Group group, int mirrorY); +void groupSetTagEach(Group group, int tag); void groupPointToEach(Group group, double x, double y); void groupSetSpeedAndDirectionEach(Group group, double speed, double angle); -void groupSetAnimationEach(Group group, const char *path); +void groupSetAnimationEach(Group group, Animation animation); +void groupSetAnimationPathEach(Group group, const char *path); +void groupSetNoAnimationEach(Group group); void groupSetShapeColorEach(Group group, const char *color); void groupSetTintColorEach(Group group, const char *color); void groupSetColliderEach(Group group, Collider type, double xOffset, double yOffset); diff --git a/src/private.h b/src/private.h index 34b7d47..56857ac 100644 --- a/src/private.h +++ b/src/private.h @@ -64,14 +64,17 @@ int heliStringmapRemove(HeliArray *a, const char *k); // animation -typedef struct _HeliAnimation { +typedef struct _HeliAnimationInastance { char *path; HeliArray frames; int refcount; -} HeliAnimation; +} HeliAnimationInstance; + +struct _Animation { + HeliAnimationInstance *instance; + int refcount; +}; -HeliAnimation *heliCreateAnimation(const char *path); -void heliAnimationUnref(HeliAnimation *a); void heliAnimationFinish(); diff --git a/src/sound.c b/src/sound.c index aa36d92..1678712 100644 --- a/src/sound.c +++ b/src/sound.c @@ -131,6 +131,7 @@ void soundDestroy(Sound sound) { soundStop(sound); if (--sound->instance->refcount <= 0) heliStringmapRemove(&cache, sound->instance->path); + free(sound); } diff --git a/src/sprite.c b/src/sprite.c index eb14663..107e127 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -28,6 +28,7 @@ struct _Sprite { double depth; double lifeTime; int visible; + int tag; int debug; double shapeColor[4]; @@ -38,7 +39,7 @@ struct _Sprite { HeliArray groups; - HeliAnimation *animation; + Animation animation; }; static HeliArray sprites; @@ -96,7 +97,7 @@ void spriteDestroy(Sprite sprite) { if (spritesSorted.items[i].value == sprite) { heliArrayRemove(&spritesSorted, i); break; } if (sprite->animation) - heliAnimationUnref(sprite->animation); + animationDestroy(sprite->animation); free(sprite); } @@ -164,6 +165,10 @@ int spriteGetVisible(Sprite sprite) { return sprite->visible; } void spriteSetVisible(Sprite sprite, int visible) { sprite->visible = visible != FALSE; } +int spriteGetTag(Sprite sprite) { return sprite->tag; } +void spriteSetTag(Sprite sprite, int tag) + { sprite->tag = tag; } + int spriteGetDebug(Sprite sprite) { return sprite->debug; } void spriteSetDebug(Sprite sprite, int debug) { sprite->debug = debug != FALSE; } @@ -201,20 +206,33 @@ void spriteSetColliderEx(Sprite sprite, Collider type, double xOffset, double yO void spriteSetCollider(Sprite sprite, Collider type, double xOffset, double yOffset) { spriteSetColliderEx(sprite, type, xOffset, yOffset, -1, -1, 0); } -void spriteSetAnimation(Sprite sprite, const char *path) { - HeliAnimation *prev = sprite->animation; - sprite->animation = heliCreateAnimation(path); - if (prev) heliAnimationUnref(prev); +void spriteSetAnimation(Sprite sprite, Animation animation) { + Animation prev = sprite->animation; + sprite->animation = animation; + if (animation) ++animation->refcount; + if (prev) animationDestroy(prev); spriteSetFrame(sprite, sprite->frame); } +void spriteSetAnimationPath(Sprite sprite, const char *path) { + Animation animation = createAnimation(path); + spriteSetAnimation(sprite, animation); + animationDestroy(animation); +} + +void spriteSetNoAnimation(Sprite sprite) + { spriteSetAnimation(sprite, NULL); } + +Animation spriteGetAnimation(Sprite sprite) + { return sprite->animation; } + void spritePlay(Sprite sprite) { sprite->playing = TRUE; } void spritePause(Sprite sprite) { sprite->playing = FALSE; } void spriteNextFrame(Sprite sprite) { spriteSetFrame(sprite, sprite->frame + 1); } void spriteSetFrame(Sprite sprite, int frame) { - sprite->frame = frame >= 0 && sprite->animation && sprite->animation->frames.count > 0 - ? frame % sprite->animation->frames.count : 0; + sprite->frame = frame >= 0 && sprite->animation && sprite->animation->instance->frames.count > 0 + ? frame % sprite->animation->instance->frames.count : 0; } void spriteSetShapeColor(Sprite sprite, const char *color) @@ -304,7 +322,7 @@ static void drawSprite(cairo_t *cr, Sprite s) { double hh = s->height*0.5; cairo_surface_t *frame = s->animation - ? (cairo_surface_t*)heliArrayGetValue(&s->animation->frames, s->frame) : NULL; + ? (cairo_surface_t*)heliArrayGetValue(&s->animation->instance->frames, s->frame) : NULL; double a = s->tintColor[3]; int tint = fabs(s->tintColor[0] - 1) > 1e-5 diff --git a/src/sprite.h b/src/sprite.h index aa5f28c..98f8112 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -5,6 +5,7 @@ #include "common.h" typedef struct _Sprite *Sprite; +typedef struct _Animation *Animation; typedef enum _Collider { @@ -12,6 +13,11 @@ typedef enum _Collider { COLLIDER_CIRCLE } Collider; + +Animation createAnimation(const char *path); +void animationDestroy(); + + Sprite createSprite(double x, double y); Sprite createSpriteEx(double x, double y, double width, double height); @@ -60,6 +66,9 @@ void spriteSetDepth(Sprite sprite, double depth); int spriteGetVisible(Sprite sprite); void spriteSetVisible(Sprite sprite, int visible); +int spriteGetTag(Sprite sprite); +void spriteSetTag(Sprite sprite, int tag); + int spriteGetDebug(Sprite sprite); void spriteSetDebug(Sprite sprite, int debug); @@ -76,7 +85,11 @@ void spriteSetCollider(Sprite sprite, Collider type, double xOffset, double yOff void spriteSetColliderEx(Sprite sprite, Collider type, double xOffset, double yOffset, double widthOrRadius, double height, double rotationOffset); -void spriteSetAnimation(Sprite sprite, const char *path); +void spriteSetAnimation(Sprite sprite, Animation animation); +void spriteSetNoAnimation(Sprite sprite); +void spriteSetAnimationPath(Sprite sprite, const char *path); +Animation spriteGetAnimation(Sprite sprite); + void spritePlay(Sprite sprite); void spritePause(Sprite sprite); void spriteNextFrame(Sprite sprite);