1// Dear ImGui: standalone example application for SDL2 + Vulkan
2
3// Learn about Dear ImGui:
4// - FAQ https://dearimgui.com/faq
5// - Getting Started https://dearimgui.com/getting-started
6// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
7// - Introduction, links and more at the top of imgui.cpp
8
9// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
10// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
11// You will use those if you want to use this rendering backend in your engine/app.
12// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
13// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
14// Read comments in imgui_impl_vulkan.h.
15
16#include "imgui.h"
17#include "imgui_impl_sdl2.h"
18#include "imgui_impl_vulkan.h"
19#include <stdio.h> // printf, fprintf
20#include <stdlib.h> // abort
21#include <SDL.h>
22#include <SDL_vulkan.h>
23
24// Volk headers
25#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
26#define VOLK_IMPLEMENTATION
27#include <volk.h>
28#endif
29
30//#define APP_USE_UNLIMITED_FRAME_RATE
31#ifdef _DEBUG
32#define APP_USE_VULKAN_DEBUG_REPORT
33#endif
34
35// Data
36static VkAllocationCallbacks* g_Allocator = nullptr;
37static VkInstance g_Instance = VK_NULL_HANDLE;
38static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
39static VkDevice g_Device = VK_NULL_HANDLE;
40static uint32_t g_QueueFamily = (uint32_t)-1;
41static VkQueue g_Queue = VK_NULL_HANDLE;
42static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE;
43static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
44static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
45
46static ImGui_ImplVulkanH_Window g_MainWindowData;
47static uint32_t g_MinImageCount = 2;
48static bool g_SwapChainRebuild = false;
49
50static void check_vk_result(VkResult err)
51{
52 if (err == VK_SUCCESS)
53 return;
54 fprintf(stderr, format: "[vulkan] Error: VkResult = %d\n", err);
55 if (err < 0)
56 abort();
57}
58
59#ifdef APP_USE_VULKAN_DEBUG_REPORT
60static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
61{
62 (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
63 fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
64 return VK_FALSE;
65}
66#endif // APP_USE_VULKAN_DEBUG_REPORT
67
68static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properties, const char* extension)
69{
70 for (const VkExtensionProperties& p : properties)
71 if (strcmp(s1: p.extensionName, s2: extension) == 0)
72 return true;
73 return false;
74}
75
76static void SetupVulkan(ImVector<const char*> instance_extensions)
77{
78 VkResult err;
79#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
80 volkInitialize();
81#endif
82
83 // Create Vulkan Instance
84 {
85 VkInstanceCreateInfo create_info = {};
86 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
87
88 // Enumerate available extensions
89 uint32_t properties_count;
90 ImVector<VkExtensionProperties> properties;
91 vkEnumerateInstanceExtensionProperties(pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: nullptr);
92 properties.resize(new_size: properties_count);
93 err = vkEnumerateInstanceExtensionProperties(pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: properties.Data);
94 check_vk_result(err);
95
96 // Enable required extensions
97 if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
98 instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
99#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
100 if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME))
101 {
102 instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
103 create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
104 }
105#endif
106
107 // Enabling validation layers
108#ifdef APP_USE_VULKAN_DEBUG_REPORT
109 const char* layers[] = { "VK_LAYER_KHRONOS_validation" };
110 create_info.enabledLayerCount = 1;
111 create_info.ppEnabledLayerNames = layers;
112 instance_extensions.push_back("VK_EXT_debug_report");
113#endif
114
115 // Create Vulkan Instance
116 create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size;
117 create_info.ppEnabledExtensionNames = instance_extensions.Data;
118 err = vkCreateInstance(pCreateInfo: &create_info, pAllocator: g_Allocator, pInstance: &g_Instance);
119 check_vk_result(err);
120#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
121 volkLoadInstance(g_Instance);
122#endif
123
124 // Setup the debug report callback
125#ifdef APP_USE_VULKAN_DEBUG_REPORT
126 auto f_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT");
127 IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr);
128 VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
129 debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
130 debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
131 debug_report_ci.pfnCallback = debug_report;
132 debug_report_ci.pUserData = nullptr;
133 err = f_vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport);
134 check_vk_result(err);
135#endif
136 }
137
138 // Select Physical Device (GPU)
139 g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(instance: g_Instance);
140 IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE);
141
142 // Select graphics queue family
143 g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(physical_device: g_PhysicalDevice);
144 IM_ASSERT(g_QueueFamily != (uint32_t)-1);
145
146 // Create Logical Device (with 1 queue)
147 {
148 ImVector<const char*> device_extensions;
149 device_extensions.push_back(v: "VK_KHR_swapchain");
150
151 // Enumerate physical device extension
152 uint32_t properties_count;
153 ImVector<VkExtensionProperties> properties;
154 vkEnumerateDeviceExtensionProperties(physicalDevice: g_PhysicalDevice, pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: nullptr);
155 properties.resize(new_size: properties_count);
156 vkEnumerateDeviceExtensionProperties(physicalDevice: g_PhysicalDevice, pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: properties.Data);
157#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
158 if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
159 device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
160#endif
161
162 const float queue_priority[] = { 1.0f };
163 VkDeviceQueueCreateInfo queue_info[1] = {};
164 queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
165 queue_info[0].queueFamilyIndex = g_QueueFamily;
166 queue_info[0].queueCount = 1;
167 queue_info[0].pQueuePriorities = queue_priority;
168 VkDeviceCreateInfo create_info = {};
169 create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
170 create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
171 create_info.pQueueCreateInfos = queue_info;
172 create_info.enabledExtensionCount = (uint32_t)device_extensions.Size;
173 create_info.ppEnabledExtensionNames = device_extensions.Data;
174 err = vkCreateDevice(physicalDevice: g_PhysicalDevice, pCreateInfo: &create_info, pAllocator: g_Allocator, pDevice: &g_Device);
175 check_vk_result(err);
176 vkGetDeviceQueue(device: g_Device, queueFamilyIndex: g_QueueFamily, queueIndex: 0, pQueue: &g_Queue);
177 }
178
179 // Create Descriptor Pool
180 // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets.
181 {
182 VkDescriptorPoolSize pool_sizes[] =
183 {
184 { .type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE },
185 };
186 VkDescriptorPoolCreateInfo pool_info = {};
187 pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
188 pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
189 pool_info.maxSets = 0;
190 for (VkDescriptorPoolSize& pool_size : pool_sizes)
191 pool_info.maxSets += pool_size.descriptorCount;
192 pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
193 pool_info.pPoolSizes = pool_sizes;
194 err = vkCreateDescriptorPool(device: g_Device, pCreateInfo: &pool_info, pAllocator: g_Allocator, pDescriptorPool: &g_DescriptorPool);
195 check_vk_result(err);
196 }
197}
198
199// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
200// Your real engine/app may not use them.
201static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
202{
203 wd->Surface = surface;
204
205 // Check for WSI support
206 VkBool32 res;
207 vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice: g_PhysicalDevice, queueFamilyIndex: g_QueueFamily, surface: wd->Surface, pSupported: &res);
208 if (res != VK_TRUE)
209 {
210 fprintf(stderr, format: "Error no WSI support on physical device 0\n");
211 exit(status: -1);
212 }
213
214 // Select Surface Format
215 const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
216 const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
217 wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device: g_PhysicalDevice, surface: wd->Surface, request_formats: requestSurfaceImageFormat, request_formats_count: (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), request_color_space: requestSurfaceColorSpace);
218
219 // Select Present Mode
220#ifdef APP_USE_UNLIMITED_FRAME_RATE
221 VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
222#else
223 VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
224#endif
225 wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(physical_device: g_PhysicalDevice, surface: wd->Surface, request_modes: &present_modes[0], IM_ARRAYSIZE(present_modes));
226 //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
227
228 // Create SwapChain, RenderPass, Framebuffer, etc.
229 IM_ASSERT(g_MinImageCount >= 2);
230 ImGui_ImplVulkanH_CreateOrResizeWindow(instance: g_Instance, physical_device: g_PhysicalDevice, device: g_Device, wd, queue_family: g_QueueFamily, allocator: g_Allocator, w: width, h: height, min_image_count: g_MinImageCount);
231}
232
233static void CleanupVulkan()
234{
235 vkDestroyDescriptorPool(device: g_Device, descriptorPool: g_DescriptorPool, pAllocator: g_Allocator);
236
237#ifdef APP_USE_VULKAN_DEBUG_REPORT
238 // Remove the debug report callback
239 auto f_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT");
240 f_vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator);
241#endif // APP_USE_VULKAN_DEBUG_REPORT
242
243 vkDestroyDevice(device: g_Device, pAllocator: g_Allocator);
244 vkDestroyInstance(instance: g_Instance, pAllocator: g_Allocator);
245}
246
247static void CleanupVulkanWindow()
248{
249 ImGui_ImplVulkanH_DestroyWindow(instance: g_Instance, device: g_Device, wd: &g_MainWindowData, allocator: g_Allocator);
250}
251
252static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
253{
254 VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
255 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
256 VkResult err = vkAcquireNextImageKHR(device: g_Device, swapchain: wd->Swapchain, UINT64_MAX, semaphore: image_acquired_semaphore, VK_NULL_HANDLE, pImageIndex: &wd->FrameIndex);
257 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
258 g_SwapChainRebuild = true;
259 if (err == VK_ERROR_OUT_OF_DATE_KHR)
260 return;
261 if (err != VK_SUBOPTIMAL_KHR)
262 check_vk_result(err);
263
264 ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
265 {
266 err = vkWaitForFences(device: g_Device, fenceCount: 1, pFences: &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking
267 check_vk_result(err);
268
269 err = vkResetFences(device: g_Device, fenceCount: 1, pFences: &fd->Fence);
270 check_vk_result(err);
271 }
272 {
273 err = vkResetCommandPool(device: g_Device, commandPool: fd->CommandPool, flags: 0);
274 check_vk_result(err);
275 VkCommandBufferBeginInfo info = {};
276 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
277 info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
278 err = vkBeginCommandBuffer(commandBuffer: fd->CommandBuffer, pBeginInfo: &info);
279 check_vk_result(err);
280 }
281 {
282 VkRenderPassBeginInfo info = {};
283 info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
284 info.renderPass = wd->RenderPass;
285 info.framebuffer = fd->Framebuffer;
286 info.renderArea.extent.width = wd->Width;
287 info.renderArea.extent.height = wd->Height;
288 info.clearValueCount = 1;
289 info.pClearValues = &wd->ClearValue;
290 vkCmdBeginRenderPass(commandBuffer: fd->CommandBuffer, pRenderPassBegin: &info, contents: VK_SUBPASS_CONTENTS_INLINE);
291 }
292
293 // Record dear imgui primitives into command buffer
294 ImGui_ImplVulkan_RenderDrawData(draw_data, command_buffer: fd->CommandBuffer);
295
296 // Submit command buffer
297 vkCmdEndRenderPass(commandBuffer: fd->CommandBuffer);
298 {
299 VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
300 VkSubmitInfo info = {};
301 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
302 info.waitSemaphoreCount = 1;
303 info.pWaitSemaphores = &image_acquired_semaphore;
304 info.pWaitDstStageMask = &wait_stage;
305 info.commandBufferCount = 1;
306 info.pCommandBuffers = &fd->CommandBuffer;
307 info.signalSemaphoreCount = 1;
308 info.pSignalSemaphores = &render_complete_semaphore;
309
310 err = vkEndCommandBuffer(commandBuffer: fd->CommandBuffer);
311 check_vk_result(err);
312 err = vkQueueSubmit(queue: g_Queue, submitCount: 1, pSubmits: &info, fence: fd->Fence);
313 check_vk_result(err);
314 }
315}
316
317static void FramePresent(ImGui_ImplVulkanH_Window* wd)
318{
319 if (g_SwapChainRebuild)
320 return;
321 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
322 VkPresentInfoKHR info = {};
323 info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
324 info.waitSemaphoreCount = 1;
325 info.pWaitSemaphores = &render_complete_semaphore;
326 info.swapchainCount = 1;
327 info.pSwapchains = &wd->Swapchain;
328 info.pImageIndices = &wd->FrameIndex;
329 VkResult err = vkQueuePresentKHR(queue: g_Queue, pPresentInfo: &info);
330 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
331 g_SwapChainRebuild = true;
332 if (err == VK_ERROR_OUT_OF_DATE_KHR)
333 return;
334 if (err != VK_SUBOPTIMAL_KHR)
335 check_vk_result(err);
336 wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
337}
338
339// Main code
340int main(int, char**)
341{
342 // Setup SDL
343 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
344 {
345 printf(format: "Error: %s\n", SDL_GetError());
346 return -1;
347 }
348
349 // From 2.0.18: Enable native IME.
350#ifdef SDL_HINT_IME_SHOW_UI
351 SDL_SetHint(SDL_HINT_IME_SHOW_UI, value: "1");
352#endif
353
354 // Create window with Vulkan graphics context
355 SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
356 SDL_Window* window = SDL_CreateWindow(title: "Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w: 1280, h: 720, flags: window_flags);
357 if (window == nullptr)
358 {
359 printf(format: "Error: SDL_CreateWindow(): %s\n", SDL_GetError());
360 return -1;
361 }
362
363 ImVector<const char*> extensions;
364 uint32_t extensions_count = 0;
365 SDL_Vulkan_GetInstanceExtensions(window, pCount: &extensions_count, pNames: nullptr);
366 extensions.resize(new_size: extensions_count);
367 SDL_Vulkan_GetInstanceExtensions(window, pCount: &extensions_count, pNames: extensions.Data);
368 SetupVulkan(extensions);
369
370 // Create Window Surface
371 VkSurfaceKHR surface;
372 VkResult err;
373 if (SDL_Vulkan_CreateSurface(window, instance: g_Instance, surface: &surface) == 0)
374 {
375 printf(format: "Failed to create Vulkan surface.\n");
376 return 1;
377 }
378
379 // Create Framebuffers
380 int w, h;
381 SDL_GetWindowSize(window, w: &w, h: &h);
382 ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
383 SetupVulkanWindow(wd, surface, width: w, height: h);
384
385 // Setup Dear ImGui context
386 IMGUI_CHECKVERSION();
387 ImGui::CreateContext();
388 ImGuiIO& io = ImGui::GetIO(); (void)io;
389 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
390 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
391 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
392 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
393 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
394 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
395
396 // Setup Dear ImGui style
397 ImGui::StyleColorsDark();
398 //ImGui::StyleColorsLight();
399
400 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
401 ImGuiStyle& style = ImGui::GetStyle();
402 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
403 {
404 style.WindowRounding = 0.0f;
405 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
406 }
407
408 // Setup Platform/Renderer backends
409 ImGui_ImplSDL2_InitForVulkan(window);
410 ImGui_ImplVulkan_InitInfo init_info = {};
411 //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version.
412 init_info.Instance = g_Instance;
413 init_info.PhysicalDevice = g_PhysicalDevice;
414 init_info.Device = g_Device;
415 init_info.QueueFamily = g_QueueFamily;
416 init_info.Queue = g_Queue;
417 init_info.PipelineCache = g_PipelineCache;
418 init_info.DescriptorPool = g_DescriptorPool;
419 init_info.RenderPass = wd->RenderPass;
420 init_info.Subpass = 0;
421 init_info.MinImageCount = g_MinImageCount;
422 init_info.ImageCount = wd->ImageCount;
423 init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
424 init_info.Allocator = g_Allocator;
425 init_info.CheckVkResultFn = check_vk_result;
426 ImGui_ImplVulkan_Init(info: &init_info);
427
428 // Load Fonts
429 // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
430 // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
431 // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
432 // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
433 // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
434 // - Read 'docs/FONTS.md' for more instructions and details.
435 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
436 //io.Fonts->AddFontDefault();
437 //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
438 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
439 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
440 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
441 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese());
442 //IM_ASSERT(font != nullptr);
443
444 // Our state
445 bool show_demo_window = true;
446 bool show_another_window = false;
447 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
448
449 // Main loop
450 bool done = false;
451 while (!done)
452 {
453 // Poll and handle events (inputs, window resize, etc.)
454 // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
455 // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
456 // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
457 // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
458 SDL_Event event;
459 while (SDL_PollEvent(event: &event))
460 {
461 ImGui_ImplSDL2_ProcessEvent(event: &event);
462 if (event.type == SDL_QUIT)
463 done = true;
464 if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
465 done = true;
466 }
467 if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
468 {
469 SDL_Delay(ms: 10);
470 continue;
471 }
472
473 // Resize swap chain?
474 int fb_width, fb_height;
475 SDL_GetWindowSize(window, w: &fb_width, h: &fb_height);
476 if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
477 {
478 ImGui_ImplVulkan_SetMinImageCount(min_image_count: g_MinImageCount);
479 ImGui_ImplVulkanH_CreateOrResizeWindow(instance: g_Instance, physical_device: g_PhysicalDevice, device: g_Device, wd: &g_MainWindowData, queue_family: g_QueueFamily, allocator: g_Allocator, w: fb_width, h: fb_height, min_image_count: g_MinImageCount);
480 g_MainWindowData.FrameIndex = 0;
481 g_SwapChainRebuild = false;
482 }
483
484 // Start the Dear ImGui frame
485 ImGui_ImplVulkan_NewFrame();
486 ImGui_ImplSDL2_NewFrame();
487 ImGui::NewFrame();
488
489 // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
490 if (show_demo_window)
491 ImGui::ShowDemoWindow(p_open: &show_demo_window);
492
493 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
494 {
495 static float f = 0.0f;
496 static int counter = 0;
497
498 ImGui::Begin(name: "Hello, world!"); // Create a window called "Hello, world!" and append into it.
499
500 ImGui::Text(fmt: "This is some useful text."); // Display some text (you can use a format strings too)
501 ImGui::Checkbox(label: "Demo Window", v: &show_demo_window); // Edit bools storing our window open/close state
502 ImGui::Checkbox(label: "Another Window", v: &show_another_window);
503
504 ImGui::SliderFloat(label: "float", v: &f, v_min: 0.0f, v_max: 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
505 ImGui::ColorEdit3(label: "clear color", col: (float*)&clear_color); // Edit 3 floats representing a color
506
507 if (ImGui::Button(label: "Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
508 counter++;
509 ImGui::SameLine();
510 ImGui::Text(fmt: "counter = %d", counter);
511
512 ImGui::Text(fmt: "Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
513 ImGui::End();
514 }
515
516 // 3. Show another simple window.
517 if (show_another_window)
518 {
519 ImGui::Begin(name: "Another Window", p_open: &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
520 ImGui::Text(fmt: "Hello from another window!");
521 if (ImGui::Button(label: "Close Me"))
522 show_another_window = false;
523 ImGui::End();
524 }
525
526 // Rendering
527 ImGui::Render();
528 ImDrawData* main_draw_data = ImGui::GetDrawData();
529 const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
530 wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
531 wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
532 wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
533 wd->ClearValue.color.float32[3] = clear_color.w;
534 if (!main_is_minimized)
535 FrameRender(wd, draw_data: main_draw_data);
536
537 // Update and Render additional Platform Windows
538 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
539 {
540 ImGui::UpdatePlatformWindows();
541 ImGui::RenderPlatformWindowsDefault();
542 }
543
544 // Present Main Platform Window
545 if (!main_is_minimized)
546 FramePresent(wd);
547 }
548
549 // Cleanup
550 err = vkDeviceWaitIdle(device: g_Device);
551 check_vk_result(err);
552 ImGui_ImplVulkan_Shutdown();
553 ImGui_ImplSDL2_Shutdown();
554 ImGui::DestroyContext();
555
556 CleanupVulkanWindow();
557 CleanupVulkan();
558
559 SDL_DestroyWindow(window);
560 SDL_Quit();
561
562 return 0;
563}
564

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of imgui/examples/example_sdl2_vulkan/main.cpp