diff options
| -rw-r--r-- | graphics.c | 206 |
1 files changed, 185 insertions, 21 deletions
@@ -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; } |
