//! ---------------------------------------------------- //! SDL3 + Vulkan //! //! Used dear_bindings with docking imgui branch //! https://mrscriptx.github.io/devlog/zig/2025/04/30/zig-linking-dear-imgui.html //! ---------------------------------------------------- const im = @import("imgui"); const im_vk = @import("imgui_impl_vulkan"); const im_sdl = @import("imgui_impl_sdl3"); const std = @import("std"); const sdl = @import("sdl"); const Gfx = @import("gfx"); pub fn main(init: std.process.Init) !void { // // SDL // // --- # --- if (!sdl.SDL_Init(sdl.SDL_INIT_VIDEO)) return error.FailedToInitSDL; defer sdl.SDL_Quit(); // --- # --- const window = sdl.SDL_CreateWindow("NYXGFX", 800, 600, sdl.SDL_WINDOW_VULKAN) orelse return error.FailedTomakeWindow; defer sdl.SDL_DestroyWindow(window); // --- # --- const props = sdl.SDL_GetWindowProperties(window); const display = sdl.SDL_GetPointerProperty(props, sdl.SDL_PROP_WINDOW_X11_DISPLAY_POINTER, null); const xwindow = sdl.SDL_GetNumberProperty(props, sdl.SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); // // GFX // var gfx: Gfx = try .init(init.gpa, init.io); defer gfx.deinit(); const instance = try gfx.makeInstance(.{ .vulkan = .{}, }); const surface = try gfx.makeSurface(.{ .window = .{ .xlib = .{ .window = @intCast(xwindow), .display = display.?, }, }, .instance = instance, }); const adapter = try gfx.makeAdapter(.{ .instance = instance, }); const device = try gfx.makeDevice(.{ .instance = instance, .adapter = adapter, .surface = surface, }); const swapchain = try gfx.makeSwapchain(.{ .format = .rgba8_unorm, .surface = surface, .adapter = adapter, .device = device, }); // // IMGUI // // --- CREATE IMGUI CTX --- const ctx = im.ImGui_CreateContext(null) orelse return error.FailedToCreateImGuiContext; defer im.ImGui_DestroyContext(ctx); // --- INIT IMGUI FOR SDL3 + VK --- if (!im_sdl.cImGui_ImplSDL3_InitForVulkan(@ptrCast(window))) return error.FailedToImplImGuiForSDL; defer im_sdl.cImGui_ImplSDL3_Shutdown(); // --- SET IO --- const io = im.ImGui_GetIO() orelse return error.FailedToGetImGuiIO; io.*.ConfigFlags |= im.ImGuiConfigFlags_NavEnableKeyboard; io.*.ConfigFlags |= im.ImGuiConfigFlags_DockingEnable; // --- GET VK RAW DEVICE --- const raw_device = switch (try gfx.getRawDevice(device)) { .vulkan => |v| v, }; // --- GET VK RAW SWAPCHAIN --- const raw_swapchain = try gfx.getRawSwapchain(swapchain); // --- INIT IMGUI FOR VK --- var color_format: im_vk.VkFormat = raw_swapchain.format; var im_info: im_vk.ImGui_ImplVulkan_InitInfo = .{ .Instance = @ptrCast((try gfx.getRawInstance(instance)).vulkan), .PhysicalDevice = blk: { switch (try gfx.getRawAdapter(adapter)) { .vulkan => |v| break :blk @ptrCast(v), } }, .Device = @ptrCast(raw_device.device), .Queue = @ptrCast(raw_device.present_queue), .DescriptorPoolSize = 1024, .MinImageCount = 2, .ImageCount = @intCast(raw_swapchain.images.len), .PipelineInfoMain = .{ .MSAASamples = im_vk.VK_SAMPLE_COUNT_1_BIT, .PipelineRenderingCreateInfo = .{ .sType = im_vk.VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, .colorAttachmentCount = 1, .pColorAttachmentFormats = &color_format, }, }, .UseDynamicRendering = true, // <--- vulkan implementation specific }; if (!im_vk.cImGui_ImplVulkan_Init(&im_info)) return error.FailedToImplImGuiForVulkan; defer { _ = im_vk.vkDeviceWaitIdle(@ptrCast(raw_device.device)); im_vk.cImGui_ImplVulkan_Shutdown(); } // // MAIN LOOP // // --- MISC --- var event: sdl.SDL_Event = undefined; var running: bool = true; while (running) { // --- INPUTS --- while (sdl.SDL_PollEvent(&event)) { switch (event.type) { sdl.SDL_EVENT_QUIT => running = false, else => {}, } _ = im_sdl.cImGui_ImplSDL3_ProcessEvent(@ptrCast(&event)); } { // IMGUI // --- NEW IMGUI FRAME --- im_sdl.cImGui_ImplSDL3_NewFrame(); im_vk.cImGui_ImplVulkan_NewFrame(); im.ImGui_NewFrame(); // --- UI --- if (im.ImGui_Begin("Inspector", null, 0)) { defer im.ImGui_End(); im.ImGui_Text("Hello World"); if (im.ImGui_Button("Click Me")) {} } // --- DEMO --- im.ImGui_ShowDemoWindow(null); // --- RENDER IMGUI --- im.ImGui_Render(); } // --- FRAME --- try gfx.beginFrame(swapchain, device); defer gfx.endFrame(swapchain, device) catch unreachable; // --- NEW PASS --- if (gfx.beginPass(swapchain, .{ .clear_color = .{ 0.01, 0.01, 0.01, 1.0 }, })) |pass| { defer pass.end(); // --- RENDER IMGUI --- switch (try gfx.getRawFrame()) { .vulkan => |v| { const draw_data = im.ImGui_GetDrawData() orelse return; im_vk.cImGui_ImplVulkan_RenderDrawData( @ptrCast(draw_data), @ptrCast(v.cmd_buf), ); }, } } } }