#include "Animation.h" #include 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); } }