From 1269018e61894762cc23715d57455f12e4bc2949 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Tue, 9 Jul 2024 13:19:56 -0400 Subject: [PATCH] refactor stub --- src/App.zig | 16 +++ src/au.zig | 1 + src/main.zig | 288 +++------------------------------------------ src/nu.zig | 22 ++++ src/nu/Bus.zig | 294 ++++++++++++++++++++++++++++++++++++++++++++++ src/nu/ImGui.zig | 20 ++++ src/nu/Render.zig | 23 ++++ src/nu/Window.zig | 77 ++++++++++++ 8 files changed, 468 insertions(+), 273 deletions(-) create mode 100644 src/App.zig create mode 100644 src/nu.zig create mode 100644 src/nu/Bus.zig create mode 100644 src/nu/ImGui.zig create mode 100644 src/nu/Render.zig create mode 100644 src/nu/Window.zig diff --git a/src/App.zig b/src/App.zig new file mode 100644 index 0000000..69ab7ca --- /dev/null +++ b/src/App.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const nu = @import("nu.zig"); + +const Self = @This(); + +pub fn init(alloc: std.mem.Allocator, render: *nu.Render, imgui: *nu.ImGui) !Self { + _ = alloc; + _ = render; + _ = imgui; + + return .{}; +} + +pub fn deinit(self: *Self) void { + _ = self; +} diff --git a/src/au.zig b/src/au.zig index 4732283..2ce76d9 100644 --- a/src/au.zig +++ b/src/au.zig @@ -105,6 +105,7 @@ fn init_glfw() !void { return error.glfwInitFailed; errdefer c.glfwTerminate(); + // todo move to render if (c.glfwVulkanSupported() != c.GLFW_TRUE) return error.glfwNoVulkan; } diff --git a/src/main.zig b/src/main.zig index 0482c77..59eae20 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,287 +1,29 @@ const std = @import("std"); -const vk = @import("vk"); -const c = @import("c.zig"); -const shaders = @import("shaders"); -const Allocator = std.mem.Allocator; -const au = @import("au.zig"); -const Uber = @import("Uber.zig"); +const nu = @import("nu.zig"); -const ui = @import("au/ui.zig"); - -const vertices = [_]Uber.Vertex{ - // Vulkan depth range is 0, 1 instead of OpenGL -1, 1 - .{ .pos = .{ -0.5, -0.5, -0.5, 1.0 }, .color = .{ 1, 0, 0 } }, - .{ .pos = .{ -0.5, 0.5, -0.5, 1.0 }, .color = .{ 0, 1, 0 } }, - .{ .pos = .{ 0.5, -0.5, -0.5, 1.0 }, .color = .{ 0, 0, 1 } }, - .{ .pos = .{ 0.5, 0.5, -0.5, 1.0 }, .color = .{ 1, 1, 0 } }, - .{ .pos = .{ -0.5, -0.5, 0.5, 1.0 }, .color = .{ 1, 0, 0 } }, - .{ .pos = .{ -0.5, 0.5, 0.5, 1.0 }, .color = .{ 0, 1, 0 } }, - .{ .pos = .{ 0.5, -0.5, 0.5, 1.0 }, .color = .{ 0, 0, 1 } }, - .{ .pos = .{ 0.5, 0.5, 0.5, 1.0 }, .color = .{ 1, 1, 0 } }, -}; - -const indices = [_]Uber.Index{ 4, 5, 6, 6, 5, 7 }; - -const uniform = Uber.Uniform{ - .mat = .{ - 0.5, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, - }, -}; - -fn record_render( - cmd: au.CommandBufferProxy, - uber: Uber, - area: vk.Rect2D, // render area, scissor, and viewport. - vertex_buffer: vk.Buffer, - index_buffer: vk.Buffer, - descriptor_set: vk.DescriptorSet, -) void { - cmd.setViewport(0, 1, &.{.{ - .x = @floatFromInt(area.offset.x), - .y = @floatFromInt(area.offset.y), - .width = @floatFromInt(area.extent.width), - .height = @floatFromInt(area.extent.height), - .min_depth = 0, - .max_depth = 1, - }}); - cmd.setScissor(0, 1, &.{area}); - - cmd.bindPipeline(.graphics, uber.pipeline); - cmd.bindDescriptorSets(.graphics, uber.layout, 0, 1, &.{descriptor_set}, 0, null); - cmd.bindVertexBuffers(0, 1, &.{vertex_buffer}, &.{0}); - cmd.bindIndexBuffer(index_buffer, 0, .uint16); - cmd.drawIndexed(indices.len, 1, 0, 0, 0); -} +const App = @import("App.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.detectLeaks(); const alloc = gpa.allocator(); - try au.init(alloc); - defer au.deinit(); + var window = try nu.Window.init(alloc, .{ .title = "Hello World" }); + defer window.deinit(); - { - const pdev_prop = au.I.getPhysicalDeviceProperties(au.device_config.pdev); - std.debug.print("Selected '{s}' in mode '{any}'\n", .{ pdev_prop.device_name, au.device_config.mode }); - } + var render = try nu.Render.init(alloc, &window); + defer render.deinit(); - var sc = try au.SwapChain.init(alloc); - defer sc.deinit(); + var imgui = try nu.ImGui.init(alloc, &window, &render); + defer imgui.deinit(); - var flights = try au.Flights.init(alloc, 3); // FRAMES IN FLIGHT - defer flights.deinit(); + var app = try App.init(alloc, &render, &imgui); + defer app.deinit(); - const ctx = try ui.init(flights.flights.len); - defer ui.deinit(ctx); - - const descriptorPool = try au.D.createDescriptorPool(&vk.DescriptorPoolCreateInfo{ - .flags = .{ .free_descriptor_set_bit = true }, - .pool_size_count = 1, - .p_pool_sizes = &.{ - vk.DescriptorPoolSize{ .descriptor_count = 32, .type = .combined_image_sampler }, - }, - .max_sets = 32, - }, null); - defer au.D.destroyDescriptorPool(descriptorPool, null); - - _ = try sc.rebuild(); - - const cache = try au.D.createPipelineCache(&vk.PipelineCacheCreateInfo{}, null); - defer au.D.destroyPipelineCache(cache, null); - - const uber = try Uber.init(cache); - defer uber.deinit(); - - const vkalloc = au.VkAllocator.init(); - - const vertex_buffer = try au.D.createBuffer(&vk.BufferCreateInfo{ - .size = @sizeOf(@TypeOf(vertices)), - .usage = .{ .vertex_buffer_bit = true }, - .sharing_mode = .exclusive, - }, null); - defer au.D.destroyBuffer(vertex_buffer, null); - const vertex_memory = try vkalloc.alloc( - au.D.getBufferMemoryRequirements(vertex_buffer), - .{ .host_visible_bit = true, .host_coherent_bit = true }, - ); - defer vkalloc.free(vertex_memory); - try au.D.bindBufferMemory(vertex_buffer, vertex_memory, 0); - const vertex_data: *align(1) @TypeOf(vertices) = - @ptrCast(try au.D.mapMemory(vertex_memory, 0, vk.WHOLE_SIZE, .{})); - defer au.D.unmapMemory(vertex_memory); - vertex_data.* = vertices; - - const index_buffer = try au.D.createBuffer(&vk.BufferCreateInfo{ - .size = @sizeOf(@TypeOf(indices)), - .usage = .{ .index_buffer_bit = true }, - .sharing_mode = .exclusive, - }, null); - defer au.D.destroyBuffer(index_buffer, null); - const index_memory = try vkalloc.alloc( - au.D.getBufferMemoryRequirements(index_buffer), - .{ .host_visible_bit = true, .host_coherent_bit = true }, - ); - defer vkalloc.free(index_memory); - try au.D.bindBufferMemory(index_buffer, index_memory, 0); - const index_data: *align(1) @TypeOf(indices) = - @ptrCast(try au.D.mapMemory(index_memory, 0, vk.WHOLE_SIZE, .{})); - defer au.D.unmapMemory(index_memory); - index_data.* = indices; - - // todo ring buffer for frames in flight. need to use an offset when binding - // use dynamic offset - descriptor type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC - const uniform_buffer = try au.D.createBuffer(&vk.BufferCreateInfo{ - .size = @sizeOf(@TypeOf(uniform)), - .usage = .{ .uniform_buffer_bit = true }, - .sharing_mode = .exclusive, - }, null); - defer au.D.destroyBuffer(uniform_buffer, null); - const uniform_memory = try vkalloc.alloc( - au.D.getBufferMemoryRequirements(uniform_buffer), - .{ .host_visible_bit = true, .host_coherent_bit = true }, - ); - defer vkalloc.free(uniform_memory); - try au.D.bindBufferMemory(uniform_buffer, uniform_memory, 0); - const uniform_data: *align(1) @TypeOf(uniform) = - @ptrCast(try au.D.mapMemory(uniform_memory, 0, vk.WHOLE_SIZE, .{})); - defer au.D.unmapMemory(uniform_memory); - uniform_data.* = uniform; - - var descriptorSet: vk.DescriptorSet = undefined; - try au.D.allocateDescriptorSets(&vk.DescriptorSetAllocateInfo{ - .descriptor_pool = descriptorPool, - .descriptor_set_count = 1, - .p_set_layouts = &.{uber.set_layout}, - }, @ptrCast(&descriptorSet)); - defer au.D.freeDescriptorSets(descriptorPool, 1, &.{descriptorSet}) catch unreachable; // todo handle this? - - au.D.updateDescriptorSets( - 1, - &.{ - vk.WriteDescriptorSet{ - .dst_set = descriptorSet, - .dst_binding = 0, - .dst_array_element = 0, - .descriptor_type = .uniform_buffer, - .descriptor_count = 1, - .p_image_info = undefined, - .p_texel_buffer_view = undefined, - .p_buffer_info = &.{ - vk.DescriptorBufferInfo{ - .buffer = uniform_buffer, - .offset = 0, - .range = vk.WHOLE_SIZE, - }, - }, - }, - }, - 0, - null, - ); - - var prng = std.Random.Sfc64.init(std.crypto.random.int(u64)); - const rand = prng.random(); - - while (!au.W.should_close()) { - ui.NewFrame(); - ui.igShowMetricsWindow(null); - ui.EndFrame(); - - const flight = flights.next(); - - const events = if (au.W.focused()) - au.poll_events() - else - au.wait_events_timeout(0.5); - - for (events) |u| { - switch (u) { - .framebufferSize => sc.mark(), - .cursorPos, .windowPos, .windowSize, .windowRefresh => {}, - else => |e| std.debug.print("{any}\n", .{e}), - } - } - - _ = try au.D.waitForFences(1, &.{flight.fence}, vk.TRUE, std.math.maxInt(u64)); - try au.D.resetFences(1, &.{flight.fence}); - - // TODO need to check the standard to see what happens to a fence or semaphore on OutOfDateKHR error. - // acquire, submit, and present. - - while (true) { - _ = try sc.rebuild(); - - const target = sc.acquire(flight.acquire, .null_handle) catch |err| switch (err) { - error.OutOfDateKHR => { - sc.mark(); - continue; - }, - else => return err, - }; - - try au.D.resetCommandPool(flight.pool, .{}); - var cmd = au.CommandBufferProxy.init(flight.cmd, au.D.wrapper); - try cmd.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); - - const render_area: vk.Rect2D = .{ - .offset = .{ .x = 0, .y = 0 }, - .extent = sc.cinfo.image_extent, - }; - - target.begin_rendering(cmd, render_area); - record_render( - cmd, - uber, - render_area, - vertex_buffer, - index_buffer, - descriptorSet, - ); - ui.Draw(cmd); - target.end_rendering(cmd); - - for (vertex_data) |*v| { - for (v.pos[0..2]) |*f| { - f.* += (rand.float(f32) - 0.5) * 0.001; - } - } - - try cmd.endCommandBuffer(); - - try au.Q.submit( - 1, - &.{ - vk.SubmitInfo{ - .wait_semaphore_count = 1, - .p_wait_semaphores = @ptrCast(&flight.acquire), - .p_wait_dst_stage_mask = @ptrCast(&vk.PipelineStageFlags{ .color_attachment_output_bit = true }), - .command_buffer_count = 1, - .p_command_buffers = @ptrCast(&cmd.handle), - .signal_semaphore_count = 1, - .p_signal_semaphores = @ptrCast(&flight.complete), - }, - }, - flight.fence, - ); - - if (sc.present(&.{flight.complete}, target)) |_| { - break; - } else |err| switch (err) { - error.OutOfDateKHR => { - _ = try au.D.waitForFences(1, &.{flight.fence}, vk.TRUE, std.math.maxInt(u64)); - try au.D.resetFences(1, &.{flight.fence}); - sc.mark(); - continue; - }, - else => return err, - } - } - } - - try au.D.deviceWaitIdle(); + try nu.run(&window, .{ + &app, + &imgui, + &render, + }); } diff --git a/src/nu.zig b/src/nu.zig new file mode 100644 index 0000000..3bafb54 --- /dev/null +++ b/src/nu.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +pub const Window = @import("nu/Window.zig"); +pub const Render = @import("nu/Render.zig"); +pub const ImGui = @import("nu/ImGui.zig"); + +pub fn run( + driver: anytype, + modules: anytype, +) !void { + while (driver.next()) |events| { + // todo event handler + _ = events; + + inline for (modules) |module| { + if (std.meta.hasMethod(@TypeOf(module), "frame")) + module.frame(); + } + + // todo fixed timestep + } +} diff --git a/src/nu/Bus.zig b/src/nu/Bus.zig new file mode 100644 index 0000000..0dc8e33 --- /dev/null +++ b/src/nu/Bus.zig @@ -0,0 +1,294 @@ +const std = @import("std"); +// const vk = @import("vk"); +// const c = @import("../c.zig"); +// const Window = @import("../au.zig").Window; +const Self = @This(); + +const Window = @import("Window.zig"); +const c = Window.c; + +alloc: std.mem.Allocator, +events: std.ArrayListUnmanaged(Event) = .{}, // todo bounded array? +drops: std.ArrayListUnmanaged([][]const u8) = .{}, // todo bounded array? + +pub fn init(alloc: std.mem.Allocator) Self { + return .{ + .alloc = alloc, + }; +} + +pub fn deinit(self: *Self) void { + self.clear(); + + self.events.deinit(self.alloc); + self.drops.deinit(self.alloc); +} + +pub fn connect(self: *Self, handle: *c.GLFWwindow) void { + // todo somehow prevent double-connect? + c.glfwSetWindowUserPointer(handle, self); + _ = c.glfwSetWindowPosCallback(handle, onWindowPos); + _ = c.glfwSetWindowSizeCallback(handle, onWindowSize); + _ = c.glfwSetWindowCloseCallback(handle, onWindowClose); + _ = c.glfwSetWindowRefreshCallback(handle, onWindowRefresh); + _ = c.glfwSetWindowFocusCallback(handle, onWindowFocus); + _ = c.glfwSetWindowIconifyCallback(handle, onWindowIconify); + _ = c.glfwSetWindowMaximizeCallback(handle, onWindowMaximize); + _ = c.glfwSetFramebufferSizeCallback(handle, onFramebufferSize); + _ = c.glfwSetWindowContentScaleCallback(handle, onWindowContentScale); + _ = c.glfwSetMouseButtonCallback(handle, onMouseButton); + _ = c.glfwSetCursorPosCallback(handle, onCursorPos); + _ = c.glfwSetCursorEnterCallback(handle, onCursorEnter); + _ = c.glfwSetScrollCallback(handle, onScroll); + _ = c.glfwSetKeyCallback(handle, onKey); + _ = c.glfwSetCharModsCallback(handle, onCharMods); + _ = c.glfwSetDropCallback(handle, onDrop); +} + +pub fn disconnect(_: *Self, handle: *c.GLFWwindow) void { + // todo somehow prevent double-disconnect? + c.glfwSetWindowUserPointer(handle, null); + _ = c.glfwSetWindowPosCallback(handle, null); + _ = c.glfwSetWindowSizeCallback(handle, null); + _ = c.glfwSetWindowCloseCallback(handle, null); + _ = c.glfwSetWindowRefreshCallback(handle, null); + _ = c.glfwSetWindowFocusCallback(handle, null); + _ = c.glfwSetWindowIconifyCallback(handle, null); + _ = c.glfwSetWindowMaximizeCallback(handle, null); + _ = c.glfwSetFramebufferSizeCallback(handle, null); + _ = c.glfwSetWindowContentScaleCallback(handle, null); + _ = c.glfwSetMouseButtonCallback(handle, null); + _ = c.glfwSetCursorPosCallback(handle, null); + _ = c.glfwSetCursorEnterCallback(handle, null); + _ = c.glfwSetScrollCallback(handle, null); + _ = c.glfwSetKeyCallback(handle, null); + _ = c.glfwSetCharModsCallback(handle, null); + _ = c.glfwSetDropCallback(handle, null); +} + +pub fn clear(self: *Self) void { + for (self.drops.items) |drop| { + for (drop) |path| { + self.alloc.free(path); + } + self.alloc.free(drop); + } + self.drops.clearAndFree(self.alloc); + + self.events.clearRetainingCapacity(); +} + +fn getBus(handle: ?*c.GLFWwindow) *Self { + return @alignCast(@ptrCast(c.glfwGetWindowUserPointer(handle))); +} + +pub const Event = union(enum) { + const WindowPos = struct { x: i32, y: i32 }; + const WindowSize = struct { x: i32, y: i32 }; + const WindowClose = struct {}; + const WindowRefresh = struct {}; + const WindowFocus = struct { focused: bool }; + const WindowIconify = struct { iconified: bool }; + const WindowMaximize = struct { maximized: bool }; + const FramebufferSize = struct { width: u32, height: u32 }; + const WindowContentScale = struct { x: f32, y: f32 }; + const MouseButton = struct { + button: c_int, // todo enum + action: c_int, // todo enum + mods: c_int, // todo bitmask + }; + const CursorPos = struct { x: f64, y: f64 }; + const CursorEnter = struct { entered: bool }; + const Scroll = struct { dx: f64, dy: f64 }; + const Key = struct { + key: c_int, // todo enum + scan: c_int, // todo ??? + action: c_int, // todo enum + mods: c_int, // todo bitmask + }; + const Char = struct { + code: u21, + }; + const CharMods = struct { + code: u21, + mods: c_int, // todo bitmask + }; + const Drop = struct { + paths: []const []const u8, + }; + + windowPos: WindowPos, + windowSize: WindowSize, + windowClose: WindowClose, + windowRefresh: WindowRefresh, + windowFocus: WindowFocus, + windowIconify: WindowIconify, + windowMaximize: WindowMaximize, + framebufferSize: FramebufferSize, + windowContentScale: WindowContentScale, + mouseButton: MouseButton, + cursorPos: CursorPos, + cursorEnter: CursorEnter, + scroll: Scroll, + key: Key, + char: Char, + charMods: CharMods, + drop: Drop, +}; + +fn onWindowPos(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowPos = .{ + .x = @intCast(x), + .y = @intCast(y), + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowSize(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowSize = .{ + .x = @intCast(x), + .y = @intCast(y), + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowClose(handle: ?*c.GLFWwindow) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowClose = .{}, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowRefresh(handle: ?*c.GLFWwindow) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowRefresh = .{}, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowFocus(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowFocus = .{ + .focused = focused == c.GLFW_TRUE, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowIconify(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowIconify = .{ + .iconified = iconified == c.GLFW_TRUE, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowMaximize(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowMaximize = .{ + .maximized = maximized == c.GLFW_TRUE, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onFramebufferSize(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .framebufferSize = .{ + .width = @intCast(width), + .height = @intCast(height), + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onWindowContentScale(handle: ?*c.GLFWwindow, x: f32, y: f32) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .windowContentScale = .{ + .x = x, + .y = y, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onMouseButton(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .mouseButton = .{ + .button = button, + .action = action, + .mods = mods, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onCursorPos(handle: ?*c.GLFWwindow, x: f64, y: f64) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .cursorPos = .{ + .x = x, + .y = y, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onCursorEnter(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .cursorEnter = .{ + .entered = entered == c.GLFW_TRUE, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onScroll(handle: ?*c.GLFWwindow, dx: f64, dy: f64) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .scroll = .{ + .dx = dx, + .dy = dy, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onKey(handle: ?*c.GLFWwindow, key: c_int, scan: c_int, action: c_int, mods: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .key = .{ + .key = key, + .scan = scan, + .action = action, + .mods = mods, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onCharMods(handle: ?*c.GLFWwindow, code: c_uint, mods: c_int) callconv(.C) void { + const bus = getBus(handle); + bus.events.append(bus.alloc, .{ + .charMods = .{ + .code = @intCast(code), + .mods = mods, + }, + }) catch unreachable; // todo circular queue; warn +} + +fn onDrop(handle: ?*c.GLFWwindow, count: c_int, paths: [*c][*c]const u8) callconv(.C) void { + const bus = getBus(handle); + + const drops = bus.alloc.alloc([]const u8, @intCast(count)) catch unreachable; // todo warn + for (drops, paths) |*dst, src| { + dst.* = bus.alloc.dupe(u8, std.mem.sliceTo(src, 0)) catch unreachable; // todo warn + } + bus.drops.append(bus.alloc, drops) catch unreachable; // todo warn + + bus.events.append(bus.alloc, .{ + .drop = .{ .paths = drops }, + }) catch unreachable; // todo circular queue; warn +} diff --git a/src/nu/ImGui.zig b/src/nu/ImGui.zig new file mode 100644 index 0000000..8dbdf6a --- /dev/null +++ b/src/nu/ImGui.zig @@ -0,0 +1,20 @@ +//! all imgui code through this path + +const std = @import("std"); + +const Self = @This(); + +const Window = @import("Window.zig"); +const Render = @import("Render.zig"); + +pub fn init(alloc: std.mem.Allocator, window: *Window, render: *Render) !Self { + _ = alloc; + _ = window; + _ = render; + + return .{}; +} + +pub fn deinit(self: *Self) void { + _ = self; +} diff --git a/src/nu/Render.zig b/src/nu/Render.zig new file mode 100644 index 0000000..54dc41b --- /dev/null +++ b/src/nu/Render.zig @@ -0,0 +1,23 @@ +const std = @import("std"); + +const Window = @import("Window.zig"); + +const Self = @This(); + +// isolate all the vulkan code through this path +// except for imgui code + +// const au = @import("au.zig"); + +pub fn init(alloc: std.mem.Allocator, window: *Window) !Self { + _ = alloc; + _ = window; + + // todo check vulkan supported + // todo create window surface + return .{}; +} + +pub fn deinit(self: *Self) void { + _ = self; +} diff --git a/src/nu/Window.zig b/src/nu/Window.zig new file mode 100644 index 0000000..52234ca --- /dev/null +++ b/src/nu/Window.zig @@ -0,0 +1,77 @@ +//! GLFW Adaptor + +const std = @import("std"); + +pub const c = @cImport({ + @cDefine("GLFW_INCLUDE_NONE", {}); + @cInclude("GLFW/glfw3.h"); +}); + +const Self = @This(); + +pub const Bus = @import("Bus.zig"); + +pub const Options = struct { + title: [*:0]const u8, + width: u32 = 1280, + height: u32 = 720, + x11_class_name: [*:0]const u8 = "floating_window", + x11_instance_name: [*:0]const u8 = "floating_window", +}; + +alloc: std.mem.Allocator, +bus: *Bus, +handle: *c.GLFWwindow, + +pub fn init(alloc: std.mem.Allocator, options: Options) !Self { + if (c.glfwInit() != c.GLFW_TRUE) + return error.glfwInitFailed; + errdefer c.glfwTerminate(); + + const bus: *Bus = try alloc.create(Bus); + errdefer alloc.destroy(bus); + bus.* = Bus.init(alloc); + errdefer bus.deinit(); + + c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API); + c.glfwWindowHintString(c.GLFW_X11_CLASS_NAME, options.x11_class_name); + c.glfwWindowHintString(c.GLFW_X11_INSTANCE_NAME, options.x11_instance_name); + + const handle: *c.GLFWwindow = c.glfwCreateWindow( + @intCast(options.width), + @intCast(options.height), + options.title, + null, + null, + ) orelse + return error.glfWCreateWindowFailed; + errdefer c.glfwDestroyWindow(handle); + + bus.connect(handle); + errdefer bus.disconnect(handle); + + return .{ + .alloc = alloc, + .bus = bus, + .handle = handle, + }; +} + +pub fn deinit(self: *Self) void { + self.bus.deinit(); + self.alloc.destroy(self.bus); + c.glfwDestroyWindow(self.handle); + c.glfwTerminate(); +} + +pub fn next(self: *Self) ?[]Bus.Event { + self.bus.clear(); + + if (c.glfwWindowShouldClose(self.handle) == c.GLFW_TRUE) + return null; + + // c.glfwPollEvents(); + c.glfwWaitEvents(); + + return self.bus.events.items; +}