diff options
| author | Syndamia <kamen@syndamia.com> | 2026-03-15 12:23:21 +0200 |
|---|---|---|
| committer | Syndamia <kamen@syndamia.com> | 2026-03-15 12:23:21 +0200 |
| commit | 2202e87c466803eeaddd974006aa9950d8e0d067 (patch) | |
| tree | 55cac9843e5789ac6ff29345ecd4fc44775c6b31 /Animation.c | |
| parent | 47e28b44615b9b068776f61b8741ea8692461c1d (diff) | |
| download | ppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.tar ppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.tar.gz ppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.zip | |
Diffstat (limited to 'Animation.c')
| -rw-r--r-- | Animation.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/Animation.c b/Animation.c new file mode 100644 index 0000000..3ce79dc --- /dev/null +++ b/Animation.c @@ -0,0 +1,110 @@ +#include "Animation.h" +#include <stdlib.h> + +struct AnimationEventNode { + AnimationEventNode* next; + + u32 startFrame; + u32 endFrame; + PixelRenderer renderCallback; + void* privateData; +}; + +AnimationEventNode* +AnimationEventNode_new(u32 startFrame, u32 endFrame, PixelRenderer renderCallback, void* privateData) { + AnimationEventNode* aen = (AnimationEventNode*)malloc(sizeof(AnimationEventNode)); + aen->next = NULL; + aen->startFrame = startFrame; + aen->endFrame = endFrame; + aen->renderCallback = renderCallback; + aen->privateData = privateData; + + return aen; +} + +Animation +Animation_new(u32 width, u32 height, u32 frameCount) { + return (Animation){ + .width = width, + .height = height, + .frameCount = frameCount, + .duplicateFrames = 0, + .frameBuffer = RGBImage_new(width, height), + .events = NULL, + }; +} + +void +Animation_free(Animation anim) { + RGBImage_free(anim.frameBuffer); + while (anim.events != NULL) { + AnimationEventNode* toFree = anim.events; + anim.events = anim.events->next; + free(toFree); + } +} + +void +Animation_delete(Animation* anim) { + Animation_free(*anim); + anim->width = anim->height = anim->frameCount = 0; + RGBImage_delete(&anim->frameBuffer); +} + +void +Animation_pushEvent(Animation* anim, u32 startFrame, u32 endFrame, PixelRenderer renderer, void* privateData) { + if (anim->events == NULL) { + anim->events = AnimationEventNode_new(startFrame, endFrame, renderer, privateData); + return; + } + + AnimationEventNode* prevNode = NULL, *currNode = anim->events; + while (currNode != NULL) { + if (startFrame < currNode->startFrame) { + prevNode->next = AnimationEventNode_new(startFrame, endFrame, renderer, privateData); + prevNode->next->next = currNode; + return; + } + + prevNode = currNode; + currNode = currNode->next; + } + + prevNode->next = AnimationEventNode_new(startFrame, endFrame, renderer, privateData); +} + +void +Animation_render(Animation* anim) { + for (int currFrame = 0; currFrame < anim->frameCount; ++currFrame) { + + if (anim->events != NULL) + for (i32 r = 0; r < anim->frameBuffer.width; ++r) + for (i32 c = 0; c < anim->frameBuffer.height; ++c) { + for (AnimationEventNode* aen = anim->events; aen != NULL && aen->startFrame <= currFrame; aen = aen->next) { + ARGB* pixel = RGBImage_at(anim->frameBuffer, r, c); + ARGB newPixel = aen->renderCallback(anim, currFrame, *pixel, r, c, aen->privateData); + ARGB_merge(pixel, newPixel); + } + + AnimationEventNode* prevNode = NULL, *currNode = anim->events; + while (currNode != NULL && currNode->startFrame <= currFrame) { + if (currNode->endFrame <= currFrame) { + if (prevNode != NULL) + prevNode->next = currNode->next; + else + anim->events = NULL; + free(currNode); + } + else { + prevNode = currNode; + currNode = currNode->next; + } + } + } + + ppm6_write(stdout, anim->frameBuffer); + + for (u32 duplicates = 0; duplicates < anim->duplicateFrames; ++duplicates) + ppm6_write(stdout, anim->frameBuffer); + } +} |
