summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-04-06 23:04:02 +0200
committerMitya Selivanov <automainint@guattari.tech>2025-04-06 23:04:02 +0200
commite2ad36c4cd9f757b3843ac59c5c436819b70f442 (patch)
treee445f1d412dd10c67bca17424c382cadd11540ef
parent7ecc024796fc2e63c4e1731691d36817edc14916 (diff)
downloadreduced_system_layer-e2ad36c4cd9f757b3843ac59c5c436819b70f442.zip
Dynamic libraries; Refactor
-rwxr-xr-xgraphics.c36
-rwxr-xr-xreduced_system_layer.c573
2 files changed, 365 insertions, 244 deletions
diff --git a/graphics.c b/graphics.c
index c1c879c..ced6963 100755
--- a/graphics.c
+++ b/graphics.c
@@ -141,6 +141,7 @@ typedef struct graphics_request_ {
f64 width;
} line;
struct {
+ i32 font;
vec4_f32 color;
Box area;
vec2 max_size;
@@ -148,6 +149,7 @@ typedef struct graphics_request_ {
c32 * text;
} text_area;
struct {
+ i32 font;
vec4_f32 color;
Box area;
vec2 max_size;
@@ -218,8 +220,8 @@ void fill_triangles_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 position,
void fill_quad_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]);
void fill_ellipse_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area);
void fill_line_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[2], f64 width);
-void draw_text_area_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
-void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
+void draw_text_area_to_buffer (Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
+void draw_text_cursor_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
void draw_pixels_cached (Box area, Pixel_Buffer src);
void fill_rectangle_cached (vec4_f32 color, Box area);
@@ -228,8 +230,8 @@ void fill_triangles_cached (vec4_f32 color, vec2 position, vec2 scale, i64 num_
void fill_quad_cached (vec4_f32 color, vec2 vertices[4]);
void fill_ellipse_cached (vec4_f32 color, Box area);
void fill_line_cached (vec4_f32 color, vec2 vertices[2], f64 width);
-void draw_text_area_cached (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
-void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
+void draw_text_area_cached (i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
+void draw_text_cursor_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
void draw_pixels (Box area, Pixel_Buffer src);
void fill_rectangle (vec4_f32 color, Box area);
@@ -238,8 +240,8 @@ void fill_triangles (vec4_f32 color, vec2 position, vec2 scale, i64 num_triangl
void fill_quad (vec4_f32 color, vec2 vertices[4]);
void fill_ellipse (vec4_f32 color, Box area);
void fill_line (vec4_f32 color, vec2 vertices[2], f64 width);
-void draw_text_area (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
-void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
+void draw_text_area (i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text);
+void draw_text_cursor(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection);
void perform_graphics_request(Graphics_Context context, Graphics_Request req);
@@ -809,7 +811,7 @@ void external_font_render_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color,
}
#endif // !defined(GRAPHICS_ENABLE_EXTERNAL_FONT)
-void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
+void draw_text_area_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
if (text == NULL || num_chars <= 0 || max_size.x < EPSILON || max_size.y < EPSILON)
return;
@@ -830,7 +832,7 @@ void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 m
draw_text_(dst, color, area.x, area.y, kx, ky, num_chars, text);
}
-void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
+void draw_text_cursor_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
if (max_size.x < EPSILON || max_size.y < EPSILON)
return;
@@ -1361,12 +1363,13 @@ void fill_line_cached(vec4_f32 color, vec2 vertices[2], f64 width) {
);
}
-void draw_text_area_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
+void draw_text_area_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
perform_graphics_request(
(Graphics_Context) {0},
(Graphics_Request) {
.op = GRAPHICS_DRAW_TEXT_AREA,
.text_area = {
+ .font = font,
.color = color,
.area = area,
.max_size = max_size,
@@ -1377,12 +1380,13 @@ void draw_text_area_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_char
);
}
-void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
+void draw_text_cursor_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
perform_graphics_request(
(Graphics_Context) {0},
(Graphics_Request) {
.op = GRAPHICS_DRAW_TEXT_CURSOR,
.text_cursor = {
+ .font = font,
.color = color,
.area = area,
.max_size = max_size,
@@ -1499,12 +1503,13 @@ void fill_line(vec4_f32 color, vec2 vertices[2], f64 width) {
);
}
-void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
+void draw_text_area(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
perform_graphics_request(
(Graphics_Context) { .disable_cache = 1, },
(Graphics_Request) {
.op = GRAPHICS_DRAW_TEXT_AREA,
.text_area = {
+ .font = font,
.color = color,
.area = area,
.max_size = max_size,
@@ -1515,12 +1520,13 @@ void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32
);
}
-void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
+void draw_text_cursor(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) {
perform_graphics_request(
(Graphics_Context) { .disable_cache = 1, },
(Graphics_Request) {
.op = GRAPHICS_DRAW_TEXT_CURSOR,
.text_cursor = {
+ .font = font,
.color = color,
.area = area,
.max_size = max_size,
@@ -1586,6 +1592,7 @@ static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) {
break;
case GRAPHICS_DRAW_TEXT_AREA:
+ blake2b_update(S, (u8 *) &req.text_area.font, sizeof req.text_area.font);
blake2b_update(S, (u8 *) &req.text_area.color, sizeof req.text_area.color);
blake2b_update(S, (u8 *) &req.text_area.area, sizeof req.text_area.area);
blake2b_update(S, (u8 *) &req.text_area.max_size, sizeof req.text_area.max_size);
@@ -1598,6 +1605,7 @@ static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) {
break;
case GRAPHICS_DRAW_TEXT_CURSOR:
+ blake2b_update(S, (u8 *) &req.text_cursor.font, sizeof req.text_cursor.font);
blake2b_update(S, (u8 *) &req.text_cursor.color, sizeof req.text_cursor.color);
blake2b_update(S, (u8 *) &req.text_cursor.area, sizeof req.text_cursor.area);
blake2b_update(S, (u8 *) &req.text_cursor.max_size, sizeof req.text_cursor.max_size);
@@ -1927,6 +1935,7 @@ static void perform_graphics_request_to_buffer_(Pixel_Buffer dst, Graphics_Reque
case GRAPHICS_DRAW_TEXT_AREA:
draw_text_area_to_buffer(
dst,
+ req.text_area.font,
req.text_area.color,
req.text_area.area,
req.text_area.max_size,
@@ -1938,6 +1947,7 @@ static void perform_graphics_request_to_buffer_(Pixel_Buffer dst, Graphics_Reque
case GRAPHICS_DRAW_TEXT_CURSOR:
draw_text_cursor_to_buffer(
dst,
+ req.text_cursor.font,
req.text_cursor.color,
req.text_cursor.area,
req.text_cursor.max_size,
@@ -2244,7 +2254,7 @@ BENCHMARK("draw text area") {
BENCHMARK_BEGIN;
{
c32 text[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'S', 'a', 'i', 'l', 'o', 'r', '!', };
- draw_text_area_to_buffer(_test_pixels, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text);
+ draw_text_area_to_buffer(_test_pixels, 0, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text);
}
BENCHMARK_END;
}
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index cf7db67..f083ec8 100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -41,9 +41,6 @@
#/ To-Do list
#/
#/ - Work in progress
-#/ - Clipboard
-#/ - Images - BMP, PPM
-#/ - Sound - WAV
#/ - Graphics perf - request cache
#/ Requires:
#/ + [ ] Graphics tests
@@ -63,6 +60,18 @@
#/ - UI
#/ - Icons
#/ - Folder widget
+#/ - Clipboard
+#/ - Images - BMP, PPM
+#/ - Sound - WAV
+#/ - Clipboard
+#/ - Images - BMP, PPM
+#/ - Sound - WAV
+#/ - Dynamic libraries - load dependencies conditionally
+#/ - X11
+#/ - Wayland
+#/ - ALSA
+#/ - Sockets
+#/ - Windows
#/ - Cross-platform networking - UDP + TCP + WebSocket
#/ Requires:
#/ - [ ] Sockets - UDP, TCP
@@ -102,12 +111,6 @@
#/ - Windows sockets
#/ - fetch - via libcurl on native platforms
#/ - Lattice-based cipher suite
-#/ - dlopen - load libraries conditionally
-#/ - X11
-#/ - Wayland
-#/ - ALSA
-#/ - Sockets
-#/ - Windows
#/ - Switching canvas - Web
#/ - File system
#/ - Secure random
@@ -705,7 +708,12 @@ b8 network_open(u16 slot, Network_Address address, u16 *local_port);
i64 network_recv(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port, Network_Address *remote_address);
i64 network_send(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port);
-// NOTE: This will shutdown main window, networking and audio.
+// Dynamic libraries
+void dynamic_library_open (u16 slot, c8 *name);
+void *dynamic_library_get_proc_address(u16 slot, c8 *proc);
+
+// NOTE: This will shutdown main window, networking, audio,
+// and close all opened dynamic libraries.
// If g_platform.graceful_shutdown is 0, this does nothing.
void shutdown_all_systems(void);
@@ -736,23 +744,7 @@ extern Platform g_platform;
#ifndef REDUCED_SYSTEM_LAYER_IMPL_GUARD_
#define REDUCED_SYSTEM_LAYER_IMPL_GUARD_
-Platform g_platform = {0};
-
-static i64 _sound_clock_time = 0;
-static i64 _sound_clock_carry = 0;
-static i64 _sound_position = 0;
-static i64 _frame_index = 0;
-
-static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0};
-static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0};
-
-void run_main_window_event_loop(void) {
- init_main_window();
-#if !defined(__wasm__)
- while (!g_platform.done) update_and_render_frame();
- shutdown_all_systems();
-#endif
-}
+// ----------------------------------------------------------------
static void mem_set_(void *dst, u8 x, i64 size) {
for (i64 i = 0; i < size; ++i)
@@ -803,199 +795,6 @@ void log_error_impl(i32 file_len, c8 const *file, i32 line, i32 func_len, c8 con
// ================================================================
//
-// Memory buffer allocator
-//
-// ================================================================
-
-static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0};
-
-static i64 align_(i64 x, i64 alignment) {
- return ((x + (alignment - 1)) / alignment) * alignment;
-}
-
-static i64 memory_buffer_occupied_len_(i64 buffer_size) {
- return (buffer_size + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE);
-}
-
-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.");
- 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_;
- }
-
- i64 occupied_len = memory_buffer_occupied_len_(g_platform.memory_buffer_size);
- i64 occupied_len_bytes = occupied_len * 8;
- i64 occupied_len_bits = occupied_len * 64;
-
- u64 *occupied = (u64 *) g_platform.memory_buffer;
-
- if (g_platform.memory_buffer_size <= occupied_len_bytes) {
- LOG_ERROR("Memory buffer too small.");
- return NULL;
- }
-
- if (alignment <= 0) {
- LOG_ERROR("Invalid alignment: %lld", alignment);
- return NULL;
- }
-
- if (size < 0) {
- LOG_ERROR("Invalid size: %lld", size);
- return NULL;
- }
-
- if (previous_size < 0) {
- LOG_ERROR("Invalid previous size: %lld", previous_size);
- return NULL;
- }
-
- if (previous_size > 0 && previous_data == NULL) {
- LOG_ERROR("Invalid previous data.");
- return NULL;
- }
-
- u8 *data = g_platform.memory_buffer + occupied_len_bytes;
-
- i64 prev_num_chunks = 0;
- i64 prev_chunk = 0;
-
- if (previous_size > 0) {
- prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
- prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE;
- }
-
- i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
- i64 chunk = (g_platform.memory_buffer_size + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
-
- if (num_chunks == prev_num_chunks)
- return previous_data;
-
- u8 *dst = NULL;
-
- if (num_chunks < prev_num_chunks) {
- // Reuse previously allocated space.
- chunk = prev_chunk;
- dst = data + chunk * MEMORY_CHUNK_SIZE;
- } else {
- // Search free space
- for (i64 i = 0;; ++i) {
- while ((i % 64) == 0
- && i < occupied_len_bits
- && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks)
- && occupied[i / 64] == ~0ull)
- i += 64;
- while ((i % 8) == 0
- && i < occupied_len_bits
- && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks)
- && ((u8 *) occupied)[i / 8] == 255u)
- i += 8;
- if (i >= occupied_len_bits) break;
- b8 is_occupied = 0;
- for (i64 j = i; j < i + num_chunks; ++j) {
- if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue;
- if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue;
- is_occupied = 1;
- break;
- }
- if (!is_occupied) {
- chunk = i;
- break;
- }
- }
-
- // Check if out of memory
- dst = data + chunk * MEMORY_CHUNK_SIZE;
- if (dst + size > g_platform.memory_buffer + g_platform.memory_buffer_size) {
- LOG_ERROR("Out of memory: %lld bytes", size - previous_size);
- return NULL;
- }
-
- // Claim required space
- for (i64 j = chunk; j < chunk + num_chunks; ++j)
- occupied[j / 64] |= 1ull << (j % 64);
- }
-
- if (chunk != prev_chunk) {
- // Copy data
- i64 len = size < previous_size ? size : previous_size;
- u8 *s0 = data + prev_chunk * MEMORY_CHUNK_SIZE;
- u8 *s1 = s0 + len - 1;
- u8 *d0 = dst;
- u8 *d1 = dst + len - 1;
- if (d0 > s0)
- for (u8 *d = d1, *s = s1; d >= d0; --d, --s)
- *d = *s;
- else
- for (u8 *d = d0, *s = s0; d <= d1; ++d, ++s)
- *d = *s;
- }
-
- // Free previous space
- for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) {
- if (j >= chunk && j < chunk + num_chunks) continue;
- occupied[j / 64] &= ~(1ull << (j % 64));
- }
-
- if (num_chunks == 0)
- return NULL;
-
- return dst;
-}
-
-void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new_num) {
- if (num == NULL || data == NULL) {
- LOG_ERROR("Sanity");
- return;
- }
-
- if (*num == new_num)
- return;
-
- i64 alignment = max2_i64_(8, element_size);
-
- void *new_data = memory_buffer_allocate(
- new_num * element_size,
- alignment,
- *num * element_size,
- *data
- );
-
- if (new_data == NULL && new_num > 0)
- // Out of memory.
- return;
-
- *num = new_num;
- *data = new_data;
-}
-
-void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 element_size, i64 new_num) {
- if (num == NULL || capacity == NULL || data == NULL) {
- LOG_ERROR("Sanity");
- return;
- }
-
- if (*num == new_num)
- return;
-
- if (new_num > *capacity)
- resize_dynamic_array_exact(capacity, data, element_size, new_num);
-
- if (new_num <= *capacity)
- *num = new_num;
-}
-
-// ================================================================
-//
// BLAKE2B
//
// ================================================================
@@ -1331,7 +1130,7 @@ i32 blake2b(u8 *out, void *in, void *key, u8 outlen, u64 inlen, u8 keylen) {
// ================================================================
//
-// Utilities
+// UTF-8
//
// ================================================================
@@ -1434,6 +1233,228 @@ static vec3_f32 rgb_f32_from_u32_(u32 c) {
}
// ================================================================
+
+// TODO: Move this to separate sections.
+
+Platform g_platform = {0};
+
+static i64 _sound_clock_time = 0;
+static i64 _sound_clock_carry = 0;
+static i64 _sound_position = 0;
+static i64 _frame_index = 0;
+
+static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0};
+static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0};
+
+void run_main_window_event_loop(void) {
+ init_main_window();
+#if !defined(__wasm__)
+ while (!g_platform.done) update_and_render_frame();
+ shutdown_all_systems();
+#endif
+}
+
+// ================================================================
+//
+// Memory buffer allocator
+//
+// ================================================================
+
+static i64 align_(i64 x, i64 alignment) {
+ return ((x + (alignment - 1)) / alignment) * alignment;
+}
+
+static i64 memory_buffer_occupied_len_(i64 buffer_size) {
+ return (buffer_size + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE);
+}
+
+static void *memory_buffer_allocate_from_(i64 memory_buffer_size, u8 *memory_buffer, i64 size, i64 alignment, i64 previous_size, void *previous_data) {
+ if (memory_buffer_size <= 0) {
+ LOG_ERROR("Invalid memory buffer size.");
+ return NULL;
+ }
+
+ if (memory_buffer == NULL) {
+ LOG_ERROR("Invalid memory buffer.");
+ return NULL;
+ }
+
+ i64 occupied_len = memory_buffer_occupied_len_(memory_buffer_size);
+ i64 occupied_len_bytes = occupied_len * 8;
+ i64 occupied_len_bits = occupied_len * 64;
+
+ u64 *occupied = (u64 *) memory_buffer;
+
+ if (memory_buffer_size <= occupied_len_bytes) {
+ LOG_ERROR("Memory buffer too small.");
+ return NULL;
+ }
+
+ if (alignment <= 0) {
+ LOG_ERROR("Invalid alignment: %lld", alignment);
+ return NULL;
+ }
+
+ if (size < 0) {
+ LOG_ERROR("Invalid size: %lld", size);
+ return NULL;
+ }
+
+ if (previous_size < 0) {
+ LOG_ERROR("Invalid previous size: %lld", previous_size);
+ return NULL;
+ }
+
+ if (previous_size > 0 && previous_data == NULL) {
+ LOG_ERROR("Invalid previous data.");
+ return NULL;
+ }
+
+ u8 *data = memory_buffer + occupied_len_bytes;
+
+ i64 prev_num_chunks = 0;
+ i64 prev_chunk = 0;
+
+ if (previous_size > 0) {
+ prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE;
+ }
+
+ i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ i64 chunk = (memory_buffer_size + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+
+ if (num_chunks == prev_num_chunks)
+ return previous_data;
+
+ u8 *dst = NULL;
+
+ if (num_chunks < prev_num_chunks) {
+ // Reuse previously allocated space.
+ chunk = prev_chunk;
+ dst = data + chunk * MEMORY_CHUNK_SIZE;
+ } else {
+ // Search free space
+ for (i64 i = 0;; ++i) {
+ while ((i % 64) == 0
+ && i < occupied_len_bits
+ && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks)
+ && occupied[i / 64] == ~0ull)
+ i += 64;
+ while ((i % 8) == 0
+ && i < occupied_len_bits
+ && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks)
+ && ((u8 *) occupied)[i / 8] == 255u)
+ i += 8;
+ if (i >= occupied_len_bits) break;
+ b8 is_occupied = 0;
+ for (i64 j = i; j < i + num_chunks; ++j) {
+ if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue;
+ if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue;
+ is_occupied = 1;
+ break;
+ }
+ if (!is_occupied) {
+ chunk = i;
+ break;
+ }
+ }
+
+ // Check if out of memory
+ dst = data + chunk * MEMORY_CHUNK_SIZE;
+ if (dst + size > memory_buffer + memory_buffer_size) {
+ LOG_ERROR("Out of memory: %lld bytes", size - previous_size);
+ return NULL;
+ }
+
+ // Claim required space
+ for (i64 j = chunk; j < chunk + num_chunks; ++j)
+ occupied[j / 64] |= 1ull << (j % 64);
+ }
+
+ if (chunk != prev_chunk) {
+ // Copy data
+ i64 len = size < previous_size ? size : previous_size;
+ u8 *s0 = data + prev_chunk * MEMORY_CHUNK_SIZE;
+ u8 *s1 = s0 + len - 1;
+ u8 *d0 = dst;
+ u8 *d1 = dst + len - 1;
+ if (d0 > s0)
+ for (u8 *d = d1, *s = s1; d >= d0; --d, --s)
+ *d = *s;
+ else
+ for (u8 *d = d0, *s = s0; d <= d1; ++d, ++s)
+ *d = *s;
+ }
+
+ // Free previous space
+ for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) {
+ if (j >= chunk && j < chunk + num_chunks) continue;
+ occupied[j / 64] &= ~(1ull << (j % 64));
+ }
+
+ if (num_chunks == 0)
+ return NULL;
+
+ return dst;
+}
+
+static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0};
+
+void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) {
+ 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_;
+ }
+
+ return memory_buffer_allocate_from_(g_platform.memory_buffer_size, g_platform.memory_buffer, size, alignment, previous_size, previous_data);
+}
+
+void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new_num) {
+ if (num == NULL || data == NULL) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ if (*num == new_num)
+ return;
+
+ i64 alignment = max2_i64_(8, element_size);
+
+ void *new_data = memory_buffer_allocate(
+ new_num * element_size,
+ alignment,
+ *num * element_size,
+ *data
+ );
+
+ if (new_data == NULL && new_num > 0)
+ // Out of memory.
+ return;
+
+ if (new_num > *num)
+ mem_set_(*data, 0, new_num - *num);
+
+ *num = new_num;
+ *data = new_data;
+}
+
+void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 element_size, i64 new_num) {
+ if (num == NULL || capacity == NULL || data == NULL) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ if (*num == new_num)
+ return;
+
+ if (new_num > *capacity)
+ resize_dynamic_array_exact(capacity, data, element_size, new_num);
+
+ if (new_num <= *capacity)
+ *num = new_num;
+}
+
+// ================================================================
//
// Platform
//
@@ -1502,12 +1523,7 @@ static void drop_files_set_num_(i64 num) {
return;
}
- i64 prev_num = g_platform.num_drop_files;
-
resize_dynamic_array_exact(&g_platform.num_drop_files, (void **) &g_platform.drop_files, sizeof *g_platform.drop_files, num);
-
- if (prev_num < g_platform.num_drop_files)
- mem_set_(g_platform.drop_files + prev_num, 0, sizeof *g_platform.drop_files * (g_platform.num_drop_files - prev_num));
}
static void drop_files_set_name_(i64 index, i64 name_len, c8 *name) {
@@ -1738,6 +1754,102 @@ static void store_clipboard_text_(i64 size, c8 *data) {
// ================================================================
//
+// Dynamic libraries
+//
+// ================================================================
+
+#if defined(__unix__)
+#include <dlfcn.h>
+
+typedef struct {
+ void *handle;
+} Dynamic_Library_Slot_;
+
+typedef struct {
+ i64 num_slots;
+ Dynamic_Library_Slot_ *slots;
+} Dynamic_Libraries_;
+
+static Dynamic_Libraries_ dynamic_libraries_ = {0};
+
+void dynamic_library_open(u16 slot, c8 *name) {
+ if (name == NULL) {
+ LOG_ERROR("Sanity");
+ return;
+ }
+
+ if (slot >= dynamic_libraries_.num_slots)
+ resize_dynamic_array_exact(&dynamic_libraries_.num_slots, (void **) &dynamic_libraries_.slots, sizeof *dynamic_libraries_.slots, (i64) slot + 1);
+
+ if (dynamic_libraries_.slots[slot].handle != NULL) {
+ dlclose(dynamic_libraries_.slots[slot].handle);
+ dynamic_libraries_.slots[slot].handle = NULL;
+ }
+
+ void *h = dlopen(name, RTLD_LAZY);
+
+ if (h == NULL) {
+ LOG_ERROR("Failed to open: %s", name);
+ LOG_ERROR("%s", dlerror());
+ return;
+ }
+
+ dynamic_libraries_.slots[slot].handle = h;
+}
+
+void *dynamic_library_get_proc_address(u16 slot, c8 *proc) {
+ if (slot >= dynamic_libraries_.num_slots) {
+ LOG_ERROR("Invalid slot: %d", (i32) slot);
+ return NULL;
+ }
+
+ if (proc == NULL) {
+ LOG_ERROR("Sanity");
+ return NULL;
+ }
+
+ if (dynamic_libraries_.slots[slot].handle == NULL) {
+ LOG_ERROR("Slot is closed: %d", (i32) slot);
+ return NULL;
+ }
+
+ void *proc_address = dlsym(dynamic_libraries_.slots[slot].handle, proc);
+
+ if (proc_address == NULL) {
+ LOG_ERROR("Failed to get: %s", proc);
+ LOG_ERROR("%s", dlerror());
+ }
+
+ return proc_address;
+}
+
+static void close_all_dynamic_libraries_(void) {
+ for (i64 i = 0; i < dynamic_libraries_.num_slots; ++i)
+ if (dynamic_libraries_.slots[i].handle != NULL)
+ dlclose(dynamic_libraries_.slots[i].handle);
+ resize_dynamic_array_exact(&dynamic_libraries_.num_slots, (void **) &dynamic_libraries_.slots, sizeof *dynamic_libraries_.slots, 0);
+}
+#endif // defined(__unix__)
+
+#if defined(__wasm__)
+void dynamic_library_open(u16 slot, c8 *name) {
+ (void) slot;
+ (void) name;
+
+ LOG_ERROR("Dynamic library not found: %s", name);
+}
+
+void *dynamic_library_get_proc_address(u16 slot, c8 *proc) {
+ (void) slot;
+ (void) proc;
+
+ LOG_ERROR("Proc address not found: %s", proc);
+ return NULL;
+}
+#endif // defined(__wasm__)
+
+// ================================================================
+//
// Unix
//
// ================================================================
@@ -1816,10 +1928,8 @@ static void network_init_(u16 slot) {
i64 num = (i64) (u64) slot;
i64 prev_num = _num_sockets;
- if (num > prev_num) {
+ if (num > prev_num)
resize_dynamic_array_exact(&_num_sockets, (void **) &_sockets, sizeof *_sockets, num);
- mem_set_(_sockets + prev_num, 0, num - prev_num);
- }
}
static void network_cleanup_(void) {
@@ -3069,6 +3179,7 @@ void shutdown_all_systems(void) {
cleanup_pixel_buffers_();
network_cleanup_();
sound_cleanup_();
+ close_all_dynamic_libraries_();
g_platform.input_len = 0;
resize_dynamic_array_exact(&g_platform.input_capacity, (void **) &g_platform.input, sizeof *g_platform.input, 0);
@@ -3313,7 +3424,7 @@ i32 handle_main_window_events(void) {
ev.xselection.requestor,
_dnd_selection,
0,
- g_platform.memory_buffer_size,
+ STATIC_MEMORY_BUFFER_SIZE, // FIXME
False,
ev.xselection.target,
&(Atom) {0},
@@ -3368,7 +3479,7 @@ i32 handle_main_window_events(void) {
_window,
_clipboard,
0,
- g_platform.memory_buffer_size,
+ STATIC_MEMORY_BUFFER_SIZE, // FIXME
False,
AnyPropertyType,
&(Atom) {0},