From 8535a3b3f277de57e587e65500e0813bf08331d4 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Mar 14 2020 11:09:34 +0000 Subject: second commit --- diff --git a/heliantus/animation.c b/heliantus/animation.c new file mode 100644 index 0000000..3f897d4 --- /dev/null +++ b/heliantus/animation.c @@ -0,0 +1,73 @@ + +#include +#include + +#include "private.h" + + +static HeliArray cache; + +static cairo_status_t read(void *closure, unsigned char *data, unsigned int length) { + return fread(data, length, 1, (FILE*)closure) + ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_READ_ERROR; +} + +static cairo_surface_t* loadFrame(const char *path) { + if (!heliStringEndsWithLowcase(path, ".png")) + return NULL; + FILE *f = g_fopen(path); + if (f) { + cairo_surface_t *frame = cairo_image_surface_create_from_png_stream(&read, f); + fclose(f); + if (!frame) + fprintf(stderr, "helianthus: cannot load PNG content form file: %s", path); + return frame; + } + fprintf(stderr, "helianthus: cannot open image file: %s", path); + return NULL; +} + +static HeliAnimation* load(const char *path) { + HeliAnimation *a = calloc(1, sizeof(*a)); + a->path = heliStringCopy(path); + + GDir *dir = g_dir_open(path, 0, NULL); + if (dir) { + while(TRUE) { + const char* name = g_dir_read_name(dir); + if (!name) break; + char *p = heliStringConcat3(path, "/", name); + cairo_surface_t *frame = loadFrame(p); + free(p); + if (frame) heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy); + } + } else { + cairo_surface_t *frame = loadFrame(path); + if (frame) { + heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy); + } else { + fprintf(stderr, "helianthus: cannot load animation by path: %s", path); + } + } + + return a; +} + +static void unload(HeliAnimation *a) { + assert(!a->refcount); + free(a->path); + heliArrayDestroy(&a->frames); + free(a); +} + +HeliAnimation *heliCreateAnimation(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 heliAnimationUnref(HeliAnimation *a) + { if (--a->refcount <= 0) heliStringmapRemove(&cache, a->path); } + diff --git a/heliantus/array.c b/heliantus/array.c new file mode 100644 index 0000000..b15c1b7 --- /dev/null +++ b/heliantus/array.c @@ -0,0 +1,129 @@ + +#include "private.h" + + +void heliPairInit(HeliPair *p) { + p->key = p->value = NULL; + p->freeKey = p->freeValue = NULL; +} + +void heliPairDestroy(HeliPair *p) { + if (p->key && p->freeKey) p->freeKey(p->key); + if (p->value && p->freeValue) p->freeKey(p->value); + heliPairInit(p); +} + +int heliArrayInit(HeliArray *a) { + a->items = NULL; + a->count = a->allocated = 0; +} + +int heliArrayDestroy(HeliArray *a) { + heliArrayClear(a); + free(a->items); + heliArrayInit(a); +} + +HeliPair* heliArrayGet(HeliArray *a, int i) + { return i >= 0 && i < a->count ? &a->items[i] : NULL; } + +void* heliArrayGetKey(HeliArray *a, int i) { + HeliPair *item = heliArrayGet(a, i); + return item ? item->key : NULL; +} + +void* heliArrayGetValue(HeliArray *a, int i) { + HeliPair *item = heliArrayGet(a, i); + return item ? item->value : NULL; +} + +HeliPair* heliArrayInsertPair(HeliArray *a, int i, void *k, void *v, HeliFreeCallback fk, HeliFreeCallback fv) { + if (i < 0 || i > a->count) + i = a->count; + if (a->allocated < a->count + 1) { + a->allocated += a->allocated/4 + 32; + a->items = realloc(a->items, a->allocated); + memset(&a->items[a->count], 0, (a->allocated - a->count)*sizeof(a->items[0])); + } + if (i < a->count) { + memmove(&a->items[i+1], &a->items[i], (a->count-i)*sizeof(a->items[0])); + memset(&a->items[i], 0, sizeof(a->items[0])); + } + ++a->count; + + HeliPair *item = &a->items[i]; + item->key = k; + item->value = v; + item->freeKey = fk; + item->freeValue = fv; + return item; +} + +HeliPair* heliArrayInsert(HeliArray *a, int i, void *v, HeliFreeCallback fv) + { return heliArrayInsertPair(a, i, NULL, NULL, v, fv); } + +void heliArrayRemove(HeliArray *a, int i) { + if (i < 0 || i >= a->count) return; + heliPairDestroy(&a->items[i]); + memmove(&a->items[i], &a->items[i+1], (a->count-i-1)*sizeof(a->items[0])); + --a->count; + memset(&a->items[a->count], 0, sizeof(a->items[0])); +} + +void heliArrayClear(HeliArray *a) { + while(a->count > 0) + heliArrayRemove(a, a->count-1); +} + +HeliPair* heliStringmapFind(HeliArray *a, const char *k, int *gtOrEqIndex) { + int i0 = 0; + int i1 = a->count - 1; + int cmp = i0 < a->count ? strcmp((char*)a->items[i0].key, k) : -1; + if (cmp >= 0) { + if (gtOrEqIndex) *gtOrEqIndex = i0; + return cmp ? NULL : &a->items[i0]; + } + if (i1 > i0) cmp = strcmp((char*)a->items[i1].key, k); + if (cmp <= 0) { + if (gtOrEqIndex) *gtOrEqIndex = a->count; + return cmp ? NULL : &a->items[i1]; + } + + while(i0 + 1 < i1) { + int i = (i0 + i1)/2; + cmp = strcmp((char*)a->items[i].key, k); + if (cmp == 0) { + if (gtOrEqIndex) *gtOrEqIndex = i; + return &a->items[i]; + } + if (cmp < 0) i0 = i; else i1 = i; + } + if (gtOrEqIndex) *gtOrEqIndex = i1; + return NULL; +} + +HeliPair* heliStringmapGet(HeliArray *a, const char *k) + { return heliStringmapFind(a, k, NULL); } + +HeliPair* heliStringmapAdd(HeliArray *a, const char *k, void *v, HeliFreeCallback fv) { + int i; + HeliPair *item = heliStringmapFind(a, k, &i); + if (item) { + if (item->value && item->freeValue) item->freeValue(item->value); + item->value = v; + item->freeValue = fv; + } else { + item = heliArrayInsertPair(a, i, heliStringCopy(k), v, &free, fv); + } + return item; +} + +int heliStringmapRemove(HeliArray *a, const char *k) { + int i; + if (heliStringmapFind(a, k, &i)) { + heliArrayRemove(a, i); + return TRUE; + } + return FALSE; +} + diff --git a/heliantus/collider.c b/heliantus/collider.c new file mode 100644 index 0000000..500cc28 --- /dev/null +++ b/heliantus/collider.c @@ -0,0 +1,27 @@ + +#include "private.h" + +int heliCheckCollision(HeliCollider *a, HeliCollider *b, double *normX, double *normY) { + // corner with side + // corner with circle + // circle with circle + #warning "TODO: heliCheckCollision: not implemented yet" + return FALSE; +} + +int heliPointCollision(HeliCollider *c, double x, double y) { + x -= c->x; + y -= c->y; + if (c->type == COLLIDER_CIRCLE) { + return x*x + y*y <= c->radius*c->radius; + } else + if (c->type == COLLIDER_RECTANGLE) { + double a = c->rotation*(PI/180); + double sn = sin(a); + double cn = cos(a); + return fabs(x*cn - y*sn) <= c->width*0.5 + && fabs(x*sn + y*cn) <= c->height*0.5; + } + return FALSE; +} + diff --git a/heliantus/common.c b/heliantus/common.c new file mode 100644 index 0000000..fbbb68d --- /dev/null +++ b/heliantus/common.c @@ -0,0 +1,50 @@ + +#include "private.h" + + +cairo_t *heliCairo; + + +int randomNumber(int min, int max) + { return max <= min ? min : rand()%(max - min + 1) + min; } + +double randomFloat() + { return (double)rand()/(double)RAND_MAX; } + + +char* heliStringCopy(const char *x) { + int len = strlen(x) + 1; + char *cp = malloc(len + 1); + memcpy(cp, x, len); + return cp; +} + +char* heliStringConcat3(const char *a, const char *b, const char *c) { + int la = strlen(a); + int lb = strlen(b); + int lc = strlen(c); + char *s = malloc(la + lb + lc + 1); + memcpy(s, a, la); + memcpy(s + la, b, lb); + memcpy(s + la + lb, c, lc); + s[la + lb + lc] = 0; + return s; +} + +int heliStringEndsWithLowcase(const char *s, const char *tail) { + int ls = strlen(s); + int lt = strlen(tail); + if (lt > ls) return FALSE; + for(int i = 0; i < lt; ++i) + if (tolower(s[ls - i]) != tolower(tail[lt - i])) + return FALSE; + return TRUE; +} + +void heliLowercase(char *x) + { while(*x) *x = tolower(*x); } + +void heliParseColor(const char *x, double *color) { + #error +} + diff --git a/heliantus/common.h b/heliantus/common.h index 692b93c..1a25cb9 100644 --- a/heliantus/common.h +++ b/heliantus/common.h @@ -10,6 +10,10 @@ #define FALSE 0 #endif +#ifndef PI +#define PI 3.14159265358979323846 +#endif + int randomNumber(int min, int max); double randomFloat(); diff --git a/heliantus/drawing.h b/heliantus/drawing.h index 7dfff33..9f493f8 100644 --- a/heliantus/drawing.h +++ b/heliantus/drawing.h @@ -4,33 +4,33 @@ #include "common.h" -enum HAlign { +typedef enum _HAlign { HALIGN_LEFT, HALIGN_CENTER, HALIGN_RIGHT -}; +} HAlign; -enum VAlign { +typedef enum _VAlign { VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM -}; +} VAlign; -void background(char *color); -void fill(char *color); +void background(const char *color); +void fill(const char *color); void noFill(); -void stroke(char *color); +void stroke(const char *color); void noStroke(); void strokeWeight(double weight); char* rgb(double r, double g, double b); char* rgba(double r, double g, double b, double a); void rect(double x, double y, double width, double height); void ellipse(double x, double y, double width, double height); -void text(char *text, double x, double y); -void textEx(char *text, double x, double y, double x2, double y2); +void text(const char *text, double x, double y); +void textEx(const char *text, double x, double y, double x2, double y2); void textAlign(HAlign hor, VAlign vert); -void textFont(char *font); +void textFont(const char *font); void textSize(double size); void arc(double x, double y, double w, double h, double start, double stop); void line(double x1, double y1, double x1, double y1); diff --git a/heliantus/group.c b/heliantus/group.c new file mode 100644 index 0000000..b55f676 --- /dev/null +++ b/heliantus/group.c @@ -0,0 +1,203 @@ + +#include "private.h" +#include "group.h" +#include "world.h" + +struct _Group { + HeliArray sprites; +}; + + +Group createGroup() { + Group g = calloc(1, sizeof(*g)); + return g; +} + +Group createEdgesGroupEx(double x1, double y1, double x2, double y2, double borderWidth) { + if (x2 < x1) { double x = x2; x2 = x1; x1 = x; } + if (y2 < y1) { double y = y2; y2 = y1; y1 = y; } + if (borderWidth < 0.1) borderWidth = 0.1; + + double b = borderWidth; + double w = x2 - x1 + b*2; + double h = y2 - y1 + b*2; + x1 -= b; + y1 -= b; + + Group g = createGroup(); + groupAdd(g, createSpriteEx(x1, y1, w, b)); + groupAdd(g, createSpriteEx(x1, y2, w, b)); + groupAdd(g, createSpriteEx(x1, y1, b, h)); + groupAdd(g, createSpriteEx(x2, y1, b, h)); + return g; +} + +Group createEdgesGroup() + { return createEdgesGroupEx(0, 0, worldGetWidth(), worldGetHeight(), 10); } + + +void groupDestroy(Group group) { + heliArrayDestroy(&group->sprites); + free(group); +} + +void groupDestroyEx(Group group, int destroySprites) { + groupClearEx(group, destroySprites); + groupDestroy(group); +} + +void groupAdd(Group group, Sprite sprite) { + if (groupContains(group, sprite)) return; + heliArrayInsert(&group->sprites, -1, sprite, NULL); + heliArrayInsert(heliSpriteGetGroups(sprite), -1, sprite, NULL); +} + +void groupRemove(Group group, Sprite sprite) { + for(int i = group->sprites.count-1; i >= 0; --i) + if (group->sprites.items[i].value == sprite) + heliArrayRemove(&group->sprites, i); + HeliArray *groups = heliSpriteGetGroups(sprite); + for(int i = groups->count-1; i >= 0; --i) + if (groups->items[i].value == group) + heliArrayRemove(groups, i); +} + +void groupClearEx(Group group, int destroySprites) { + while(groupGetCount(group) > 0) { + Sprite s = groupGet(group, 0); + groupRemove(group, s); + if (destroySprites) spriteDestroy(s); + } +} + +void groupClear(Group group) + { groupClearEx(group, FALSE); } +void groupDestroyEach(Group group) + { groupClearEx(group, TRUE); } + +int groupContains(Group group, Sprite sprite) { + for(int i = group->sprites.count-1; i >= 0; --i) + if (group->sprites.items[i].value == sprite) + return TRUE; + return FALSE; +} + +int groupGetCount(Group group) + { return group->sprites.count; } +Sprite groupGet(Group group, int i) + { return (Sprite)heliArrayGetValue(group, i); } + +int groupOverlap(Group group, Sprite sprite) + { return groupCollideEx(group, sprite, TRUE, TRUE, 0); } +int groupCollide(Group group, Sprite sprite, double bounciness) + { return groupCollideEx(group, sprite, FALSE, FALSE, bounciness); } +int groupBounceOff(Group group, Sprite sprite, double bounciness) + { return groupCollideEx(group, sprite, FALSE, TRUE, bounciness); } +int groupPush(Group group, Sprite sprite, double bounciness); + { return groupCollideEx(group, sprite, TRUE, FALSE, bounciness); } +int groupCollideEx(Group group, Sprite sprite, int keepVelocityGroup, int keepVelocitySprite, double bounciness) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteCollideEx(groupGet(group, i), sprite, keepVelocityGroup, keepVelocitySprite, bounciness); +} + +int groupOverlapGroup(Group a, Group b); + { return groupCollideGroupEx(a, b, TRUE, TRUE, 0); } +int groupCollideGroup(Group a, Group b, double bounciness); + { return groupCollideGroupEx(a, b, FALSE, FALSE, bounciness); } +int groupBounceOffGroup(Group group, Group other, double bounciness); + { return groupCollideGroupEx(a, b, FALSE, TRUE, bounciness); } +int groupPushGroup(Group group, Group other, double bounciness); + { return groupCollideGroupEx(a, b, TRUE, FALSE, bounciness); } +int groupCollideGroupEx(Group a, Group b, int keepVelocityA, int keepVelocityB, double bounciness) { + for(int i = 0; i < groupGetCount(b); ++i) + groupCollideEx(a, groupGet(b, i), keepVelocityA, keepVelocityB, bounciness); +} + +double groupGetMinDepth(Group group) { + if (groupGetCount(group) <= 0) return 0; + double md = spriteGetDepth(groupGet(group, 0)); + for(int i = 1; i < groupGetCount(group); ++i) { + double d = spriteGetDepth(groupGet(group, i)); + if (d < md) md = d; + } + return md; +} + +double groupGetMaxDepth(Group group) { + if (groupGetCount(group) <= 0) return 0; + double md = spriteGetDepth(groupGet(group, 0)); + for(int i = 1; i < groupGetCount(group); ++i) { + double d = spriteGetDepth(groupGet(group, i)); + if (d > md) md = d; + } + return md; +} + + +static void foreachInt(Group group, int value, void(*func)(Sprite, int)) + { for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); } +static void foreachDouble(Group group, double value, void(*func)(Sprite, double)) + { for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); } +static void foreachString(Group group, const char *value, void(*func)(Sprite, const char*)) + { for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); } + + +void groupDestroyTimerEach(Group group, double lifetime) + { foreachDouble(group, lifetime, &spriteDestroyTimer); } + +void groupSetVisibleEach(Group group, int visible) + { foreachInt(group, visible, &spriteSetVisible); } +void groupSetWidthEach(Group group, double width) + { foreachDouble(group, width, &spriteSetWidth); } +void groupSetHeightEach(Group group, double height) + { foreachDouble(group, height, &spriteSetHeight); } +void groupSetDepthEach(Group group, double depth) + { foreachDouble(group, depth, &spriteSetDepth); } +void groupSetVelocityXEach(Group group, double x) + { foreachDouble(group, x, &spriteSetVelocityX); } +void groupSetVelocityYEach(Group group, double y) + { foreachDouble(group, y, &spriteSetVelocityY); } +void groupSetRotateToDirectionEach(Group group, int rotateToDirection) + { foreachInt(group, rotateToDirection, &spriteSetRotateToDirection); } +void groupSetRotationEach(Group group, double rotation) + { foreachDouble(group, rotation, &spriteSetRotation); } +void groupSetRotationSpeedEach(Group group, double rotationSpeed) + { foreachDouble(group, rotationSpeed, &spriteSetRotationSpeed); } +void groupSetScaleEach(Group group, double scale) + { foreachDouble(group, scale, &spriteSetScale); } +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 groupSetShapeColorEach(Group group, const char *color) + { foreachString(group, color, &spriteSetShapeColor); } +void groupSetTintColorEach(Group group, const char *color) + { foreachString(group, color, &spriteSetTintColor); } + +void groupPointToEach(Group group, double x, double y) { + for(int i = 0; i < groupGetCount(b); ++i) + spritePointTo(groupGet(group, i), x, y); +} + +void groupSetSpeedAndDirectionEach(Group group, double speed, double angle) { + for(int i = 0; i < groupGetCount(b); ++i) + spriteSetSpeedAndDirection(groupGet(group, i), speed, angle); +} + +void groupSetVelocityEach(Group group, double x, double y) { + for(int i = 0; i < groupGetCount(b); ++i) + spriteSetVelocityXY(groupGet(group, i), x, y); +} + +void groupSetColliderEachEx(Group group, Collider type, double xOffset, double yOffset, + double widthOrRadius, double height, double rotationOffset) +{ + for(int i = 0; i < groupGetCount(b); ++i) + spriteSetColliderEx(groupGet(group, i), type, xOffset, yOffset, + widthOrRadius, height, rotationOffset); +} + +void groupSetColliderEach(Group group, Collider type, double xOffset, double yOffset) + { groupSetColliderEachEx(group, type, xOffset, yOffset, -1, -1, 0); } diff --git a/heliantus/group.h b/heliantus/group.h index fa8a405..241577c 100644 --- a/heliantus/group.h +++ b/heliantus/group.h @@ -9,35 +9,44 @@ typedef struct _Group *Group; Group createGroup(); -void gorupDestroy(Group group); +Group createEdgesGroup(); +Group createEdgesGroupEx(double x1, double y1, double x2, double y2, double borderWidth); + +void groupDestroy(Group group); +void groupDestroyEx(Group group, int destroySprites); void groupAdd(Group group, Sprite sprite); void groupRemove(Group group, Sprite sprite); void groupClear(Group group); +void groupClearEx(Group group, int destroySprites); int groupContains(Group group, Sprite sprite); int groupGetCount(Group group); Sprite groupGet(Group group, int i); -int groupGetColliderId(Group group); - -int groupIsTouching(Group group, int colliderId); +int groupOverlap(Group group, Sprite sprite); +int groupCollide(Group group, Sprite sprite, double bounciness); +int groupBounceOff(Group group, Sprite sprite, double bounciness); +int groupPush(Group group, Sprite sprite, double bounciness); +int groupCollideEx(Group group, Sprite sprite, int keepVelocityGroup, int keepVelocitySprite, double bounciness); -int groupBounce(Group group, int colliderId); -int groupBounceOff(Group group, int colliderId); -int groupCollide(Group group, int colliderId); -int groupDisplace(Group group, int colliderId); -int groupOverlap(Group group, int colliderId); +int groupOverlapGroup(Group a, Group b); +int groupCollideGroup(Group a, Group b, double bounciness); +int groupBounceOffGroup(Group group, Group other, double bounciness); +int groupPushGroup(Group group, Group other, double bounciness); +int groupCollideGroupEx(Group a, Group b, int keepVelocityA, int keepVelocityB, double bounciness); double groupGetMinDepth(Group group); double groupGetMaxDepth(Group group); void groupDestroyEach(Group group); +void groupDestroyTimerEach(Group group, double lifetime); + void groupSetVisibleEach(Group group, int visible); void groupSetWidthEach(Group group, double width); void groupSetHeightEach(Group group, double height); void groupSetDepthEach(Group group, double depth); -void groupSetVelocityXEach(Group group, double velocityX); -void groupSetVelocityYEach(Group group, double velocityY); +void groupSetVelocityXEach(Group group, double x); +void groupSetVelocityYEach(Group group, double y); void groupSetVelocityEach(Group group, double x, double y); void groupSetLifetimeEach(Group group, double lifetime); void groupSetRotateToDirectionEach(Group group, int rotateToDirection); @@ -48,8 +57,9 @@ void groupSetMirrorXEach(Group group, int mirrorX); void groupSetMirrorYEach(Group group, int mirrorY); void groupPointToEach(Group group, double x, double y); void groupSetSpeedAndDirectionEach(Group group, double speed, double angle); -void groupSetAnimationEach(Group group, char *label); -void groupSetColorEach(Group group, char *color); +void groupSetAnimationEach(Group group, const char *path); +void groupSetShapeColorEach(Group group, const char *color); +void groupSetTintColorEach(Group group, const char *color); void groupSetColliderEach(Group group, Collider type, double xOffset, double yOffset); void groupSetColliderEachEx(Group group, Collider type, double xOffset, double yOffset, double widthOrRadius, double height, double rotationOffset); diff --git a/heliantus/private.c b/heliantus/private.c deleted file mode 100644 index 5175c9a..0000000 --- a/heliantus/private.c +++ /dev/null @@ -1,114 +0,0 @@ - -#include "private.h" - - - -static char* heliStringCopy(char *x) { - int len = strlen(x) + 1; - char *cp = malloc(len + 1); - memcpy(cp, x, len); - return cp; -} - -static void heliLowercase(char *x) - { while(*x) *x = tolower(*x); } - - - -int heliArrayInit(HeliArray *a) { - a->items = NULL; - a->count = a->allocated = 0; -} - -void heliArrayClear(HeliArray *a, int freeData) { - if (freeData) - for(int i = 0; i < a->count; ++i) - free(a->items[i]); - a->count = 0; -} - -int heliArrayDestroy(HeliArray *a, int freeData) { - heliArrayClear(a, freeData); - free(a->items); - a->items = NULL; - a->count = a->allocated = 0; -} - -void* heliArrayGet(HeliArray *a, int i) - { return i >= 0 && i < a->count ? a->items[i] : NULL; } - -void heliArrayInsert(HeliArray *a, int i, void *item) { - if (i < 0 || i > a->count) - i = a->count; - if (a->allocated < a->count + 1) { - a->allocated += a->allocated/4 + 32; - a->items = realloc(a->items, a->allocated); - } - if (i < a->count) - memmove(&a->items[i+1], &a->items[i], (a->count-i)*sizeof(a->items[0])); - ++a->count; - a->items[i] = item; -} - -void heliArrayAppend(HeliArray *a, void *data) - { heliArrayInsert(a, a->count, data); } - -void heliArrayRemove(HeliArray *a, int i, int freeData) { - if (i < 0 || i >= a->count) - return; - if (freeData) free(a->items[i]); - memmove(&a->items[i], &a->items[i+1], (a->count-i-1)*sizeof(a->items[0])); - --a->count; -} - -int heliStringsetFind(HeliArray *a, char *x, int *gtOrEqIndex) { - for(int i = 0; i < a->count; ++i) { - int cmp = strcmp((char*)a->items[i], x); - if (cmp < 0) continue; - if (gtOrEqIndex) *gtOrEqIndex = i; - return cmp == 0; - } - if (gtOrEqIndex) *gtOrEqIndex = a->count; - return 0; -} - -int heliStringsetGet(HeliArray *a, char *x) - { return heliStringsetFind(a, x, NULL); } - -void heliStringsetAdd(HeliArray *a, char *x) { - int i; - if (heliStringsetFind(a, x, &i)) return; - heliArrayInsert(a, i, heliStringCopy(x)); -} - -void heliStringsetRemove(HeliArray *a, char *x) { - int i; - if (!heliStringsetFind(a, x, &i)) return; - heliArrayRemove(a, i, TRUE); -} - - - -int heliCheckCollision(HeliCollider *a, HeliCollider *b, double *normX, double *normY) { - // corner with side - // corner with circle - // circle with circle - #warning "TODO: heliCheckCollision: not implemented yet" - return FALSE; -} - -int heliPointCollision(HeliCollider *c, double x, double y) { - x -= c->x; - y -= c->y; - if (c->type == COLLIDER_CIRCLE) { - return x*x + y*y <= c->radius*c->radius; - } else - if (c->type == COLLIDER_RECTANGLE) { - double a = c->rotation/180.0*M_PI; - double sn = sin(a); - double cn = cos(a); - return fabs(x*cn - y*sn) <= c->width*0.5 - && fabs(x*sn + y*cn) <= c->height*0.5; - } - return FALSE; -} diff --git a/heliantus/private.h b/heliantus/private.h index 62734c3..4e98887 100644 --- a/heliantus/private.h +++ b/heliantus/private.h @@ -2,44 +2,75 @@ #include #include #include +#include #include #include +#include + #include "common.h" #include "sprite.h" -// sprite +// globals -void heliUpdateSprites(); +extern cairo_t *heliCairo; // string -char* heliStringCopy(char *x); +char* heliStringCopy(const char *x); +char* heliStringConcat3(const char *a, const char *b, const char *c); +int heliStringEndsWithLowcase(const char *s, const char *tail); void heliLowercase(char *x); - +void heliParseColor(const char *x, double *color); // pointer array +typedef void (*HeliFreeCallback)(void*); + +typedef struct _HeliPair { + void *key; + void *value; + HeliFreeCallback freeKey; + HeliFreeCallback freeValue; +} HeliPair; + typedef struct _HeliArray { - void **items; + HeliPair *items; int count; int allocated; } HeliArray; +void heliPairInit(HeliPair *p); +void heliPairDestroy(HeliPair *p); + int heliArrayInit(HeliArray *a); -void heliArrayClear(HeliArray *a, int freeData); -int heliArrayDestroy(HeliArray *a, int freeData); -void* heliArrayGet(HeliArray *a, int i); -void heliArrayInsert(HeliArray *a, int i, void *item); -void heliArrayAppend(HeliArray *a, void *item); -void heliArrayRemove(HeliArray *a, int i, int freeData); +void heliArrayClear(HeliArray *a); +int heliArrayDestroy(HeliArray *a); +HeliPair* heliArrayGet(HeliArray *a, int i); +void* heliArrayGetKey(HeliArray *a, int i); +void* heliArrayGetValue(HeliArray *a, int i); +HeliPair* heliArrayInsert(HeliArray *a, int i, void *v, HeliFreeCallback fv); +HeliPair* heliArrayInsertPair(HeliArray *a, int i, void *k, void *v, HeliFreeCallback fk, HeliFreeCallback fv); +void heliArrayRemove(HeliArray *a, int i); + +HeliPair* heliStringmapFind(HeliArray *a, const char *k, int *gtOrEqIndex); +HeliPair* heliStringmapGet(HeliArray *a, const char *k); +HeliPair* heliStringmapAdd(HeliArray *a, const char *k, void *v, HeliFreeCallback fv); +int heliStringmapRemove(HeliArray *a, const char *k); -int heliStringsetFind(HeliArray *a, char *x, int *gtOrEqIndex); -int heliStringsetGet(HeliArray *a, char *x); -void heliStringsetAdd(HeliArray *a, char *x); -void heliStringsetRemove(HeliArray *a, char *x); + +// animation + +typedef struct _HeliAnimation { + char *path; + HeliArray frames; + int refcount; +} HeliAnimation; + +HeliAnimation *heliCreateAnimation(const char *path); +void heliAnimationUnref(HeliAnimation *a); // collider @@ -57,3 +88,9 @@ typedef struct _HeliCollider { int heliCheckCollision(HeliCollider *a, HeliCollider *b, double *normX, double *normY); int heliPointCollision(HeliCollider *c, double x, double y); + +// sprite + +void heliUpdateSprites(double dt); +HeliArray* heliSpriteGetGroups(Sprite sprite); + diff --git a/heliantus/sprite.c b/heliantus/sprite.c index 69c7dd9..af8a7fa 100644 --- a/heliantus/sprite.c +++ b/heliantus/sprite.c @@ -1,8 +1,11 @@ +#include + #include "private.h" #include "sprite.h" #include "world.h" +#include "group.h" struct _Sprite { double x; @@ -17,7 +20,6 @@ struct _Sprite { double rotationSpeed; HeliCollider collider; - int colliderId; double bounciness; int rotateToDirection; @@ -25,42 +27,326 @@ struct _Sprite { int mirrorY; double depth; double lifeTime; + int visible; int debug; - double color[4]; - double tint[4]; + double shapeColor[4]; + double tintColor[4]; int playing; int frame; - HeliArray images; + HeliArray groups; + + HeliAnimation *animation; }; static HeliArray sprites; -static HeliArray sortedSprites; +static HeliArray spritesSorted; static void prepareCollider(Sprite sprite, HeliCollider *collider) { - #error + collider->type = sprite->collider.type; + collider->x = sprite->collider.x + sprite->x; + collider->y = sprite->collider.y + sprite->y; + collider->width = sprite->collider.width >= 0 ? sprite->collider.width : sprite->width; + collider->height = sprite->collider.height >= 0 ? sprite->collider.height : sprite->height; + collider->radius = sprite->collider.radius >= 0 ? sprite->collider.radius : collider->width; + collider->rotation = sprite->collider.rotation + sprite->rotation; +} + + + +Sprite createSpriteEx(double x, double y, double width, double height) { + Sprite s = calloc(1, sizeof(*s)); + s->x = x; + s->y = y; + s->width = width; + s->height = height; + + s->scale = 1; + s->collider.type = COLLIDER_RECTANGLE; + s->collider.width = s->collider.height = s->collider.radius = -1; + + s->mirrorX = 1; + s->mirrorY = 1; + s->lifeTime = -1; + s->visible = TRUE; + + s->shapeColor[0] = s->shapeColor[1] = s->shapeColor[2] = 0.5; + s->shapeColor[3] = 1; + s->tintColor[0] = s->tintColor[1] = s->tintColor[2] = s->tintColor[3] = 1; + + heliArrayInsert(&sprites, -1, s, NULL); + heliArrayInsert(&spritesSorted, -1, s, NULL); +} + +Sprite createSprite(double x, double y) + { return createSpriteEx(x, y, 100, 100); } + +void spriteDestroy(Sprite sprite) { + while(sprite->groups.count > 0) + groupRemove((Group)sprite->groups.items[0].value, sprite); + for(int i = 0; i < sprites.count; ++i) + if (sprites.items[i].value == sprite) + { heliArrayRemove(&sprites, i); break; } + for(int i = 0; i < spritesSorted.count; ++i) + if (spritesSorted.items[i].value == sprite) + { heliArrayRemove(&spritesSorted, i); break; } + if (sprite->animation) + heliAnimationUnref(sprite->animation); + free(sprite); +} + +void spriteDestroyTimer(Sprite sprite, double lifeTime) { + if (lifeTime <= 0) { spriteDestroy(sprite); return; } + sprite->lifeTime = lifeTime; +} + +double spriteGetX(Sprite sprite) { return sprite->x; } +void spriteSetX(Sprite sprite, double x) { sprite->x = x; } + +double spriteGetY(Sprite sprite) { return sprite->y; } +void spriteSetY(Sprite sprite, double y) { sprite->y = y; } + +double spriteGetVelocityX(Sprite sprite) { return sprite->vx; } +void spriteSetVelocityX(Sprite sprite, double x) + { spriteSetVelocityXY(sprite, x, sprite->vy); } + +double spriteGetVelocityY(Sprite sprite) { return sprite->vy; } +void spriteSetVelocityY(Sprite sprite, double y) + { spriteSetVelocityXY(sprite, sprite->vx, y); } + +double spriteGetScale(Sprite sprite) { return sprite->scale; } +void spriteSetScale(Sprite sprite, double scale) { sprite->scale = scale; } + +double spriteGetWidth(Sprite sprite) { return sprite->width; } +void spriteSetWidth(Sprite sprite, double width) + { sprite->width = width > 0 ? width : 0; } + +double spriteGetHeight(Sprite sprite) { return sprite->height; } +void spriteSetHeight(Sprite sprite, double height) + { sprite->height = height > 0 ? height : 0; } + +int spriteGetRotateToDirection(Sprite sprite) { return sprite->rotateToDirection; } +void spriteSetRotateToDirection(Sprite sprite, int rotateToDirection) { + if (rotateToDirection) { + sprite->rotateToDirection = TRUE; + sprite->rotation = spriteGetDirection(sprite); + } else { + sprite->rotateToDirection = FALSE; + } +} + +double spriteGetRotation(Sprite sprite) { return sprite->rotation; } +void spriteSetRotation(Sprite sprite, double rotation) + { if (!sprite->rotateToDirection) sprite->rotation = rotation; } + +double spriteGetRotationSpeed(Sprite sprite) { return sprite->rotationSpeed; } +void spriteSetRotationSpeed(Sprite sprite, double rotationSpeed) + { sprite->rotationSpeed = rotationSpeed; } + +int spriteGetMirrorX(Sprite sprite) { return sprite->mirrorX; } +void spriteSetMirrorX(Sprite sprite, int mirrorX) + { sprite->mirrorX = mirrorX < 0 ? -1 : 1; } + +int spriteGetMirrorY(Sprite sprite) { return sprite->mirrorY; } +void spriteSetMirrorY(Sprite sprite, int mirrorY); + { sprite->mirrorY = mirrorY < 0 ? -1 : 1; } + +double spriteGetDepth(Sprite sprite) { return sprite->depth; } +void spriteSetDepth(Sprite sprite, double depth) + { sprite->depth = depth; } + +int spriteGetVisible(Sprite sprite) { return sprite->visible; } +void spriteSetVisible(Sprite sprite, int visible) + { sprite->visible = visible != FALSE; } + +int spriteGetDebug(Sprite sprite) { return sprite->debug; } +void spriteSetDebug(Sprite sprite, int debug) + { sprite->debug = debug != FALSE; } + +int spriteOverlap(Sprite a, Sprite b) + { return spriteCollideEx(a, b, TRUE, TRUE, 0); } +int spriteCollide(Sprite a, Sprite b, double bounciness) + { return spriteCollideEx(a, b, FALSE, FALSE, bounciness); } +int spriteBounceOff(Sprite sprite, Sprite other, double bounciness) + { return spriteCollideEx(sprite, other, FALSE, TRUE, bounciness); } +int spritePush(Sprite sprite, Sprite other, double bounciness) + { return spriteCollideEx(sprite, other, TRUE, FALSE, bounciness); } + +int spriteCollideEx(Sprite a, Sprite b, int keepVelocityA, int keepVelocityB, double bounciness) { + #warning "TODO: spriteCollision: not implemented yet" + return FALSE; +} + + +double spriteGetBounciness(Sprite sprite) { return sprite->bounciness; } +void spriteSetBounciness(Sprite sprite, double bounciness) + { sprite->bounciness = bounciness > 0 ? bounciness : 0; } + +void spriteSetColliderEx(Sprite sprite, Collider type, double xOffset, double yOffset, + double widthOrRadius, double height, double rotationOffset) +{ + sprite->collider.type = type; + sprite->collider.x = xOffset; + sprite->collider.y = yOffset; + sprite->collider.width = sprite->collider.radius = widthOrRadius; + sprite->collider.height = height; + sprite->collider.rotation = rotationOffset; +} + +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); + heliAnimationUnref(prev); + spriteSetFrame(sprite, sprite->frame); +} + +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; } +void spriteSetShapeColor(Sprite sprite, const char *color) + { heliParseColor(color, sprite->shapeColor); } +void spriteSetTintColor(Sprite sprite, const char *color) + { heliParseColor(color, sprite->tintColor); } + +void spriteSetVelocityXY(Sprite sprite, double x, double y) { + sprite->vx = x; + sprite->vy = y; + if (sprite->rotateToDirection) + sprite->rotation = spriteGetDirection(sprite); +} + +void spriteSetSpeedAndDirection(Sprite sprite, double speed, double angle) { + double a = angle*(PI/180); + spriteSetVelocityXY(sprite, cos(a)*speed, sin(a)*speed); +} + +double spriteGetSpeed(Sprite sprite) + { return sqrt(sprite->vx*sprite->vx + sprite->vy*sprite->vy); } +double spriteGetDirection(Sprite sprite) { + return fabs(sprite->vx) > 1e-6 || fabs(sprite->vy) > 1e-6 + ? atan2(sprite->vy, sprite->vx)*(180/PI) : 0; +} +void spritePointTo(Sprite sprite, double x, double y) + { spriteSetRotation( sprite, atan2(y - sprite->y, x - sprite->x)*(PI/180) ); } + +double spriteGetScaledWidth(Sprite sprite) + { return sprite->width * sprite->scale; } +double spriteGetScaledHeight(Sprite sprite) + { return sprite->height * sprite->scale; } + int worldGetSpriteCount() { return sprites.count; } Sprite worldGetSprite(int i) { - { return (Sprite)heliArrayGet(&sprites, i); } + { return (Sprite)heliArrayGetValue(&sprites, i); } -void drawSprites() { - // copy - for(int i = 0; i < sprites.count; ++i) - heliArrayAppend(&sortedSprites, sprites.items[i]); + +static void drawSpriteDebug(cairo_t *cr, Sprite s) { + cairo_save(cr); + cairo_translate(cr, s->x, s->y); + cairo_scale(cr, s->scale*s->mirrorX, s->scale*s->mirrorY); + + double hw = s->width*0.5; + double hh = s->height*0.5; + + cairo_set_source_rgba(cr, 0, 0, 0, 0.75); + cairo_move_to(cr, -hw, -hh); + cairo_line_to(cr, hw, -hh); + cairo_line_to(cr, hw, hh); + cairo_line_to(cr, -hw, hh); + cairo_close_path(cr); + cairo_stroke(); + + cairo_move_to(cr, -hw*0.25, 0); + cairo_line_to(cr, hw*0.25, 0); + cairo_move_to(cr, 0, -hh*0.25); + cairo_line_to(cr, 0, hh*0.25); + cairo_stroke(); + + char buf[1024]; + snprintf(buf, sizeof(buf)-1, "%f", s->depth); + + double s1 = hw*0.5; + double s2 = hh*0.5; + cairo_set_font_size(cr, s1 < s2 ? s1 : s2); + cairo_move_to(cr, -hw*0.9, -hh*0.9); + cairo_show_text(cr, buf); + + cairo_restore(cr); +} + +static void drawSprite(cairo_t *cr, Sprite s) { + cairo_save(cr); + cairo_translate(cr, s->x, s->y); + cairo_scale(cr, s->scale*s->mirrorX, s->scale*s->mirrorY); + + double hw = s->width*0.5; + double hh = s->height*0.5; + + cairo_surface_t *frame = s->animation + ? (cairo_surface_t*)heliArrayGetValue(&s->animation->frames, s->frame) : NULL; + + cairo_push_group(cr); + + if (frame) { + // image + double ihw = cairo_image_surface_get_width(frame)*0.5; + double ihh = cairo_image_surface_get_height(frame)*0.5; + if (ihw > 1e-6 && ihh > 1e-6) { + cairo_save(cr); + cairo_scale(cr, hw/ihw, hh/ihh); + cairo_set_source_surface(cr, frame, -ihw, -ihh); + cairo_restore(cr); + } + } else { + // rectangle + cairo_set_source_rgba(cr, s->shapeColor[0], s->shapeColor[1], s->shapeColor[2], s->shapeColor[3]); + cairo_move_to(cr, -hw, -hh); + cairo_line_to(cr, hw, -hh); + cairo_line_to(cr, hw, hh); + cairo_line_to(cr, -hw, hh); + cairo_close_path(cr); + cairo_fill(); + } + + // tint + cairo_save(cr); + cairo_set_source_rgba(cr, s->tintColor[0], s->tintColor[1], s->tintColor[2], s->tintColor[3]); + cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY); + cairo_move_to(cr, -hw, -hh); + cairo_line_to(cr, hw, -hh); + cairo_line_to(cr, hw, hh); + cairo_line_to(cr, -hw, hh); + cairo_close_path(cr); + cairo_fill(); + cairo_restore(cr); + cairo_pop_group_to_source(cr); + cairo_paint(); + + cairo_restore(cr); +} + +void drawSprites() { // sort int found = TRUE; while(found) { found = FALSE; + // forward for(int i = 1; i < sortedSprites.count; ++i) { if (((Sprite)sortedSprites.items[i-1])->depth < ((Sprite)sortedSprites.items[i])->depth) { void *x = sortedSprites.items[i]; @@ -69,16 +355,30 @@ void drawSprites() { found = TRUE; } } + if (!found) break; + // backward + found = FALSE; + for(int i = sortedSprites.count - 1; i > 0; --i) { + if (((Sprite)sortedSprites.items[i-1])->depth < ((Sprite)sortedSprites.items[i])->depth) { + void *x = sortedSprites.items[i]; + sortedSprites.items[i] = sortedSprites.items[i-1]; + sortedSprites.items[i-1] = x; + } + found = TRUE; + } } // draw - for(int i = 1; i < sortedSprites.count; ++i) { - Sprite s = (Sprite)(sortedSprites.items[i]); - #error + if (heliCairo) { + for(int i = 0; i < sortedSprites.count; ++i) { + Sprite s = (Sprite)(sortedSprites.items[i]); + if (s->visible) drawSprite(heliCairo, s); + } + for(int i = 0; i < sortedSprites.count; ++i) { + Sprite s = (Sprite)(sortedSprites.items[i]); + if (s->debug) drawSpriteDebug(heliCairo, s); + } } - - // clear - heliArrayClear(sortedSprites, FALSE); } int mouseIsOver(Sprite sprite) { @@ -88,22 +388,25 @@ int mouseIsOver(Sprite sprite) { } void heliUpdateSprites(double dt) { - for(int i = 1; i < sprites.count; ++i) { - Sprite s = (Sprite)(sprites.items[i]); + // auto-remove + for(int i = sprites.count - 1; i > 0; --i) { + if (s->lifeTime >= 0) { + s->lifeTime -= dt; + if (s->lifeTime <= 1e-5) + spriteDestroy(s); + } + } + + // update + for(int i = 0; i < sprites.count; ++i) { + Sprite s = (Sprite)sprites.items[i].value; s->x += s->vx*dt; s->y += s->vy*dt; - s->rotation += s->rotationSpeed*dt; - if (s->playing) { - ++s->frame; - if (s->frames.count <= 0) { - s->frame = 0; - } else - if (s->frame > s->frames.count) { - s->frame %= s->frames.count; - } else - if (s->frame < 0) { - s->frame = 0; - } - } + if (!s->rotateToDirection) + s->rotation += s->rotationSpeed*dt; + if (s->playing) spriteNextFrame(s); } } + +HeliArray* heliSpriteGetGroups(Sprite sprite) + { return &sprite->groups; } diff --git a/heliantus/sprite.h b/heliantus/sprite.h index 8b8e45f..aa5f28c 100644 --- a/heliantus/sprite.h +++ b/heliantus/sprite.h @@ -16,6 +16,7 @@ Sprite createSprite(double x, double y); Sprite createSpriteEx(double x, double y, double width, double height); void spriteDestroy(Sprite sprite); +void spriteDestroyTimer(Sprite sprite, double lifetime); double spriteGetX(Sprite sprite); void spriteSetX(Sprite sprite, double x); @@ -56,21 +57,17 @@ void spriteSetMirrorY(Sprite sprite, int mirrorY); double spriteGetDepth(Sprite sprite); void spriteSetDepth(Sprite sprite, double depth); -double spriteGetLifeTime(Sprite sprite); -void spriteSetLifeTime(Sprite sprite, double lifeTime); +int spriteGetVisible(Sprite sprite); +void spriteSetVisible(Sprite sprite, int visible); int spriteGetDebug(Sprite sprite); void spriteSetDebug(Sprite sprite, int debug); -int spriteGetColliderId(Sprite sprite); - -int spriteIsTouching(Sprite sprite, int colliderId); - -int spriteBounce(Sprite sprite, int colliderId); -int spriteBounceOff(Sprite sprite, int colliderId); -int spriteCollide(Sprite sprite, int colliderId); -int spriteDisplace(Sprite sprite, int colliderId); -int spriteOverlap(Sprite sprite, int colliderId); +int spriteOverlap(Sprite a, Sprite b); +int spriteCollide(Sprite a, Sprite b, double bounciness); +int spriteBounceOff(Sprite sprite, Sprite other, double bounciness); +int spritePush(Sprite sprite, Sprite other, double bounciness); +int spriteCollideEx(Sprite a, Sprite b, int keepVelocityA, int keepVelocityB, double bounciness); double spriteGetBounciness(Sprite sprite); void spriteSetBounciness(Sprite sprite, double bounciness); @@ -79,13 +76,13 @@ 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, char *label); +void spriteSetAnimation(Sprite sprite, const char *path); void spritePlay(Sprite sprite); void spritePause(Sprite sprite); void spriteNextFrame(Sprite sprite); void spriteSetFrame(Sprite sprite, int frame); -void spriteSetShapeColor(Sprite sprite, char *color); -void spriteSetTint(Sprite sprite, char *color); +void spriteSetShapeColor(Sprite sprite, const char *color); +void spriteSetTintColor(Sprite sprite, const char *color); void spriteSetVelocityXY(Sprite sprite, double x, double y); void spriteSetSpeedAndDirection(Sprite sprite, double speed, double angle); @@ -97,7 +94,4 @@ double spriteGetScaledWidth(Sprite sprite); double spriteGetScaledHeight(Sprite sprite); -void createEdgeSprites(); - - #endif diff --git a/heliantus/world.c b/heliantus/world.c index d9908d2..14b766c 100644 --- a/heliantus/world.c +++ b/heliantus/world.c @@ -8,9 +8,6 @@ #include "world.h" -cairo_t *heliCairo; - - static GtkWidget *window; static int started; @@ -51,36 +48,36 @@ static int buttonsCount = (int)(sizeof(buttonNames)/sizeof(*buttonNames)); -void playSound(char *path, int loop) { +void playSound(const char *path, int loop) { #warning "TODO: playSound: not implemented yet" } -void stopSound(char *path) { +void stopSound(const char *path) { #warning "TODO: stopSound: not implemented yet" } -int keyDown(char *code) - { return heliStringsetGet(&keysPressed, code); } -int keyWentDown(char *code); - { return heliStringsetGet(&keysPressedInFrame, code); } -int keyWentUp(char *code); - { return heliStringsetGet(&keysReleasedInFrame, code); } +int keyDown(const char *code) + { return heliStringmapGet(&keysPressed, code) != NULL; } +int keyWentDown(const char *code); + { return heliStringmapGet(&keysPressedInFrame, code) != NULL; } +int keyWentUp(const char *code); + { return heliStringmapGet(&keysReleasedInFrame, code) != NULL; } int mouseDidMove() { return mouseMovedInFrame; } -int mouseDown(char *code) - { return heliStringsetGet(&buttonsPressed, code); } -int mouseWentDown(char *code) - { return heliStringsetGet(&buttonsPressedInFrame, code); } -int mouseWentUp(char *code) - { return heliStringsetGet(&buttonsReleasedInFrame, code); } +int mouseDown(const char *code) + { return heliStringmapGet(&buttonsPressed, code) != NULL; } +int mouseWentDown(const char *code) + { return heliStringmapGet(&buttonsPressedInFrame, code) != NULL; } +int mouseWentUp(const char *code) + { return heliStringmapGet(&buttonsReleasedInFrame, code) != NULL; } double mouseX() { return _mouseX; } double mouseY() { return _mouseY; } int mousePressedOver(Sprite sprite) - { return buttonsPressed.count && int mouseIsOver(sprite); } + { return buttonsPressed.count && mouseIsOver(sprite); } int worldGetWidth() { return width; } @@ -167,10 +164,10 @@ static gboolean draw(GtkWidget *widget G_GNUC_UNUSED, cairo_t *cr, gpointer data startTime = currentTime = newTime; if (initCallback) initCallback(); if (drawCallback) drawCallback(); - heliArrayClear(&keysPressedInFrame, TRUE); - heliArrayClear(&keysReleasedInFrame, TRUE); - heliArrayClear(&buttonsPressedInFrame, TRUE); - heliArrayClear(&buttonsReleasedInFrame, TRUE); + heliArrayClear(&keysPressedInFrame); + heliArrayClear(&keysReleasedInFrame); + heliArrayClear(&buttonsPressedInFrame); + heliArrayClear(&buttonsReleasedInFrame); ++frameCount; } else { double dt = 1/frameRate; @@ -180,10 +177,10 @@ static gboolean draw(GtkWidget *widget G_GNUC_UNUSED, cairo_t *cr, gpointer data ++frameCount; heliUpdateSprites(dt); if (drawCallback) drawCallback(); - heliArrayClear(&keysPressedInFrame, TRUE); - heliArrayClear(&keysReleasedInFrame, TRUE); - heliArrayClear(&buttonsPressedInFrame, TRUE); - heliArrayClear(&buttonsReleasedInFrame, TRUE); + heliArrayClear(&keysPressedInFrame); + heliArrayClear(&keysReleasedInFrame); + heliArrayClear(&buttonsPressedInFrame); + heliArrayClear(&buttonsReleasedInFrame); } } @@ -199,22 +196,22 @@ static gboolean handleEvent(GtkWidget *widget G_GNUC_UNUSED, GdkEvent *event, gp case GDK_KEY_PRESS: keyname = heliStringCopy( gdk_keyval_name(event->key.keyval) ); heliLowercase(keyname); - heliStringsetAdd(&keysPressed, keyname); - heliStringsetAdd(&keysPressedInFrame, keyname); + heliStringmapAdd(&keysPressed, keyname, NULL, NULL); + heliStringmapAdd(&keysPressedInFrame, keyname, NULL, NULL); free(keyname); return TRUE; case GDK_KEY_RELEASE: keyname = heliStringCopy( gdk_keyval_name(event->key.keyval) ); heliLowercase(keyname); - heliStringsetRemove(&keysPressed, keyname); - heliStringsetAdd(&keysReleasedInFrame, keyname); + heliStringmapRemove(&keysPressed, keyname); + heliStringmapAdd(&keysReleasedInFrame, keyname, NULL, NULL); free(keyname); return TRUE; case GDK_BUTTON_PRESS: button = event->button.button; if (button >= 0 && button < buttonsCount) { - heliStringsetAdd(&buttonsPressed, buttonNames[button]); - heliStringsetAdd(&buttonsPressedInFrame, buttonNames[button]); + heliStringmapAdd(&buttonsPressed, buttonNames[button], NULL, NULL); + heliStringmapAdd(&buttonsPressedInFrame, buttonNames[button], NULL, NULL); } _mouseX = event->button.x; _mouseY = event->button.y; @@ -222,8 +219,8 @@ static gboolean handleEvent(GtkWidget *widget G_GNUC_UNUSED, GdkEvent *event, gp case GDK_BUTTON_RELEASE: button = event->button.button; if (button >= 0 && button < buttonsCount) { - heliStringsetRemove(&buttonsPressed, buttonNames[button]); - heliStringsetAdd(&buttonsReleasedInFrame, buttonNames[button]); + heliStringmapRemove(&buttonsPressed, buttonNames[button]); + heliStringmapAdd(&buttonsReleasedInFrame, buttonNames[button], NULL, NULL); } _mouseX = event->button.x; _mouseY = event->button.y; @@ -271,13 +268,13 @@ void worldRun() { while(worldGetSpriteCount()) { spriteDestroy(worldGetSprite(0)); } - heliArrayDestroy(&keysPressed, TRUE); - heliArrayDestroy(&keysPressed, TRUE); - heliArrayDestroy(&keysPressedInFrame, TRUE); - heliArrayDestroy(&keysReleasedInFrame, TRUE); - heliArrayDestroy(&buttonsPressed, TRUE); - heliArrayDestroy(&buttonsPressedInFrame, TRUE); - heliArrayDestroy(&buttonsReleasedInFrame, TRUE); + heliArrayDestroy(&keysPressed); + heliArrayDestroy(&keysPressed); + heliArrayDestroy(&keysPressedInFrame); + heliArrayDestroy(&keysReleasedInFrame); + heliArrayDestroy(&buttonsPressed); + heliArrayDestroy(&buttonsPressedInFrame); + heliArrayDestroy(&buttonsReleasedInFrame); started = FALSE; } diff --git a/heliantus/world.h b/heliantus/world.h index 1500d83..8faff8b 100644 --- a/heliantus/world.h +++ b/heliantus/world.h @@ -11,17 +11,17 @@ typedef void (*Callback)(); void drawSprites(); -void playSound(char *path, int loop); -void stopSound(char *path); +void playSound(const char *path, int loop); +void stopSound(const char *path); -int keyDown(char *code); -int keyWentDown(char *code); -int keyWentUp(char *code); +int keyDown(const char *code); +int keyWentDown(const char *code); +int keyWentUp(const char *code); int mouseDidMove(); -int mouseDown(char *code); -int mouseWentDown(char *code); -int mouseWentUp(char *code); +int mouseDown(const char *code); +int mouseWentDown(const char *code); +int mouseWentUp(const char *code); double mouseX(); double mouseY();