diff --git a/src/App.zig b/src/App.zig index 95a830a..cf4d0b7 100644 --- a/src/App.zig +++ b/src/App.zig @@ -1,8 +1,24 @@ const std = @import("std"); const nu = @import("nu.zig"); +const Bus = @import("nu/Bus.zig"); +const Render = @import("nu/Render.zig"); +const ImGui = @import("nu/ImGui.zig"); + pub fn init(alloc: std.mem.Allocator) !void { _ = alloc; } pub fn deinit() void {} + +pub fn nu_frame() void {} + +// pub fn nu_events(events: []const Bus.Event) void { +// std.debug.print("{any}\n", .{events}); +// } + +// pub fn nu_render_present(_: Render.au.CommandBufferProxy) void {} + +pub fn nu_imgui_frame() void { + ImGui.igShowMetricsWindow(null); +} diff --git a/src/main.zig b/src/main.zig index 21cff7a..b8848d5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -11,8 +11,17 @@ pub const nu_options: nu.Options = .{ }, }; -pub const nu_driver = nu.Window; +// todo declare or infer module dependencies, topological sort for init order. clean up "init" lines in main. +// +// problem: where should gpa go? probably some "Engine" structure in nu.zig +// +// don't necessarily need to declare topological sort - depth-first traversal +// of each module's dependencies without repeats would do. +// +// idea - use a structure like std.Build.Step where the polymorphic part is a +// component of the larger structure. +pub const nu_driver = nu.Window; pub const nu_modules = .{ App, nu.ImGui, @@ -24,15 +33,6 @@ pub fn main() !void { defer _ = gpa.detectLeaks(); const alloc = gpa.allocator(); - // todo declare or infer module dependencies, topological sort for init order - // problem: where should gpa go? probably some "Engine" structure in nu.zig - - // don't necessarily need to declare topological sort - depth-first traversal - // of each module's dependencies without repeats would do. - - // idea - use a structure like std.Build.Step where the polymorphic part is a - // component of the larger structure. - try nu.Window.init(alloc); defer nu.Window.deinit(); diff --git a/src/nu.zig b/src/nu.zig index 6ceccb9..887515b 100644 --- a/src/nu.zig +++ b/src/nu.zig @@ -8,13 +8,30 @@ pub const ImGui = @import("nu/ImGui.zig"); pub const Options = struct { window: Window.Options = .{}, render: Render.Options = .{}, - // imgui: ImGui.Options = .{}, + imgui: ImGui.Options = .{}, }; pub const options: Options = if (@hasDecl(root, "nu_options")) root.nu_options else .{}; pub const modules = root.nu_modules; pub const driver = root.nu_driver; +pub fn run() !void { + try invoke_hook("nu_enter", .{}); + + while (driver.next()) |events| { + if (events.len > 0) { + try invoke_hook("nu_events", .{events}); + } + + // todo frame timer + try invoke_hook("nu_frame", .{}); + + // todo fixed timestep + } + + try invoke_hook("nu_close", .{}); +} + fn invoke(func: anytype, args: anytype) !void { if (@typeInfo(@TypeOf(func)).Fn.return_type) |R| { switch (@typeInfo(R)) { @@ -28,6 +45,10 @@ fn invoke(func: anytype, args: anytype) !void { } } +// todo specify hook type. +// - special handling for error unions +// - allow per-hook state somehow declared in the handler + pub fn invoke_hook(comptime name: []const u8, args: anytype) !void { inline for (modules) |module| { if (@hasDecl(module, name)) { @@ -35,14 +56,3 @@ pub fn invoke_hook(comptime name: []const u8, args: anytype) !void { } } } - -pub fn run() !void { - while (driver.next()) |events| { - // todo event handler - _ = events; - - try invoke_hook("frame", .{}); - - // todo fixed timestep - } -} diff --git a/src/nu/ImGui.zig b/src/nu/ImGui.zig index ee9bfa0..ed69fb1 100644 --- a/src/nu/ImGui.zig +++ b/src/nu/ImGui.zig @@ -12,6 +12,8 @@ const Window = @import("Window.zig"); const im = @import("cimgui"); pub usingnamespace im; +pub const Options = struct {}; + pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction { return au.glfwGetInstanceProcAddress(au.I.handle, procname); } @@ -75,34 +77,30 @@ pub fn init() !void { if (!im.impl.ImGui_ImplVulkan_CreateFontsTexture()) { return error.igVulkanFontTextureFailed; } - - try Render.add_present_callback(present); - errdefer Render.remove_present_callback(present); } -pub fn frame() void { +pub fn nu_frame() !void { im.impl.ImGui_ImplGlfw_NewFrame(); im.impl.ImGui_ImplVulkan_NewFrame(); im.igNewFrame(); - im.igShowDemoWindow(null); + try nu.invoke_hook("nu_imgui_frame", .{}); im.igEndFrame(); im.igRender(); } -pub fn deinit() void { - Render.remove_present_callback(present); - im.impl.ImGui_ImplVulkan_Shutdown(); - au.D.destroyDescriptorPool(descriptor_pool, null); - im.impl.ImGui_ImplGlfw_Shutdown(); - im.igDestroyContext(ctx); -} - -pub fn present(cmd: au.CommandBufferProxy) void { +pub fn nu_render_present(cmd: au.CommandBufferProxy) void { im.impl.ImGui_ImplVulkan_RenderDrawData( @ptrCast(im.igGetDrawData()), @ptrFromInt(@intFromEnum(cmd.handle)), null, ); } + +pub fn deinit() void { + im.impl.ImGui_ImplVulkan_Shutdown(); + au.D.destroyDescriptorPool(descriptor_pool, null); + im.impl.ImGui_ImplGlfw_Shutdown(); + im.igDestroyContext(ctx); +} diff --git a/src/nu/Render.zig b/src/nu/Render.zig index 9dcd518..0d4d843 100644 --- a/src/nu/Render.zig +++ b/src/nu/Render.zig @@ -30,33 +30,11 @@ pub const Options = struct { var sc: au.SwapChain = undefined; var flights: au.Flights = undefined; -const PresentCallback = *const fn (au.CommandBufferProxy) void; -var present_callbacks: std.ArrayList(PresentCallback) = undefined; - -pub fn add_present_callback(cb: PresentCallback) !void { - if (std.mem.indexOfScalar(PresentCallback, present_callbacks.items, cb)) |_| { - return; - } else { - try present_callbacks.append(cb); - } -} - -pub fn remove_present_callback(cb: PresentCallback) void { - if (std.mem.indexOfScalar(PresentCallback, present_callbacks.items, cb)) |idx| { - _ = present_callbacks.orderedRemove(idx); - } else { - return; - } -} - pub fn init(alloc: std.mem.Allocator) !void { // todo pick apart au into helpers; not a sub-module filled with its own globals. try au.init(alloc); errdefer au.deinit(); - present_callbacks = std.ArrayList(PresentCallback).init(alloc); - errdefer present_callbacks.deinit(); - sc = try au.SwapChain.init(alloc); errdefer sc.deinit(); @@ -64,7 +42,7 @@ pub fn init(alloc: std.mem.Allocator) !void { errdefer flights.deinit(); } -pub fn frame() !void { +pub fn nu_frame() !void { const flight: au.Flights.Flight = flights.next(); try flight.wait(); @@ -89,14 +67,11 @@ pub fn frame() !void { try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); target.begin_rendering(cmd, render_area); - for (present_callbacks.items) |cb| { - cb(cmd); - } - // todo really don't like this. - // there should be some comptime means for a module to invoke hooks on other modules. eg there should be some - // "record" hook that for each module that gets called here; but if the render module is never added then that - // hook never gets called + // todo manage frame in flight state for each hook; pass the current flight in as context. + // will need some comptime -> anytype mapping. + try nu.invoke_hook("nu_render_present", .{cmd}); + target.end_rendering(cmd); try cmd.endCommandBuffer(); @@ -127,9 +102,11 @@ pub fn frame() !void { } } +pub fn nu_close() !void { + try au.D.deviceWaitIdle(); +} + pub fn deinit() void { - present_callbacks.deinit(); - au.D.deviceWaitIdle() catch {}; flights.deinit(); sc.deinit(); au.deinit();