Commit: b25cf020007042c20ef92a810eaa5514878c986d
Parent: 023e3a3aaf9cbc286e0115cd6f2b1455db38ce5a
Author: Randy Palamar
Date: Wed, 17 Jun 2026 08:48:36 -0600
platform: make window creation a required API
multiple windows are not really possible while raylib is in use
but they will be added after raylib is removed.
Diffstat:
9 files changed, 397 insertions(+), 123 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -175,10 +175,13 @@ beamformer_init(BeamformerInput *input)
BeamformerCtx *ctx = push_struct(&memory, BeamformerCtx);
+ str8 window_title = str8("VK Beamformer");
+ ctx->main_window = os_window_create(window_title.data, window_title.length, 1280, 840);
+ ctx->window_size = (iv2){{1280, 840}};
+
Arena scratch = {.beg = memory.end - 4096L, .end = memory.end};
memory.end = scratch.beg;
- ctx->window_size = (iv2){{1280, 840}};
ctx->error_stream = error;
ctx->ui_backing_store = ui_arena;
ctx->compute_worker.arena = compute_arena;
@@ -242,12 +245,6 @@ beamformer_init(BeamformerInput *input)
beamformer_load_cuda_library(ctx, input->cuda_library_handle, memory);
- SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN);
- InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer");
- /* NOTE: do this after initing so that the window starts out floating in tiling wm */
- SetWindowState(FLAG_WINDOW_RESIZABLE);
- SetWindowMinSize(840, ctx->window_size.h);
-
load_gl(&ctx->error_stream);
ctx->shared_memory = input->shared_memory;
diff --git a/beamformer.h b/beamformer.h
@@ -69,6 +69,7 @@ typedef struct { uint64_t value[1]; } OSBarrier;
typedef struct { uint64_t value[1]; } OSHandle;
typedef struct { uint64_t value[1]; } OSLibrary;
typedef struct { uint64_t value[1]; } OSThread;
+typedef struct { uint64_t value[1]; } OSWindow;
typedef struct { uint64_t value[1]; } OSW32Semaphore;
typedef uint64_t os_thread_entry_point_fn(void *user_context);
@@ -102,6 +103,12 @@ BEAMFORMER_IMPORT void * os_lookup_symbol(OSLibrary library, const char
BEAMFORMER_IMPORT uint32_t os_wait_on_address(int32_t *lock, int32_t current, uint32_t timeout_ms);
BEAMFORMER_IMPORT void os_wake_all_waiters(int32_t *lock);
+// NOTE(rnp): currently beamformer will only create one window.
+// once raylib is removed it may request multiple
+BEAMFORMER_IMPORT OSWindow os_window_create(uint8_t *title, int64_t title_length, int32_t width, int32_t height);
+//BEAMFORMER_IMPORT void os_window_title(OSWindow window, uint8_t *title, int64_t title_length);
+//BEAMFORMER_IMPORT void os_window_destroy(OSWindow window);
+
// NOTE(rnp): eventually logging will just be done internally
BEAMFORMER_IMPORT void os_console_log(uint8_t *data, int64_t length);
BEAMFORMER_IMPORT void os_fatal(uint8_t *data, int64_t length);
@@ -125,6 +132,8 @@ BEAMFORMER_IMPORT void os_w32_semaphore_release(OSW32Semaphore, int32_
typedef enum {
BeamformerInputEventKind_ButtonPress,
BeamformerInputEventKind_ButtonRelease,
+ BeamformerInputEventKind_MouseScroll,
+ BeamformerInputEventKind_WindowResize,
BeamformerInputEventKind_ExecutableReload,
BeamformerInputEventKind_FileEvent,
} BeamformerInputEventKind;
@@ -154,13 +163,23 @@ typedef enum {
BeamformerInputModifier_Control = BeamformerInputModifier_LeftControl|BeamformerInputModifier_RightControl,
BeamformerInputModifier_Shift = BeamformerInputModifier_LeftShift|BeamformerInputModifier_RightShift,
BeamformerInputModifier_Meta = BeamformerInputModifier_LeftMeta|BeamformerInputModifier_RightMeta,
+ BeamformerInputModifier_Any = BeamformerInputModifier_Alt|
+ BeamformerInputModifier_Control|
+ BeamformerInputModifier_Shift|
+ BeamformerInputModifier_Meta,
} BeamformerInputModifiers;
typedef struct {
BeamformerInputEventKind kind;
union {
BeamformerButtonID button_id;
- void * file_watch_user_context;
+
+ struct {
+ uint32_t width, height;
+ OSWindow window;
+ } window_resize;
+
+ void *file_watch_user_context;
};
} BeamformerInputEvent;
diff --git a/beamformer_core.c b/beamformer_core.c
@@ -1,5 +1,6 @@
/* See LICENSE for license details. */
/* TODO(rnp):
+ * [ ]: backtrace dumping on SIGSEGV
* [ ]: bug? HERCULES might be broken, we may need to to chunk on transmits instead of channels
* [ ]: refactor: do_compute should build its own "command graph" which tracks
* dependencies better. It is very important that unnecessary barriers are
@@ -1652,6 +1653,13 @@ beamformer_process_input_events(BeamformerCtx *ctx, BeamformerInput *input,
BeamformerInputEvent *event = events + index;
switch (event->kind) {
+ // NOTE(rnp): ui will handle these
+ case BeamformerInputEventKind_ButtonPress:
+ case BeamformerInputEventKind_ButtonRelease:
+ case BeamformerInputEventKind_MouseScroll:
+ case BeamformerInputEventKind_WindowResize:
+ {}break;
+
case BeamformerInputEventKind_ExecutableReload:{
ui_init(ctx, ctx->ui_backing_store);
@@ -1710,11 +1718,6 @@ beamformer_frame_step(BeamformerInput *input)
dt_for_frame = (f64)(current_time - ctx->frame_timestamp) / os_system_info()->timer_frequency;
ctx->frame_timestamp = current_time;
- if (IsWindowResized()) {
- ctx->window_size.h = GetScreenHeight();
- ctx->window_size.w = GetScreenWidth();
- }
-
coalesce_timing_table(ctx->compute_timing_table, ctx->compute_shader_stats);
beamformer_process_input_events(ctx, input, input->event_queue, input->event_count);
diff --git a/beamformer_internal.h b/beamformer_internal.h
@@ -493,6 +493,9 @@ typedef struct {
ComputeTimingTable compute_timing_table[1];
BeamformWorkQueue beamform_work_queue[1];
+
+ // TODO(rnp): this should go to the UI eventually
+ OSWindow main_window;
} BeamformerCtx;
#define BeamformerContextMemory(m) (BeamformerCtx *)align_pointer_up((m), alignof(BeamformerCtx));
diff --git a/external/rcore_extended.c b/external/rcore_extended.c
@@ -1,7 +1,7 @@
#include "raylib/src/rcore.c"
// NOTE(rnp): hacky function to get the GLFWwindow handle
-void *
+RLAPI void *
GetPlatformWindowHandle(void)
{
return (void *)platform.handle;
diff --git a/main_linux.c b/main_linux.c
@@ -29,28 +29,54 @@
#include <dlfcn.h>
-typedef enum {
- OSLinux_FileWatchKindPlatform,
- OSLinux_FileWatchKindUser,
-} OSLinux_FileWatchKind;
-
+typedef struct OSLinuxEntity OSLinuxEntity;
typedef struct {
- OSLinux_FileWatchKind kind;
+ void *handle;
+ OSLinuxEntity *prev, *next;
+} OSLinuxWindow;
+
+typedef enum {
+ OSLinuxFileWatchKind_Platform,
+ OSLinuxFileWatchKind_User,
+} OSLinuxFileWatchKind;
+
+typedef struct OSLinuxFileWatchDirectory OSLinuxFileWatchDirectory;
+typedef struct OSLinuxFileWatch OSLinuxFileWatch;
+struct OSLinuxFileWatch {
+ OSLinuxFileWatchKind kind;
u64 hash;
u64 update_time;
- void * user_context;
-} OSLinux_FileWatch;
+ void *user_context;
-typedef struct {
+ OSLinuxFileWatchDirectory *parent;
+ OSLinuxFileWatch *prev, *next;
+};
+
+struct OSLinuxFileWatchDirectory {
u64 hash;
i64 handle;
str8 name;
- OSLinux_FileWatch *data;
- da_count count;
- da_count capacity;
-} OSLinux_FileWatchDirectory;
-DA_STRUCT(OSLinux_FileWatchDirectory, OSLinux_FileWatchDirectory);
+ OSLinuxFileWatch *first_child;
+ OSLinuxFileWatch *last_child;
+ OSLinuxFileWatchDirectory *prev, *next;
+};
+
+typedef enum {
+ OSLinuxEntityKind_Window,
+ OSLinuxEntityKind_FileWatch,
+ OSLinuxEntityKind_FileWatchDirectory,
+} OSLinuxEntityKind;
+
+struct OSLinuxEntity {
+ OSLinuxEntityKind kind;
+ union {
+ OSLinuxFileWatch file_watch;
+ OSLinuxFileWatchDirectory file_watch_directory;
+ OSLinuxWindow window;
+ } as;
+ OSLinuxEntity *next;
+};
typedef struct {
Arena arena;
@@ -58,12 +84,39 @@ typedef struct {
i32 inotify_handle;
- OSLinux_FileWatchDirectoryList file_watch_list;
+ BeamformerInput *input;
OSSystemInfo system_info;
+
+ struct {
+ OSLinuxFileWatchDirectory *first;
+ OSLinuxFileWatchDirectory *last;
+ } file_watch_directories;
+
+ struct {
+ OSLinuxEntity *first;
+ OSLinuxEntity *last;
+ } windows;
+
+ OSLinuxEntity *entity_freelist;
} OSLinux_Context;
global OSLinux_Context os_linux_context;
+function OSLinuxEntity *
+os_entity_allocate(OSLinuxEntityKind kind)
+{
+ OSLinuxEntity *result = 0;
+ DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
+ {
+ result = SLLPopFreelist(os_linux_context.entity_freelist);
+ if (!result) result = push_struct_no_zero(&os_linux_context.arena, OSLinuxEntity);
+ }
+
+ zero_struct(result);
+ result->kind = kind;
+ return result;
+}
+
BEAMFORMER_IMPORT OSSystemInfo *
os_system_info(void)
{
@@ -148,47 +201,106 @@ allocate_shared_memory(char *name, iz requested_capacity, u64 *capacity)
return result;
}
-function OSLinux_FileWatchDirectory *
-os_lookup_file_watch_directory(OSLinux_FileWatchDirectoryList *ctx, u64 hash)
+function OSLinuxFileWatchDirectory *
+os_lookup_file_watch_directory(u64 hash)
{
- OSLinux_FileWatchDirectory *result = 0;
- for (da_count i = 0; !result && i < ctx->count; i++)
- if (ctx->data[i].hash == hash)
- result = ctx->data + i;
+ OSLinuxFileWatchDirectory *result = 0;
+ for (OSLinuxFileWatchDirectory *fwd = os_linux_context.file_watch_directories.first; fwd; fwd = fwd->next) {
+ if (fwd->hash == hash) {
+ result = fwd;
+ break;
+ }
+ }
return result;
}
function void
-os_linux_add_file_watch(str8 path, void *user_context, OSLinux_FileWatchKind kind)
+os_linux_add_file_watch(str8 path, void *user_context, OSLinuxFileWatchKind kind)
{
str8 directory = path;
directory.length = str8_scan_backwards(path, '/');
assert(directory.length > 0);
- OSLinux_FileWatchDirectoryList *fwctx = &os_linux_context.file_watch_list;
-
u64 hash = u64_hash_from_str8(directory);
- OSLinux_FileWatchDirectory *dir = os_lookup_file_watch_directory(fwctx, hash);
+ OSLinuxFileWatchDirectory *dir = os_lookup_file_watch_directory(hash);
if (!dir) {
assert(path.data[directory.length] == '/');
- dir = da_push(&os_linux_context.arena, fwctx);
+ OSLinuxEntity *fwd = os_entity_allocate(OSLinuxEntityKind_FileWatchDirectory);
+ dir = &fwd->as.file_watch_directory;
+ DLLInsert(0, os_linux_context.file_watch_directories.first,
+ os_linux_context.file_watch_directories.last, dir, next, prev);
+
dir->hash = hash;
dir->name = push_str8(&os_linux_context.arena, directory);
u32 mask = IN_MOVED_TO|IN_CLOSE_WRITE;
dir->handle = inotify_add_watch(os_linux_context.inotify_handle, (c8 *)dir->name.data, mask);
}
- OSLinux_FileWatch *fw = da_push(&os_linux_context.arena, dir);
+ OSLinuxEntity *fwe = os_entity_allocate(OSLinuxEntityKind_FileWatch);
+ OSLinuxFileWatch *fw = &fwe->as.file_watch;
+ DLLInsert(0, dir->first_child, dir->last_child, fw, next, prev);
fw->user_context = user_context;
fw->hash = u64_hash_from_str8(str8_cut_head(path, dir->name.length + 1));
fw->kind = kind;
+ fw->parent = dir;
}
BEAMFORMER_IMPORT void
os_add_file_watch(const char *path, int64_t path_length, void *user_context)
{
str8 path_str = {.data = (u8 *)path, .length = path_length};
- os_linux_add_file_watch(path_str, user_context, OSLinux_FileWatchKindUser);
+ os_linux_add_file_watch(path_str, user_context, OSLinuxFileWatchKind_User);
+}
+
+function void
+os_window_resize_callback(void *window, i32 width, i32 height)
+{
+ OSWindow event_window = {0};
+ for (OSLinuxEntity *we = os_linux_context.windows.first; we; we = we->as.window.next) {
+ if (we->as.window.handle == window) {
+ event_window.value[0] = (u64)we;
+ break;
+ }
+ }
+
+ os_push_input_event(beamformer_input, (BeamformerInputEvent){
+ .kind = BeamformerInputEventKind_WindowResize,
+ .window_resize = {
+ .width = (u32)width, .height = (u32)height,
+ .window = event_window,
+ },
+ });
+
+ raylib_window_resize(window, width, height);
+}
+
+BEAMFORMER_IMPORT OSWindow
+os_window_create(u8 *title, i64 title_length, i32 width, i32 height)
+{
+ OSLinuxEntity *we = os_entity_allocate(OSLinuxEntityKind_Window);
+ OSWindow result = {(u64)we};
+ DLLInsert(0, os_linux_context.windows.first, os_linux_context.windows.last, we, as.window.next, as.window.prev);
+
+ SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN);
+
+ str8 name = {.data = title, .length = title_length};
+ DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock))
+ {
+ Arena scratch = os_linux_context.arena;
+ name.length = Min(name.length, arena_capacity(&scratch, u8) - 1);
+ str8 title_string = push_str8(&scratch, name);
+ InitWindow(width, height, (char *)title_string.data);
+ }
+
+ we->as.window.handle = GetPlatformWindowHandle();
+ os_window_equip_common(os_linux_context.input, we->as.window.handle);
+ raylib_window_resize = glfwSetWindowSizeCallback(we->as.window.handle, os_window_resize_callback);
+
+ /* NOTE: do this after initing so that the window starts out floating in tiling wm */
+ SetWindowState(FLAG_WINDOW_RESIZABLE);
+ SetWindowMinSize(320, 240);
+
+ return result;
}
function OSLibrary
@@ -226,6 +338,8 @@ debug_library_reload(BeamformerInput *input)
beamformer_library_handle = new_handle;
}
}
+#else
+#define debug_library_reload(a) (void)(a)
#endif /* BEAMFORMER_DEBUG */
function void
@@ -234,7 +348,7 @@ load_platform_libraries(BeamformerInput *input)
#if BEAMFORMER_DEBUG
debug_library_reload(input);
os_linux_add_file_watch(str8(OS_DEBUG_LIB_NAME), (void *)BeamformerInputEventKind_ExecutableReload,
- OSLinux_FileWatchKindPlatform);
+ OSLinuxFileWatchKind_Platform);
#endif
input->vulkan_library_handle = (OSLibrary){OSInvalidHandleValue};
@@ -259,46 +373,39 @@ load_platform_libraries(BeamformerInput *input)
function void
dispatch_file_watch_events(BeamformerInput *input)
{
- OSLinux_FileWatchDirectoryList *fwctx = &os_linux_context.file_watch_list;
Arena arena = os_linux_context.arena;
u8 *mem = arena_alloc(&arena, .size = 4096, .align = 16);
struct inotify_event *event;
u64 current_time = os_timer_count();
- iz rlen;
+ i64 rlen;
while ((rlen = read(os_linux_context.inotify_handle, mem, 4096)) > 0) {
for (u8 *data = mem; data < mem + rlen; data += sizeof(*event) + event->len) {
event = (struct inotify_event *)data;
- for (da_count i = 0; i < fwctx->count; i++) {
- OSLinux_FileWatchDirectory *dir = fwctx->data + i;
+ for (OSLinuxFileWatchDirectory *dir = os_linux_context.file_watch_directories.first; dir; dir = dir->next) {
if (event->wd != dir->handle)
continue;
str8 file = str8_from_c_str(event->name);
u64 hash = u64_hash_from_str8(file);
- for (da_count j = 0; j < dir->count; j++) {
- OSLinux_FileWatch *fw = dir->data + j;
- if (fw->hash == hash) {
- // NOTE(rnp): avoid multiple updates in a single frame
- if (fw->update_time < current_time) {
- BeamformerInputEvent input_event = {0};
- if (fw->kind == OSLinux_FileWatchKindPlatform) {
- assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload);
- #if BEAMFORMER_DEBUG
- if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload)
- debug_library_reload(input);
- #endif
- input_event.kind = (u64)fw->user_context;
- } else {
- input_event.kind = BeamformerInputEventKind_FileEvent;
- input_event.file_watch_user_context = fw->user_context;
- }
- os_push_input_event(input, input_event);
+ for (OSLinuxFileWatch *fw = dir->first_child; fw; fw = fw->next) if (fw->hash == hash) {
+ // NOTE(rnp): avoid multiple updates in a single frame
+ if (fw->update_time < current_time) {
+ BeamformerInputEvent input_event = {0};
+ if (fw->kind == OSLinuxFileWatchKind_Platform) {
+ assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload);
+ if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload)
+ debug_library_reload(input);
+ input_event.kind = (u64)fw->user_context;
+ } else {
+ input_event.kind = BeamformerInputEventKind_FileEvent;
+ input_event.file_watch_user_context = fw->user_context;
}
- fw->update_time = current_time;
- break;
+ os_push_input_event(input, input_event);
}
+ fw->update_time = current_time;
+ break;
}
}
}
@@ -313,12 +420,13 @@ main(void)
os_linux_context.system_info.page_size = ARCH_X64? KB(4) : getauxval(AT_PAGESZ);
os_linux_context.system_info.path_separator_byte = '/';
- Arena program_memory = os_alloc_arena(MB(16) + KB(16));
+ Arena program_memory = os_alloc_arena(MB(16) + MB(1));
- os_linux_context.arena = sub_arena(&program_memory, KB(16), KB(4));
+ os_linux_context.arena = sub_arena(&program_memory, MB(1), KB(4));
os_linux_context.inotify_handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
BeamformerInput *input = push_struct(&program_memory, BeamformerInput);
+ os_linux_context.input = input;
input->memory = program_memory.beg;
input->memory_size = program_memory.end - program_memory.beg;
input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE,
@@ -350,7 +458,9 @@ main(void)
beamformer_frame_step(input);
// NOTE(rnp): this must happen at the end of frame to allow the pre loop events through
- input->event_count = 0;
+ // TODO(rnp): hack: until raylib is removed this happens in ui since raylib will cause
+ // glfw to call the input callbacks in during EndDrawing()
+ //input->event_count = 0;
}
beamformer_terminate(input);
diff --git a/main_w32.c b/main_w32.c
@@ -59,46 +59,100 @@ W32(i32) SetThreadDescription(u64, u16 *);
X("vulkan-1.dll") \
enum {OSW32_FileWatchDirectoryBufferSize = KB(4)};
-typedef enum {
- OSW32_FileWatchKindPlatform,
- OSW32_FileWatchKindUser,
-} OSW32_FileWatchKind;
+typedef struct OSW32Entity OSW32Entity;
typedef struct {
- OSW32_FileWatchKind kind;
+ void *handle;
+ OSW32Entity *prev, *next;
+} OSW32Window;
+
+typedef enum {
+ OSW32FileWatchKind_Platform,
+ OSW32FileWatchKind_User,
+} OSW32FileWatchKind;
+
+typedef struct OSW32FileWatchDirectory OSW32FileWatchDirectory;
+typedef struct OSW32FileWatch OSW32FileWatch;
+struct OSW32FileWatch {
+ OSW32FileWatchKind kind;
u64 hash;
u64 update_time;
- void * user_context;
-} OSW32_FileWatch;
+ void *user_context;
-typedef struct {
+ OSW32FileWatchDirectory *parent;
+ OSW32FileWatch *prev, *next;
+};
+
+struct OSW32FileWatchDirectory {
u64 hash;
i64 handle;
str8 name;
- OSW32_FileWatch *data;
- da_count count;
- da_count capacity;
+ OSW32FileWatch *first_child;
+ OSW32FileWatch *last_child;
+ OSW32FileWatchDirectory *prev, *next;
w32_overlapped overlapped;
w32_io_completion_event event;
void *buffer;
-} OSW32_FileWatchDirectory;
-DA_STRUCT(OSW32_FileWatchDirectory, OSW32_FileWatchDirectory);
+};
+
+typedef enum {
+ OSW32EntityKind_Window,
+ OSW32EntityKind_FileWatch,
+ OSW32EntityKind_FileWatchDirectory,
+} OSW32EntityKind;
+
+struct OSW32Entity {
+ OSW32EntityKind kind;
+ union {
+ OSW32FileWatch file_watch;
+ OSW32FileWatchDirectory file_watch_directory;
+ OSW32Window window;
+ } as;
+ OSW32Entity *next;
+};
typedef struct {
Arena arena;
i32 arena_lock;
- iptr error_handle;
- iptr io_completion_handle;
+ i64 error_handle;
+ i64 io_completion_handle;
+
+ BeamformerInput *input;
+
+ struct {
+ OSW32FileWatchDirectory *first;
+ OSW32FileWatchDirectory *last;
+ } file_watch_directories;
- OSW32_FileWatchDirectoryList file_watch_list;
+ struct {
+ OSW32Entity *first;
+ OSW32Entity *last;
+ } windows;
+
+ OSW32Entity *entity_freelist;
OSSystemInfo system_info;
} OSW32_Context;
global OSW32_Context os_w32_context;
+function OSW32Entity *
+os_entity_allocate(OSW32EntityKind kind)
+{
+ OSW32Entity *result = 0;
+ DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock))
+ {
+ result = SLLPopFreelist(os_w32_context.entity_freelist);
+ if (!result) push_struct_no_zero(&os_w32_context.arena, OSW32Entity);
+ }
+
+ zero_struct(result);
+ result->kind = kind;
+ return result;
+}
+
BEAMFORMER_IMPORT OSSystemInfo *
os_system_info(void)
{
@@ -177,31 +231,36 @@ allocate_shared_memory(char *name, iz requested_capacity, u64 *capacity)
return result;
}
-function OSW32_FileWatchDirectory *
-os_lookup_file_watch_directory(OSW32_FileWatchDirectoryList *ctx, u64 hash)
+function OSW32FileWatchDirectory *
+os_lookup_file_watch_directory(u64 hash)
{
- OSW32_FileWatchDirectory *result = 0;
- for (da_count i = 0; !result && i < ctx->count; i++)
- if (ctx->data[i].hash == hash)
- result = ctx->data + i;
+ OSW32FileWatchDirectory *result = 0;
+ for (OSW32FileWatchDirectory *fwd = os_w32_context.file_watch_directories.first; fwd; fwd = fwd->next) {
+ if (fwd->hash == hash) {
+ result = fwd;
+ break;
+ }
+ }
return result;
}
function void
-os_w32_add_file_watch(str8 path, void *user_context, OSW32_FileWatchKind kind)
+os_w32_add_file_watch(str8 path, void *user_context, OSW32FileWatchKind kind)
{
str8 directory = path;
directory.length = str8_scan_backwards(path, '\\');
assert(directory.length > 0);
- OSW32_FileWatchDirectoryList *fwctx = &os_w32_context.file_watch_list;
-
u64 hash = u64_hash_from_str8(directory);
- OSW32_FileWatchDirectory *dir = os_lookup_file_watch_directory(fwctx, hash);
+ OSW32FileWatchDirectory *dir = os_lookup_file_watch_directory(hash);
if (!dir) {
assert(path.data[directory.length] == '\\');
- dir = da_push(&os_w32_context.arena, fwctx);
+ OSW32Entity *fwd = os_entity_allocate(OSW32EntityKind_FileWatchDirectory);
+ dir = &fwd->as.file_watch_directory;
+ DLLInsert(0, os_w32_context.file_watch_directories.first,
+ os_w32_context.file_watch_directories.last, dir, next, prev);
+
dir->hash = hash;
dir->name = push_str8(&os_w32_context.arena, directory);
dir->handle = CreateFileA((c8 *)dir->name.data, GENERIC_READ, FILE_SHARE_READ, 0,
@@ -217,17 +276,71 @@ os_w32_add_file_watch(str8 path, void *user_context, OSW32_FileWatchKind kind)
FILE_NOTIFY_CHANGE_LAST_WRITE, 0, &dir->overlapped, 0);
}
- OSW32_FileWatch *fw = da_push(&os_w32_context.arena, dir);
+ OSW32Entity *fwe = os_entity_allocate(OSW32EntityKind_FileWatch);
+ OSW32FileWatch *fw = &fwe->as.file_watch;
+ DLLInsert(0, dir->first_child, dir->last_child, fw, next, prev);
fw->user_context = user_context;
fw->hash = u64_hash_from_str8(str8_cut_head(path, dir->name.length + 1));
fw->kind = kind;
+ fw->parent = dir;
}
BEAMFORMER_IMPORT void
os_add_file_watch(const char *path, int64_t path_length, void *user_context)
{
str8 path_str = {.data = (u8 *)path, .length = path_length};
- os_w32_add_file_watch(path_str, user_context, OSW32_FileWatchKindUser);
+ os_w32_add_file_watch(path_str, user_context, OSW32FileWatchKind_User);
+}
+
+function void
+os_window_resize_callback(void *window, i32 width, i32 height)
+{
+ OSWindow event_window = {0};
+ for (OSW32Entity *we = os_w32_context.windows.first; we; we = we->as.window.next) {
+ if (we->as.window.handle == window) {
+ event_window.value[0] = (u64)we;
+ break;
+ }
+ }
+
+ os_push_input_event(beamformer_input, (BeamformerInputEvent){
+ .kind = BeamformerInputEventKind_WindowResize,
+ .window_resize = {
+ .width = (u32)width, .height = (u32)height,
+ .window = event_window,
+ },
+ });
+
+ raylib_window_resize(window, width, height);
+}
+
+BEAMFORMER_IMPORT OSWindow
+os_window_create(u8 *title, i64 title_length, i32 width, i32 height)
+{
+ OSW32Entity *we = os_entity_allocate(OSW32EntityKind_Window);
+ OSWindow result = {(u64)we};
+ DLLInsert(0, os_w32_context.windows.first, os_w32_context.windows.last, we, as.window.next, as.window.prev);
+
+ SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN);
+
+ str8 name = {.data = title, .length = title_length};
+ DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock))
+ {
+ Arena scratch = os_w32_context.arena;
+ name.length = Min(name.length, arena_capacity(&scratch, u8) - 1);
+ str8 title_string = push_str8(&scratch, name);
+ InitWindow(width, height, (char *)title_string.data);
+ }
+
+ we->as.window.handle = GetPlatformWindowHandle();
+ os_window_equip_common(os_w32_context.input, we->as.window.handle);
+ raylib_window_resize = glfwSetWindowSizeCallback(we->as.window.handle, os_window_resize_callback);
+
+ /* NOTE: do this after initing so that the window starts out floating in tiling wm */
+ SetWindowState(FLAG_WINDOW_RESIZABLE);
+ SetWindowMinSize(320, 240);
+
+ return result;
}
#if BEAMFORMER_RENDERDOC_HOOKS
@@ -275,6 +388,8 @@ debug_library_reload(BeamformerInput *input)
beamformer_library_handle = new_handle;
}
}
+#else
+#define debug_library_reload(a) (void)(a)
#endif /* BEAMFORMER_DEBUG */
function void
@@ -283,7 +398,7 @@ load_platform_libraries(BeamformerInput *input)
#if BEAMFORMER_DEBUG
debug_library_reload(input);
os_w32_add_file_watch(str8(OS_DEBUG_LIB_NAME), (void *)BeamformerInputEventKind_ExecutableReload,
- OSW32_FileWatchKindPlatform);
+ OSW32FileWatchKind_Platform);
#endif
input->vulkan_library_handle = (OSLibrary){OSInvalidHandleValue};
@@ -306,7 +421,7 @@ load_platform_libraries(BeamformerInput *input)
}
function void
-dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32_FileWatchDirectory *fw_dir)
+dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32FileWatchDirectory *fw_dir)
{
TempArena save_point = {0};
i64 offset = 0;
@@ -328,28 +443,23 @@ dispatch_file_watch(BeamformerInput *input, Arena arena, u64 current_time, OSW32
str8 file_name = str8_from_str16(&arena, (str16){.data = fni->filename, .length = fni->filename_size / 2});
u64 hash = u64_hash_from_str8(file_name);
- for (da_count i = 0; i < fw_dir->count; i++) {
- OSW32_FileWatch *fw = fw_dir->data + i;
- if (fw->hash == hash) {
- // NOTE(rnp): avoid multiple updates in a single frame
- if (fw->update_time < current_time) {
- BeamformerInputEvent input_event = {0};
- if (fw->kind == OSW32_FileWatchKindPlatform) {
- assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload);
- #if BEAMFORMER_DEBUG
- if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload)
- debug_library_reload(input);
- #endif
- input_event.kind = (u64)fw->user_context;
- } else {
- input_event.kind = BeamformerInputEventKind_FileEvent;
- input_event.file_watch_user_context = fw->user_context;
- }
- os_push_input_event(input, input_event);
+ for (OSW32FileWatch *fw = fw_dir->first_child; fw; fw = fw->next) if (fw->hash == hash) {
+ // NOTE(rnp): avoid multiple updates in a single frame
+ if (fw->update_time < current_time) {
+ BeamformerInputEvent input_event = {0};
+ if (fw->kind == OSW32FileWatchKind_Platform) {
+ assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload);
+ if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload)
+ debug_library_reload(input);
+ input_event.kind = (u64)fw->user_context;
+ } else {
+ input_event.kind = BeamformerInputEventKind_FileEvent;
+ input_event.file_watch_user_context = fw->user_context;
}
- fw->update_time = current_time;
- break;
+ os_push_input_event(input, input_event);
}
+ fw->update_time = current_time;
+ break;
}
offset = fni->next_entry_offset;
@@ -371,7 +481,7 @@ clear_io_queue(BeamformerInput *input, Arena arena)
w32_io_completion_event *event = (w32_io_completion_event *)user_data;
switch (event->tag) {
case W32IOEvent_FileWatch:{
- OSW32_FileWatchDirectory *dir = (OSW32_FileWatchDirectory *)event->context;
+ OSW32FileWatchDirectory *dir = (OSW32FileWatchDirectory *)event->context;
dispatch_file_watch(input, arena, current_time, dir);
zero_struct(&dir->overlapped);
ReadDirectoryChangesW(dir->handle, dir->buffer, OSW32_FileWatchDirectoryBufferSize, 0,
@@ -400,6 +510,7 @@ main(void)
os_w32_context.arena = sub_arena(&program_memory, MB(2), os_w32_context.system_info.page_size);
BeamformerInput *input = push_struct(&program_memory, BeamformerInput);
+ os_w32_context.input = input;
input->memory = program_memory.beg;
input->memory_size = program_memory.end - program_memory.beg;
input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE,
@@ -428,7 +539,9 @@ main(void)
beamformer_frame_step(input);
// NOTE(rnp): this must happen at the end of frame to allow the pre loop events through
- input->event_count = 0;
+ // TODO(rnp): hack: until raylib is removed this happens in ui since raylib will cause
+ // glfw to call the input callbacks in during EndDrawing()
+ //input->event_count = 0;
}
beamformer_terminate(input);
diff --git a/ui.c b/ui.c
@@ -4224,6 +4224,14 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformerFrame *frame_to_dr
ui->latest_plane_valid[frame_plane] = 0;
}
+ for EachIndex(input->event_count, it) {
+ if (input->event_queue[it].kind == BeamformerInputEventKind_WindowResize) {
+ // TODO(rnp): match window against window list
+ ctx->window_size.w = input->event_queue[it].window_resize.width;
+ ctx->window_size.h = input->event_queue[it].window_resize.height;
+ }
+ }
+
asan_poison_region(ui->arena.beg, ui->arena.end - ui->arena.beg);
u32 selected_block = ui->selected_parameter_block % BeamformerMaxParameterBlocks;
@@ -4339,6 +4347,10 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformerFrame *frame_to_dr
draw_ui_regions(ui, window_rect, mouse);
draw_floating_widgets(ui, window_rect, mouse);
+
+ // TODO(rnp): hack: until raylib is removed this happens in ui since raylib will cause
+ // glfw to call the input callbacks during EndDrawing()
+ input->event_count = 0;
EndDrawing();
ui->last_mouse = (v2){{input->mouse_x, input->mouse_y}};
diff --git a/util_os_ui.c b/util_os_ui.c
@@ -2,6 +2,17 @@
// NOTE(rnp): functions which require platform layer support but
// otherwise share implementation
+// TODO(rnp): replace all this with platform specific functions
+
+void *GetPlatformWindowHandle(void);
+
+// see: external/raylib/src/external/glfw/include/GLFW/glfw3.h
+typedef void glfw_window_resize_fn(void *window, i32 width, i32 height);
+
+glfw_window_resize_fn *glfwSetWindowSizeCallback(void *window, glfw_window_resize_fn *callback);
+
+global BeamformerInput *beamformer_input;
+global glfw_window_resize_fn *raylib_window_resize;
function void
os_push_input_event(BeamformerInput *input, BeamformerInputEvent event)
@@ -12,6 +23,12 @@ os_push_input_event(BeamformerInput *input, BeamformerInputEvent event)
}
function void
+os_window_equip_common(BeamformerInput *input, void *window)
+{
+ beamformer_input = input;
+}
+
+function void
os_build_frame_input(BeamformerInput *input)
{
Vector2 new_mouse = {-1, -1};