easy comptime hooks
This commit is contained in:
16
src/App.zig
16
src/App.zig
@@ -1,8 +1,24 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const nu = @import("nu.zig");
|
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 {
|
pub fn init(alloc: std.mem.Allocator) !void {
|
||||||
_ = alloc;
|
_ = alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {}
|
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);
|
||||||
|
}
|
||||||
|
20
src/main.zig
20
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 = .{
|
pub const nu_modules = .{
|
||||||
App,
|
App,
|
||||||
nu.ImGui,
|
nu.ImGui,
|
||||||
@@ -24,15 +33,6 @@ pub fn main() !void {
|
|||||||
defer _ = gpa.detectLeaks();
|
defer _ = gpa.detectLeaks();
|
||||||
const alloc = gpa.allocator();
|
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);
|
try nu.Window.init(alloc);
|
||||||
defer nu.Window.deinit();
|
defer nu.Window.deinit();
|
||||||
|
|
||||||
|
34
src/nu.zig
34
src/nu.zig
@@ -8,13 +8,30 @@ pub const ImGui = @import("nu/ImGui.zig");
|
|||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
window: Window.Options = .{},
|
window: Window.Options = .{},
|
||||||
render: Render.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 options: Options = if (@hasDecl(root, "nu_options")) root.nu_options else .{};
|
||||||
pub const modules = root.nu_modules;
|
pub const modules = root.nu_modules;
|
||||||
pub const driver = root.nu_driver;
|
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 {
|
fn invoke(func: anytype, args: anytype) !void {
|
||||||
if (@typeInfo(@TypeOf(func)).Fn.return_type) |R| {
|
if (@typeInfo(@TypeOf(func)).Fn.return_type) |R| {
|
||||||
switch (@typeInfo(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 {
|
pub fn invoke_hook(comptime name: []const u8, args: anytype) !void {
|
||||||
inline for (modules) |module| {
|
inline for (modules) |module| {
|
||||||
if (@hasDecl(module, name)) {
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -12,6 +12,8 @@ const Window = @import("Window.zig");
|
|||||||
const im = @import("cimgui");
|
const im = @import("cimgui");
|
||||||
pub usingnamespace im;
|
pub usingnamespace im;
|
||||||
|
|
||||||
|
pub const Options = struct {};
|
||||||
|
|
||||||
pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction {
|
pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction {
|
||||||
return au.glfwGetInstanceProcAddress(au.I.handle, procname);
|
return au.glfwGetInstanceProcAddress(au.I.handle, procname);
|
||||||
}
|
}
|
||||||
@@ -75,34 +77,30 @@ pub fn init() !void {
|
|||||||
if (!im.impl.ImGui_ImplVulkan_CreateFontsTexture()) {
|
if (!im.impl.ImGui_ImplVulkan_CreateFontsTexture()) {
|
||||||
return error.igVulkanFontTextureFailed;
|
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_ImplGlfw_NewFrame();
|
||||||
im.impl.ImGui_ImplVulkan_NewFrame();
|
im.impl.ImGui_ImplVulkan_NewFrame();
|
||||||
im.igNewFrame();
|
im.igNewFrame();
|
||||||
|
|
||||||
im.igShowDemoWindow(null);
|
try nu.invoke_hook("nu_imgui_frame", .{});
|
||||||
|
|
||||||
im.igEndFrame();
|
im.igEndFrame();
|
||||||
im.igRender();
|
im.igRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn nu_render_present(cmd: au.CommandBufferProxy) 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 {
|
|
||||||
im.impl.ImGui_ImplVulkan_RenderDrawData(
|
im.impl.ImGui_ImplVulkan_RenderDrawData(
|
||||||
@ptrCast(im.igGetDrawData()),
|
@ptrCast(im.igGetDrawData()),
|
||||||
@ptrFromInt(@intFromEnum(cmd.handle)),
|
@ptrFromInt(@intFromEnum(cmd.handle)),
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit() void {
|
||||||
|
im.impl.ImGui_ImplVulkan_Shutdown();
|
||||||
|
au.D.destroyDescriptorPool(descriptor_pool, null);
|
||||||
|
im.impl.ImGui_ImplGlfw_Shutdown();
|
||||||
|
im.igDestroyContext(ctx);
|
||||||
|
}
|
||||||
|
@@ -30,33 +30,11 @@ pub const Options = struct {
|
|||||||
var sc: au.SwapChain = undefined;
|
var sc: au.SwapChain = undefined;
|
||||||
var flights: au.Flights = 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 {
|
pub fn init(alloc: std.mem.Allocator) !void {
|
||||||
// todo pick apart au into helpers; not a sub-module filled with its own globals.
|
// todo pick apart au into helpers; not a sub-module filled with its own globals.
|
||||||
try au.init(alloc);
|
try au.init(alloc);
|
||||||
errdefer au.deinit();
|
errdefer au.deinit();
|
||||||
|
|
||||||
present_callbacks = std.ArrayList(PresentCallback).init(alloc);
|
|
||||||
errdefer present_callbacks.deinit();
|
|
||||||
|
|
||||||
sc = try au.SwapChain.init(alloc);
|
sc = try au.SwapChain.init(alloc);
|
||||||
errdefer sc.deinit();
|
errdefer sc.deinit();
|
||||||
|
|
||||||
@@ -64,7 +42,7 @@ pub fn init(alloc: std.mem.Allocator) !void {
|
|||||||
errdefer flights.deinit();
|
errdefer flights.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame() !void {
|
pub fn nu_frame() !void {
|
||||||
const flight: au.Flights.Flight = flights.next();
|
const flight: au.Flights.Flight = flights.next();
|
||||||
try flight.wait();
|
try flight.wait();
|
||||||
|
|
||||||
@@ -89,14 +67,11 @@ pub fn frame() !void {
|
|||||||
|
|
||||||
try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||||
target.begin_rendering(cmd, render_area);
|
target.begin_rendering(cmd, render_area);
|
||||||
for (present_callbacks.items) |cb| {
|
|
||||||
cb(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo really don't like this.
|
// todo manage frame in flight state for each hook; pass the current flight in as context.
|
||||||
// there should be some comptime means for a module to invoke hooks on other modules. eg there should be some
|
// will need some comptime -> anytype mapping.
|
||||||
// "record" hook that for each module that gets called here; but if the render module is never added then that
|
try nu.invoke_hook("nu_render_present", .{cmd});
|
||||||
// hook never gets called
|
|
||||||
target.end_rendering(cmd);
|
target.end_rendering(cmd);
|
||||||
try cmd.endCommandBuffer();
|
try cmd.endCommandBuffer();
|
||||||
|
|
||||||
@@ -127,9 +102,11 @@ pub fn frame() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nu_close() !void {
|
||||||
|
try au.D.deviceWaitIdle();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
present_callbacks.deinit();
|
|
||||||
au.D.deviceWaitIdle() catch {};
|
|
||||||
flights.deinit();
|
flights.deinit();
|
||||||
sc.deinit();
|
sc.deinit();
|
||||||
au.deinit();
|
au.deinit();
|
||||||
|
Reference in New Issue
Block a user