summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgraphics.c223
-rw-r--r--reduced_system_layer.c7
-rw-r--r--test.c2
3 files changed, 167 insertions, 65 deletions
diff --git a/graphics.c b/graphics.c
index bc49267..95b9a30 100755
--- a/graphics.c
+++ b/graphics.c
@@ -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)
diff --git a/test.c b/test.c
index 8ae0af6..51f0051 100644
--- a/test.c
+++ b/test.c
@@ -43,7 +43,7 @@
//
// ----------------------------------------------------------------
//
-// (C) 2025 Mitya Selivanov <guattari.tech>, MIT License
+// (C) 2025 Mitya Selivanov <guattari.tech>
//
// ================================================================