diff --git a/build.zig b/build.zig index 6d0b4dc6..df950f7a 100644 --- a/build.zig +++ b/build.zig @@ -123,7 +123,8 @@ pub fn build(b: *std.build.Builder) void { compile_all.dependOn(b.getInstallStep()); // compiles the `libmach` shared library - const lib = b.addSharedLibrary("mach", "src/bindings.zig", .unversioned); + const lib = b.addSharedLibrary("mach", "src/platform/libmach.zig", .unversioned); + lib.main_pkg_path = "src/"; const app_pkg = std.build.Pkg{ .name = "app", .source = .{ .path = "src/platform/libmach.zig" }, diff --git a/libmach/test.c b/libmach/test.c index 07b1e67b..b5ec47a1 100644 --- a/libmach/test.c +++ b/libmach/test.c @@ -4,13 +4,18 @@ typedef void resize_callback(void*, uint32_t, uint32_t); +typedef enum { + MachFailure, + MachSuccess +} MachReturn; + // `libmach` exported API bindings -void* mach_init_core(void); -void mach_deinit(void*); -void mach_set_should_close(void*); -bool mach_window_should_close(void*); -int mach_update(void*, resize_callback); -float mach_delta_time(void*); +void* mach_core_init(void); +void mach_core_deinit(void*); +void mach_core_set_should_close(void*); +bool mach_core_window_should_close(void*); +MachReturn mach_core_update(void*, resize_callback); +float mach_core_delta_time(void*); void resize_fn(void* core, uint32_t width, uint32_t height) { printf("Resize callback: %u %u\n", width, height); @@ -19,28 +24,28 @@ void resize_fn(void* core, uint32_t width, uint32_t height) { static float elapsed = 0; int main() { - void* core = mach_init_core(); + void* core = mach_core_init(); if (core == 0) { printf("Error instantiating mach core\n"); return 0; } - while (!mach_window_should_close(core)) { - if (mach_update(core, resize_fn) == 0) { + while (!mach_core_window_should_close(core)) { + if (mach_core_update(core, resize_fn) == MachFailure) { printf("Error updating Mach\n"); break; }; - elapsed += mach_delta_time(core); + elapsed += mach_core_delta_time(core); if (elapsed > 5.0) { - mach_set_should_close(core); + mach_core_set_should_close(core); } // printf("Elapsed: %f\n", elapsed); } - mach_deinit(core); + mach_core_deinit(core); return 0; } diff --git a/libmach/test.lisp b/libmach/test.lisp index d51c5ac4..c361ccf7 100644 --- a/libmach/test.lisp +++ b/libmach/test.lisp @@ -15,29 +15,24 @@ ;; Note: CFFI automatically translates C_style names into lispier kebab-case ones -;; void* mach_init(void); -(defcfun "mach_init_core" :pointer) -;; for some reason, calling "mach_init" always returns a null pointer, and I have no clue why... -;; So I renamed the API function name to "mach_init_core" instead +(defcfun "mach_core_init" :pointer) -;; int mach_update(void*, resize_callback); -(defcfun "mach_update" :int +(defcfun "mach_core_update" :int (core :pointer) (resize-fn :pointer)) -;; void mach_deinit(void*); -(defcfun "mach_deinit" :void +(defcfun "mach_core_deinit" :void (core :pointer)) ;; void mach_set_should_close(void*); -(defcfun "mach_set_should_close" :void +(defcfun "mach_core_set_should_close" :void (core :pointer)) ;; float mach_delta_time(void*); -(defcfun "mach_delta_time" :float +(defcfun "mach_core_delta_time" :float (core :pointer)) ;; bool mach_window_should_close(void*); -(defcfun "mach_window_should_close" :bool +(defcfun "mach_core_window_should_close" :bool (core :pointer)) ;; main @@ -46,20 +41,18 @@ (defcallback resize-fn :void ((core :pointer) (width :unsigned-int) (height :unsigned-int)) (format t "Resize Callback: ~S ~S~%" width height)) -(setf core (mach-init-core)) - -(format t "Core: ~S~%" core) +(setf core (mach-core-init)) (when (pointer-eq core (null-pointer)) (format t "Failed to initialize mach core~%") (sb-ext:exit)) -(loop while (not (mach-window-should-close core)) +(loop while (not (mach-core-window-should-close core)) do (progn - (when (= 0 (mach-update core (callback resize-fn))) + (when (= 0 (mach-core-update core (callback resize-fn))) (format t "Error updating mach~%") (sb-ext:exit)) - (when (> (incf *elapsed* (mach-delta-time core)) 5.0) - (mach-set-should-close core)))) + (when (> (incf *elapsed* (mach-core-delta-time core)) 5.0) + (mach-core-set-should-close core)))) (sb-ext:exit) diff --git a/src/platform/libmach.zig b/src/platform/libmach.zig index 03ed2160..32463869 100644 --- a/src/platform/libmach.zig +++ b/src/platform/libmach.zig @@ -3,6 +3,7 @@ const Core = @import("../Core.zig"); const gpu = @import("gpu"); const ecs = @import("ecs"); const glfw = @import("glfw"); +const native = @import("native.zig"); pub const App = @This(); @@ -19,89 +20,42 @@ pub fn update(_: *App, _: *Core) !void { } // 2. Core might need to expose more state so more API functions can be exposed (for example, the WebGPU API) // 3. Be very careful about arguments, types, memory, etc - any mismatch will result in undefined behavior -pub export fn mach_set_should_close(core: *Core) void { +pub export fn mach_core_set_should_close(core: *Core) void { core.setShouldClose(true); } -pub export fn mach_delta_time(core: *Core) f32 { +pub export fn mach_core_delta_time(core: *Core) f32 { return core.delta_time; } +pub export fn mach_core_window_should_close(core: *Core) bool { + return core.internal.window.shouldClose(); +} + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); -// Initializes and returns Mach's core structure -// Uses an optional type so it is valid to return 0 (on an error) -// TODO: come up with a better error reporting system -pub export fn mach_init_core() ?*Core { - const core: *Core = allocator.create(Core) catch { - return @intToPtr(?*Core, 0); // on error, return null pointer +// Returns a pointer to a newly allocated Core +// Will return a null pointer if an error occurred while initializing Core +pub export fn mach_core_init() ?*Core { + const core = native.core_init(allocator) catch { + return @intToPtr(?*Core, 0); }; - core.* = Core.init(allocator) catch { - return @intToPtr(?*Core, 0); // on error, return null pointer - }; - - // // Glfw specific: initialize the user pointer used in callbacks - core.*.internal.initCallback(); - return core; } -// Deinitializes mach core structure -pub export fn mach_deinit(core: *Core) void { - core.internal.deinit(); - allocator.destroy(core); +pub export fn mach_core_deinit(core: *Core) void { + native.core_deinit(core); } -pub export fn mach_window_should_close(core: *Core) bool { - return core.internal.window.shouldClose(); +pub export fn mach_core_update(core: *Core, resize: ?native.CoreResizeCallback) MachReturn { + native.core_update(core, resize) catch { + return MachReturn.Failure; + }; + return MachReturn.Success; } -pub const CoreCallback = fn (*Core, u32, u32) callconv(.C) void; - -// Adapted from native.zig -pub export fn mach_update(core: *Core, resize_fn: ?CoreCallback) i32 { - if (core.internal.wait_event_timeout > 0.0) { - if (core.internal.wait_event_timeout == std.math.inf(f64)) { - // Wait for an event - glfw.waitEvents() catch { - return 0; - }; - } else { - // Wait for an event with a timeout - glfw.waitEventsTimeout(core.internal.wait_event_timeout) catch { - return 0; - }; - } - } else { - // Don't wait for events - glfw.pollEvents() catch { - return 0; - }; - } - - core.delta_time_ns = core.timer.lapPrecise(); - core.delta_time = @intToFloat(f32, core.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s); - - var framebuffer_size = core.getFramebufferSize(); - core.target_desc.width = framebuffer_size.width; - core.target_desc.height = framebuffer_size.height; - - if (core.swap_chain == null or !core.current_desc.equal(&core.target_desc)) { - const use_legacy_api = core.surface == null; - if (!use_legacy_api) { - core.swap_chain = core.device.nativeCreateSwapChain(core.surface, &core.target_desc); - } else core.swap_chain.?.configure( - core.swap_chain_format, - .{ .render_attachment = true }, - core.target_desc.width, - core.target_desc.height, - ); - - if (resize_fn != null) { - resize_fn.?(core, core.target_desc.width, core.target_desc.height); - } - core.current_desc = core.target_desc; - } - return 1; -} +const MachReturn = enum(c_int) { + Failure, + Success, +}; diff --git a/src/platform/native.zig b/src/platform/native.zig index 8848946b..aaa2c62c 100644 --- a/src/platform/native.zig +++ b/src/platform/native.zig @@ -587,60 +587,81 @@ pub const Platform = struct { pub const BackingTimer = std.time.Timer; +var app: App = undefined; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); - var core = try Core.init(allocator); - defer core.internal.deinit(); - var app: App = undefined; + var core = try core_init(allocator); + defer core_deinit(core); - try app.init(&core); - defer app.deinit(&core); + try app.init(core); + defer app.deinit(core); - // Glfw specific: initialize the user pointer used in callbacks - core.internal.initCallback(); + while (!core.internal.window.shouldClose()) { + try core_update(core, null); - const window = core.internal.window; - while (!window.shouldClose()) { - if (core.internal.wait_event_timeout > 0.0) { - if (core.internal.wait_event_timeout == std.math.inf(f64)) { - // Wait for an event - try glfw.waitEvents(); - } else { - // Wait for an event with a timeout - try glfw.waitEventsTimeout(core.internal.wait_event_timeout); - } - } else { - // Don't wait for events - try glfw.pollEvents(); - } - - core.delta_time_ns = core.timer.lapPrecise(); - core.delta_time = @intToFloat(f32, core.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s); - - var framebuffer_size = core.getFramebufferSize(); - core.target_desc.width = framebuffer_size.width; - core.target_desc.height = framebuffer_size.height; - - if (core.swap_chain == null or !core.current_desc.equal(&core.target_desc)) { - const use_legacy_api = core.surface == null; - if (!use_legacy_api) { - core.swap_chain = core.device.nativeCreateSwapChain(core.surface, &core.target_desc); - } else core.swap_chain.?.configure( - core.swap_chain_format, - .{ .render_attachment = true }, - core.target_desc.width, - core.target_desc.height, - ); - - if (@hasDecl(App, "resize")) { - try app.resize(&core, core.target_desc.width, core.target_desc.height); - } - core.current_desc = core.target_desc; - } - - try app.update(&core); + try app.update(core); + } +} + +pub fn core_init(allocator: std.mem.Allocator) !*Core { + const core: *Core = try allocator.create(Core); + core.* = try Core.init(allocator); + + // // Glfw specific: initialize the user pointer used in callbacks + core.*.internal.initCallback(); + + return core; +} + +pub export fn core_deinit(core: *Core) void { + core.internal.deinit(); + // assumes that core.allocator is the same allocator used to allocate core + core.allocator.destroy(core); // "I used the core to destroy the core" +} + +pub const CoreResizeCallback = fn (*Core, u32, u32) callconv(.C) void; + +pub fn core_update(core: *Core, resize: ?CoreResizeCallback) !void { + if (core.internal.wait_event_timeout > 0.0) { + if (core.internal.wait_event_timeout == std.math.inf(f64)) { + // Wait for an event + try glfw.waitEvents(); + } else { + // Wait for an event with a timeout + try glfw.waitEventsTimeout(core.internal.wait_event_timeout); + } + } else { + // Don't wait for events + try glfw.pollEvents(); + } + + core.delta_time_ns = core.timer.lapPrecise(); + core.delta_time = @intToFloat(f32, core.delta_time_ns) / @intToFloat(f32, std.time.ns_per_s); + + var framebuffer_size = core.getFramebufferSize(); + core.target_desc.width = framebuffer_size.width; + core.target_desc.height = framebuffer_size.height; + + if (core.swap_chain == null or !core.current_desc.equal(&core.target_desc)) { + const use_legacy_api = core.surface == null; + if (!use_legacy_api) { + core.swap_chain = core.device.nativeCreateSwapChain(core.surface, &core.target_desc); + } else core.swap_chain.?.configure( + core.swap_chain_format, + .{ .render_attachment = true }, + core.target_desc.width, + core.target_desc.height, + ); + + if (@hasDecl(App, "resize")) { + try app.resize(core, core.target_desc.width, core.target_desc.height); + } else if (resize != null) { + resize.?(core, core.target_desc.width, core.target_desc.height); + } + core.current_desc = core.target_desc; } }