VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
VulkanImGUIWrapper.cpp
2
3#if DEBUG
4#include <backends/imgui_impl_sdl3.h>
5#include <backends/imgui_impl_vulkan.h>
6#include <filesystem>
7#include <ImGuizmo.h>
8#endif
9
10namespace vex {
11
12 VulkanImGUIWrapper::VulkanImGUIWrapper(SDL_Window* window, VulkanContext& vulkanContext)
13 : m_p_window(window), m_r_context(vulkanContext) {}
14
16#if DEBUG
17 if (m_initialized) {
18 vkDeviceWaitIdle(m_r_context.device);
19
20 ImGui_ImplVulkan_Shutdown();
21
22 if (m_imguiPool != VK_NULL_HANDLE) {
23 vkDestroyDescriptorPool(m_r_context.device, m_imguiPool, nullptr);
24 m_imguiPool = VK_NULL_HANDLE;
25 }
26
27 ImGui_ImplSDL3_Shutdown();
28 ImGui::DestroyContext();
29 }
30#endif
31 }
32
33 VkDescriptorSet VulkanImGUIWrapper::addTexture(VkSampler sampler, VkImageView imageView, VkImageLayout layout) {
34 #if DEBUG
35 return ImGui_ImplVulkan_AddTexture(sampler, imageView, layout);
36 #else
37 return VK_NULL_HANDLE;
38 #endif
39 }
40
41 void VulkanImGUIWrapper::removeTexture(VkDescriptorSet descriptorSet) {
42 #if DEBUG
43 if (descriptorSet != VK_NULL_HANDLE) {
44 ImGui_ImplVulkan_RemoveTexture(descriptorSet);
45 //vkFreeDescriptorSets(m_r_context.device, m_imguiPool, 1, &descriptorSet);
46 }
47 #endif
48 }
49
50#if DEBUG
52 try {
53 log("Initialization of DearImGUI");
54
55 volatile auto forceLink = ImGuizmo::BeginFrame;
56
57 IMGUI_CHECKVERSION();
58 try {
59 ImGui::CreateContext();
60 } catch (const std::exception& e) {
61 log(LogLevel::ERROR, "ImGUI Init Failed");
63 }
64 ImGuiIO& io = ImGui::GetIO();
65
66 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
67 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
68 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
69
70 if(std::filesystem::exists("../Assets/Sono-SemiBold.ttf")){
71 ImFont* myFont = io.Fonts->AddFontFromFileTTF("../Assets/Sono-SemiBold.ttf", 14.0f);
72
73 if (myFont == nullptr) {
74 log(LogLevel::WARNING, "Failed to load editor font!");
75 io.Fonts->AddFontDefault();
76 }
77 }else{
78 log(LogLevel::WARNING, "Failed to load editor font!");
79 io.Fonts->AddFontDefault();
80 }
81
82 if (!vkCreateSampler || !vkCreateDescriptorPool) {
83 throw_error("Critical Vulkan function pointers are null!");
84 }
85
86 ImGui_ImplSDL3_InitForVulkan(m_p_window);
87
88 createDescriptorPool();
89
90 ImGui_ImplVulkan_InitInfo initInfo = {};
91 initInfo.Instance = m_r_context.instance;
92 initInfo.PhysicalDevice = m_r_context.physicalDevice;
93 initInfo.Device = m_r_context.device;
94 initInfo.QueueFamily = m_r_context.graphicsQueueFamily;
95 initInfo.Queue = m_r_context.graphicsQueue;
96 initInfo.PipelineCache = VK_NULL_HANDLE;
97 initInfo.MinImageCount = m_r_context.swapchainImages.size();
98 initInfo.ImageCount = m_r_context.swapchainImages.size();
99 initInfo.CheckVkResultFn = [](VkResult err) {
100 if (err != VK_SUCCESS) {
101 SDL_LogError(SDL_LOG_CATEGORY_ERROR, "ImGui Vulkan error: %d", err);
102 }
103 };
104 initInfo.Allocator = nullptr;
105 initInfo.DescriptorPool = m_imguiPool;
106 initInfo.UseDynamicRendering = true;
107
108 // Setup for dynamic rendering
109 VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo = {};
110 pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
111 pipelineRenderingCreateInfo.colorAttachmentCount = 1;
112 pipelineRenderingCreateInfo.pColorAttachmentFormats = &m_r_context.swapchainImageFormat;
113 pipelineRenderingCreateInfo.depthAttachmentFormat = m_r_context.depthFormat;
114
115 ImGui_ImplVulkan_PipelineInfo pipelineInfoMain = {};
116 pipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
117 pipelineInfoMain.PipelineRenderingCreateInfo = pipelineRenderingCreateInfo;
118
119 initInfo.PipelineInfoMain = pipelineInfoMain;
120
121 log("Initing ImGui Vulkan backend");
122 if (!ImGui_ImplVulkan_Init(&initInfo)) {
123 throw_error("Failed to initialize ImGui Vulkan backend");
124 }
125
126 setupStyle();
127
128 m_initialized = true;
129 } catch (const std::exception& e) {
130 log(LogLevel::ERROR, "ImGUI Init Failed");
132 }
133 }
134
136 ImGui_ImplVulkan_NewFrame();
137 ImGui_ImplSDL3_NewFrame();
138 ImGui::NewFrame();
139
140 ImGuiIO& io = ImGui::GetIO();
141 io.DisplaySize = ImVec2(
142 (float)m_r_context.currentRenderResolution.x,
143 (float)m_r_context.currentRenderResolution.y
144 );
145 io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
146 }
147
149 ImGui::Render();
150
151 ImGuiIO& io = ImGui::GetIO();
152 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
153 ImGui::UpdatePlatformWindows();
154 ImGui::RenderPlatformWindowsDefault();
155 }
156 }
157
158 void VulkanImGUIWrapper::draw(VkCommandBuffer commandBuffer) {
159 ImDrawData* drawData = ImGui::GetDrawData();
160 if (drawData) {
161 ImGui_ImplVulkan_RenderDrawData(drawData, commandBuffer);
162 }
163 }
164
165 void VulkanImGUIWrapper::processEvent(const SDL_Event* event) {
166 ImGuiIO& io = ImGui::GetIO();
167
168 // Calculate scale factors (window-to-render)
169 float scaleX = (float)m_r_context.swapchainExtent.width /
170 (float)m_r_context.currentRenderResolution.x;
171 float scaleY = (float)m_r_context.swapchainExtent.height /
172 (float)m_r_context.currentRenderResolution.y;
173
174 switch (event->type) {
175 case SDL_EVENT_MOUSE_MOTION: {
176 io.MousePos = ImVec2(
177 event->motion.x / scaleX,
178 event->motion.y / scaleY
179 );
180 break;
181 }
182 case SDL_EVENT_MOUSE_BUTTON_DOWN:
183 case SDL_EVENT_MOUSE_BUTTON_UP: {
184 io.MousePos = ImVec2(
185 event->button.x / scaleX,
186 event->button.y / scaleY
187 );
188 ImGui_ImplSDL3_ProcessEvent(event);
189 break;
190 }
191 default: {
192 ImGui_ImplSDL3_ProcessEvent(event);
193 break;
194 }
195 }
196 }
197
198 ImGuiIO& VulkanImGUIWrapper::getIO() {
199 return ImGui::GetIO();
200 }
201
202 void VulkanImGUIWrapper::createDescriptorPool() {
203 log("Creating ImGUI DescriptorPools");
204
205 VkDescriptorPoolSize poolSizes[] = {
206 { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
207 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
208 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
209 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
210 { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
211 { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
212 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
213 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
214 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
215 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
216 { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
217 };
218
219 VkDescriptorPoolCreateInfo poolInfo = {};
220 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
221 poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
222 poolInfo.maxSets = 1000 * IM_ARRAYSIZE(poolSizes);
223 poolInfo.poolSizeCount = (uint32_t)IM_ARRAYSIZE(poolSizes);
224 poolInfo.pPoolSizes = poolSizes;
225
226 if (vkCreateDescriptorPool(m_r_context.device, &poolInfo, nullptr, &m_imguiPool) != VK_SUCCESS) {
227 throw_error("Failed to create descriptor pool for ImGui");
228 }
229 }
230
231 void VulkanImGUIWrapper::setupStyle() {
232 ImGui::StyleColorsDark();
233
234 ImGuiStyle& style = ImGui::GetStyle();
235
236 style.WindowPadding = ImVec2(10, 10);
237 style.FramePadding = ImVec2(5, 5);
238 style.ItemSpacing = ImVec2(6, 6);
239 style.ItemInnerSpacing = ImVec2(4, 4);
240 style.IndentSpacing = 4.0f;
241 style.ScrollbarSize = 12.0f;
242 style.GrabMinSize = 4.0f;
243
244 style.WindowRounding = 6.0f;
245 style.ChildRounding = 6.0f;
246 style.FrameRounding = 4.0f;
247 style.PopupRounding = 6.0f;
248 style.ScrollbarRounding = 9.0f;
249 style.GrabRounding = 4.0f;
250 style.TabRounding = 6.0f;
251
252 ImVec4* colors = style.Colors;
253
254 // Used ai (Gemini Pro) to generate these colors from palette I found online
255 const ImVec4 colTextWhite = ImVec4(0.94f, 0.85f, 0.85f, 1.00f);
256 const ImVec4 colOrangeBase = ImVec4(1.00f, 0.23f, 0.01f, 1.00f);
257 const ImVec4 colRedBase = ImVec4(0.47f, 0.05f, 0.05f, 1.00f);
258 const ImVec4 colBgBase = ImVec4(0.015f, 0.015f, 0.019f, 1.00f);
259 const ImVec4 colBgDark = ImVec4(0.012f, 0.012f, 0.014f, 1.00f);
260 const ImVec4 colBgLight = ImVec4(0.02f, 0.02f, 0.024f, 1.00f);
261
262 // Text
263 colors[ImGuiCol_Text] = colTextWhite;
264 colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
265
266 // Windows & Backgrounds
267 colors[ImGuiCol_WindowBg] = colBgBase;
268 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
269 colors[ImGuiCol_PopupBg] = colBgLight;
270 colors[ImGuiCol_MenuBarBg] = colBgDark;
271
272 // Borders - Subtle Red
273 colors[ImGuiCol_Border] = ImVec4(0.47f, 0.05f, 0.05f, 0.40f);
274 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
275
276 // Inputs
277 colors[ImGuiCol_FrameBg] = colBgDark;
278 colors[ImGuiCol_FrameBgHovered] = colBgBase;
279 colors[ImGuiCol_FrameBgActive] = ImVec4(0.47f, 0.05f, 0.05f, 0.50f);
280
281 // Title Bars
282 colors[ImGuiCol_TitleBg] = colBgDark;
283 colors[ImGuiCol_TitleBgActive] = colBgBase;
284 colors[ImGuiCol_TitleBgCollapsed] = colBgDark;
285
286 // Scrollbars
287 colors[ImGuiCol_ScrollbarBg] = colBgDark;
288 colors[ImGuiCol_ScrollbarGrab] = ImVec4(1.00f, 0.23f, 0.01f, 0.40f);
289 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.00f, 0.23f, 0.01f, 0.70f);
290 colors[ImGuiCol_ScrollbarGrabActive] = colOrangeBase;
291
292 // Interactive Elements
293 colors[ImGuiCol_CheckMark] = colOrangeBase;
294 colors[ImGuiCol_SliderGrab] = colOrangeBase;
295 colors[ImGuiCol_SliderGrabActive] = colOrangeBase;
296
297 // Buttons
298 colors[ImGuiCol_Button] = colBgLight;
299 colors[ImGuiCol_ButtonHovered] = ImVec4(1.00f, 0.23f, 0.01f, 0.20f);
300 colors[ImGuiCol_ButtonActive] = ImVec4(1.00f, 0.23f, 0.01f, 0.40f);
301
302 // Headers
303 colors[ImGuiCol_Header] = colBgLight;
304 colors[ImGuiCol_HeaderHovered] = ImVec4(1.00f, 0.23f, 0.01f, 0.30f);
305 colors[ImGuiCol_HeaderActive] = ImVec4(1.00f, 0.23f, 0.01f, 0.50f);
306
307 // Separators
308 colors[ImGuiCol_Separator] = ImVec4(0.47f, 0.05f, 0.05f, 0.40f);
309 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.47f, 0.05f, 0.05f, 0.70f);
310 colors[ImGuiCol_SeparatorActive] = colRedBase;
311
312 // Resize
313 colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 0.23f, 0.01f, 0.25f);
314 colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 0.23f, 0.01f, 0.67f);
315 colors[ImGuiCol_ResizeGripActive] = colOrangeBase;
316
317 // Tabs
318 colors[ImGuiCol_Tab] = colBgDark;
319 colors[ImGuiCol_TabHovered] = ImVec4(1.00f, 0.23f, 0.01f, 0.40f);
320 colors[ImGuiCol_TabActive] = colBgBase;
321 colors[ImGuiCol_TabUnfocused] = colBgDark;
322 colors[ImGuiCol_TabUnfocusedActive] = colBgBase;
323
324 // Docking
325 colors[ImGuiCol_DockingPreview] = ImVec4(1.00f, 0.23f, 0.01f, 0.30f);
326 colors[ImGuiCol_DockingEmptyBg] = colBgBase;
327
328 // Misc
329 colors[ImGuiCol_PlotLines] = colTextWhite;
330 colors[ImGuiCol_PlotLinesHovered] = colOrangeBase;
331 colors[ImGuiCol_PlotHistogram] = colOrangeBase;
332 colors[ImGuiCol_PlotHistogramHovered] = colOrangeBase;
333 colors[ImGuiCol_TextSelectedBg] = ImVec4(1.00f, 0.23f, 0.01f, 0.35f);
334 colors[ImGuiCol_DragDropTarget] = colOrangeBase;
335 colors[ImGuiCol_NavHighlight] = colOrangeBase;
336
337 colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.5f);
338 }
339#endif
340}
This file defines class with Imgui for vulkan backend definition.
virtual ~VulkanImGUIWrapper()
Destructor for VulkanImGUIWrapper.
void init() override
Initialization called inside Engine class.
VulkanImGUIWrapper(SDL_Window *window, VulkanContext &vulkanContext)
Constructor for VulkanImGUIWrapper.
void processEvent(const SDL_Event *event) override
Its used to process input needed by interaction with ImGui.
void beginFrame() override
Begining of UI rendering called in vex::Renderer::renderFrame.
void removeTexture(VkDescriptorSet descriptorSet)
Removes a texture from the ImGUI wrapper.
void endFrame() override
Ends UI rendering for frame.
VkDescriptorSet addTexture(VkSampler sampler, VkImageView imageView, VkImageLayout layout)
Adds a texture to the ImGUI wrapper.
void VEX_EXPORT throw_error(const std::string &msg)
Throws an error or terminates the application.
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
void VEX_EXPORT handle_critical_exception(const std::exception &e)
Handles a critical exception, forcing termination.
Struct holding all vulkan data, like device, surface, swapchain, images, views, and more.
Definition context.hpp:26