summaryrefslogtreecommitdiff
path: root/graphics.c
diff options
context:
space:
mode:
Diffstat (limited to 'graphics.c')
-rw-r--r--graphics.c201
1 files changed, 190 insertions, 11 deletions
diff --git a/graphics.c b/graphics.c
index b79bd66..cd4f561 100644
--- a/graphics.c
+++ b/graphics.c
@@ -1,3 +1,7 @@
+/* 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
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -91,6 +95,22 @@ ppm6_write(FILE* f, RGBImage img) {
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;
@@ -100,6 +120,7 @@ typedef struct Animation {
u32 width;
u32 height;
u32 frameCount;
+ u32 duplicateFrames;
RGBImage frameBuffer;
AnimationEventNode* events;
@@ -134,6 +155,7 @@ Animation_new(u32 width, u32 height, u32 frameCount) {
.width = width,
.height = height,
.frameCount = frameCount,
+ .duplicateFrames = 0,
.frameBuffer = RGBImage_new(width, height),
.events = NULL,
};
@@ -208,6 +230,9 @@ Animation_render(Animation* anim) {
}
ppm6_write(stdout, anim->frameBuffer);
+
+ for (u32 duplicates = 0; duplicates < anim->duplicateFrames; ++duplicates)
+ ppm6_write(stdout, anim->frameBuffer);
}
}
@@ -253,30 +278,104 @@ Square(const Animation* anim, u32 frameIndex, ARGB pixel, u32 r, u32 c, void* pr
return pixel;
}
+struct Image {
+ RGBImage img;
+ double zoom;
+ bool noRepeat;
+};
+
+ARGB
+Image(const Animation* anim, u32 frameIndex, ARGB pixel, u32 r, u32 c, void* priv) {
+ struct Image img = *(struct Image*)priv;
+
+ if (img.noRepeat == true &&
+ (img.img.width * img.zoom <= c ||
+ 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, u32 r, u32 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;
+
u32 startRow;
u32 startCol;
float dRow;
float dCol;
- PixelRenderer callback;
- void* priv;
+ bool wrapCoordinates;
};
ARGB
MoveLinear(const Animation* anim, u32 frameIndex, ARGB pixel, u32 r, u32 c, void* priv) {
struct MoveLinear ml = *(struct MoveLinear*)priv;
- r = (r + ml.startRow - (u32)(frameIndex * ml.dRow)) % anim->width;
- c = (c + ml.startCol - (u32)(frameIndex * ml.dCol)) % anim->height;
+ r = (r - ml.startRow - (u32)(frameIndex * ml.dRow));
+ c = (c - ml.startCol - (u32)(frameIndex * ml.dCol));
+
+ if (ml.wrapCoordinates == true) {
+ r %= anim->width;
+ c %= anim->height;
+ }
return ml.callback(anim, frameIndex, pixel, r, c, ml.priv);
}
struct MoveRotate {
- float radius;
- float theta;
PixelRenderer callback;
void* priv;
+
+ float radius;
+ float theta;
};
ARGB
@@ -289,6 +388,31 @@ MoveRotate(const Animation* anim, u32 frameIndex, ARGB pixel, u32 r, u32 c, void
return mr.callback(anim, frameIndex, pixel, r, c, mr.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, u32 r, u32 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);
@@ -300,12 +424,52 @@ main() {
};
struct MoveLinear ml1 = {
.startRow = 0, .startCol = 0,
- .dRow = 1, .dCol = 1,
+ .dRow = -1, .dCol = -1,
.callback = CheckerPattern, .priv = &chp1,
};
Animation_pushEvent(&anim, 0, 120, MoveLinear, &ml1);
+ // Image
+ FILE* fbclc = fopen("bclc.ppm", "r");
+ struct Image bclc;
+ struct MoveLinear ml10;
+ if (fbclc != NULL) {
+ bclc.img = ppm_read(fbclc);
+ bclc.noRepeat = true;
+ bclc.zoom = 0.4;
+
+ ml10 = (struct MoveLinear){
+ .startRow = 0, .startCol = 0,
+ .dRow = 0.5, .dCol = 0.5,
+
+ .callback = Image, .priv = &bclc,
+ };
+ Animation_pushEvent(&anim, 0, 100, MoveLinear, &ml10);
+ }
+
+ // Line
+ struct Line l1start = {
+ .a = -8, .b = 6, .c = -128,
+ .width = 0.5,
+ .color = 0xFF50F0F5
+ };
+ struct Line l1end = {
+ .a = 8, .b = -4, .c = 0,
+ .width = 10,
+ .color = 0xFFF550F0
+ };
+ struct Line l1;
+
+ struct Interpolate i1 = {
+ .startFrame = 0, .endFrame = 120,
+ .value = &l1, .initialState = &l1start, .finalState = &l1end,
+ .interpolate = LineInterpolate,
+
+ .callback = Line, .priv = &l1,
+ };
+ Animation_pushEvent(&anim, 0, 120, Interpolate, &i1);
+
// Yellow square
struct SquareSettings s1 = {
.width = 20, .height = 20, .color = 0xFFFFFF00,
@@ -323,21 +487,36 @@ main() {
};
Animation_pushEvent(&anim, 0, 80, MoveLinear, &ml3);
+ // Yellow square
+ struct SquareSettings s4 = {
+ .width = 20, .height = 20, .color = 0xFFFFFFFF,
+ };
+ struct MoveLinear ml4 = {
+ .startRow = 40, .startCol = 40,
+ .dRow = 2, .dCol = 2,
+ .wrapCoordinates = true,
+
+ .callback = Square, .priv = &s4,
+ };
+ Animation_pushEvent(&anim, 0, 80, MoveLinear, &ml4);
+
// Green square
struct SquareSettings s2 = {
- .width = 25, .height = 40, .color = 0xA009FAA5,
+ .width = 35, .height = 50, .color = 0xA009FAA5,
};
struct MoveLinear ml2 = {
.startRow = 20, .startCol = 5,
- .dRow = -4, .dCol = -10,
+ .dRow = -4, .dCol = -2,
+ .wrapCoordinates = true,
.callback = Square, .priv = &s2,
};
- Animation_pushEvent(&anim, 60, 100, MoveLinear, &ml2);
-
+ Animation_pushEvent(&anim, 30, 110, MoveLinear, &ml2);
Animation_render(&anim);
+ fclose(fbclc);
+ RGBImage_delete(&bclc.img);
Animation_delete(&anim);
return 0;