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 | |
| parent | 47e28b44615b9b068776f61b8741ea8692461c1d (diff) | |
| download | ppm_graphics-master.tar ppm_graphics-master.tar.gz ppm_graphics-master.zip | |
| -rw-r--r-- | Animation.c | 110 | ||||
| -rw-r--r-- | Animation.h | 29 | ||||
| -rw-r--r-- | AnimationInterpolate.c | 42 | ||||
| -rw-r--r-- | AnimationInterpolate.h | 22 | ||||
| -rw-r--r-- | AnimationMove.c | 32 | ||||
| -rw-r--r-- | AnimationMove.h | 30 | ||||
| -rw-r--r-- | AnimationObject.c | 55 | ||||
| -rw-r--r-- | AnimationObject.h | 40 | ||||
| -rw-r--r-- | RGBImage.c | 76 | ||||
| -rw-r--r-- | RGBImage.h | 35 | ||||
| -rw-r--r-- | global.h | 14 | ||||
| -rw-r--r-- | graphics.c | 484 |
12 files changed, 521 insertions, 448 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); + } +} 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 <math.h> + +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 <math.h> + +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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +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 <stdio.h> + +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 <stdint.h> + +typedef uint8_t bool; +#define false 0 +#define true 1 + +typedef int32_t i32; +typedef uint32_t u32; + + +#endif /* _GLOBAL */ @@ -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 <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <math.h> - -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); |
