// not used at this time const std = @import("std"); const vk = @import("vulkan"); const graphics = @import("graphics"); const RenderThread = graphics.RenderThread; const platform = @import("platform"); const vk_renderer = graphics.vk_renderer; const core = @import("core"); const tracy = core.tracy; const vk_constants = graphics.constants; pub const api = @import("cimgui.zig"); pub const c = api.c; const NeonVkContext = vk_renderer.NeonVkContext; pub const Module: core.ModuleDescription = .{ .name = "vkImgui", .enabledByDefault = true, }; // new imgui integration // // arather than call imgui newframe only during the draw step. // // imgui NewFrame will be called in engine pre-tick // // this will make it safe to call imgui functions from anywhere within tick(); fn vkCast(comptime T: type, handle: anytype) T { return @as(T, @ptrFromInt(@as(u64, @intFromEnum(handle)))); } // this data structure represents the imgui integration setup. // it is invalid until you call setup() // // largely don't need to touch this structure from the user's side. pub const NeonVkImGui = struct { const Self = @This(); pub var NeonObjectTable = core.EngineObjectVTable.from(Self); pub const RendererInterfaceVTable = graphics.RendererInterface.from(Self); allocator: std.mem.Allocator, ctx: *NeonVkContext = undefined, descriptorPool: vk.DescriptorPool = undefined, pub fn init(allocator: std.mem.Allocator) !*Self { const self = try allocator.create(Self); self.* = Self{ .allocator = allocator, }; return self; } // NeonObject interface pub fn preTick(_: *Self, _: f64) core.EngineDataEventError!void { c.ImGui_ImplGlfw_NewFrame(); c.cImGui_vk_NewFrame(); c.igNewFrame(); } // VkRenderer interface pub fn preDraw(self: *@This(), frameId: usize) void { _ = self; _ = frameId; } pub fn sendShared(self: *@This(), frameIndex: u32) void { _ = self; const z = core.tracy.ZoneN(@src(), "imgui uploading shared data"); defer z.End(); c.igRenderPlatformWindowsDefault(null, null); c.igRender(); c.cimgui_vk_UploadSharedData(@intCast(frameIndex), c.igGetDrawData()); c.igUpdatePlatformWindows(); } pub fn rtPostDraw(self: *@This(), rt: *RenderThread, cmd: vk.CommandBuffer, frameIndex: u32) void { const z = core.tracy.ZoneN(@src(), "imgui render"); defer z.End(); _ = rt; _ = self; c.cImGui_vk_RenderDrawData( c.cimgui_vk_GetSharedData(@intCast(frameIndex)), vkCast(c.VkCommandBuffer, cmd), vkCast(c.VkPipeline, vk.Pipeline.null_handle), ); c.cimgui_vk_ReleaseSharedData(@intCast(frameIndex)); } pub fn postDraw(self: *@This(), cmd: vk.CommandBuffer, frameIndex: usize, deltaTime: f64) void { _ = self; _ = deltaTime; const z = core.tracy.ZoneN(@src(), "imgui render"); c.igRenderPlatformWindowsDefault(null, null); c.igRender(); c.cimgui_vk_UploadSharedData(@intCast(frameIndex), c.igGetDrawData()); c.cImGui_vk_RenderDrawData( c.cimgui_vk_GetSharedData(@intCast(frameIndex)), vkCast(c.VkCommandBuffer, cmd), vkCast(c.VkPipeline, vk.Pipeline.null_handle), ); c.cimgui_vk_ReleaseSharedData(@intCast(frameIndex)); c.igUpdatePlatformWindows(); z.End(); } // VkRenderer interface end pub fn setup(self: *Self, ctx: *NeonVkContext) !void { self.ctx = ctx; std.debug.print("vkImGui = {d}\n", .{@sizeOf(c.ImGuiStyle)}); std.debug.print("size of InputEvent = {d}\n", .{@sizeOf(c.ImGuiInputEvent)}); // const descriptorPoolSizes = [_]vk.DescriptorPoolSize{ // .{ .type = .sampler, .descriptor_count = 1000 }, // .{ .type = .combined_image_sampler, .descriptor_count = 1000 }, // .{ .type = .sampled_image, .descriptor_count = 1000 }, // .{ .type = .storage_image, .descriptor_count = 1000 }, // .{ .type = .uniform_texel_buffer, .descriptor_count = 1000 }, // .{ .type = .storage_texel_buffer, .descriptor_count = 1000 }, // .{ .type = .uniform_buffer, .descriptor_count = 1000 }, // .{ .type = .storage_buffer, .descriptor_count = 1000 }, // .{ .type = .uniform_buffer_dynamic, .descriptor_count = 1000 }, // .{ .type = .storage_buffer_dynamic, .descriptor_count = 1000 }, // .{ .type = .input_attachment, .descriptor_count = 1000 }, // }; // var poolInfo = vk.DescriptorPoolCreateInfo{ // .flags = .{}, // .max_sets = 1000, // .pool_size_count = @intCast(descriptorPoolSizes.len), // .p_pool_sizes = &descriptorPoolSizes, // }; self.descriptorPool = ctx.descriptorPool; // try ctx.vkd.createDescriptorPool(ctx.dev, &poolInfo, null); _ = c.igCreateContext(null); const io: *c.ImGuiIO = c.igGetIO(); io.*.ConfigFlags |= c.ImGuiConfigFlags_NavEnableKeyboard; io.*.ConfigFlags |= c.ImGuiConfigFlags_DockingEnable; // io.*.ConfigFlags |= c.ImGuiConfigFlags_ViewportsEnable; // const font = c.ImFontAtlas_AddFontFromFileTTF(io.*.Fonts, "content/VT323.ttf", 36, null, null); // _ = font; _ = c.ImGui_ImplGlfw_InitForVulkan(@ptrCast(platform.getInstance().window), true); const style = c.igGetStyle(); c.igStyleColorsDark(style); style.*.WindowRounding = 0.0; style.*.Colors[c.ImGuiCol_WindowBg].w = 1.0; var imguiInit = c.ImGui_ImplVulkan_InitInfo{ .Instance = vkCast(c.VkInstance, ctx.instance), .PhysicalDevice = vkCast(c.VkPhysicalDevice, ctx.physicalDevice), .Device = vkCast(c.VkDevice, ctx.dev), .QueueFamily = ctx.graphicsQueue.family, .Queue = vkCast(c.VkQueue, ctx.graphicsQueue.handle), .PipelineCache = vkCast(c.VkPipelineCache, vk.PipelineCache.null_handle), .DescriptorPool = vkCast(c.VkDescriptorPool, self.descriptorPool), .Subpass = 0, .MinImageCount = 2, .ImageCount = vk_constants.NUM_FRAMES, .MSAASamples = 0x1, .Allocator = null, .CheckVkResultFn = checkVkResult, }; // core.debug_struct("instance: ", ctx.instance); // core.debug_struct("huh: ", imguiInit); _ = c.cImGui_vk_Init(&imguiInit, vkCast(c.VkRenderPass, ctx.renderPass)); // try ctx.start_upload_context(&ctx.uploadContext); try ctx.uploader.startUploadContext(); _ = c.cImGui_vk_CreateFontsTexture(vkCast(c.VkCommandBuffer, ctx.uploader.commandBuffer)); try ctx.uploader.finishUploadContext(); _ = c.cImGui_vk_DestroyFontUploadObjects(); _ = c.SetupImguiColors(); c.cimgui_vk_PrepareSharedData(); try self.ctx.registerRendererPlugin(self); } pub fn onRendererTeardown(self: *Self) void { c.cImGui_vk_Shutdown(); _ = self; } pub fn deinit(self: *Self) void { const ctx = self.ctx; ctx.vkd.deviceWaitIdle(ctx.dev) catch unreachable; // ctx.vkd.destroyDescriptorPool(ctx.dev, self.descriptorPool, null); self.allocator.destroy(self); } }; export fn checkVkResult(result: c_int) void { const r: vk.Result = @enumFromInt(result); if (r == vk.Result.success) return; core.graphics_log("This is a big problem, imgui call result: {any}", .{r}); unreachable; } pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { _ = args; _ = programSpec; _ = allocator; if (core.isUtility()) { return; } const neonVkImgui = try core.createObject(NeonVkImGui, .{}); try neonVkImgui.setup(graphics.getContext()); } pub fn shutdown_module(allocator: std.mem.Allocator) void { _ = allocator; }