diff --git a/demo/src/phisics.c b/demo/src/phisics.c index 42074f5..b3824b7 100644 --- a/demo/src/phisics.c +++ b/demo/src/phisics.c @@ -14,22 +14,22 @@ static Sound beep; void phisicsInit() { ball = createSpriteEx(200, 200, 64, 64); - spriteSetAnimation(ball, "data/sprite/breadball.png"); + spriteSetAnimation(ball, createAnimation("data/sprite/breadball.png")); spriteSetColliderCircle(ball, 0, 0, -1); spriteSetRotateToDirection(ball, TRUE); brick1 = createSpriteEx(200-32, 200+64, 64, 64); - spriteSetAnimation(brick1, "data/sprite/bricks.png"); + spriteSetAnimation(brick1, createAnimation("data/sprite/bricks.png")); spriteSetTintColor(brick1, rgb(0, 0, 1)); spriteSetColliderRectangle(brick1, 0, 0, 0, -1, -1, 20); spriteSetBounciness(brick1, 0.5); brick2 = createSpriteEx(200+32, 200+64, 64, 64); - spriteSetAnimation(brick2, "data/sprite/bricks.png"); + spriteSetAnimation(brick2, createAnimation("data/sprite/bricks.png")); spriteSetColliderRectangle(brick2, 0, 0, 0, -1, -1, 20); brick3 = createSpriteEx(200+32+64, 200+64, 64, 64); - spriteSetAnimation(brick3, "data/sprite/bricks.png"); + spriteSetAnimation(brick3, createAnimation("data/sprite/bricks.png")); spriteSetTintColor(brick3, rgba(1, 0, 1, 0.5)); spriteSetColliderRectangle(brick3, 0, 0, 0, -1, -1, 20); spriteSetBounciness(brick3, 2); diff --git a/demo/src/sprites.c b/demo/src/sprites.c index 4c746e9..8e64421 100644 --- a/demo/src/sprites.c +++ b/demo/src/sprites.c @@ -18,19 +18,19 @@ void spritesInit() { // normal s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks.png")); groupAdd(pulse, s); x += 64; // indexed colors s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/snail-indexed.png"); + spriteSetAnimation(s, createAnimation("data/sprite/snail-indexed.png")); groupAdd(pulse, s); x += 64; // without alpha s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); groupAdd(pulse, s); x += 64; @@ -42,14 +42,14 @@ void spritesInit() { // with tint color s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks.png")); spriteSetTintColor(s, "red"); groupAdd(pulse, s); x += 64; // semi-transparent s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks.png")); spriteSetTintColor(s, rgba(1, 1, 1, 0.5)); groupAdd(pulse, s); x += 64; @@ -59,27 +59,27 @@ void spritesInit() { // tiles s = createSpriteEx(x - 48/2, y + 48/2, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks.png")); groupAdd(pulse, s); s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); s = createSpriteEx(x, y + 48, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); x -= 48; s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); s = createSpriteEx(x, y + 48, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); x -= 64; // blend two sprites s = createSpriteEx(x, y, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); spriteSetTintColor(s, rgba(1, 1, 1, 0.5)); groupAdd(pulse, s); x -= 16; s = createSpriteEx(x, y + 16, 48, 48); - spriteSetAnimation(s, "data/sprite/bricks-tile.png"); + spriteSetAnimation(s, createAnimation("data/sprite/bricks-tile.png")); spriteSetTintColor(s, rgba(1, 1, 1, 0.5)); groupAdd(pulse, s); x -= 64; @@ -88,7 +88,7 @@ void spritesInit() { double k = 0.25, w = 343*k, h = 221*k; x += 48/2 - w/2; s = createSpriteEx(x, y, w, h); - spriteSetAnimation(s, "data/sprite/snake.png"); + spriteSetAnimation(s, createAnimation("data/sprite/snake.png")); spriteSetDebug(s, TRUE); groupAdd(pulse, s); } diff --git a/src/SConstruct b/src/SConstruct index 306d2ad..f69b2a6 100644 --- a/src/SConstruct +++ b/src/SConstruct @@ -36,6 +36,7 @@ else: target = name headers = [ + 'animation.h', 'common.h', 'drawing.h', 'font.h', diff --git a/src/animation.c b/src/animation.c index cce244b..a98fb7f 100644 --- a/src/animation.c +++ b/src/animation.c @@ -3,10 +3,26 @@ #include "private.h" #include "world.h" -#include "sprite.h" +#include "animation.h" static HeliArray cache; +static Animation first, last; + +typedef struct _HeliTexture { + const char *key; + unsigned int id; + int refcount; +} HeliTexture; + +struct _Animation { + int playing; + int loop; + double fps; + double pos; + HeliArray frames; + Animation prev, next; +}; @@ -41,21 +57,16 @@ static void mipy(float *buffer, int *w, int *h) { } -static void unloadFrame(void *x) { - unsigned int texid = (unsigned int)(size_t)x; - glDeleteTextures(1, &texid); -} - - -static unsigned int loadFrame(const char *path) { - if (!heliStringEndsWithLowcase(path, ".png")) - return 0; +int imageLoad(const char *path, int *outWidth, int *outHeight, unsigned char **outPixels) { + *outWidth = 0; + *outHeight = 0; + *outPixels = NULL; // load image SDL_Surface *surface = IMG_Load(path); if (!surface) { fprintf(stderr, "helianthus: cannot load image: %s\n", path); - return 0; + return FALSE; } // convert to RGBA @@ -67,31 +78,44 @@ static unsigned int loadFrame(const char *path) { surface = converted; } - // convert to float and premult alpha + // copy SDL_LockSurface(surface); int w = surface->w; int h = surface->h; - size_t rcount = (size_t)w*4; - size_t count = rcount*h; + assert(w > 0 && h > 0); + size_t rsize = (size_t)w*4; + unsigned char *pixels = malloc(h*rsize); + for(int i = 0; i < h; ++i) + memcpy(pixels + i*rsize, surface->pixels + surface->pitch*i, rsize); + SDL_UnlockSurface(surface); + SDL_FreeSurface(surface); + + *outPixels = pixels; + *outWidth = w; + *outHeight = h; + return TRUE; +} + + +unsigned int imageToGLTexture(int width, int height, const unsigned char *pixels, int horWrap, int vertWrap) { + // convert to float and premult alpha + size_t count = (size_t)width*height*4; float *buffer = (float*)malloc(count*sizeof(float)); - const unsigned char *pp = (const unsigned char *)surface->pixels; - for(float *p = buffer, *end = p + count; p < end; pp += surface->pitch - rcount) { - for(float *rend = p + rcount; p < rend; p += 4, pp += 4) { - if (pp[0]) { - float a = pp[0]/255.f; - p[0] = pp[3]/255.f*a; - p[1] = pp[2]/255.f*a; - p[2] = pp[1]/255.f*a; - p[3] = a; - } else { - p[0] = p[1] = p[2] = p[3] = 0; - } + const unsigned char *pp = pixels; + for(float *p = buffer, *end = p + count; p < end; p += 4, pp += 4) { + if (pp[0]) { + float a = pp[0]/255.f; + p[0] = pp[3]/255.f*a; + p[1] = pp[2]/255.f*a; + p[2] = pp[1]/255.f*a; + p[3] = a; + } else { + p[0] = p[1] = p[2] = p[3] = 0; } } - SDL_UnlockSurface(surface); - SDL_FreeSurface(surface); // resample to power of two + int w = width, h = height; int fw = fixsize(w); int fh = fixsize(h); if (fw != w || fh != h) { @@ -147,8 +171,8 @@ static unsigned int loadFrame(const char *path) { glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vertWrap ? GL_REPEAT : GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.7f); // build mip levels @@ -182,61 +206,221 @@ static unsigned int loadFrame(const char *path) { free(ibuffer); free(buffer); glBindTexture(GL_TEXTURE_2D, 0); - + return texid; } -static HeliAnimation* load(const char *path) { - HeliAnimation *a = calloc(1, sizeof(*a)); - a->path = heliStringCopy(path); +static void unloadTexture(HeliTexture *texture) { + assert(!texture->refcount); + glDeleteTextures(1, &texture->id); +} + + +static HeliTexture* loadTexture(const char *key) { + HeliTexture *texture = calloc(1, sizeof(*texture)); + texture->key = heliStringCopy(key); + int w = 0, h = 0; + unsigned char *pixels = NULL; + if (imageLoad(key+2, &w, &h, &pixels)) { + texture->id = imageToGLTexture(w, h, pixels, key[0] == 'W', key[1] == 'W'); + free(pixels); + } + return texture; +} + + +static HeliTexture *getTexture(const char *key) { + HeliPair *item = heliStringmapGet(&cache, key); + if (!item) item = heliStringmapAdd(&cache, key, loadTexture(key), (HeliFreeCallback)&unloadTexture); + HeliTexture *texture = (HeliTexture*)item->value; + ++texture->refcount; + return texture; +} + + +static void unrefTexture(HeliTexture *texture) { + if (--texture->refcount <= 0) + heliStringmapRemove(&cache, texture->key); +} + + +static void heliAnimationFixPos(Animation animation) { + double maxPos = animation->frames.count - HELI_PRECISION_SQR; + if (!(animation->pos < maxPos)) animation->pos = maxPos; + if (!(animation->pos > 0)) animation->pos = 0; +} + + +Animation createAnimationEmpty() { + Animation animation = calloc(1, sizeof(*animation)); + animation->prev = last; + *(animation->prev ? &animation->prev->next : &first) = last = animation; + + double minFps = worldGetMinFrameRate(); + double maxFps = worldGetMaxFrameRate(); + animation->fps = HELI_DEFAULT_FPS; + if (animation->fps > maxFps) animation->fps = maxFps; + if (animation->fps < minFps) animation->fps = minFps; + animation->loop = TRUE; + + heliObjectRegister(animation, (HeliFreeCallback)&animationDestroy); + return animation; +} + +Animation createAnimationEx(const char* path, int horWrap, int vertWrap) { + Animation animation = createAnimationEmpty(); + char *key = heliStringConcat("CC", path); + if (horWrap) key[0] = 'W'; + if (vertWrap) key[1] = 'W'; - Directory d = openDirectory(path); + Directory d = openDirectory(key + 2); if (d) { int count = directoryGetCount(d); for(int i = 0; i < count; ++i) { - char *p = heliStringConcat3(path, "/", directoryGet(d, i)); - size_t texid = loadFrame(p); - free(p); - if (texid) heliArrayInsert(&a->frames, -1, (void*)texid, &unloadFrame); + const char *file = directoryGet(d, i); + if (heliStringEndsWithLowcase(file, ".png")) { + char *k = heliStringConcat3(key, "/", file); + heliArrayInsert(&animation->frames, -1, getTexture(k), (HeliFreeCallback)&unrefTexture); + free(k); + } } closeDirectory(d); } else { - size_t texid = loadFrame(path); - if (texid) { - heliArrayInsert(&a->frames, -1, (void*)texid, &unloadFrame); - } else { - fprintf(stderr, "helianthus: cannot load animation by path: %s\n", path); - } + heliArrayInsert(&animation->frames, -1, getTexture(key), (HeliFreeCallback)&unrefTexture); } + return animation; +} + +Animation createAnimation(const char *path) + { return createAnimationEx(path, FALSE, FALSE); } + +void animationDestroy(Animation animation) { + *(animation->prev ? &animation->prev->next : &first) = animation->next; + *(animation->next ? &animation->next->prev : &last ) = animation->prev; + heliArrayDestroy(&animation->frames); + heliObjectUnregister(animation); + free(animation); +} + +Animation animationCloneEx(Animation animation, int from, int to) { + Animation a = createAnimationEmpty(); + animationInsertEx(a, 0, animation, from, to); + animationSetFps(a, animationGetFps(animation)); + animationSetPos(a, animationGetPos(animation)); + if (animationIsPlaying(animation)) animationPlay(a); else animationPause(a); return a; } +Animation animationClone(Animation animation) + { return animationCloneEx(animation, 0, animationGetFramesCount(animation)); } -static void unload(HeliAnimation *a) { - assert(!a->refcount); - free(a->path); - heliArrayDestroy(&a->frames); - free(a); +unsigned int animationGetGLTexId(Animation animation) { + if (animationGetFramesCount(animation) <= 0) return 0; + int i = animationGetFrame(animation); + HeliTexture *texture = (HeliTexture*)animation->frames.items[i].value; + return texture->id; } +int animationGetFramesCount(Animation animation) + { return animation->frames.count; } -HeliAnimation* heliAnimationLoad(const char *path) { - HeliPair *item = heliStringmapGet(&cache, path); - if (!item) item = heliStringmapAdd(&cache, path, load(path), (HeliFreeCallback)&unload); - HeliAnimation *a = (HeliAnimation*)item->value; - ++a->refcount; - return a; +void animationInsertEx(Animation animation, int index, Animation other, int start, int count) { + int dcnt = animationGetFramesCount(animation); + int scnt = animationGetFramesCount(other); + int i0 = start; + int i1 = i0 + count; + if (i0 < 0) i0 = 0; + if (i1 > scnt) i1 = scnt; + if (index < 0 || index > dcnt) index = dcnt; + for(int i = i0; i < i1; ++i, ++index) { + HeliTexture *texture = (HeliTexture*)other->frames.items[i].value; + ++texture->refcount; + heliArrayInsert(&animation->frames, index, texture, (HeliFreeCallback)&unrefTexture); + } +} + +void animationInsert(Animation animation, int index, Animation other) + { animationInsertEx(animation, index, other, 0, animationGetFramesCount(other)); } + +void animationRemove(Animation animation, int start, int count) { + int cnt = animationGetFramesCount(animation); + int i0 = start; + int i1 = i0 + count; + if (i0 < 0) i0 = 0; + if (i1 > cnt) i1 = cnt; + for(int i = i1 - 1; i >= i0; --i) + heliArrayRemove(&animation->frames, i); + heliAnimationFixPos(animation); } +void animationClear(Animation animation) + { animationRemove(animation, 0, animationGetFramesCount(animation)); } -void heliAnimationUnref(HeliAnimation *a) { - if (--a->refcount <= 0) - heliStringmapRemove(&cache, a->path); +double animationGetFps(Animation animation) + { return animation->fps; } +void animationSetFps(Animation animation, double fps) { + animation->fps = !(fps > HELI_MIN_FPS) ? HELI_MIN_FPS + : !(fps > HELI_MAX_FPS) ? HELI_MAX_FPS : fps; + } +int animationIsPlaying(Animation animation) + { return animation->playing; } +void animationPlay(Animation animation) + { animation->playing = TRUE; } +void animationPause(Animation animation) + { animation->playing = FALSE; } + +void animationAddTime(Animation animation, double time) { + int cnt = animationGetFramesCount(animation); + if (cnt <= 0) return; + double t = animation->fps * time; + if (animation->loop) { + t /= cnt; t -= floor(t); t *= cnt; + animation->pos += t; + if (animation->pos > cnt) animation->pos -= cnt; + } else { + animation->pos += t; + } + heliAnimationFixPos(animation); +} + +int animationGetLoop(Animation animation) + { return animation->loop; } +void animationSetLoop(Animation animation, int loop) + { animation->loop = loop != FALSE; } + +double animationGetPos(Animation animation) + { return animation->pos; } + +void animationSetPos(Animation animation, double pos) + { animation->pos = pos; heliAnimationFixPos(animation); } -void heliAnimationFinish() - { heliArrayDestroy(&cache); } +int animationGetFrame(Animation animation) { + int cnt = animationGetFramesCount(animation); + int i = floor(animation->pos + HELI_PRECISION); + if (i > cnt) i = cnt; + if (i < 0) i = 0; + return i; +} + +void animationSetFrame(Animation animation, int frame) + { animationSetPos(animation, frame); } + +void animationNextFrame(Animation animation) + { animationAddTime(animation, 1/animationGetFps(animation)); } + + +void heliAnimationUpdate(double dt) { + for(Animation animation = first; animation; animation = animation->next) + if (animationIsPlaying(animation)) + animationAddTime(animation, dt); +} + +void heliAnimationFinish() { + assert(!cache.count); + heliArrayDestroy(&cache); +} diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 0000000..009b420 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,49 @@ +#ifndef HELI_ANIMATION_H +#define HELI_ANIMATION_H + + +#include "common.h" + +typedef struct _Animation *Animation; + + +int imageLoad(const char *path, int *outWidth, int *outHeight, unsigned char **outPixels); +unsigned int imageToGLTexture(int width, int height, const unsigned char *pixels, int horWrap, int vertWrap); + + +Animation createAnimation(const char *path); +Animation createAnimationEx(const char *path, int horWrap, int vertWrap); +Animation createAnimationEmpty(); +void animationDestroy(Animation animation); + +Animation animationClone(Animation animation); +Animation animationCloneEx(Animation animation, int start, int count); + +unsigned int animationGetGLTexId(Animation animation); + +int animationGetFramesCount(Animation animation); +void animationInsert(Animation animation, int index, Animation other); +void animationInsertEx(Animation animation, int index, Animation other, int start, int count); +void animationRemove(Animation animation, int start, int count); +void animationClear(Animation animation); + +double animationGetFps(Animation animation); +void animationSetFps(Animation animation, double fps); + +int animationIsPlaying(Animation animation); +void animationPlay(Animation animation); +void animationPause(Animation animation); + +void animationAddTime(Animation animation, double time); + +int animationGetLoop(Animation animation); +void animationSetLoop(Animation animation, int loop); + +double animationGetPos(Animation animation); +void animationSetPos(Animation animation, double pos); +int animationGetFrame(Animation animation); +void animationSetFrame(Animation animation, int frame); +void animationNextFrame(Animation animation); + +#endif + diff --git a/src/common.c b/src/common.c index ed13547..331af3f 100644 --- a/src/common.c +++ b/src/common.c @@ -93,6 +93,16 @@ char* heliStringCopy(const char *x) { return cp; } +char* heliStringConcat(const char *a, const char *b) { + int la = strlen(a); + int lb = strlen(b); + char *s = malloc(la + lb + 1); + memcpy(s, a, la); + memcpy(s + la, b, lb); + s[la + lb] = 0; + return s; +} + char* heliStringConcat3(const char *a, const char *b, const char *c) { int la = strlen(a); int lb = strlen(b); diff --git a/src/group.c b/src/group.c index f040286..a2acd38 100644 --- a/src/group.c +++ b/src/group.c @@ -197,15 +197,18 @@ void groupSetMirrorYEach(Group group, int mirrorY) { foreachInt(group, mirrorY, &spriteSetMirrorY); } void groupSetTagEach(Group group, int tag) { foreachInt(group, tag, &spriteSetTag); } -void groupSetAnimationEach(Group group, const char *path) - { foreachString(group, path, &spriteSetAnimation); } 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 = groupGetCount(group) - 1; i >= 0 ; --i) + spriteSetAnimation(groupGet(group, i), animation); +} + void groupSetNoAnimationEach(Group group) { - for(int i = 0; i < groupGetCount(group); ++i) + for(int i = groupGetCount(group) - 1; i >= 0 ; --i) spriteSetNoAnimation(groupGet(group, i)); } diff --git a/src/group.h b/src/group.h index 4506168..b618c7c 100644 --- a/src/group.h +++ b/src/group.h @@ -62,7 +62,7 @@ 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 groupSetNoAnimationEach(Group group); void groupSetShapeColorEach(Group group, const char *color); void groupSetTintColorEach(Group group, const char *color); diff --git a/src/private.h b/src/private.h index 31a8459..4f530e1 100644 --- a/src/private.h +++ b/src/private.h @@ -21,6 +21,9 @@ #define HELI_PRECISION 1e-6 #define HELI_PRECISION_SQR 1e-12 +#define HELI_MIN_FPS 1 +#define HELI_MAX_FPS 100 +#define HELI_DEFAULT_FPS 24 // blobs @@ -32,6 +35,7 @@ extern int heliBlobDefaultFontSize asm("heliBlobDefaultFontSize"); // string char* heliStringCopy(const char *x); +char* heliStringConcat(const char *a, const char *b); char* heliStringConcat3(const char *a, const char *b, const char *c); int heliStringEndsWithLowcase(const char *s, const char *tail); void heliLowercase(char *x); @@ -117,14 +121,7 @@ void heliObjectUnregister(void *o); // animation -typedef struct _HeliAnimation { - char *path; - HeliArray frames; - int refcount; -} HeliAnimation; - -HeliAnimation* heliAnimationLoad(const char *path); -void heliAnimationUnref(HeliAnimation *a); +void heliAnimationUpdate(double dt); void heliAnimationFinish(); diff --git a/src/sprite.c b/src/sprite.c index b36257e..c181568 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -5,6 +5,7 @@ #include "world.h" #include "group.h" #include "drawing.h" +#include "animation.h" struct _Sprite { @@ -34,12 +35,9 @@ struct _Sprite { double shapeColor[4]; double tintColor[4]; - int playing; - int frame; - HeliArray groups; - HeliAnimation *animation; + Animation animation; }; static HeliArray sprites; @@ -300,26 +298,11 @@ void spriteSetColliderEx( } } -void spriteSetAnimation(Sprite sprite, const char *path) { - HeliAnimation *prev = sprite->animation; - sprite->animation = heliAnimationLoad(path); - if (prev) heliAnimationUnref(prev); - spriteSetFrame(sprite, sprite->frame); -} - -void spriteSetNoAnimation(Sprite sprite) { - if (sprite->animation) heliAnimationUnref(sprite->animation); - sprite->animation = NULL; -} - -void spritePlay(Sprite sprite) { sprite->playing = TRUE; } -void spritePause(Sprite sprite) { sprite->playing = FALSE; } -void spriteNextFrame(Sprite sprite) { spriteSetFrame(sprite, sprite->frame + 1); } +void spriteSetAnimation(Sprite sprite, Animation animation) + { sprite->animation = animation; } -void spriteSetFrame(Sprite sprite, int frame) { - sprite->frame = frame >= 0 && sprite->animation && sprite->animation->frames.count > 0 - ? frame % sprite->animation->frames.count : 0; -} +void spriteSetNoAnimation(Sprite sprite) + { spriteSetAnimation(sprite, NULL); } void spriteSetShapeColor(Sprite sprite, const char *color) { heliParseColor(color, sprite->shapeColor); } @@ -406,8 +389,7 @@ static void drawSpriteDebug(Sprite s) { } static void drawSprite(Sprite s, double aaBorder) { - unsigned int texid = s->animation - ? (unsigned int)(size_t)heliArrayGetValue(&s->animation->frames, s->frame) : 0u; + unsigned int texid = s->animation ? animationGetGLTexId(s->animation) : 0u; double color[4] = { (texid ? 1.0 : s->shapeColor[0])*s->tintColor[0], @@ -620,7 +602,6 @@ void heliSpriteUpdate(double dt) { s->y += s->vy*dt; if (!s->rotateToDirection) s->rotation += s->rotationSpeed*dt; - if (s->playing) spriteNextFrame(s); } } diff --git a/src/sprite.h b/src/sprite.h index d948bcc..b5497f0 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -3,6 +3,8 @@ #include "common.h" +#include "animation.h" + typedef struct _Sprite *Sprite; @@ -86,12 +88,9 @@ void spriteSetColliderEx( double xOffset, double yOffset, double rotationOffset, double width, double height, double radius); -void spriteSetAnimation(Sprite sprite, const char *path); +void spriteSetAnimation(Sprite sprite, Animation animation); void spriteSetNoAnimation(Sprite sprite); -void spritePlay(Sprite sprite); -void spritePause(Sprite sprite); -void spriteNextFrame(Sprite sprite); -void spriteSetFrame(Sprite sprite, int frame); + void spriteSetShapeColor(Sprite sprite, const char *color); void spriteSetTintColor(Sprite sprite, const char *color); diff --git a/src/world.c b/src/world.c index 84f1f81..f6a0a4c 100644 --- a/src/world.c +++ b/src/world.c @@ -35,9 +35,9 @@ static int height = 512; static int resizable; static char title[1000]; static int titleSize = (int)(sizeof(title)/sizeof(*title)); -static double minFPS = 24; -static double maxFPS = 24; -static double frameTime = 1/24; +static double minFPS = HELI_DEFAULT_FPS; +static double maxFPS = HELI_DEFAULT_FPS; +static double frameTime = 1.0/HELI_DEFAULT_FPS; static HeliArray keyEvents[6]; static int keyEventsCount = (int)(sizeof(keyEvents)/sizeof(*keyEvents)); @@ -157,10 +157,10 @@ double worldGetMinFrameRate() double worldGetMaxFrameRate() { return minFPS; } void worldSetFrameRateEx(double minFrameRate, double maxFrameRate) { - if (!(minFrameRate > 1)) minFrameRate = 1; - if (!(minFrameRate < 100)) minFrameRate = 100; - if (!(maxFrameRate > 1)) maxFrameRate = 1; - if (!(maxFrameRate < 100)) maxFrameRate = 100; + if (!(minFrameRate > HELI_MIN_FPS)) minFrameRate = HELI_MIN_FPS; + if (!(minFrameRate < HELI_MAX_FPS)) minFrameRate = HELI_MAX_FPS; + if (!(maxFrameRate > HELI_MIN_FPS)) maxFrameRate = HELI_MIN_FPS; + if (!(maxFrameRate < HELI_MAX_FPS)) maxFrameRate = HELI_MAX_FPS; if (minFrameRate > maxFrameRate) minFrameRate = maxFrameRate; minFPS = minFrameRate; maxFPS = maxFrameRate; @@ -206,8 +206,8 @@ void messageBox(const char *message) { prevFrameTimeMs = SDL_GetTicks(); } -void askText(const char *question, char *answer, int maxAnswerSize) - { askTextEx(question, answer, maxAnswerSize, FALSE, FALSE); } +int askText(const char *question, char *answer, int maxAnswerSize) + { return askTextEx(question, answer, maxAnswerSize, FALSE, FALSE); } static void resetEvents() { @@ -243,6 +243,7 @@ static void draw() { elapsedTimeUs += encountedTimeUs; ++frameCount; frameTime = firstFrame ? 1/maxFPS : dt; + heliAnimationUpdate(dt); heliSpriteUpdate(dt); } heliSoundUpdate(); @@ -418,7 +419,7 @@ static void handleEvent(SDL_Event *e) { } -void askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password) { +int askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password) { if (maxAnswerSize < 0 || !answer) maxAnswerSize = 0; memset(&dialog, 0, sizeof(dialog)); @@ -442,6 +443,7 @@ void askTextEx(const char *question, char *answer, int maxAnswerSize, int multil } SDL_StopTextInput(); + int success = dialog.success; if (dialog.success && maxAnswerSize > 0) strcpy(answer, dialog.answer); free(dialog.answer); free(dialog.passwordText); @@ -453,6 +455,8 @@ void askTextEx(const char *question, char *answer, int maxAnswerSize, int multil prevFrameTimeMs = SDL_GetTicks(); heliDrawingPrepareFrame(); + + return success; } diff --git a/src/world.h b/src/world.h index 3dcf00e..1b0c93f 100644 --- a/src/world.h +++ b/src/world.h @@ -46,8 +46,8 @@ int mouseIsOver(Sprite sprite); int mousePressedOver(Sprite sprite); void messageBox(const char *message); -void askText(const char *question, char *answer, int maxAnswerSize); -void askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password); +int askText(const char *question, char *answer, int maxAnswerSize); +int askTextEx(const char *question, char *answer, int maxAnswerSize, int multiline, int password); int worldGetSpriteCount(); Sprite worldGetSprite(int i);