summaryrefslogtreecommitdiff
path: root/graphics.c
diff options
context:
space:
mode:
authorSyndamia <kamen@syndamia.com>2026-03-14 22:37:42 +0200
committerSyndamia <kamen@syndamia.com>2026-03-14 22:38:20 +0200
commit6545985fa7d2fdae1a7787d8f4a86d6e5011a36c (patch)
treeb74e89f1c5804556899795d3b3994b8eb62943aa /graphics.c
parent643aa74994fb8bca341958433c1028f495931d3e (diff)
downloadppm_graphics-6545985fa7d2fdae1a7787d8f4a86d6e5011a36c.tar
ppm_graphics-6545985fa7d2fdae1a7787d8f4a86d6e5011a36c.tar.gz
ppm_graphics-6545985fa7d2fdae1a7787d8f4a86d6e5011a36c.zip
feat: Implement Animation structure
Diffstat (limited to 'graphics.c')
-rw-r--r--graphics.c206
1 files changed, 185 insertions, 21 deletions
diff --git a/graphics.c b/graphics.c
index df10685..2100cc8 100644
--- a/graphics.c
+++ b/graphics.c
@@ -1,39 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
inline int
OK(int x) {
return x == 0;
}
+typedef uint8_t bool;
+#define false 0
+#define true 1
+
+typedef uint32_t u32;
+
////RGBImage////
typedef uint8_t byte;
typedef uint16_t byte2;
typedef uint32_t byte4;
-typedef struct _RGB {
+typedef struct RGB {
byte r;
byte g;
byte b;
} RGB;
void
-ARGB_set(RGB* rgb, byte4 color) {
+RGB_set(RGB* rgb, byte4 color) {
rgb->r = (0xFF0000 & color) >> 16;
rgb->g = (0x00FF00 & color) >> 8;
rgb->b = (0x0000FF & color);
}
-typedef struct _RGBImage {
- int width;
- int height;
+typedef struct RGBImage {
+ u32 width;
+ u32 height;
RGB* img;
} RGBImage;
RGBImage
-RGBImage_new(int width, int height) {
+RGBImage_new(u32 width, u32 height) {
return (RGBImage){
.width = width,
.height = height,
@@ -65,30 +72,187 @@ ppm6_write(FILE* f, RGBImage img) {
return fflush(f);
}
+////Animation////
+
+struct AnimationEventNode;
+typedef struct AnimationEventNode AnimationEventNode;
+
+typedef struct Animation {
+ u32 width;
+ u32 height;
+ u32 frameCount;
+
+ RGBImage frameBuffer;
+ AnimationEventNode* events;
+} Animation;
+
+typedef RGB (*PixelRenderer)(const Animation* anim, u32 currentFrame, const RGB* pixel, u32 row, u32 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,
+ .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 (int r = 0; r < anim->frameBuffer.width; ++r)
+ for (int c = 0; c < anim->frameBuffer.height; ++c) {
+ for (AnimationEventNode* aen = anim->events; aen != NULL && aen->startFrame <= currFrame; aen = aen->next) {
+ RGB* pixel = RGBImage_at(anim->frameBuffer, r, c);
+ RGB newPixel = aen->renderCallback(anim, currFrame, pixel, r, c, aen->privateData);
+ memcpy(pixel, &newPixel, sizeof(RGB));
+ }
+
+ 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);
+ }
+}
+
////main////
+RGB
+MovingBackground(const Animation* anim, u32 frameIndex, const RGB* currentPixel, u32 r, u32 c, void* priv) {
+ RGB pixel;
+
+ r = (r + frameIndex) / 32;
+ c = (c + frameIndex) / 32;
+
+ if ((r + c) % 2 == 0) {
+ RGB_set(&pixel, 0x000000);
+ }
+ else {
+ RGB_set(&pixel, 0xFF00FF);
+ }
+
+ return pixel;
+}
+
+struct SquareSettings {
+ u32 width;
+ u32 height;
+ byte4 color;
+};
+
+RGB
+Square(const Animation* anim, u32 frameIndex, const RGB* currentPixel, u32 r, u32 c, void* priv) {
+ RGB pixel;
+ memcpy(&pixel, currentPixel, sizeof(RGB));
+
+ struct SquareSettings* set = (struct SquareSettings*)priv;
+
+ r = (r - frameIndex * 8) % anim->width;
+ c = (c - frameIndex * 8) % anim->height;
+
+ if (0 <= r && r <= set->width && 0 <= c && c <= set->height) {
+ RGB_set(&pixel, set->color);
+ }
+
+ return pixel;
+}
+
int
main() {
- RGBImage frame = RGBImage_new(512, 512);
+ Animation anim = Animation_new(512, 512, 120);
- for (int frameIndex = 0; frameIndex < 120; ++frameIndex) {
+ Animation_pushEvent(&anim, 0, 120, MovingBackground, NULL);
- for (int r = 0; r < frame.width; ++r)
- for (int c = 0; c < frame.height; ++c) {
- RGB* pixel = RGBImage_at(frame, r, c);
+ struct SquareSettings s1 = {
+ .width = 20, .height = 20, .color = 0xFFFF00,
+ };
+ Animation_pushEvent(&anim, 0, 30, Square, &s1);
- if (((r + frameIndex) / 32 + (c + frameIndex) / 32) % 2 == 0) {
- ARGB_set(pixel, 0x000000);
- }
- else {
- ARGB_set(pixel, 0xFF00FF);
- }
- }
+ struct SquareSettings s2 = {
+ .width = 10, .height = 25, .color = 0x09FAA5,
+ };
+ Animation_pushEvent(&anim, 60, 100, Square, &s2);
- ppm6_write(stdout, frame);
- }
+ Animation_render(&anim);
- RGBImage_delete(&frame);
+ Animation_delete(&anim);
return 0;
}