From 2202e87c466803eeaddd974006aa9950d8e0d067 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 15 Mar 2026 12:23:21 +0200 Subject: feat!: Split into separate files --- Animation.c | 110 +++++++++++ Animation.h | 29 +++ AnimationInterpolate.c | 42 +++++ AnimationInterpolate.h | 22 +++ AnimationMove.c | 32 ++++ AnimationMove.h | 30 +++ AnimationObject.c | 55 ++++++ AnimationObject.h | 40 ++++ RGBImage.c | 76 ++++++++ RGBImage.h | 35 ++++ global.h | 14 ++ graphics.c | 484 ++++--------------------------------------------- 12 files changed, 521 insertions(+), 448 deletions(-) create mode 100644 Animation.c create mode 100644 Animation.h create mode 100644 AnimationInterpolate.c create mode 100644 AnimationInterpolate.h create mode 100644 AnimationMove.c create mode 100644 AnimationMove.h create mode 100644 AnimationObject.c create mode 100644 AnimationObject.h create mode 100644 RGBImage.c create mode 100644 RGBImage.h create mode 100644 global.h 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 + +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); + } +} diff --git a/Animation.h b/Animation.h new file mode 100644 index 0000000..96fa765 --- /dev/null +++ b/Animation.h @@ -0,0 +1,29 @@ +#ifndef _ANIMATION +#define _ANIMATION + +#include "RGBImage.h" + +struct AnimationEventNode; +typedef struct AnimationEventNode AnimationEventNode; + +typedef struct Animation { + u32 width; + u32 height; + u32 frameCount; + u32 duplicateFrames; + + RGBImage frameBuffer; + AnimationEventNode* events; +} Animation; + +typedef ARGB (*PixelRenderer)(const Animation* anim, u32 currentFrame, ARGB pixel, i32 row, i32 col, void* priv); + +AnimationEventNode* AnimationEventNode_new(u32 startFrame, u32 endFrame, PixelRenderer renderCallback, void* privateData); +Animation Animation_new(u32 width, u32 height, u32 frameCount); +void Animation_free(Animation anim); +void Animation_delete(Animation* anim); + +void Animation_pushEvent(Animation* anim, u32 startFrame, u32 endFrame, PixelRenderer renderer, void* privateData); +void Animation_render(Animation* anim); + +#endif /* _ANIMATION */ diff --git a/AnimationInterpolate.c b/AnimationInterpolate.c new file mode 100644 index 0000000..2ff4a8b --- /dev/null +++ b/AnimationInterpolate.c @@ -0,0 +1,42 @@ +#include "AnimationInterpolate.h" +#include "AnimationObject.h" + +#define NUM_INTERPOLATE(a, b, perc) (a * (1.0 - (perc)) + b * (perc)) + +byte4 +colorInterpolate(byte4 ina, byte4 inb, double percentage) { + ARGB a, b; + ARGB_set(&a, ina); + ARGB_set(&b, inb); + + a.a = NUM_INTERPOLATE(a.a, b.a, percentage); + a.r = NUM_INTERPOLATE(a.r, b.r, percentage); + a.g = NUM_INTERPOLATE(a.g, b.g, percentage); + a.b = NUM_INTERPOLATE(a.b, b.b, percentage); + + return a.a << 24 | a.r << 16 | a.g << 8 | a.b; +} + +ARGB +A_Interpolate(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct A_Interpolate in = *(struct A_Interpolate*)priv; + + double perc = (double)(frameIndex - in.startFrame) / (in.endFrame - in.startFrame); + if (perc < 0.0) perc = 0.0; + if (perc > 1.0) perc = 1.0; + + in.interpolate(in.value, in.initialState, in.finalState, perc); + + return in.callback(anim, frameIndex, pixel, r, c, in.priv); +} + +void +AO_LineInterpolate(void* valueLine, const void* initialLine, const void* finalLine, double percentage) { + struct AO_Line* value = valueLine; + const struct AO_Line* initial = initialLine, *final = finalLine; + value->a = NUM_INTERPOLATE(initial->a, final->a, percentage); + value->b = NUM_INTERPOLATE(initial->b, final->b, percentage); + value->c = NUM_INTERPOLATE(initial->c, final->c, percentage); + value->width = NUM_INTERPOLATE(initial->width, final->width, percentage); + value->color = colorInterpolate(initial->color, final->color, percentage); +} diff --git a/AnimationInterpolate.h b/AnimationInterpolate.h new file mode 100644 index 0000000..e9fcd57 --- /dev/null +++ b/AnimationInterpolate.h @@ -0,0 +1,22 @@ +#ifndef _ANIMATION_INTERPOLATE +#define _ANIMATION_INTERPOLATE + +#include "Animation.h" + +struct A_Interpolate { + PixelRenderer callback; + void* priv; + + u32 startFrame; + u32 endFrame; + void* value; + void* initialState; + void* finalState; + void (*interpolate)(void* value, const void* initialState, const void* finalState, double percentage); +}; + +ARGB A_Interpolate(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +void AO_LineInterpolate(void* valueLine, const void* initialLine, const void* finalLine, double percentage); + +#endif /* _ANIMATION_INTERPOLATE */ diff --git a/AnimationMove.c b/AnimationMove.c new file mode 100644 index 0000000..487d220 --- /dev/null +++ b/AnimationMove.c @@ -0,0 +1,32 @@ +#include "AnimationMove.h" +#include + +ARGB +AM_MoveLinear(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AM_MoveLinear ml = *(struct AM_MoveLinear*)priv; + + r = (r - ml.startRow - (i32)(frameIndex * ml.dRow)); + c = (c - ml.startCol - (i32)(frameIndex * ml.dCol)); + + if (ml.wrapCoordinates == true) { + r %= anim->width; + c %= anim->height; + } + + return ml.callback(anim, frameIndex, pixel, r, c, ml.priv); +} + +ARGB +AM_MoveSpin(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AM_MoveSpin ms = *(struct AM_MoveSpin*)priv; + + double radius = sqrt(r * r + c * c); + double phi = atan2(c, r); + + phi += ms.theta * frameIndex; + + r = (ms.centerRow + (i32)(radius * cos(phi))); + c = (ms.centerCol + (i32)(radius * sin(phi))); + + return ms.callback(anim, frameIndex, pixel, r, c, ms.priv); +} diff --git a/AnimationMove.h b/AnimationMove.h new file mode 100644 index 0000000..4516934 --- /dev/null +++ b/AnimationMove.h @@ -0,0 +1,30 @@ +#ifndef _ANIMATION_MOVE +#define _ANIMATION_MOVE + +#include "Animation.h" + +struct AM_MoveLinear { + PixelRenderer callback; + void* priv; + + i32 startRow; + i32 startCol; + float dRow; + float dCol; + bool wrapCoordinates; +}; + +ARGB AM_MoveLinear(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +struct AM_MoveSpin { + PixelRenderer callback; + void* priv; + + float theta; + i32 centerRow; + i32 centerCol; +}; + +ARGB AM_MoveSpin(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +#endif /* _ANIMATION_MOVE */ diff --git a/AnimationObject.c b/AnimationObject.c new file mode 100644 index 0000000..af3798b --- /dev/null +++ b/AnimationObject.c @@ -0,0 +1,55 @@ +#include "AnimationObject.h" +#include + +ARGB +AO_CheckerPattern(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AO_CheckerPattern chp = *(struct AO_CheckerPattern*)priv; + + r /= chp.squareSize; + c /= chp.squareSize; + + if ((r + c) % 2 == 0) { + ARGB_set(&pixel, 0xFF000000); + } + else { + ARGB_set(&pixel, 0xFFFF00FF); + } + + return pixel; +} + +ARGB +AO_Square(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AO_SquareSettings* set = (struct AO_SquareSettings*)priv; + + if (0 <= r && r <= set->width && 0 <= c && c <= set->height) { + ARGB_set(&pixel, set->color); + } + + return pixel; +} + +ARGB +AO_Image(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AO_Image img = *(struct AO_Image*)priv; + + if (img.noRepeat == true && + (c < 0 || img.img.width * img.zoom <= c || + r < 0 || img.img.height * img.zoom <= r)) + { + return pixel; + } + + return *RGBImage_at(*(RGBImage*)priv, r / img.zoom, c / img.zoom); +} + +ARGB +AO_Line(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { + struct AO_Line l = *(struct AO_Line*)priv; + + if (fabs(l.a * c + l.b * r + l.c) / sqrt(l.a * l.a + l.b * l.b) < l.width) { + ARGB_set(&pixel, l.color); + } + + return pixel; +} diff --git a/AnimationObject.h b/AnimationObject.h new file mode 100644 index 0000000..cec9268 --- /dev/null +++ b/AnimationObject.h @@ -0,0 +1,40 @@ +#ifndef _ANIMATION_OBJECT +#define _ANIMATION_OBJECT + +#include "Animation.h" + +struct AO_CheckerPattern { + u32 squareSize; + byte4 colorA; + byte4 colorB; +}; + +ARGB AO_CheckerPattern(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +struct AO_SquareSettings { + u32 width; + u32 height; + byte4 color; +}; + +ARGB AO_Square(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +struct AO_Image { + RGBImage img; + double zoom; + bool noRepeat; +}; + +ARGB AO_Image(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +struct AO_Line { + double a; + double b; + double c; + double width; + byte4 color; +}; + +ARGB AO_Line(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv); + +#endif /* _ANIMATION_OBJECT */ diff --git a/RGBImage.c b/RGBImage.c new file mode 100644 index 0000000..2fe37ba --- /dev/null +++ b/RGBImage.c @@ -0,0 +1,76 @@ +#include "RGBImage.h" +#include +#include +#include + +void +ARGB_set(ARGB* rgb, byte4 color) { + rgb->a = (0xFF000000 & color) >> 24; + rgb->r = (0x00FF0000 & color) >> 16; + rgb->g = (0x0000FF00 & color) >> 8; + rgb->b = (0x000000FF & color); +} + +void +ARGB_merge(ARGB* bottom, ARGB top) { + bottom->a = 255; + double perc = top.a / 255.0; + + bottom->r = (bottom->r * (1.0 - perc)) + (top.r * perc); + bottom->g = (bottom->g * (1.0 - perc)) + (top.g * perc); + bottom->b = (bottom->b * (1.0 - perc)) + (top.b * perc); +} + +RGBImage +RGBImage_new(u32 width, u32 height) { + return (RGBImage){ + .width = width, + .height = height, + .img = malloc(sizeof(ARGB) * width * height) + }; +} + +void +RGBImage_free(RGBImage img) { + free(img.img); +} + +void +RGBImage_delete(RGBImage* img) { + RGBImage_free(*img); + img->width = img->height = 0; + img->img = NULL; +} + +ARGB* +RGBImage_at(RGBImage img, int row, int col) { + return img.img + (row % img.height) * img.width + col % img.width; +} + +int +ppm6_write(FILE* f, RGBImage img) { + fprintf(f, "P6\n%d %d\n255\n", img.width, img.height); + size_t size = img.width * img.height; + for (size_t i = 0; i < size; ++i) { + fputc(img.img[i].r, f); + fputc(img.img[i].g, f); + fputc(img.img[i].b, f); + } + return fflush(f); +} + +RGBImage +ppm_read(FILE* f) { + u32 type, width, height, colors; + fscanf(f, "P%d\n%d %d\n%d\n", &type, &width, &height, &colors); + + RGBImage img = RGBImage_new(width, height); + ARGB* pixel = img.img; + for (size_t i = img.width * img.height; i > 0; --i, ++pixel) { + if (type == 3) { + pixel->a = 0xFF; + fscanf(f, "%d %d %d ", &pixel->r, &pixel->g, &pixel->b); + } + } + return img; +} diff --git a/RGBImage.h b/RGBImage.h new file mode 100644 index 0000000..ba32785 --- /dev/null +++ b/RGBImage.h @@ -0,0 +1,35 @@ +#ifndef _RGBIMAGE +#define _RGBIMAGE + +#include "global.h" +#include + +typedef uint8_t byte; +typedef uint16_t byte2; +typedef uint32_t byte4; + +typedef struct ARGB { + byte a; + byte r; + byte g; + byte b; +} ARGB; + +void ARGB_set(ARGB* rgb, byte4 color); +void ARGB_merge(ARGB* bottom, ARGB top); + +typedef struct RGBImage { + u32 width; + u32 height; + ARGB* img; +} RGBImage; + +RGBImage RGBImage_new(u32 width, u32 height); +void RGBImage_free(RGBImage img); +void RGBImage_delete(RGBImage* img); +ARGB* RGBImage_at(RGBImage img, int row, int col); + +int ppm6_write(FILE* f, RGBImage img); +RGBImage ppm_read(FILE* f); + +#endif /* _RGBIMAGE */ diff --git a/global.h b/global.h new file mode 100644 index 0000000..9b322a9 --- /dev/null +++ b/global.h @@ -0,0 +1,14 @@ +#ifndef _GLOBAL +#define _GLOBAL + +#include + +typedef uint8_t bool; +#define false 0 +#define true 1 + +typedef int32_t i32; +typedef uint32_t u32; + + +#endif /* _GLOBAL */ diff --git a/graphics.c b/graphics.c index 499bd6c..b752cef 100644 --- a/graphics.c +++ b/graphics.c @@ -1,524 +1,112 @@ -/* gcc -std=c99 graphics.c -lm && ./a.out | mpv --no-correct-pts --container-fps-override=30 - - * gcc -std=c99 graphics.c -lm && ./a.out | ffmpeg -r 30 -i - output.mp4 +/* gcc -std=c99 *.c -lm && ./a.out | mpv --no-correct-pts --container-fps-override=30 - + * gcc -std=c99 *.c -lm && ./a.out | ffmpeg -r 30 -i - output.mp4 */ +#include "Animation.h" +#include "AnimationObject.h" +#include "AnimationMove.h" +#include "AnimationInterpolate.h" #include -#include -#include -#include -#include - -inline int -OK(int x) { - return x == 0; -} - -typedef uint8_t bool; -#define false 0 -#define true 1 - -typedef int32_t i32; -typedef uint32_t u32; - -////RGBImage//// - -typedef uint8_t byte; -typedef uint16_t byte2; -typedef uint32_t byte4; - -typedef struct ARGB { - byte a; - byte r; - byte g; - byte b; -} ARGB; - -void -ARGB_set(ARGB* rgb, byte4 color) { - rgb->a = (0xFF000000 & color) >> 24; - rgb->r = (0x00FF0000 & color) >> 16; - rgb->g = (0x0000FF00 & color) >> 8; - rgb->b = (0x000000FF & color); -} - -void -ARGB_merge(ARGB* bottom, ARGB top) { - bottom->a = 255; - double perc = top.a / 255.0; - - bottom->r = (bottom->r * (1.0 - perc)) + (top.r * perc); - bottom->g = (bottom->g * (1.0 - perc)) + (top.g * perc); - bottom->b = (bottom->b * (1.0 - perc)) + (top.b * perc); -} - -typedef struct RGBImage { - u32 width; - u32 height; - ARGB* img; -} RGBImage; - -RGBImage -RGBImage_new(u32 width, u32 height) { - return (RGBImage){ - .width = width, - .height = height, - .img = malloc(sizeof(ARGB) * width * height) - }; -} - -void -RGBImage_free(RGBImage img) { - free(img.img); -} - -void -RGBImage_delete(RGBImage* img) { - RGBImage_free(*img); - img->width = img->height = 0; - img->img = NULL; -} - -ARGB* -RGBImage_at(RGBImage img, int row, int col) { - return img.img + (row % img.height) * img.width + col % img.width; -} - -int -ppm6_write(FILE* f, RGBImage img) { - fprintf(f, "P6\n%d %d\n255\n", img.width, img.height); - size_t size = img.width * img.height; - for (size_t i = 0; i < size; ++i) { - fputc(img.img[i].r, f); - fputc(img.img[i].g, f); - fputc(img.img[i].b, f); - } - return fflush(f); -} - -RGBImage -ppm_read(FILE* f) { - u32 type, width, height, colors; - fscanf(f, "P%d\n%d %d\n%d\n", &type, &width, &height, &colors); - - RGBImage img = RGBImage_new(width, height); - ARGB* pixel = img.img; - for (size_t i = img.width * img.height; i > 0; --i, ++pixel) { - if (type == 3) { - pixel->a = 0xFF; - fscanf(f, "%d %d %d ", &pixel->r, &pixel->g, &pixel->b); - } - } - return img; -} - -////Animation//// - -struct AnimationEventNode; -typedef struct AnimationEventNode AnimationEventNode; - -typedef struct Animation { - u32 width; - u32 height; - u32 frameCount; - u32 duplicateFrames; - - RGBImage frameBuffer; - AnimationEventNode* events; -} Animation; - -typedef ARGB (*PixelRenderer)(const Animation* anim, u32 currentFrame, ARGB pixel, i32 row, i32 col, void* priv); - -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); - } -} - -////main//// - -struct CheckerPattern { - u32 squareSize; - byte4 colorA; - byte4 colorB; -}; - -ARGB -CheckerPattern(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct CheckerPattern chp = *(struct CheckerPattern*)priv; - - r /= chp.squareSize; - c /= chp.squareSize; - - if ((r + c) % 2 == 0) { - ARGB_set(&pixel, 0xFF000000); - } - else { - ARGB_set(&pixel, 0xFFFF00FF); - } - - return pixel; -} - -struct SquareSettings { - u32 width; - u32 height; - byte4 color; -}; - -ARGB -Square(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct SquareSettings* set = (struct SquareSettings*)priv; - - if (0 <= r && r <= set->width && 0 <= c && c <= set->height) { - ARGB_set(&pixel, set->color); - } - - return pixel; -} - -struct Image { - RGBImage img; - double zoom; - bool noRepeat; -}; - -ARGB -Image(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct Image img = *(struct Image*)priv; - - if (img.noRepeat == true && - (c < 0 || img.img.width * img.zoom <= c || - r < 0 || img.img.height * img.zoom <= r)) - { - return pixel; - } - - return *RGBImage_at(*(RGBImage*)priv, r / img.zoom, c / img.zoom); -} - -struct Line { - double a; - double b; - double c; - double width; - byte4 color; -}; - -ARGB -Line(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct Line l = *(struct Line*)priv; - - if (fabs(l.a * c + l.b * r + l.c) / sqrt(l.a * l.a + l.b * l.b) < l.width) { - ARGB_set(&pixel, l.color); - } - - return pixel; -} - -#define NUM_INTERPOLATE(a, b, perc) (a * (1.0 - (perc)) + b * (perc)) - -byte4 -colorInterpolate(byte4 ina, byte4 inb, double percentage) { - ARGB a, b; - ARGB_set(&a, ina); - ARGB_set(&b, inb); - - a.a = NUM_INTERPOLATE(a.a, b.a, percentage); - a.r = NUM_INTERPOLATE(a.r, b.r, percentage); - a.g = NUM_INTERPOLATE(a.g, b.g, percentage); - a.b = NUM_INTERPOLATE(a.b, b.b, percentage); - - return a.a << 24 | a.r << 16 | a.g << 8 | a.b; -} - -void -LineInterpolate(void* valueLine, const void* initialLine, const void* finalLine, double percentage) { - struct Line* value = valueLine; - const struct Line* initial = initialLine, *final = finalLine; - value->a = NUM_INTERPOLATE(initial->a, final->a, percentage); - value->b = NUM_INTERPOLATE(initial->b, final->b, percentage); - value->c = NUM_INTERPOLATE(initial->c, final->c, percentage); - value->width = NUM_INTERPOLATE(initial->width, final->width, percentage); - value->color = colorInterpolate(initial->color, final->color, percentage); -} - -struct MoveLinear { - PixelRenderer callback; - void* priv; - - i32 startRow; - i32 startCol; - float dRow; - float dCol; - bool wrapCoordinates; -}; - -ARGB -MoveLinear(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct MoveLinear ml = *(struct MoveLinear*)priv; - - r = (r - ml.startRow - (i32)(frameIndex * ml.dRow)); - c = (c - ml.startCol - (i32)(frameIndex * ml.dCol)); - - if (ml.wrapCoordinates == true) { - r %= anim->width; - c %= anim->height; - } - - return ml.callback(anim, frameIndex, pixel, r, c, ml.priv); -} - -struct MoveSpin { - PixelRenderer callback; - void* priv; - - float theta; - i32 centerRow; - i32 centerCol; -}; - -ARGB -MoveSpin(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct MoveSpin ms = *(struct MoveSpin*)priv; - - double radius = sqrt(r * r + c * c); - double phi = atan2(c, r); - - phi += ms.theta * frameIndex; - - r = (ms.centerRow + (i32)(radius * cos(phi))); - c = (ms.centerCol + (i32)(radius * sin(phi))); - - return ms.callback(anim, frameIndex, pixel, r, c, ms.priv); -} - - -struct Interpolate { - PixelRenderer callback; - void* priv; - - u32 startFrame; - u32 endFrame; - void* value; - void* initialState; - void* finalState; - void (*interpolate)(void* value, const void* initialState, const void* finalState, double percentage); -}; - -ARGB -Interpolate(const Animation* anim, u32 frameIndex, ARGB pixel, i32 r, i32 c, void* priv) { - struct Interpolate in = *(struct Interpolate*)priv; - - double perc = (double)(frameIndex - in.startFrame) / (in.endFrame - in.startFrame); - if (perc < 0.0) perc = 0.0; - if (perc > 1.0) perc = 1.0; - - in.interpolate(in.value, in.initialState, in.finalState, perc); - - return in.callback(anim, frameIndex, pixel, r, c, in.priv); -} int main() { Animation anim = Animation_new(512, 512, 120); // Background - struct CheckerPattern chp1 = { + struct AO_CheckerPattern chp1 = { .squareSize = 32, .colorA = 0xFF000000, .colorB = 0xFFFF00FF, }; - struct MoveLinear ml1 = { + struct AM_MoveLinear ml1 = { .startRow = 0, .startCol = 0, .dRow = -1, .dCol = -1, - .callback = CheckerPattern, .priv = &chp1, + .callback = AO_CheckerPattern, .priv = &chp1, }; - Animation_pushEvent(&anim, 0, 120, MoveLinear, &ml1); + Animation_pushEvent(&anim, 0, 120, AM_MoveLinear, &ml1); // Image FILE* fbclc = fopen("bclc.ppm", "r"); - struct Image bclc; - struct MoveLinear ml10; + struct AO_Image bclc; + struct AM_MoveLinear ml10; if (fbclc != NULL) { bclc.img = ppm_read(fbclc); bclc.noRepeat = true; bclc.zoom = 0.4; - ml10 = (struct MoveLinear){ + ml10 = (struct AM_MoveLinear){ .startRow = 0, .startCol = 0, .dRow = 0.5, .dCol = 0.5, - .callback = Image, .priv = &bclc, + .callback = AO_Image, .priv = &bclc, }; - Animation_pushEvent(&anim, 0, 100, MoveLinear, &ml10); + Animation_pushEvent(&anim, 0, 100, AM_MoveLinear, &ml10); } // Line - struct Line l1start = { + struct AO_Line l1start = { .a = -8, .b = 6, .c = -128, .width = 0.5, .color = 0xFF50F0F5 }; - struct Line l1end = { + struct AO_Line l1end = { .a = 8, .b = -4, .c = 0, .width = 10, .color = 0xFFF550F0 }; - struct Line l1; + struct AO_Line l1; - struct Interpolate i1 = { + struct A_Interpolate i1 = { .startFrame = 0, .endFrame = 120, .value = &l1, .initialState = &l1start, .finalState = &l1end, - .interpolate = LineInterpolate, + .interpolate = AO_LineInterpolate, - .callback = Line, .priv = &l1, + .callback = AO_Line, .priv = &l1, }; - Animation_pushEvent(&anim, 0, 120, Interpolate, &i1); + Animation_pushEvent(&anim, 0, 120, A_Interpolate, &i1); // Yellow square - struct SquareSettings s1 = { + struct AO_SquareSettings s1 = { .width = 20, .height = 20, .color = 0xFFFFFF00, }; - struct MoveSpin ms1 = { + struct AM_MoveSpin ms1 = { .theta = 3.14159 / 15, .centerCol = 10, .centerRow = 10, - .callback = Square, .priv = &s1, + .callback = AO_Square, .priv = &s1, }; - struct MoveLinear ml3 = { + struct AM_MoveLinear ml3 = { .startRow = 100, .startCol = 100, .dRow = 3, .dCol = 1, - .callback = MoveSpin, .priv = &ms1, + .callback = AM_MoveSpin, .priv = &ms1, }; - Animation_pushEvent(&anim, 0, 80, MoveLinear, &ml3); + Animation_pushEvent(&anim, 0, 80, AM_MoveLinear, &ml3); // White square - struct SquareSettings s4 = { + struct AO_SquareSettings s4 = { .width = 20, .height = 20, .color = 0xFFFFFFFF, }; - struct MoveLinear ml4 = { + struct AM_MoveLinear ml4 = { .startRow = 40, .startCol = 40, .dRow = 2, .dCol = 2, .wrapCoordinates = true, - .callback = Square, .priv = &s4, + .callback = AO_Square, .priv = &s4, }; - Animation_pushEvent(&anim, 0, 80, MoveLinear, &ml4); + Animation_pushEvent(&anim, 0, 80, AM_MoveLinear, &ml4); // Green square - struct SquareSettings s2 = { + struct AO_SquareSettings s2 = { .width = 35, .height = 50, .color = 0xA009FAA5, }; - struct MoveLinear ml2 = { + struct AM_MoveLinear ml2 = { .startRow = 20, .startCol = 5, .dRow = -4, .dCol = -2, .wrapCoordinates = true, - .callback = Square, .priv = &s2, + .callback = AO_Square, .priv = &s2, }; - Animation_pushEvent(&anim, 30, 110, MoveLinear, &ml2); + Animation_pushEvent(&anim, 30, 110, AM_MoveLinear, &ml2); Animation_render(&anim); -- cgit v1.2.3