diff options
| author | Syndamia <kamen@syndamia.com> | 2026-03-28 23:49:45 +0200 |
|---|---|---|
| committer | Syndamia <kamen@syndamia.com> | 2026-03-28 23:49:45 +0200 |
| commit | 7bca1ce8c15c3a5892aa44624d270f6ae8d35aaa (patch) | |
| tree | ea3f50abb889c668d8d701bde622f87340337fd5 | |
| parent | aa16453072477ed1f90def01bdd55bebac696f61 (diff) | |
| download | ppm_graphics-7bca1ce8c15c3a5892aa44624d270f6ae8d35aaa.tar ppm_graphics-7bca1ce8c15c3a5892aa44624d270f6ae8d35aaa.tar.gz ppm_graphics-7bca1ce8c15c3a5892aa44624d270f6ae8d35aaa.zip | |
feat: Implement line segment and make node moving animation
| -rw-r--r-- | AnimationRender/F_Interpolate.c | 9 | ||||
| -rw-r--r-- | AnimationRender/F_Interpolate.h | 2 | ||||
| -rw-r--r-- | FrameRender/P_LineSegment.c | 44 | ||||
| -rw-r--r-- | FrameRender/P_LineSegment.h | 17 | ||||
| -rw-r--r-- | graphics.c | 92 |
5 files changed, 119 insertions, 45 deletions
diff --git a/AnimationRender/F_Interpolate.c b/AnimationRender/F_Interpolate.c index 3cb3b5a..4686adf 100644 --- a/AnimationRender/F_Interpolate.c +++ b/AnimationRender/F_Interpolate.c @@ -63,6 +63,15 @@ void Interpolate_Image(Image* value, const Image* start, const Image* end, doubl fprintf(stderr, "Refusing to interpolate between images!"); } +void Interpolate_LineSegment(LineSegment* value, const LineSegment* start, const LineSegment* end, double progress) { + value->aX = NUM_INTERPOLATE(start->aX, end->aX, progress); + value->aY = NUM_INTERPOLATE(start->aY, end->aY, progress); + value->bX = NUM_INTERPOLATE(start->bX, end->bX, progress); + value->bY = NUM_INTERPOLATE(start->bY, end->bY, progress); + value->width = NUM_INTERPOLATE(start->width, end->width, progress); + value->color = colorInterpolate(start->color, end->color, progress); +} + void Interpolate_TransformCenter(TransformCenter* value, const TransformCenter* start, const TransformCenter* end, double progress) { value->centerX = NUM_INTERPOLATE(start->centerX, end->centerX, progress); value->centerY = NUM_INTERPOLATE(start->centerY, end->centerY, progress); diff --git a/AnimationRender/F_Interpolate.h b/AnimationRender/F_Interpolate.h index 2f68c53..90b1eaf 100644 --- a/AnimationRender/F_Interpolate.h +++ b/AnimationRender/F_Interpolate.h @@ -6,6 +6,7 @@ #include "../FrameRender/P_Circle.h" #include "../FrameRender/P_Checker.h" #include "../FrameRender/P_Image.h" +#include "../FrameRender/P_LineSegment.h" #include "../FrameRender/P_TransformCenter.h" #include "../FrameRender/P_TransformRotate.h" @@ -24,6 +25,7 @@ void Interpolate_Square(Square* value, const Square* start, const Square* end, d void Interpolate_Circle(Circle* value, const Circle* start, const Circle* end, double progress); void Interpolate_Checker(Checker* value, const Checker* start, const Checker* end, double progress); void Interpolate_Image(Image* value, const Image* start, const Image* end, double progress); +void Interpolate_LineSegment(LineSegment* value, const LineSegment* start, const LineSegment* end, double progress); void Interpolate_TransformCenter(TransformCenter* value, const TransformCenter* start, const TransformCenter* end, double progress); void Interpolate_TransformRotate(TransformRotate* value, const TransformRotate* start, const TransformRotate* end, double progress); diff --git a/FrameRender/P_LineSegment.c b/FrameRender/P_LineSegment.c new file mode 100644 index 0000000..f2236ff --- /dev/null +++ b/FrameRender/P_LineSegment.c @@ -0,0 +1,44 @@ +#include "P_LineSegment.h" +#include "PixelCallback.h" +#include <math.h> +#include <stdlib.h> +#include <string.h> + +void rotatePoint(i32* x, i32* y, double angle) { + i32 xR = *x * cos(angle) + *y * sin(angle); + i32 yR = - *x * sin(angle) + *y * cos(angle); + *x = xR; + *y = yR; +} + +void LineSegment_callback(LineSegment* self, struct PixelContext* fc) { + /* IDK if this is the most efficient, online results seem + * to do more complicated calculations. + * Center coordianates around aX,aY + * Then unrotate bX,bY and x,y relative to 0,0 (aX,aY), + * so that bX,bY lies on the horizontal axis. + * Now the line is flat from 0,0 to the "right" (increasing x). + */ + i32 x = fc->x - self->aX, y = fc->y - self->aY; + i32 bX = self->bX - self->aX, bY = self->bY - self->aY; + + double phi = atan2(bY, bX); + rotatePoint(&y, &x, -phi); + rotatePoint(&bY, &bX, -phi); + + if (0 <= x && x <= bX && + -(i32)self->width / 2 <= y && y <= self->width / 2) + { + ARGB_merge(&fc->pixel, self->color); + } +} + +PixelCallback* LineSegment_setup(LineSegment obj) { + PixelCallback* pca = malloc(sizeof(struct PixelCallback)); + + pca->callback = (PixelCallback_callback)LineSegment_callback; + pca->callback_self = malloc(sizeof(obj)); + memcpy(pca->callback_self, &obj, sizeof(obj)); + + return pca; +} diff --git a/FrameRender/P_LineSegment.h b/FrameRender/P_LineSegment.h new file mode 100644 index 0000000..2e52766 --- /dev/null +++ b/FrameRender/P_LineSegment.h @@ -0,0 +1,17 @@ +#ifndef P_LINE_SEGMENT +#define P_LINE_SEGMENT + +#include "PixelCallback.h" + +typedef struct LineSegment { + i32 aX; + i32 aY; + i32 bX; + i32 bY; + u32 width; + color color; +} LineSegment; + +PixelCallback* LineSegment_setup(LineSegment obj); + +#endif /* P_LINE_SEGMENT */ @@ -11,6 +11,7 @@ #include "FrameRender/P_Checker.h" #include "FrameRender/P_Circle.h" #include "FrameRender/P_Image.h" +#include "FrameRender/P_LineSegment.h" #include "FrameRender/P_Square.h" #include "FrameRender/P_TransformCenter.h" #include "FrameRender/P_TransformRotate.h" @@ -24,75 +25,77 @@ int main() { u32 width = 512; u32 height = 512; + const u32 FPS = 60; + u32 frames = FPS * 5; - FILE* fbclc = fopen("bclc.ppm", "rb"); - RGBImage bclc = ppm_read(fbclc); - fclose(fbclc); + TransformCenter childLeft = { .centerX = width / 4, .centerY = height * 3 / 4, }; + TransformCenter childRight = { .centerX = width * 3 / 4, .centerY = height * 3 / 4, }; + LineSegment segmentRight = { + .aX = width / 2, .aY = height / 4, + .bX = width * 3 / 4, .bY = height * 3 / 4, + .width = 10, .color = 0xFFFF00FF, + }; + LineSegment segmentLeft = { + .aX = width / 2, .aY = height / 4, + .bX = width / 4, .bY = height * 3 / 4, + .width = 10, .color = 0xFFFF00FF, + }; PixelCallback* callbacks[] = { - Checker_setup((Checker){ - .squareSize = 64, .colorA = 0xFF000000, .colorB = 0xFFFF00FF, - }), - TransformCenter_setup((TransformCenter){ - .centerX = width / 2, .centerY = height / 2, - }), - Square_setup((Square){ - .size = 100, .color = 0xFFFFFF00, - }), - NULL, - TransformRotate_setup((TransformRotate){ - .angle = M_PI / 8, - }), + /* Background */ Square_setup((Square){ - .size = 200, .color = 0xFF00FFFF, + .size = width, .color = 0xFFF0F0F0, }), - NULL, + /* Root node */ TransformCenter_setup((TransformCenter){ - .centerX = width * 3/4, .centerY = height / 2, + .centerX = width / 2, .centerY = height / 4, }), Circle_setup((Circle){ - .radius = 50, .color = 0x80FFFFFF, + .radius = 60, .color = 0xFFFF0000, }), + /* Child node */ NULL, - TransformCenter_setup((TransformCenter){ - .centerX = width / 8, .centerY = height * 3/5, + TransformCenter_setup(childRight), + Circle_setup((Circle){ + .radius = 60, .color = 0xFF00FF00, }), - Image_setup((Image){ - .img = bclc, - .scale = 0.2, + /* Connecting line */ + NULL, + LineSegment_setup((LineSegment){ + .aX = width / 2, .aY = height / 4, + .bX = width * 3 / 4, .bY = height * 3 / 4, + .width = 10, .color = 0xFFFF00FF, }), }; u32 sizeCallbacks = sizeof(callbacks) / sizeof(*callbacks); - TransformCenter img1 = { .centerX = width / 8, .centerY = height * 3/5 }, - img2 = { .centerX = height / 8, .centerY = width / 8 }; - - TransformRotate r1 = { .angle = M_PI / 8 }, r2 = { .angle = M_PI * 2 }; - - Circle c1 = { .radius = 50, .color = 0x00FFFFFF, }, c2 = { .radius = 50, .color = 0xFFFFFFFF, }; - FrameCallback* frameCallbacks[] = { - Interpolate_setup((Interpolate){ - .startValue = &c1, .endValue = &c2, - .value = callbacks[8]->callback_self, - .interpolate = (f_interpolate)Interpolate_Circle, - }), FrameRange_setup((FrameRange){ - .startFrame = 25, .endFrame = 125, + .startFrame = frames / 3 - FPS, .endFrame = frames / 3, }), Interpolate_setup((Interpolate){ - .startValue = &img1, .endValue = &img2, - .value = callbacks[10]->callback_self, + .startValue = &childRight, .endValue = &childLeft, + .value = callbacks[4]->callback_self, .interpolate = (f_interpolate)Interpolate_TransformCenter, }), + Interpolate_setup((Interpolate){ + .startValue = &segmentRight, .endValue = &segmentLeft, + .value = callbacks[7]->callback_self, + .interpolate = (f_interpolate)Interpolate_LineSegment, + }), NULL, FrameRange_setup((FrameRange){ - .startFrame = 0, .endFrame = 50, + .startFrame = frames * 2 / 3 - FPS, .endFrame = frames * 2 / 3, }), Interpolate_setup((Interpolate){ - .startValue = &r1, .endValue = &r2, + .startValue = &childLeft, .endValue = &childRight, .value = callbacks[4]->callback_self, - .interpolate = (f_interpolate)Interpolate_TransformRotate, + .interpolate = (f_interpolate)Interpolate_TransformCenter, + }), + Interpolate_setup((Interpolate){ + .startValue = &segmentLeft, .endValue = &segmentRight, + .value = callbacks[7]->callback_self, + .interpolate = (f_interpolate)Interpolate_LineSegment, }), NULL, Draw_setup((Draw){ @@ -101,9 +104,8 @@ main() { }; u32 sizeFrameCallbacks = sizeof(frameCallbacks) / sizeof(*frameCallbacks); - RenderAnimation(width, height, 150, (const FrameCallback**)frameCallbacks, sizeFrameCallbacks); + RenderAnimation(width, height, frames, (const FrameCallback**)frameCallbacks, sizeFrameCallbacks); - RGBImage_delete(&bclc); for (u32 i = 0; i < sizeCallbacks; ++i) { if (callbacks[i] == NULL) continue; free(callbacks[i]->callback_self); |
