summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild_all.sh3
-rwxr-xr-xgraphics.c185
-rwxr-xr-x[-rw-r--r--]reduced_system_layer.c919
-rwxr-xr-xstackless_coroutine.c2
4 files changed, 842 insertions, 267 deletions
diff --git a/build_all.sh b/build_all.sh
index d5c2305..e4674e4 100755
--- a/build_all.sh
+++ b/build_all.sh
@@ -7,10 +7,9 @@ FLAGS_X11=" \
-Wno-unused-parameter \
-Wno-overlength-strings \
-D NDEBUG \
- -D NO_WAYLAND=0 \
-O3 \
-fsanitize=undefined,address,leak \
- -lX11 -lm -lasound \
+ -lm -lX11 -lasound \
-lwayland-client"
FLAGS_WEB=" \
diff --git a/graphics.c b/graphics.c
index c89e746..4fa8a49 100755
--- a/graphics.c
+++ b/graphics.c
@@ -12,23 +12,25 @@
#/ Self-testing shell script
#/
#/ ================================================================
+
SRC=${0##*./}
BIN=${SRC%.*}
-gcc \
- -Wall -Wextra -Werror -pedantic \
- -Wno-missing-braces \
- -Wno-old-style-declaration \
- -Wno-overlength-strings \
- -O3 -D NDEBUG \
- -D NO_WAYLAND=1 \
- -D GRAPHICS_TEST_SUITE \
- -lX11 -lm -lasound \
- -o $BIN $SRC && \
+gcc \
+ -Wall -Wextra -Werror -pedantic \
+ -Wno-missing-braces \
+ -Wno-old-style-declaration \
+ -Wno-overlength-strings \
+ -O3 -D NDEBUG \
+ -D ENABLE_WAYLAND=0 \
+ -D GRAPHICS_TEST_SUITE \
+ -lX11 -lm -lasound \
+ -o $BIN $SRC && \
./$BIN $@
STATUS=$?
rm -f $BIN
-exit $? # */
+exit $STATUS # */
#endif
+
// ================================================================
#ifndef GRAPHICS_HEADER_GUARD_
@@ -107,25 +109,25 @@ vec3_f32 rgb_f32_from_u32(u32 color);
u32 rgba_u32_from_f32(vec4_f32 color);
vec4_f32 rgba_f32_from_u32(u32 color);
-b8 rectangle_contains(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py);
-b8 triangle_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 py);
-b8 quad_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3, f64 px, f64 py);
-b8 ellipse_contains (f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py);
-b8 line_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py);
+b8 hit_rectangle(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py);
+b8 hit_triangle (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 py);
+b8 hit_quad (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3, f64 px, f64 py);
+b8 hit_ellipse (f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py);
+b8 hit_line (f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py);
// ================================================================
enum {
- OP_NONE = 0,
- OP_REQUESTS,
- OP_PIXELS,
- OP_RECTANGLE,
- OP_TRIANGLE,
- OP_QUAD,
- OP_ELLIPSE,
- OP_LINE,
- OP_TEXT_AREA,
- OP_TEXT_CURSOR,
+ GRAPHICS_OP_NONE = 0,
+ GRAPHICS_OP_REQUESTS,
+ GRAPHICS_OP_PIXELS,
+ GRAPHICS_OP_RECTANGLE,
+ GRAPHICS_OP_TRIANGLE,
+ GRAPHICS_OP_QUAD,
+ GRAPHICS_OP_ELLIPSE,
+ GRAPHICS_OP_LINE,
+ GRAPHICS_OP_TEXT_AREA,
+ GRAPHICS_OP_TEXT_CURSOR,
};
typedef struct {
@@ -135,12 +137,12 @@ typedef struct {
f64 height;
} Box;
-typedef struct gx_request {
+typedef struct graphics_request_ {
u16 op;
union {
struct {
- i64 num;
- struct gx_request *values;
+ i64 num;
+ struct graphics_request_ *values;
} requests;
struct {
Box area;
@@ -184,21 +186,16 @@ typedef struct gx_request {
c32 * text;
} text_cursor;
};
-} Gx_Request;
-
-typedef struct {
- i64 x;
- i64 y;
- Pixel_Buffer buffer;
-} Gx_Baked;
+} Graphics_Request;
typedef struct {
- i64 sketch_size;
- vec4_f32 *sketch;
- vec2 scale;
-} Gx_Context;
+ i64 sketch_size;
+ vec4_f32 * sketch;
+ vec2 scale;
+ Pixel_Buffer dst;
+} Graphics_Context;
-void gx_render(Gx_Context context, Pixel_Buffer dst, Gx_Request req);
+void perform_graphics_reqeust(Graphics_Context context, Graphics_Request req);
#endif // GRAPHICS_HEADER_GUARD_
@@ -437,13 +434,13 @@ void fill_triangle_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 x1,
i64 right = i0;
for (i64 i = i0; i <= i1; ++i)
- if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) {
+ if (hit_triangle(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) {
left = i;
break;
}
for (i64 i = i1; i >= i0; --i)
- if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) {
+ if (hit_triangle(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) {
right = i;
break;
}
@@ -471,13 +468,13 @@ void fill_quad_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 x1, f64
i64 right = i0;
for (i64 i = i0; i <= i1; ++i)
- if (quad_contains(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) {
+ if (hit_quad(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) {
left = i;
break;
}
for (i64 i = i1; i >= i0; --i)
- if (quad_contains(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) {
+ if (hit_quad(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) {
right = i;
break;
}
@@ -1089,11 +1086,11 @@ vec4_f32 rgba_f32_from_u32(u32 color) {
};
}
-b8 rectangle_contains(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py) {
+b8 hit_rectangle(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py) {
return px >= x0 && px < x0 + width && py >= y0 && py < y0 + height;
}
-b8 triangle_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 py) {
+b8 hit_triangle(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 py) {
// Z-components of cross-products
//
@@ -1118,12 +1115,12 @@ b8 triangle_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64
&& same_sign_(z2, pz2);
}
-b8 quad_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3, f64 px, f64 py) {
- return triangle_contains(x0, y0, x1, y1, x2, y2, px, py)
- || triangle_contains(x0, y0, x2, y2, x3, y3, px, py);
+b8 hit_quad(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3, f64 px, f64 py) {
+ return hit_triangle(x0, y0, x1, y1, x2, y2, px, py)
+ || hit_triangle(x0, y0, x2, y2, x3, y3, px, py);
}
-b8 ellipse_contains(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py) {
+b8 hit_ellipse(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py) {
f64 dw = width / 2;
f64 dh = height / 2;
@@ -1141,7 +1138,7 @@ b8 ellipse_contains(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py) {
return dx * dx + dy * dy - 1.0 < EPSILON;
}
-b8 line_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py) {
+b8 hit_line(f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py) {
f64 dx = x1 - x0;
f64 dy = y1 - y0;
@@ -1157,21 +1154,21 @@ b8 line_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py) {
tx *= width * .5;
ty *= width * .5;
- return quad_contains(x0 - tx, y0 - ty, x0 + tx, y0 + ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty, px, py);
+ return hit_quad(x0 - tx, y0 - ty, x0 + tx, y0 + ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty, px, py);
}
// ================================================================
-void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
+void perform_raw_graphics_request_(Graphics_Context context, Graphics_Request req) {
switch (req.op) {
- case OP_REQUESTS:
+ case GRAPHICS_OP_REQUESTS:
for (i64 i = 0; i < req.requests.num; ++i)
- gx_render_raw_(context, dst, req.requests.values[i]);
+ perform_raw_graphics_request_(context, req.requests.values[i]);
break;
- case OP_PIXELS:
+ case GRAPHICS_OP_PIXELS:
draw_pixels_raw(
- dst,
+ context.dst,
req.pixels.area.x,
req.pixels.area.y,
req.pixels.area.width,
@@ -1180,9 +1177,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_RECTANGLE:
+ case GRAPHICS_OP_RECTANGLE:
fill_rectangle_raw(
- dst,
+ context.dst,
req.rectangle.color,
req.rectangle.area.x,
req.rectangle.area.y,
@@ -1191,9 +1188,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_TRIANGLE:
+ case GRAPHICS_OP_TRIANGLE:
fill_triangle_raw(
- dst,
+ context.dst,
req.triangle.color,
req.triangle.vertices[0].x,
req.triangle.vertices[0].y,
@@ -1204,9 +1201,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_QUAD:
+ case GRAPHICS_OP_QUAD:
fill_quad_raw(
- dst,
+ context.dst,
req.quad.color,
req.quad.vertices[0].x,
req.quad.vertices[0].y,
@@ -1219,9 +1216,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_ELLIPSE:
+ case GRAPHICS_OP_ELLIPSE:
fill_ellipse_raw(
- dst,
+ context.dst,
req.ellipse.color,
req.ellipse.area.x,
req.ellipse.area.y,
@@ -1230,9 +1227,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_LINE:
+ case GRAPHICS_OP_LINE:
fill_line_raw(
- dst,
+ context.dst,
req.line.color,
req.line.vertices[0].x,
req.line.vertices[0].y,
@@ -1242,9 +1239,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_TEXT_AREA:
+ case GRAPHICS_OP_TEXT_AREA:
draw_text_area_raw(
- dst,
+ context.dst,
req.text_area.color,
req.text_area.area.x,
req.text_area.area.y,
@@ -1257,9 +1254,9 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
);
break;
- case OP_TEXT_CURSOR:
+ case GRAPHICS_OP_TEXT_CURSOR:
draw_text_cursor_raw(
- dst,
+ context.dst,
req.text_cursor.color,
req.text_cursor.area.x,
req.text_cursor.area.y,
@@ -1278,30 +1275,30 @@ void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
}
}
-Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
- Gx_Request scaled = req;
+Graphics_Request graphics_request_scaled_(Graphics_Request req, vec2 scale) {
+ Graphics_Request scaled = req;
switch (req.op) {
- case OP_REQUESTS:
+ case GRAPHICS_OP_REQUESTS:
for (i64 i = 0; i < req.requests.num; ++i)
- scaled.requests.values[i] = gx_scaled_(req.requests.values[i], scale);
+ scaled.requests.values[i] = graphics_request_scaled_(req.requests.values[i], scale);
break;
- case OP_PIXELS:
+ case GRAPHICS_OP_PIXELS:
scaled.pixels.area.x *= scale.x;
scaled.pixels.area.y *= scale.y;
scaled.pixels.area.width *= scale.x;
scaled.pixels.area.height *= scale.y;
break;
- case OP_RECTANGLE:
+ case GRAPHICS_OP_RECTANGLE:
scaled.rectangle.area.x *= scale.x;
scaled.rectangle.area.y *= scale.y;
scaled.rectangle.area.width *= scale.x;
scaled.rectangle.area.height *= scale.y;
break;
- case OP_TRIANGLE:
+ case GRAPHICS_OP_TRIANGLE:
scaled.triangle.vertices[0].x *= scale.x;
scaled.triangle.vertices[0].y *= scale.y;
scaled.triangle.vertices[1].x *= scale.x;
@@ -1310,7 +1307,7 @@ Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
scaled.triangle.vertices[2].y *= scale.y;
break;
- case OP_QUAD:
+ case GRAPHICS_OP_QUAD:
scaled.quad.vertices[0].x *= scale.x;
scaled.quad.vertices[0].y *= scale.y;
scaled.quad.vertices[1].x *= scale.x;
@@ -1321,14 +1318,14 @@ Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
scaled.quad.vertices[3].y *= scale.y;
break;
- case OP_ELLIPSE:
+ case GRAPHICS_OP_ELLIPSE:
scaled.ellipse.area.x *= scale.x;
scaled.ellipse.area.y *= scale.y;
scaled.ellipse.area.width *= scale.x;
scaled.ellipse.area.height *= scale.y;
break;
- case OP_LINE:
+ case GRAPHICS_OP_LINE:
scaled.line.vertices[0].x *= scale.x;
scaled.line.vertices[0].y *= scale.y;
scaled.line.vertices[1].x *= scale.x;
@@ -1351,7 +1348,7 @@ Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
break;
- case OP_TEXT_AREA:
+ case GRAPHICS_OP_TEXT_AREA:
scaled.text_area.area.x *= scale.x;
scaled.text_area.area.y *= scale.y;
scaled.text_area.area.width *= scale.x;
@@ -1360,7 +1357,7 @@ Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
scaled.text_area.max_size.y *= scale.y;
break;
- case OP_TEXT_CURSOR:
+ case GRAPHICS_OP_TEXT_CURSOR:
scaled.text_cursor.area.x *= scale.x;
scaled.text_cursor.area.y *= scale.y;
scaled.text_cursor.area.width *= scale.x;
@@ -1375,21 +1372,23 @@ Gx_Request gx_scaled_(Gx_Request req, vec2 scale) {
return scaled;
}
-void gx_render_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
- gx_render_raw_(context, dst, gx_scaled_(req, context.scale));
+void scale_and_perform_graphics_request_(Graphics_Context context, Graphics_Request req) {
+ perform_raw_graphics_request_(context, graphics_request_scaled_(req, context.scale));
}
-void gx_render(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
+// ================================================================
+
+void perform_graphics_request(Graphics_Context context, Graphics_Request req) {
if (context.sketch == NULL) {
context.sketch_size = MAX_NUM_PIXELS;
context.sketch = g_platform.sketch;
}
- if (dst.pixels == NULL) {
- dst.width = g_platform.frame_width;
- dst.height = g_platform.frame_height;
- dst.stride = g_platform.frame_width;
- dst.pixels = g_platform.pixels;
+ if (context.dst.pixels == NULL) {
+ context.dst.width = g_platform.frame_width;
+ context.dst.height = g_platform.frame_height;
+ context.dst.stride = g_platform.frame_width;
+ context.dst.pixels = g_platform.pixels;
if (context.scale.x == 0. && context.scale.y == 0.)
context.scale = (vec2) {
@@ -1398,7 +1397,7 @@ void gx_render(Gx_Context context, Pixel_Buffer dst, Gx_Request req) {
};
}
- gx_render_(context, dst, req);
+ scale_and_perform_graphics_request_(context, req);
}
// ================================================================
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index fff4f44..847edae 100644..100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -1,149 +1,176 @@
-// ================================================================
-//
-// reduced_system_layer.c
-//
-// This is a reduced system layer.
-// It allows you to create a window, draw graphics in it, handle
-// input events, write samples to audio output, send and receive
-// UDP packets, etc. All code is single-threaded.
-//
-// Primary target platforms: Linux (X11), Windows, Web.
-//
-// ----------------------------------------------------------------
-//
-// DESIGN PRINCIPLES
-//
-// - Minimalistic feature set. For graphics, you have access to the
-// pixel buffer, and that's it.
-//
-// - No implicit control flow. No callbacks. You write your own
-// main and call everything explicitly. But the number of things
-// you have to call to do something is as little as possible.
-//
-// - Optimized to use in a single source file.
-// Installation process? Ctrl+C, Ctrl+V, done.
-//
-// STYLE CONVENTIONS
-//
-// - Capitalized_Snake_Case - Type name.
-// - snake_case - Non-type name.
-// - UPPER_SNAKE_CASE - Macro or constant.
-// - g_ prefix - Global variable name.
-//
-// Most procedures have long and descriptive names.
-// Some procedures have prefixes according to their domain.
-//
-// There may be exceptions if convenient.
-//
-// ----------------------------------------------------------------
-//
-// To-Do list
-//
-// - Work in progress
-// - Clipboard
-// - Images
-// - Sound
-// - Seldom allocator
-// - Logging
-// - Graphics perf - request cache
-// Requires:
-// + [ ] Graphics tests
-// + [x] Graphics requests
-// + [ ] Seldom allocator
-// + [ ] Blake2 hash
-// + [ ] Requests cache
-// + [ ] Incremental rendering
-// - Examples
-// - Conway's Game of Life
-// - Julia Set
-// - Labyrinth
-// - Chat
-// - Graphics
-// - UI
-// - Icons
-// - Vector math
-// - CMYK color
-// - Textures
-// - Test suite
-// - Improve microbenchmarks library
-// - System
-// - Window
-// - Wayland
-// - Windows graphics
-// - Sound
-// - Windows audio
-// - Recording
-// - Device selection
-// - Switching canvases - Web
-// - Networking
-// - Windows sockets
-// - TCP
-// - fetch - via libcurl on native platforms
-// - Cross-platform networking - UDP + TCP + WebSocket
-// Requires:
-// - [ ] Sockets - UDP, TCP
-// - [ ] HTTP client
-// - [ ] HTTP server
-// - [ ] Web sockets
-// - [ ] Key exchange
-// - [ ] Cipher suite (Lattice-based?)
-// - [ ] TLS
-// - [ ] Web sockets over TLS
-// - Long term
-// - dlopen - load libraries conditionally
-// - X11
-// - Wayland
-// - ALSA
-// - Allocator
-// - Parsing
-// - Printing
-// - File system
-// - Secure random
-// - Process
-// - Shared memory
-// - Shared mutex
-// - Big integer
-// - Mersenne Twister 64
-// - Arithmetic coding
-// - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper
-// - Cryptography - https://github.com/jedisct1/supercop
-// - macOS support
-// - Mobile devices support
-//
-// Done
-//
-// - Examples
-// - Echo
-// - UI
-// - Particles
-// - Graph
-// - Sine Wave
-// - Utility
-// - UTF-8
-// - Testing
-// - Stackless coroutines
-// - Graphics
-// - Font
-// - Adaptive resolution
-// - Oklab color
-// - Relative coordinates
-// - Alpha blending
-// - Self-contained impl
-// - Anti-aliasing
-// - System
-// - Window - X11, Web
-// - Screenshot - X11, Wayland
-// - Clipboard
-// - Text - X11, Web
-// - Sound - ALSA, Web
-// - Networking
-// - Unix UDP sockets
-// - Drop files - X11, Web
-//
-// ----------------------------------------------------------------
-//
-// (C) 2025 Mitya Selivanov <guattari.tech>
-//
+#if 0 /*
+#/ ================================================================
+#/
+#/ reduced_system_layer.c
+#/
+#/ This is a reduced system layer.
+#/ It allows you to create a window, draw graphics in it, handle
+#/ input events, write samples to audio output, send and receive
+#/ UDP packets, etc. All code is single-threaded.
+#/
+#/ Primary target platforms: Linux (X11), Windows, Web.
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ DESIGN PRINCIPLES
+#/
+#/ - Minimalistic feature set. For graphics, you have access to the
+#/ pixel buffer, and that's it.
+#/
+#/ - No implicit control flow. No callbacks. You write your own
+#/ main and call everything explicitly. But the number of things
+#/ you have to call to do something is as little as possible.
+#/
+#/ - Optimized to use in a single source file.
+#/ Installation process? Ctrl+C, Ctrl+V, done.
+#/
+#/ STYLE CONVENTIONS
+#/
+#/ - Pascal_Snake_Case - Type name.
+#/ - snake_case - Non-type name.
+#/ - UPPER_SNAKE_CASE - Macro or constant.
+#/ - g_ prefix - Global variable name.
+#/
+#/ Most procedures have long and descriptive names.
+#/ Some procedures have prefixes according to their domain.
+#/
+#/ There may be exceptions if convenient.
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ To-Do list
+#/
+#/ - Work in progress
+#/ - Clipboard
+#/ - Images
+#/ - Sound
+#/ - Logging
+#/ - Graphics perf - request cache
+#/ Requires:
+#/ + [ ] Graphics tests
+#/ + [x] Graphics requests
+#/ + [x] Memory buffer allocator
+#/ + [x] Blake2 hash
+#/ + [ ] Requests cache
+#/ + [ ] Incremental rendering
+#/ - Examples
+#/ - Conway's Game of Life
+#/ - Julia Set
+#/ - Labyrinth
+#/ - Chat
+#/ - Graphics
+#/ - UI
+#/ - Icons
+#/ - Vector math
+#/ - CMYK color
+#/ - Textures
+#/ - Test suite
+#/ - Improve microbenchmarks library
+#/ - System
+#/ - Window
+#/ - Wayland
+#/ - Windows graphics
+#/ - Sound
+#/ - Windows audio
+#/ - Recording
+#/ - Device selection
+#/ - Switching canvases - Web
+#/ - Networking
+#/ - Windows sockets
+#/ - TCP
+#/ - fetch - via libcurl on native platforms
+#/ - Cross-platform networking - UDP + TCP + WebSocket
+#/ Requires:
+#/ - [ ] Sockets - UDP, TCP
+#/ - [ ] HTTP client
+#/ - [ ] HTTP server
+#/ - [ ] Web sockets
+#/ - [ ] Key exchange
+#/ - [ ] Cipher suite
+#/ - TLS_AES_128_GCM_SHA256
+#/ - Lattice-based ?
+#/ - [ ] TLS
+#/ - [ ] Web sockets over TLS
+#/ - Long term
+#/ - dlopen - load libraries conditionally
+#/ - X11
+#/ - Wayland
+#/ - ALSA
+#/ - Allocator
+#/ - Parsing
+#/ - Printing
+#/ - File system
+#/ - Secure random
+#/ - Process
+#/ - Shared memory
+#/ - Shared mutex
+#/ - Big integer
+#/ - Mersenne Twister 64
+#/ - Arithmetic coding
+#/ - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper
+#/ - Cryptography - https://github.com/jedisct1/supercop
+#/ - macOS support
+#/ - Mobile devices support
+#/
+#/ Done
+#/
+#/ - Examples
+#/ - Echo
+#/ - UI
+#/ - Particles
+#/ - Graph
+#/ - Sine Wave
+#/ - Utility
+#/ - UTF-8
+#/ - Testing
+#/ - Stackless coroutines
+#/ - Graphics
+#/ - Font
+#/ - Adaptive resolution
+#/ - Oklab color
+#/ - Relative coordinates
+#/ - Alpha blending
+#/ - Self-contained impl
+#/ - Anti-aliasing
+#/ - System
+#/ - Window - X11, Web
+#/ - Screenshot - X11, Wayland
+#/ - Clipboard
+#/ - Text - X11, Web
+#/ - Sound - ALSA, Web
+#/ - Networking
+#/ - Unix UDP sockets
+#/ - Drop files - X11, Web
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ (C) 2025 Mitya Selivanov <guattari.tech>
+#/
+#/ ================================================================
+#/
+#/ Self-testing shell script
+#/
+#/ ================================================================
+
+SRC=${0##*./}
+BIN=${SRC%.*}
+gcc \
+ -Wall -Wextra -Werror -pedantic \
+ -Wno-missing-braces \
+ -Wno-old-style-declaration \
+ -Wno-overlength-strings \
+ -O3 -D NDEBUG \
+ -fsanitize=undefined,address,leak \
+ -D REDUCED_SYSTEM_LAYER_TEST_SUITE \
+ -lm -lX11 -lasound \
+ -lwayland-client \
+ -o $BIN $SRC && \
+ ./$BIN $@
+STATUS=$?
+rm -f $BIN
+exit $STATUS # */
+#endif
+
// ================================================================
//
// Types
@@ -187,6 +214,10 @@ typedef struct { f64 v[16]; } mat4;
#ifndef REDUCED_SYSTEM_LAYER_HEADER_GUARD_
#define REDUCED_SYSTEM_LAYER_HEADER_GUARD_
+#ifdef EVERY_TEST_SUITE
+#define GRAPHICS_TEST_SUITE
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -210,18 +241,22 @@ i32 main(i32 argc, c8 **argv);
//
// ================================================================
-#ifndef NO_WAYLAND
-#define NO_WAYLAND 0
+#ifndef ENABLE_WAYLAND
+#define ENABLE_WAYLAND 1
#endif
-#ifndef NO_X11
-#define NO_X11 0
+#ifndef ENABLE_X11
+#define ENABLE_X11 1
#endif
#ifndef STATIC_MEMORY_BUFFER_SIZE
#define STATIC_MEMORY_BUFFER_SIZE (10 * 1024 * 1024)
#endif
+#ifndef MEMORY_CHUNK_SIZE
+#define MEMORY_CHUNK_SIZE 1024
+#endif
+
// ----------------------------------------------------------------
// TEMP: Static buffers.
@@ -672,7 +707,7 @@ i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_po
void shutdown_all_systems(void);
// Memory
-void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data);
+void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data);
#ifdef REDUCED_SYSTEM_LAYER_HEADER
extern Platform g_platform;
@@ -736,14 +771,18 @@ void run_main_window_event_loop(void) {
// ================================================================
//
-// Seldom memory allocator
+// Memory buffer allocator
//
// ================================================================
+enum {
+ OCCUPIED_SIZE_ = (STATIC_MEMORY_BUFFER_SIZE + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE),
+};
+
typedef struct {
- i64 offset;
- i64 size;
-} Memory_Slot_;
+ i64 next_chunk;
+ u64 occupied[OCCUPIED_SIZE_];
+} Memory_Buffer_Header_;
static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0};
@@ -751,20 +790,537 @@ static i64 num_memory_slots_(void) {
return *(i64 *) &g_platform.memory_buffer[g_platform.memory_buffer_size - 8];
}
-void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) {
- if (g_platform.memory_buffer_size < 0)
+static i64 align_(i64 x, i64 alignment) {
+ return ((x + (alignment - 1)) / alignment) * alignment;
+}
+
+void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) {
+ if (g_platform.memory_buffer_size < 0) {
LOG_ERROR("Invalid memory buffer size.");
- if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0)
+ return NULL;
+ }
+
+ if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) {
LOG_ERROR("Invalid memory buffer.");
+ return NULL;
+ }
if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) {
g_platform.memory_buffer_size = sizeof memory_buffer_;
g_platform.memory_buffer = memory_buffer_;
}
- // TODO
- LOG_ERROR("Not implemented.");
- return NULL;
+ if (g_platform.memory_buffer_size <= (i64) sizeof(Memory_Buffer_Header_)) {
+ LOG_ERROR("Memory buffer too small.");
+ return NULL;
+ }
+
+ Memory_Buffer_Header_ *h = (Memory_Buffer_Header_ *) g_platform.memory_buffer;
+ u8 * data = g_platform.memory_buffer + sizeof(Memory_Buffer_Header_);
+
+ i64 prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ i64 prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE;
+
+ i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ i64 chunk = 0;
+
+ // Find free space
+ for (i64 i = h->next_chunk; i < OCCUPIED_SIZE_ * 64; ++i) {
+ b8 occupied = 0;
+
+ for (i64 j = i; j < i + num_chunks; ++j) {
+ if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue;
+ if ((h->occupied[j / 64] & (1ull << (j % 64))) == 0) continue;
+ occupied = 1;
+ break;
+ }
+
+ if (occupied) {
+ chunk = i;
+ break;
+ }
+ }
+
+ u8 *src = data + prev_chunk * MEMORY_CHUNK_SIZE;
+ u8 *dst = data + chunk * MEMORY_CHUNK_SIZE;
+ i64 len = size < previous_size ? size : previous_size;
+
+ // Check if out of memory
+ if (data + size > g_platform.memory_buffer + g_platform.memory_buffer_size) {
+ LOG_ERROR("Out of memory.");
+ return NULL;
+ }
+
+ // Claim required space
+ for (i64 j = chunk; j < chunk + num_chunks; ++j)
+ h->occupied[j / 64] |= 1ull << (j % 64);
+
+ // Copy data
+ if (dst > src)
+ for (i64 k = len - 1; k >= 0; --k)
+ dst[k] = src[k];
+ else
+ for (i64 k = 0; k < len; ++k)
+ dst[k] = src[k];
+
+ // Free previous space
+ for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) {
+ if (j >= chunk && j < chunk + num_chunks) continue;
+ h->occupied[j / 64] &= ~(1ull << (j % 64));
+ }
+
+ if (num_chunks == 0)
+ return NULL;
+
+ return dst;
+}
+
+// ================================================================
+//
+// BLAKE2B
+//
+// ================================================================
+
+enum blake2b_constant {
+ BLAKE2B_BLOCKBYTES = 128,
+ BLAKE2B_OUTBYTES = 64,
+ BLAKE2B_KEYBYTES = 64,
+ BLAKE2B_SALTBYTES = 16,
+ BLAKE2B_PERSONALBYTES = 16
+};
+
+typedef struct {
+ u8 digest_length;
+ u8 key_length;
+ u8 fanout;
+ u8 depth;
+ u32 leaf_length;
+ u64 node_offset;
+ u8 node_depth;
+ u8 inner_length;
+ u8 reserved[14];
+ u8 salt[BLAKE2B_SALTBYTES];
+ u8 personal[BLAKE2B_PERSONALBYTES];
+} Blake2b_Param;
+
+typedef struct {
+ u64 h[8];
+ u64 t[2];
+ u64 f[2];
+ u8 buf[2 * BLAKE2B_BLOCKBYTES];
+ u64 buflen;
+ u8 last_node;
+} Blake2b_State;
+
+static u64 blake2b_IV[8] = {
+ 0x6a09e667f3bcc908ull, 0xbb67ae8584caa73bull,
+ 0x3c6ef372fe94f82bull, 0xa54ff53a5f1d36f1ull,
+ 0x510e527fade682d1ull, 0x9b05688c2b3e6c1full,
+ 0x1f83d9abfb41bd6bull, 0x5be0cd19137e2179ull
+};
+
+static u8 blake2b_sigma[12][16] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
+};
+
+static void mem_set_(void *dst, u8 x, u32 size) {
+ for (u32 i = 0; i < size; ++i)
+ ((u8 *) dst)[i] = x;
+}
+
+static void mem_cpy_(void *dst, void *src, u32 size) {
+ for (u32 i = 0; i < size; ++i)
+ ((u8 *) dst)[i] = ((u8 *) src)[i];
+}
+
+static b8 native_little_endian_(void) {
+ return ((u8 *) &(u32) { 1 })[0] == 1;
+}
+
+static u32 load32_(void *src) {
+ if (native_little_endian_())
+ return *( u32 * )( src );
+ else {
+ u8 *p = ( u8 * )src;
+ u32 w = *p++;
+ w |= ( u32 )( *p++ ) << 8;
+ w |= ( u32 )( *p++ ) << 16;
+ w |= ( u32 )( *p++ ) << 24;
+ return w;
+ }
+}
+
+static u64 load64_(void *src) {
+ if (native_little_endian_())
+ return *( u64 * )( src );
+ else {
+ u8 *p = ( u8 * )src;
+ u64 w = *p++;
+ w |= ( u64 )( *p++ ) << 8;
+ w |= ( u64 )( *p++ ) << 16;
+ w |= ( u64 )( *p++ ) << 24;
+ w |= ( u64 )( *p++ ) << 32;
+ w |= ( u64 )( *p++ ) << 40;
+ w |= ( u64 )( *p++ ) << 48;
+ w |= ( u64 )( *p++ ) << 56;
+ return w;
+ }
+}
+
+static void store32_(void *dst, u32 w) {
+ if (native_little_endian_())
+ *( u32 * )( dst ) = w;
+ else {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+ }
+}
+
+static void store64_(void *dst, u64 w) {
+ if (native_little_endian_())
+ *( u64 * )( dst ) = w;
+ else {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+ }
+}
+
+static u64 load48_(void *src) {
+ u8 *p = ( u8 * )src;
+ u64 w = *p++;
+ w |= ( u64 )( *p++ ) << 8;
+ w |= ( u64 )( *p++ ) << 16;
+ w |= ( u64 )( *p++ ) << 24;
+ w |= ( u64 )( *p++ ) << 32;
+ w |= ( u64 )( *p++ ) << 40;
+ return w;
+}
+
+static void store48_(void *dst, u64 w) {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+}
+
+static u32 rotl32_(u32 w, u32 c) {
+ return ( w << c ) | ( w >> ( 32 - c ) );
+}
+
+static u64 rotl64_(u64 w, u32 c) {
+ return ( w << c ) | ( w >> ( 64 - c ) );
+}
+
+static u32 rotr32_(u32 w, u32 c) {
+ return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+static u64 rotr64_(u64 w, u32 c) {
+ return ( w >> c ) | ( w << ( 64 - c ) );
+}
+
+static void secure_zero_memory_(void *v, u64 n) {
+ volatile u8 *p = ( volatile u8 * )v;
+ while( n-- ) *p++ = 0;
+}
+
+static i32 blake2b_set_lastnode_(Blake2b_State *S) {
+ S->f[1] = ~0ull;
+ return 0;
+}
+
+static i32 blake2b_clear_lastnode_(Blake2b_State *S) {
+ S->f[1] = 0ull;
+ return 0;
+}
+
+static i32 blake2b_set_lastblock_(Blake2b_State *S) {
+ if( S->last_node ) blake2b_set_lastnode_( S );
+
+ S->f[0] = ~0ull;
+ return 0;
+}
+
+static i32 blake2b_clear_lastblock_(Blake2b_State *S) {
+ if( S->last_node ) blake2b_clear_lastnode_( S );
+
+ S->f[0] = 0ull;
+ return 0;
+}
+
+static i32 blake2b_increment_counter_(Blake2b_State *S, u64 inc) {
+ S->t[0] += inc;
+ S->t[1] += ( S->t[0] < inc );
+ return 0;
+}
+
+static i32 blake2b_param_set_digest_length_(Blake2b_Param *P, u8 digest_length) {
+ P->digest_length = digest_length;
+ return 0;
+}
+
+static i32 blake2b_param_set_fanout_(Blake2b_Param *P, u8 fanout) {
+ P->fanout = fanout;
+ return 0;
+}
+
+static i32 blake2b_param_set_max_depth_(Blake2b_Param *P, u8 depth) {
+ P->depth = depth;
+ return 0;
+}
+
+static i32 blake2b_param_set_leaf_length_(Blake2b_Param *P, u32 leaf_length) {
+ store32_( &P->leaf_length, leaf_length );
+ return 0;
+}
+
+static i32 blake2b_param_set_node_offset_(Blake2b_Param *P, u64 node_offset) {
+ store64_( &P->node_offset, node_offset );
+ return 0;
+}
+
+static i32 blake2b_param_set_node_depth_(Blake2b_Param *P, u8 node_depth) {
+ P->node_depth = node_depth;
+ return 0;
+}
+
+static i32 blake2b_param_set_inner_length_(Blake2b_Param *P, u8 inner_length) {
+ P->inner_length = inner_length;
+ return 0;
+}
+
+static i32 blake2b_param_set_salt_(Blake2b_Param *P, u8 salt[BLAKE2B_SALTBYTES]) {
+ mem_cpy_( P->salt, salt, BLAKE2B_SALTBYTES );
+ return 0;
+}
+
+static i32 blake2b_param_set_personal_(Blake2b_Param *P, u8 personal[BLAKE2B_PERSONALBYTES]) {
+ mem_cpy_( P->personal, personal, BLAKE2B_PERSONALBYTES );
+ return 0;
+}
+
+static i32 blake2b_init0_(Blake2b_State *S) {
+ i32 i;
+ mem_set_( S, 0, sizeof( Blake2b_State ) );
+
+ for(i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
+
+ return 0;
+}
+
+static i32 blake2b_init_param_(Blake2b_State *S, Blake2b_Param *P) {
+ blake2b_init0_( S );
+ u8 *p = ( u8 * )( P );
+ u64 i;
+
+ for( i = 0; i < 8; ++i )
+ S->h[i] ^= load64_( p + sizeof( S->h[i] ) * i );
+
+ return 0;
+}
+
+i32 blake2b_init(Blake2b_State *S, u8 outlen) {
+ Blake2b_Param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = 0;
+ P->fanout = 1;
+ P->depth = 1;
+ store32_( &P->leaf_length, 0 );
+ store64_( &P->node_offset, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ mem_set_( P->reserved, 0, sizeof( P->reserved ) );
+ mem_set_( P->salt, 0, sizeof( P->salt ) );
+ mem_set_( P->personal, 0, sizeof( P->personal ) );
+ return blake2b_init_param_( S, P );
+}
+
+static i32 blake2b_compress_(Blake2b_State *S, u8 block[BLAKE2B_BLOCKBYTES]) {
+ u64 m[16];
+ u64 v[16];
+ i32 i;
+
+ for( i = 0; i < 16; ++i )
+ m[i] = load64_( block + i * sizeof( m[i] ) );
+
+ for( i = 0; i < 8; ++i )
+ v[i] = S->h[i];
+
+ v[ 8] = blake2b_IV[0];
+ v[ 9] = blake2b_IV[1];
+ v[10] = blake2b_IV[2];
+ v[11] = blake2b_IV[3];
+ v[12] = S->t[0] ^ blake2b_IV[4];
+ v[13] = S->t[1] ^ blake2b_IV[5];
+ v[14] = S->f[0] ^ blake2b_IV[6];
+ v[15] = S->f[1] ^ blake2b_IV[7];
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[blake2b_sigma[r][2*i+0]]; \
+ d = rotr64_(d ^ a, 32); \
+ c = c + d; \
+ b = rotr64_(b ^ c, 24); \
+ a = a + b + m[blake2b_sigma[r][2*i+1]]; \
+ d = rotr64_(d ^ a, 16); \
+ c = c + d; \
+ b = rotr64_(b ^ c, 63); \
+ } while(0)
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+ ROUND( 0 );
+ ROUND( 1 );
+ ROUND( 2 );
+ ROUND( 3 );
+ ROUND( 4 );
+ ROUND( 5 );
+ ROUND( 6 );
+ ROUND( 7 );
+ ROUND( 8 );
+ ROUND( 9 );
+ ROUND( 10 );
+ ROUND( 11 );
+
+ for( i = 0; i < 8; ++i )
+ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+
+#undef G
+#undef ROUND
+ return 0;
+}
+
+i32 blake2b_update(Blake2b_State *S, u8 *in, u64 inlen) {
+ while( inlen > 0 ) {
+ u64 left = S->buflen;
+ u64 fill = 2 * BLAKE2B_BLOCKBYTES - left;
+
+ if( inlen > fill ) {
+ mem_cpy_( S->buf + left, in, fill );
+ S->buflen += fill;
+ blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES );
+ blake2b_compress_( S, S->buf );
+ mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
+ S->buflen -= BLAKE2B_BLOCKBYTES;
+ in += fill;
+ inlen -= fill;
+ } else {
+ mem_cpy_( S->buf + left, in, inlen );
+ S->buflen += inlen;
+ in += inlen;
+ inlen -= inlen;
+ }
+ }
+
+ return 0;
+}
+
+i32 blake2b_init_key(Blake2b_State *S, u8 outlen, void *key, u8 keylen) {
+ Blake2b_Param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = keylen;
+ P->fanout = 1;
+ P->depth = 1;
+ store32_( &P->leaf_length, 0 );
+ store64_( &P->node_offset, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ mem_set_( P->reserved, 0, sizeof( P->reserved ) );
+ mem_set_( P->salt, 0, sizeof( P->salt ) );
+ mem_set_( P->personal, 0, sizeof( P->personal ) );
+
+ if( blake2b_init_param_( S, P ) < 0 ) return -1;
+
+ {
+ u8 block[BLAKE2B_BLOCKBYTES];
+ mem_set_( block, 0, BLAKE2B_BLOCKBYTES );
+ mem_cpy_( block, key, keylen );
+ blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
+ secure_zero_memory_( block, BLAKE2B_BLOCKBYTES );
+ }
+ return 0;
+}
+
+i32 blake2b_final(Blake2b_State *S, u8 *out, u8 outlen) {
+ u8 buffer[BLAKE2B_OUTBYTES];
+ i32 i;
+
+ if( S->buflen > BLAKE2B_BLOCKBYTES ) {
+ blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES );
+ blake2b_compress_( S, S->buf );
+ S->buflen -= BLAKE2B_BLOCKBYTES;
+ mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen );
+ }
+
+ blake2b_increment_counter_( S, S->buflen );
+ blake2b_set_lastblock_( S );
+ mem_set_( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen );
+ blake2b_compress_( S, S->buf );
+
+ for( i = 0; i < 8; ++i )
+ store64_( buffer + sizeof( S->h[i] ) * i, S->h[i] );
+
+ mem_cpy_( out, buffer, outlen );
+ return 0;
+}
+
+i32 blake2b(u8 *out, void *in, void *key, u8 outlen, u64 inlen, u8 keylen) {
+ Blake2b_State S[1];
+
+ if ( NULL == in ) return -1;
+ if ( NULL == out ) return -1;
+ if ( NULL == key ) keylen = 0;
+
+ if ( keylen > 0 ) {
+ if ( blake2b_init_key( S, outlen, key, keylen ) < 0 )
+ return -1;
+ } else {
+ if ( blake2b_init( S, outlen ) < 0 )
+ return -1;
+ }
+
+ blake2b_update( S, ( u8 * )in, inlen );
+ blake2b_final( S, out, outlen );
+ return 0;
}
// ================================================================
@@ -1556,7 +2112,7 @@ void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
//
// ================================================================
-#if defined(__linux__) && !NO_WAYLAND
+#if defined(__linux__) && ENABLE_WAYLAND
#include <sys/mman.h>
#include <wayland-client.h>
@@ -2088,7 +2644,7 @@ finalize:
return ok;
}
-#endif // defined(__linux__) && !NO_WAYLAND
+#endif // defined(__linux__) && ENABLE_WAYLAND
// ================================================================
//
@@ -2096,7 +2652,7 @@ finalize:
//
// ================================================================
-#if defined(__linux__) && !NO_X11
+#if defined(__linux__) && ENABLE_X11
#include <sys/stat.h>
#include <X11/Xlib.h>
@@ -2137,7 +2693,6 @@ static Window _dnd_source = 0;
static b8 _mapped = 0;
static b8 _requested_clipboard = 0;
-
static i16 _key_table [MAX_NUM_KEYS] = {0};
static b8 _key_repeat [MAX_NUM_KEYS] = {0};
static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0};
@@ -2151,7 +2706,7 @@ static b8 sub_str_eq_(c8 *a, c8 *b, i64 len) {
return 1;
}
-i32 x11_error_handler_(Display *display, XErrorEvent *event) {
+static i32 x11_error_handler_(Display *display, XErrorEvent *event) {
XGetErrorText(display, event->error_code, _error_buffer, sizeof _error_buffer - 1);
LOG_ERROR("%s", _error_buffer);
return 0;
@@ -3024,23 +3579,23 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels
return 1;
}
-#endif // defined(__linux__) && !NO_X11
+#endif // defined(__linux__) && ENABLE_X11
// ================================================================
-#if defined(__linux__) && (!NO_X11 || !NO_WAYLAND)
+#if defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND)
void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) {
if (width == NULL || height == NULL) {
LOG_ERROR("Invalid arguments.");
return;
}
- #if !NO_X11
+ #if ENABLE_X11
if (x11_screenshot_(max_num_pixels, width, height, pixels))
return;
#endif
- #if !NO_WAYLAND
+ #if ENABLE_WAYLAND
if (wayland_screenshot_(max_num_pixels, width, height, pixels))
return;
#endif
@@ -3048,7 +3603,7 @@ void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixe
*width = 0;
*height = 0;
}
-#endif // defined(__linux__) && (!NO_X11 || !NO_WAYLAND)
+#endif // defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND)
// ================================================================
//
@@ -3541,6 +4096,28 @@ __attribute__((export_name("js_drop"))) void js_drop(i32 name_len, i32 data_size
#endif // defined(__wasm__)
// ================================================================
+//
+// Test suite
+//
+// ================================================================
+
+#ifdef REDUCED_SYSTEM_LAYER_TEST_SUITE
+
+#define TEST_FILE reduced_system_layer
+#include "test.c"
+
+#ifndef EVERY_TEST_SUITE
+void update_and_render_frame(void) {}
+
+i32 main(i32 argc, c8 **argv) {
+ return run_tests(argc, argv);
+}
+#endif
+
+#undef TEST_FILE
+#endif // REDUCED_SYSTEM_LAYER_TEST_SUITE
+
+// ================================================================
#undef LOG_ERROR
diff --git a/stackless_coroutine.c b/stackless_coroutine.c
index d819f35..cbd02f9 100755
--- a/stackless_coroutine.c
+++ b/stackless_coroutine.c
@@ -25,7 +25,7 @@ gcc \
./$BIN $@
STATUS=$?
rm -f $BIN
-exit $? # */
+exit $STATUS # */
#endif
// ================================================================