summaryrefslogtreecommitdiff
path: root/graphics.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 /graphics.c
parent47e28b44615b9b068776f61b8741ea8692461c1d (diff)
downloadppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.tar
ppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.tar.gz
ppm_graphics-2202e87c466803eeaddd974006aa9950d8e0d067.zip
feat!: Split into separate filesHEADmaster
Diffstat (limited to 'graphics.c')
-rw-r--r--graphics.c484
1 files changed, 36 insertions, 448 deletions
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 <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);