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 --- graphics.c | 484 +++++-------------------------------------------------------- 1 file changed, 36 insertions(+), 448 deletions(-) (limited to 'graphics.c') 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