diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-01-18 15:35:32 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-01-18 15:35:32 +0100 |
commit | ab05a758736128ec6bc49a91d4c5a1136851ed43 (patch) | |
tree | d1c7d3b6cf0ec9a6ba36a2ed1211856913d786d9 | |
parent | a7070a52f3f32a24822ddd9bf0efebc4272661ab (diff) | |
download | reduced_system_layer-ab05a758736128ec6bc49a91d4c5a1136851ed43.zip |
Add tests
-rwxr-xr-x | graphics.c | 223 | ||||
-rw-r--r-- | reduced_system_layer.c | 7 | ||||
-rw-r--r-- | test.c | 2 |
3 files changed, 167 insertions, 65 deletions
@@ -16,11 +16,8 @@ SRC=${0##*./} BIN=${SRC%.*} gcc \ -Wall -Wextra -Werror -pedantic \ - -Wno-old-style-declaration \ -Wno-missing-braces \ - -Wno-unused-variable \ - -Wno-unused-but-set-variable \ - -Wno-unused-parameter \ + -Wno-old-style-declaration \ -Wno-overlength-strings \ -O3 -D NDEBUG \ -D GRAPHICS_TEST_SUITE \ @@ -33,13 +30,13 @@ exit $? # */ #endif // ================================================================ +#ifndef GRAPHICS_HEADER_GUARD_ +#define GRAPHICS_HEADER_GUARD_ + #ifdef EVERY_TEST_SUITE #define GRAPHICS_TEST_SUITE #endif -#ifndef GRAPHICS_HEADER_GUARD_ -#define GRAPHICS_HEADER_GUARD_ - #ifdef GRAPHICS_HEADER #define REDUCED_SYSTEM_LAYER_HEADER #endif @@ -334,17 +331,20 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer if (j0 < 0) j0 = 0; if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + f64 w_inv = 1. / w; + f64 h_inv = 1. / h; + if (!brush.quick) for (i64 j = j0; j <= j1; ++j) { - i64 src_j0 = (i64) floor(((j - y0) * src.height) / h + .5); - i64 src_j1 = (i64) floor(((j + 1 - y0) * src.height) / h + .5); + i64 src_j0 = (i64) floor(((j - y0) * src.height) * h_inv + .5); + i64 src_j1 = (i64) floor(((j + 1 - y0) * src.height) * h_inv + .5); if (src_j0 == src_j1) src_j1 = src_j0 + 1; if (src_j1 <= 0 || src_j0 >= src.height) continue; if (src_j0 < 0) src_j0 = 0; if (src_j1 > src.height) src_j1 = src.height; for (i64 i = i0; i <= i1; ++i) { - i64 src_i0 = (i64) floor(((i - x0) * src.width) / w + .5); - i64 src_i1 = (i64) floor(((i + 1 - x0) * src.width) / w + .5); + i64 src_i0 = (i64) floor(((i - x0) * src.width) * w_inv + .5); + i64 src_i1 = (i64) floor(((i + 1 - x0) * src.width) * w_inv + .5); if (src_i0 == src_i1) src_i1 = src_i0 + 1; if (src_i1 <= 0 || src_i0 >= src.width) continue; if (src_i0 < 0) src_i0 = 0; @@ -361,19 +361,20 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer } if (n == 0) continue; - brush.color.x = gamma_(brush.color.x / n); - brush.color.y = gamma_(brush.color.y / n); - brush.color.z = gamma_(brush.color.z / n); - brush.color.w = gamma_(brush.color.w / n); + f32 n_inv = 1.f / n; + brush.color.x = gamma_(brush.color.x * n_inv); + brush.color.y = gamma_(brush.color.y * n_inv); + brush.color.z = gamma_(brush.color.z * n_inv); + brush.color.w = gamma_(brush.color.w * n_inv); put_pixel_(brush, i, j); } } else for (i64 j = j0; j <= j1; ++j) { - i64 src_j = (i64) floor(((j - y0) * src.height) / h + .5); + i64 src_j = (i64) floor(((j - y0) * src.height) * h_inv + .5); if (src_j < 0 || src_j >= src.height) continue; for (i64 i = i0; i <= i1; ++i) { - i64 src_i = (i64) floor(((i - x0) * src.width) / w + .5); + i64 src_i = (i64) floor(((i - x0) * src.width) * w_inv + .5); if (src_i < 0 || src_i >= src.width) continue; brush.color = src.pixels[src_j * src.line_size + src_i]; put_pixel_(brush, i, j); @@ -415,10 +416,13 @@ void draw_pixels_from_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_B if (src_x + src_width > src.width || src_y + src_height > src.height || src_width <= 0 || src_height <= 0) return; - bx *= width / src_width; - by *= height / src_height; - bw *= width / src_width; - bh *= height / src_height; + f64 w_inv = 1. / src_width; + f64 h_inv = 1. / src_height; + + bx *= width * w_inv; + by *= height * h_inv; + bw *= width * w_inv; + bh *= height * h_inv; draw_pixels_(brush, x + bx, y + by, width - bw, height - bh, subimage(src, src_x, src_y, src_width, src_height)); } @@ -451,9 +455,18 @@ void fill_rectangle_(Brush brush, f64 x, f64 y, f64 width, f64 height) { f64 ky0 = j00 - y0; f64 ky1 = y1 - j10; - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_(brush, i, j); + if (brush.xor_color) + for (i64 j = j0; j < j1; ++j) + for (i64 i = i0; i < i1; ++i) + put_pixel_xor_(brush, i, j); + else if (brush.alpha) + for (i64 j = j0; j < j1; ++j) + for (i64 i = i0; i < i1; ++i) + put_pixel_alpha_(brush, i, j); + else + for (i64 j = j0; j < j1; ++j) + for (i64 i = i0; i < i1; ++i) + put_pixel_color_(brush, i, j); if (i00 > i10) { kx0 *= kx1; @@ -581,8 +594,15 @@ void fill_triangle_(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2) if (left < 0) left = 0; if (right >= brush.buffer.width) right = brush.buffer.width - 1; - for (i64 i = left; i <= right; ++i) - put_pixel_(brush, i, j); + if (brush.xor_color) + for (i64 i = left; i <= right; ++i) + put_pixel_xor_(brush, i, j); + else if (brush.alpha) + for (i64 i = left; i <= right; ++i) + put_pixel_alpha_(brush, i, j); + else + for (i64 i = left; i <= right; ++i) + put_pixel_color_(brush, i, j); } } @@ -623,8 +643,15 @@ void fill_ellipse_(Brush brush, f64 x, f64 y, f64 width, f64 height) { if (left < 0) left = 0; if (right >= brush.buffer.width) right = brush.buffer.width - 1; - for (i64 i = left; i <= right; ++i) - put_pixel_(brush, i, j); + if (brush.xor_color) + for (i64 i = left; i <= right; ++i) + put_pixel_xor_(brush, i, j); + else if (brush.alpha) + for (i64 i = left; i <= right; ++i) + put_pixel_alpha_(brush, i, j); + else + for (i64 i = left; i <= right; ++i) + put_pixel_color_(brush, i, j); } } @@ -825,16 +852,31 @@ static void draw_text_(Brush brush, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i6 if (j0 < 0) j0 = 0; if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + f64 w_inv = 1. / w; + f64 h_inv = 1. / h; + for (i64 i = i0; i <= i1; ++i) { - i64 column = (i64) floor(((i - x) * num_cols) / w + .5); + i64 column = (i64) floor(((i - x) * num_cols) * w_inv + .5); i64 offset = char_column_offset_(text[n], column); - for (i64 j = j0; j <= j1; ++j) { - i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) / h + .5); - - if (char_bit_(offset, row)) - put_pixel_(brush, i, j); - } + if (brush.xor_color) + for (i64 j = j0; j <= j1; ++j) { + i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); + if (char_bit_(offset, row)) + put_pixel_xor_(brush, i, j); + } + else if (brush.alpha) + for (i64 j = j0; j <= j1; ++j) { + i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); + if (char_bit_(offset, row)) + put_pixel_alpha_(brush, i, j); + } + else + for (i64 j = j0; j <= j1; ++j) { + i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); + if (char_bit_(offset, row)) + put_pixel_color_(brush, i, j); + } } } @@ -939,9 +981,9 @@ vec3_f32 lab_from_rgb(vec3_f32 rgb) { f64 s_ = cbrt(s); return (vec3_f32) { - .x = (f32) (0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_), - .y = (f32) (1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_), - .z = (f32) (0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_), + .x = (f32) (0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_), + .y = (f32) (1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_), + .z = (f32) (0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_), }; } @@ -1349,8 +1391,9 @@ void fill_line(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 width) { if (tl < EPSILON) return; - tx *= width / (tl * 2.0); - ty *= width / (tl * 2.0); + f64 k = .5 / tl; + tx *= width * k; + ty *= width * k; fill_quad(brush, x0 - tx, y0 - ty, x0 + tx, y0 + ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty); } @@ -1489,14 +1532,92 @@ void draw_text_cursor(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 max_ #define TEST_FILE graphics #include "test.c" -vec4_f32 g_pixels[MAX_NUM_PIXELS] = {0}; +TEST("colors") { + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { 1.f, 0.f, 0.f, }), 0xff0000); + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { 0.f, 1.f, 0.f, }), 0x00ff00); + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { 0.f, 0.f, 1.f, }), 0x0000ff); + + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { .5f, 0.f, 0.f, }), 0x800000); + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { 0.f, .5f, 0.f, }), 0x008000); + REQUIRE_EQ(rgb_u32_from_f32((vec3_f32) { 0.f, 0.f, .5f, }), 0x000080); + + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 1.f, 0.f, 0.f, 0.f, }), 0x00ff0000); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, 1.f, 0.f, 0.f, }), 0x0000ff00); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, 0.f, 1.f, 0.f, }), 0x000000ff); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, 0.f, 0.f, 1.f, }), 0xff000000); + + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { .5f, 0.f, 0.f, 0.f, }), 0x00800000); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, .5f, 0.f, 0.f, }), 0x00008000); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, 0.f, .5f, 0.f, }), 0x00000080); + REQUIRE_EQ(rgba_u32_from_f32((vec4_f32) { 0.f, 0.f, 0.f, .5f, }), 0x80000000); + + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 0.f, 0.f, }).x * 100, 0); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 1.f, 1.f, 1.f, }).x * 100, 100); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 1.f, 0.f, 0.f, }).x * 100, 62); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 1.f, 0.f, }).x * 100, 86); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 0.f, 1.f, }).x * 100, 45); + + REQUIRE_EQ(lch_from_rgb((vec3_f32) { .5f, .5f, .5f, }).y * 100, 0); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 1.f, 0.f, 0.f, }).y * 100, 25); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 1.f, 0.f, }).y * 100, 29); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 0.f, 1.f, }).y * 100, 31); + + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 1.f, 0.f, 0.f, }).z * 100, 51); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 1.f, 0.f, }).z * 100, 248); + REQUIRE_EQ(lch_from_rgb((vec3_f32) { 0.f, 0.f, 1.f, }).z * 100, -167); + + 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); + + vec3_f32 black = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 0.f, 0.f, })); + REQUIRE_EQ(black.x * 100, 0); + REQUIRE_EQ(black.y * 100, 0); + REQUIRE_EQ(black.z * 100, 0); + + vec3_f32 grey = rgb_from_lch(lch_from_rgb((vec3_f32) { .5f, .5f, .5f, })); + REQUIRE_EQ(grey.x * 100, 50); + REQUIRE_EQ((grey.y + 3e-8) * 100, 50); + REQUIRE_EQ((grey.z + 3e-7) * 100, 50); + + vec3_f32 red = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 0.f, 0.f, })); + REQUIRE_EQ(red.x * 100, 100); + REQUIRE_EQ(red.y * 100, 0); + REQUIRE_EQ(red.z * 100, 0); + + 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.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); + + vec3_f32 yellow = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 1.f, 0.f, })); + REQUIRE_EQ(yellow.x * 100, 100); + REQUIRE_EQ((yellow.y + 6e-8) * 100, 100); + REQUIRE_EQ(yellow.z * 100, 0); + + 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); + + 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); +} Brush brush = { .buffer = { .width = 1280, .height = 720, .line_size = 1280, - .pixels = g_pixels, + .pixels = g_platform.pixels, }, .position = { 0.f, 0.f, }, .scale = { 1.f, 1.f, }, @@ -1509,9 +1630,6 @@ BENCHMARK("fill rectangle") { fill_rectangle(brush, 100, 100, 300, 200); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } BENCHMARK("fill triangle") { @@ -1520,9 +1638,6 @@ BENCHMARK("fill triangle") { fill_triangle(brush, 100, 100, 300, 100, 200, 250); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } BENCHMARK("fill quad") { @@ -1531,9 +1646,6 @@ BENCHMARK("fill quad") { fill_quad(brush, 100, 100, 300, 100, 300, 200, 100, 200); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } BENCHMARK("fill ellipse") { @@ -1542,9 +1654,6 @@ BENCHMARK("fill ellipse") { fill_ellipse(brush, 80, 80, 340, 240); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } BENCHMARK("fill line") { @@ -1553,9 +1662,6 @@ BENCHMARK("fill line") { fill_line(brush, 100, 100, 300, 200, 40); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } BENCHMARK("draw text area") { @@ -1565,9 +1671,6 @@ BENCHMARK("draw text area") { draw_text_area(brush, 100, 100, 300, 200, 100, 200, sizeof text / sizeof *text, text); } BENCHMARK_END; - - for (i64 i = 0; i < MAX_NUM_PIXELS; ++i) - g_pixels[i] = (vec4_f32) {0}; } void update_and_render_frame(void) {} diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 50f3452..07087f7 100644 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -28,7 +28,6 @@ // To-Do list // // - Work in progress -// - Drop files - Web // - Seldom allocator // - Logging // - Examples @@ -43,6 +42,7 @@ // - CMYK color // - Textures // - Test suite +// - Improve microbenchmarks library // - System // - Window // - Wayland @@ -99,7 +99,7 @@ // - Sound - ALSA, Web // - Networking // - Unix UDP sockets -// - Drop files - X11 +// - Drop files - X11, Web // // ---------------------------------------------------------------- // @@ -224,7 +224,7 @@ i32 main(i32 argc, c8 **argv); #ifndef FRAME_DURATION_HARD_LIMIT // The pixel size value will reset if the frame duration is higher. -#define FRAME_DURATION_HARD_LIMIT 500 +#define FRAME_DURATION_HARD_LIMIT 400 #endif #ifndef NUM_FRAMES_AVERAGED @@ -1478,7 +1478,6 @@ static i16 _key_table [MAX_NUM_KEYS] = {0}; static b8 _key_repeat [MAX_NUM_KEYS] = {0}; static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0}; static u32 _pixels_internal [MAX_NUM_PIXELS] = {0}; -static c8 _clipboard_buffer [MAX_CLIPBOARD_SIZE] = {0}; static b8 sub_str_eq_(c8 *a, c8 *b, i64 len) { for (i64 i = 0; i < len; ++i) @@ -43,7 +43,7 @@ // // ---------------------------------------------------------------- // -// (C) 2025 Mitya Selivanov <guattari.tech>, MIT License +// (C) 2025 Mitya Selivanov <guattari.tech> // // ================================================================ |