Last active
December 20, 2022 08:45
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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