summaryrefslogtreecommitdiff
path: root/Animation.c
diff options
context:
space:
mode:
authorSyndamia <kamen@syndamia.com>2026-03-15 12:23:21 +0200
committerSyndamia <kamen@syndamia.com>2026-03-15 12:23:21 +0200
commit2202e87c466803eeaddd974006aa9950d8e0d067 (patch)
tree55cac9843e5789ac6ff29345ecd4fc44775c6b31 /Animation.c
parent47e28b44615b9b068776f61b8741ea8692461c1d (diff)
downloadppm_graphics-master.tar
ppm_graphics-master.tar.gz
ppm_graphics-master.zip
feat!: Split into separate filesHEADmaster
Diffstat (limited to 'Animation.c')
-rw-r--r--Animation.c110
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);
+ }
+}