summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-04-24 03:58:52 +0200
committerMitya Selivanov <automainint@guattari.tech>2025-04-24 03:58:52 +0200
commit27291f388b02c6ba88efb79b9728b65f158589ef (patch)
treed6cce8eccf6101a6ee04bf1b35a2186d050de56e
parentf8bd7cfdb9ed7ec99d612dd03670e50aa0c60db2 (diff)
downloadreduced_system_layer-27291f388b02c6ba88efb79b9728b65f158589ef.zip
Global gamma correction
-rw-r--r--graphics.c85
-rw-r--r--runtime.c40
2 files changed, 80 insertions, 45 deletions
diff --git a/graphics.c b/graphics.c
index f4bc699..3552792 100644
--- a/graphics.c
+++ b/graphics.c
@@ -50,13 +50,7 @@ vec4_f32 vec4_f32_lerp (vec4_f32 a, vec4_f32 b, f32 t);
// ================================================================
-typedef struct {
- // NOTE: Dimensions are in pixels.
- i64 width;
- i64 height;
- i64 stride;
- vec4_f32 *pixels;
-} Pixel_Buffer;
+// NOTE: Dimensions are in pixels.
typedef struct {
f64 x;
@@ -65,6 +59,31 @@ typedef struct {
f64 height;
} Box;
+// TODO:
+// typedef struct {
+// b8 enabled;
+// i64 x;
+// i64 y;
+// i64 width;
+// i64 height;
+// } Bounding_Box;
+
+typedef struct {
+ i64 width;
+ i64 height;
+ i64 stride;
+ // Bounding_Box bounds;
+ u8 *pixels;
+} Stencil_Buffer;
+
+typedef struct {
+ i64 width;
+ i64 height;
+ i64 stride;
+ // Bounding_Box bounds;
+ vec4_f32 *pixels;
+} Pixel_Buffer;
+
enum {
GRAPHICS_DRAW_PIXELS,
GRAPHICS_FILL_RECTANGLE,
@@ -981,49 +1000,37 @@ vec4_f32 vec4_f32_lerp(vec4_f32 a, vec4_f32 b, f32 t) {
// ================================================================
-static f64 gamma_(f64 x) {
- if (x >= 0.0031308)
- return 1.055 * pow(x, 1.0 / 2.4) - 0.055;
- return 12.92 * x;
-}
-
-static f64 gamma_re_(f64 x) {
- if (x >= 0.04045)
- return pow((x + 0.055) / 1.055, 2.4);
- return x / 12.92;
-}
-
vec3_f32 rgb_gamma_add(vec3_f32 rgb) {
return (vec3_f32) {
- .x = (f32) gamma_(rgb.x),
- .y = (f32) gamma_(rgb.y),
- .z = (f32) gamma_(rgb.z),
+ .x = gamma_(rgb.x),
+ .y = gamma_(rgb.y),
+ .z = gamma_(rgb.z),
};
}
vec3_f32 rgb_gamma_remove(vec3_f32 rgb) {
return (vec3_f32) {
- .x = (f32) gamma_re_(rgb.x),
- .y = (f32) gamma_re_(rgb.y),
- .z = (f32) gamma_re_(rgb.z),
+ .x = gamma_re_(rgb.x),
+ .y = gamma_re_(rgb.y),
+ .z = gamma_re_(rgb.z),
};
}
vec4_f32 rgba_gamma_add(vec4_f32 rgba) {
return (vec4_f32) {
- .x = (f32) gamma_(rgba.x),
- .y = (f32) gamma_(rgba.y),
- .z = (f32) gamma_(rgba.z),
- .w = (f32) gamma_(rgba.w),
+ .x = gamma_(rgba.x),
+ .y = gamma_(rgba.y),
+ .z = gamma_(rgba.z),
+ .w = gamma_(rgba.w),
};
}
vec4_f32 rgba_gamma_remove(vec4_f32 rgba) {
return (vec4_f32) {
- .x = (f32) gamma_re_(rgba.x),
- .y = (f32) gamma_re_(rgba.y),
- .z = (f32) gamma_re_(rgba.z),
- .w = (f32) gamma_re_(rgba.w),
+ .x = gamma_re_(rgba.x),
+ .y = gamma_re_(rgba.y),
+ .z = gamma_re_(rgba.z),
+ .w = gamma_re_(rgba.w),
};
}
@@ -2186,7 +2193,7 @@ TEST("colors") {
vec3_f32 white = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 1.f, 1.f, }));
REQUIRE_EQ(white.x * 100, 100);
REQUIRE_EQ(white.y * 100, 100);
- REQUIRE_EQ((white.z + 3e-7) * 100, 100);
+ REQUIRE_EQ((white.z + 6e-7) * 100, 100);
vec3_f32 black = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 0.f, 0.f, }));
REQUIRE_EQ(black.x * 100, 0);
@@ -2205,13 +2212,13 @@ TEST("colors") {
vec3_f32 green = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 1.f, 0.f, }));
REQUIRE_EQ(green.x * 100, 0);
- REQUIRE_EQ(green.y * 100, 100);
+ REQUIRE_EQ((green.y + 3e-7) * 100, 100);
REQUIRE_EQ(green.z * 100, 0);
vec3_f32 blue = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 0.f, 1.f, }));
REQUIRE_EQ(blue.x * 100, 0);
REQUIRE_EQ(blue.y * 100, 0);
- REQUIRE_EQ((blue.z + 6e-8) * 100, 100);
+ REQUIRE_EQ((blue.z + 3e-7) * 100, 100);
vec3_f32 yellow = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 1.f, 0.f, }));
REQUIRE_EQ(yellow.x * 100, 100);
@@ -2220,13 +2227,13 @@ TEST("colors") {
vec3_f32 cyan = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 1.f, 1.f, }));
REQUIRE_EQ(cyan.x * 100, 0);
- REQUIRE_EQ((cyan.y + 2e-7) * 100, 100);
- REQUIRE_EQ((cyan.z + 2e-7) * 100, 100);
+ REQUIRE_EQ((cyan.y + 3e-7) * 100, 100);
+ REQUIRE_EQ((cyan.z + 3e-7) * 100, 100);
vec3_f32 purple = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 0.f, 1.f, }));
REQUIRE_EQ(purple.x * 100, 100);
REQUIRE_EQ(purple.y * 100, 0);
- REQUIRE_EQ((purple.z + 2e-7) * 100, 100);
+ REQUIRE_EQ((purple.z + 3e-7) * 100, 100);
}
TEST("rectangle corners") {
diff --git a/runtime.c b/runtime.c
index 4ba5c15..3f20820 100644
--- a/runtime.c
+++ b/runtime.c
@@ -612,7 +612,7 @@ typedef struct {
i32 antialiasing_scale;
b8 exact_resolution : 1;
- b8 disable_gamma : 1; // TODO
+ b8 disable_gamma : 1;
b8 graceful_shutdown : 1;
b8 enable_clipboard_text : 1;
b8 enable_clipboard_image : 1;
@@ -1290,6 +1290,18 @@ i8 utf8_write(c32 c, c8 *buffer) {
//
// ================================================================
+static f32 gamma_(f32 x) {
+ if (x >= 0.0031308f)
+ return 1.055f * (f32) pow(x, 1.0 / 2.4) - 0.055f;
+ return 12.92f * x;
+}
+
+static f32 gamma_re_(f32 x) {
+ if (x >= 0.04045f)
+ return (f32) pow((x + 0.055f) / 1.055f, 2.4);
+ return x / 12.92f;
+}
+
static u32 rgb_u32_from_f32_(vec3_f32 c) {
i32 ir = (i32) floor(c.x * 255. + .5);
i32 ig = (i32) floor(c.y * 255. + .5);
@@ -1765,6 +1777,8 @@ static void convert_pixels_for_window_(void) {
return;
}
+ // TODO, PERF: Improve performance.
+
// Downscale pixels from vec4_f32 pixel buffer to internal u32 pixel buffer.
//
// FIXME: Check if the scale is 1:1.
@@ -1812,11 +1826,27 @@ static void convert_pixels_for_window_(void) {
}
}
- u32 *d_end = d + dst_width;
- vec3_f32 *im = _internal_row;
+ u32 *d_end = d + dst_width;
+ vec3_f32 *im = _internal_row;
+ vec3_f32 *im_end = _internal_row + dst_width;
+
+ if (!g_platform.disable_gamma)
+ for (; im < im_end; ++im) {
+ im->x = gamma_(im->x * k);
+ im->y = gamma_(im->y * k);
+ im->z = gamma_(im->z * k);
+ }
+ else
+ for (; im < im_end; ++im) {
+ im->x *= k;
+ im->y *= k;
+ im->z *= k;
+ }
+
+ im = _internal_row;
for (; d < d_end; ++d, ++im)
- *d = rgb_u32_from_f32_((vec3_f32) { .x = im->x * k, .y = im->y * k, .z = im->z * k, }) | 0xff000000;
+ *d = rgb_u32_from_f32_(*im) | 0xff000000;
}
PROFILER_end(PROFILE_DOWNSCALE);
@@ -1843,8 +1873,6 @@ static void convert_pixels_for_window_(void) {
PROFILER_begin(PROFILE_RESIZE);
- // TODO, PERF: Improve performance.
-
u32 x_ratio = (src_width << 16) / dst_width;
u32 y_ratio = (src_height << 16) / dst_height;