summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Animation.c110
-rw-r--r--Animation.h29
-rw-r--r--AnimationInterpolate.c42
-rw-r--r--AnimationInterpolate.h22
-rw-r--r--AnimationMove.c32
-rw-r--r--AnimationMove.h30
-rw-r--r--AnimationObject.c55
-rw-r--r--AnimationObject.h40
-rw-r--r--RGBImage.c76
-rw-r--r--RGBImage.h35
-rw-r--r--global.h14
-rw-r--r--graphics.c484
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 */
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);