Skip to content

Instantly share code, notes, and snippets.

@jmcd
Last active December 20, 2022 08:45
Show Gist options
  • Save jmcd/2ad1cf826e1b9c9c3d1d389a9dff1ab7 to your computer and use it in GitHub Desktop.
Save jmcd/2ad1cf826e1b9c9c3d1d389a9dff1ab7 to your computer and use it in GitHub Desktop.
A demo of an animation system for SDL. Sequencing function-pointers that change the values of structs representing the model that gets rendered.
#include <stdio.h>
#include <SDL2/SDL.h>
#define WINDOW_WIDTH 512
#define FPS 60
typedef struct ZRect ZRect;
typedef struct ZColor {
Uint8 r,g,b,a;
} ZColor;
typedef struct ZPoint {
int x,y;
} ZPoint;
typedef struct ZSize {
int w,h;
} ZSize;
typedef void (*ZRectMutator)(ZRect *rect, int value);
typedef struct ZAnim {
ZRect *rect;
ZRectMutator mutator;
int durationFrameCount;
int positionFrameCount;
int from;
int to;
} ZAnim;
typedef struct ZAnimSeq {
ZAnim* anims;
int animCount;
int runCount;
int animIndex;
} ZAnimSeq;
typedef struct ZRect {
struct ZPoint origin;
struct ZSize size;
struct ZColor fillColor;
} ZRect;
void ZRectSetOriginX(ZRect *rect, int value) {
rect->origin.x = value;
}
void ZRectSetOriginY(ZRect *rect, int value) {
rect->origin.y = value;
}
void ZRectSetSizeW(ZRect *rect, int value) {
rect->size.w = value;
}
void ZRectSetSizeH(ZRect *rect, int value) {
rect->size.h = value;
}
ZColor ZColorMake(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
ZColor c;
c.r = r;
c.g = g;
c.b = b;
c.a = a;
return c;
}
ZSize ZSizeMake(int w, int h) {
ZSize s;
s.w = w;
s.h = h;
return s;
}
ZPoint ZPointMake(int x, int y) {
ZPoint p;
p.x = x;
p.y = y;
return p;
}
void ZRectInit(ZRect *r, int x, int y, int w, int h, ZColor *fillColor) {
r->size = ZSizeMake(w, h);
r->origin = ZPointMake(x, y);
r->fillColor.r = fillColor->r;
r->fillColor.g = fillColor->g;
r->fillColor.b = fillColor->b;
r->fillColor.a = fillColor->a;
}
void ZAnimInit(ZAnim *a, ZRect *r, int durationFrameCount, int from, int to, ZRectMutator mutator) {
a->rect = r;
a->durationFrameCount = durationFrameCount;
a->positionFrameCount = 0;
a->from = from;
a->to = to;
a->mutator = mutator;
}
void ZAnimReverse(ZAnim *src, ZAnim *dest) {
dest->rect = src->rect;
dest->durationFrameCount = src->durationFrameCount;
dest->positionFrameCount = 0;
dest->from = src->to;
dest->to = src->from;
dest->mutator = src->mutator;
}
void ZAnimSeqInit(ZAnimSeq *as, ZAnim *anims, int animCount, int runCount) {
as->anims = anims;
as->animCount = animCount;
as->runCount = runCount;
as->animIndex = 0;
}
void ZAnimSeqInitWithRepeatingAnim(ZAnimSeq *seq, ZRect *rect, int durationFrameCount, int from, int to, ZRectMutator mutator) {
int animCount = 2;
ZAnim* anims = malloc(sizeof(ZAnim) * animCount); // memory leak
ZAnimInit(anims, rect, durationFrameCount, from, to, mutator);
ZAnimReverse(anims, anims+1);
ZAnimSeqInit(seq, anims, animCount, -1);
}
void renderFrame(SDL_Renderer* renderer, ZRect *rects, int rectCount) {
for (int i = 0; i < rectCount; i++) {
ZRect *r = rects + i;
SDL_Rect sdlRect;
sdlRect.x = r->origin.x;
sdlRect.y = r->origin.y;
sdlRect.w = r->size.w;
sdlRect.h = r->size.h;
SDL_SetRenderDrawColor(renderer, r->fillColor.r, r->fillColor.g, r->fillColor.b, r->fillColor.a);
SDL_RenderFillRect(renderer, &sdlRect);
}
}
void update(ZAnimSeq *animSeqs, int animSeqCount) {
for (int i = 0; i < animSeqCount; i++) {
ZAnimSeq *as = animSeqs + i;
if (as->runCount == 0) { continue; }
ZAnim *a = as->anims + as->animIndex;
float pct = a->positionFrameCount/(float)a->durationFrameCount;
if (pct > 1) {
as->animIndex = (as->animIndex + 1) % as->animCount;
a = as->anims + as->animIndex;
if (as->animIndex == 0) {
as->runCount--;
}
if (as->runCount != 0) {
a->positionFrameCount = 0;
pct = 0;
}
}
if (pct <= 1) {
int totalDisplacement = a->to - a->from;
int currentDisplacement = totalDisplacement * pct;
int currentValue = a->from + currentDisplacement;
(*(a->mutator))(a->rect, currentValue);
a->positionFrameCount++;
}
}
}
int main(int argc, const char * argv[]) {
ZColor yellow = ZColorMake(255, 255, 0, 255);
ZColor red = ZColorMake(255, 0, 0, 255);
int rectCount = 2;
ZRect *rects = malloc(sizeof(ZRect)*rectCount);
ZRectInit(rects, 10, 10, 50, 50, &yellow);
ZRectInit(rects+1, 100, 100, 50, 50, &red);
int seqCount = 5;
ZAnimSeq *seqs = malloc(sizeof(ZAnimSeq)*seqCount);
ZAnimSeqInitWithRepeatingAnim(seqs, rects, 60, 10, 110, ZRectSetOriginX);
ZAnimSeqInitWithRepeatingAnim(seqs+1, rects, 600, 10, 400, ZRectSetOriginY);
ZAnimSeqInitWithRepeatingAnim(seqs+2, rects+1, 600, 100, 300, ZRectSetOriginX);
ZAnimSeqInitWithRepeatingAnim(seqs+3, rects+1, 60, 50, 100, ZRectSetSizeW);
ZAnimSeqInitWithRepeatingAnim(seqs+4, rects+1, 60, 50, 100, ZRectSetSizeH);
SDL_Event event;
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
Uint32 waittime = 1000.0f/FPS;
Uint32 framestarttime = 0;
Sint32 delaytime;
while(1)
{
if (SDL_PollEvent(&event) && event.type == SDL_QUIT) {
break;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
update(seqs, seqCount);
renderFrame(renderer, rects, rectCount);
SDL_RenderPresent(renderer);
delaytime = waittime - (SDL_GetTicks() - framestarttime);
if(delaytime > 0) {
SDL_Delay((Uint32)delaytime);
}
framestarttime = SDL_GetTicks();
}
free(seqs);
free(rects);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment