summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyndamia <kamen@syndamia.com>2026-03-14 22:38:38 +0200
committerSyndamia <kamen@syndamia.com>2026-03-14 22:38:38 +0200
commit4bdd9ba823da792beae6dd4340b4d320437908cb (patch)
tree614e515613b464c19fe5a284155affdc9b990a6b
parent6545985fa7d2fdae1a7787d8f4a86d6e5011a36c (diff)
downloadppm_graphics-4bdd9ba823da792beae6dd4340b4d320437908cb.tar
ppm_graphics-4bdd9ba823da792beae6dd4340b4d320437908cb.tar.gz
ppm_graphics-4bdd9ba823da792beae6dd4340b4d320437908cb.zip
feat: Implement color opacity
-rw-r--r--graphics.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/graphics.c b/graphics.c
index 2100cc8..71365af 100644
--- a/graphics.c
+++ b/graphics.c
@@ -20,23 +20,35 @@ typedef uint8_t byte;
typedef uint16_t byte2;
typedef uint32_t byte4;
-typedef struct RGB {
+typedef struct ARGB {
+ byte a;
byte r;
byte g;
byte b;
-} RGB;
+} ARGB;
void
-RGB_set(RGB* rgb, byte4 color) {
- rgb->r = (0xFF0000 & color) >> 16;
- rgb->g = (0x00FF00 & color) >> 8;
- rgb->b = (0x0000FF & color);
+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;
- RGB* img;
+ ARGB* img;
} RGBImage;
RGBImage
@@ -44,7 +56,7 @@ RGBImage_new(u32 width, u32 height) {
return (RGBImage){
.width = width,
.height = height,
- .img = malloc(sizeof(RGB) * width * height)
+ .img = malloc(sizeof(ARGB) * width * height)
};
}
@@ -60,7 +72,7 @@ RGBImage_delete(RGBImage* img) {
img->img = NULL;
}
-RGB*
+ARGB*
RGBImage_at(RGBImage img, int row, int col) {
return img.img + (row % img.height) * img.width + col % img.width;
}
@@ -68,7 +80,12 @@ RGBImage_at(RGBImage img, int row, int col) {
int
ppm6_write(FILE* f, RGBImage img) {
fprintf(f, "P6\n%d %d\n255\n", img.width, img.height);
- fwrite(img.img, sizeof(*img.img), img.width * img.height, f);
+ 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);
}
@@ -86,7 +103,7 @@ typedef struct Animation {
AnimationEventNode* events;
} Animation;
-typedef RGB (*PixelRenderer)(const Animation* anim, u32 currentFrame, const RGB* pixel, u32 row, u32 col, void* priv);
+typedef ARGB (*PixelRenderer)(const Animation* anim, u32 currentFrame, const ARGB* pixel, u32 row, u32 col, void* priv);
struct AnimationEventNode {
AnimationEventNode* next;
@@ -167,9 +184,9 @@ Animation_render(Animation* anim) {
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));
+ 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;
@@ -194,18 +211,18 @@ Animation_render(Animation* anim) {
////main////
-RGB
-MovingBackground(const Animation* anim, u32 frameIndex, const RGB* currentPixel, u32 r, u32 c, void* priv) {
- RGB pixel;
+ARGB
+MovingBackground(const Animation* anim, u32 frameIndex, const ARGB* currentPixel, u32 r, u32 c, void* priv) {
+ ARGB pixel;
r = (r + frameIndex) / 32;
c = (c + frameIndex) / 32;
if ((r + c) % 2 == 0) {
- RGB_set(&pixel, 0x000000);
+ ARGB_set(&pixel, 0xFF000000);
}
else {
- RGB_set(&pixel, 0xFF00FF);
+ ARGB_set(&pixel, 0xFFFF00FF);
}
return pixel;
@@ -217,10 +234,10 @@ struct SquareSettings {
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));
+ARGB
+Square(const Animation* anim, u32 frameIndex, const ARGB* currentPixel, u32 r, u32 c, void* priv) {
+ ARGB pixel;
+ memcpy(&pixel, currentPixel, sizeof(ARGB));
struct SquareSettings* set = (struct SquareSettings*)priv;
@@ -228,7 +245,7 @@ Square(const Animation* anim, u32 frameIndex, const RGB* currentPixel, u32 r, u3
c = (c - frameIndex * 8) % anim->height;
if (0 <= r && r <= set->width && 0 <= c && c <= set->height) {
- RGB_set(&pixel, set->color);
+ ARGB_set(&pixel, set->color);
}
return pixel;
@@ -241,12 +258,12 @@ main() {
Animation_pushEvent(&anim, 0, 120, MovingBackground, NULL);
struct SquareSettings s1 = {
- .width = 20, .height = 20, .color = 0xFFFF00,
+ .width = 20, .height = 20, .color = 0xFFFFFF00,
};
Animation_pushEvent(&anim, 0, 30, Square, &s1);
struct SquareSettings s2 = {
- .width = 10, .height = 25, .color = 0x09FAA5,
+ .width = 10, .height = 25, .color = 0x5009FAA5,
};
Animation_pushEvent(&anim, 60, 100, Square, &s2);