move imgui stuff

This commit is contained in:
Mars 2024-11-18 20:15:42 -05:00
parent e72e9bd51f
commit 52f3e0cd8f
4 changed files with 304 additions and 196 deletions

View file

@ -41,6 +41,7 @@ executable(
sources: [
'src/main.cpp',
'src/camera/camera.cpp',
'src/gui/imgui_manager.cpp',
'src/init/vulkan_instance.cpp',
'src/init/debug_messenger.cpp',
'src/init/device_manager.cpp',

204
src/gui/imgui_manager.cpp Normal file
View file

@ -0,0 +1,204 @@
#include <fmt/format.h>
#include "imgui_manager.hpp"
ImGuiManager::~ImGuiManager() { cleanup(); }
void ImGuiManager::init(
vk::Instance instance,
vk::PhysicalDevice physicalDevice,
vk::Device device,
uint32_t queueFamily,
vk::Queue queue,
vk::RenderPass renderPass,
uint32_t minImageCount,
uint32_t imageCount,
vk::SampleCountFlagBits msaaSamples,
GLFWwindow* window
) {
mDevice = device;
// Create ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& imGuiIO = ImGui::GetIO();
imGuiIO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
imGuiIO.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
imGuiIO.IniFilename = nullptr; // Disable writing imgui.ini
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// Initialize ImGui for GLFW and Vulkan
ImGui_ImplGlfw_InitForVulkan(window, true);
vk::DescriptorPoolSize descriptorPoolSize {
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
};
vk::DescriptorPoolCreateInfo poolInfo {
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = 1,
.poolSizeCount = 1,
.pPoolSizes = &descriptorPoolSize,
};
mDescriptorPool = device.createDescriptorPoolUnique(poolInfo);
ImGui_ImplVulkan_InitInfo initInfo {
.Instance = instance,
.PhysicalDevice = physicalDevice,
.Device = device,
.QueueFamily = queueFamily,
.Queue = queue,
.DescriptorPool = mDescriptorPool.get(),
.RenderPass = renderPass,
.MinImageCount = minImageCount,
.ImageCount = imageCount,
.MSAASamples = static_cast<VkSampleCountFlagBits>(msaaSamples),
.PipelineCache = VK_NULL_HANDLE,
.Subpass = 0,
.UseDynamicRendering = false,
.PipelineRenderingCreateInfo = {},
.Allocator = nullptr,
.CheckVkResultFn = nullptr,
.MinAllocationSize = 0,
};
ImGui_ImplVulkan_Init(&initInfo);
mInitialized = true;
}
void ImGuiManager::cleanup() {
if (mInitialized) {
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
mInitialized = false;
}
}
void ImGuiManager::newFrame() {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Controls");
}
void ImGuiManager::render() {
ImGui::End();
ImGui::Render();
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
}
void ImGuiManager::renderControls(
float& cameraSpeed,
float& fieldOfView,
bool& wireframeMode,
float& lineWidth,
float maxLineWidth,
bool wideLineSupport,
Camera& camera,
LightInfo& lightSettings,
bool& needsPipelineRecreation
) {
// Camera Settings
if (ImGui::CollapsingHeader("Camera Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::SliderFloat("Camera Speed", &cameraSpeed, 0.1F, 10.0F, "%.1f");
ImGui::SliderFloat("Field of View", &fieldOfView, 45.0F, 120.0F, "%.1f");
if (ImGui::Button("Reset Camera"))
camera = Camera();
}
// Rendering Settings
if (ImGui::CollapsingHeader("Rendering Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::Checkbox("Wireframe Mode", &wireframeMode))
needsPipelineRecreation = true;
if (wireframeMode) {
if (wideLineSupport) {
if (ImGui::SliderFloat("Line Width", &lineWidth, 1.0F, maxLineWidth, "%.1f")) {
needsPipelineRecreation = true;
}
} else {
ImGui::TextColored(ImVec4(1.0F, 0.5F, 0.5F, 1.0F), "Wide lines not supported on this device");
lineWidth = 1.0F;
}
}
}
renderControlsHelp();
renderFrameMetrics();
renderCameraInfo(camera);
renderLightControls(lightSettings);
}
void ImGuiManager::renderControlsHelp() {
if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::BulletText("Use mouse to look around");
ImGui::BulletText("WASD to move horizontally");
ImGui::BulletText("Space/Shift to move up/down");
ImGui::BulletText("ESC to toggle mouse capture");
}
}
void ImGuiManager::renderFrameMetrics() {
if (ImGui::CollapsingHeader("Performance", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Text(
"Application average %.3f ms/frame (%.1f FPS)",
static_cast<double>(1000.0F / ImGui::GetIO().Framerate),
static_cast<double>(ImGui::GetIO().Framerate)
);
}
}
void ImGuiManager::renderMemoryUsage(
size_t vertexSize,
size_t indexSize,
size_t vertexCount,
size_t indexCount
) {
ImGui::Separator();
ImGui::Text("Memory Usage:");
ImGui::Text(
"Vertex Buffer: %.2f MB",
(static_cast<double>(vertexCount) * static_cast<double>(vertexSize)) / (1024.0 * 1024.0)
);
ImGui::Text(
"Index Buffer: %.2f MB",
(static_cast<double>(indexCount) * static_cast<double>(indexSize)) / (1024.0 * 1024.0)
);
}
void ImGuiManager::renderCameraInfo(const Camera& camera) {
ImGui::Separator();
ImGui::Text("Camera Information:");
ImGui::Text(
"Position: (%.2f, %.2f, %.2f)", camera.getPosition().x, camera.getPosition().y, camera.getPosition().z
);
ImGui::Text(
"Front Vector: (%.2f, %.2f, %.2f)", camera.getFront().x, camera.getFront().y, camera.getFront().z
);
ImGui::Text("Yaw: %.2f°, Pitch: %.2f°", camera.getYaw(), camera.getPitch());
}
void ImGuiManager::renderLightControls(LightInfo& lightSettings) {
ImGui::Separator();
ImGui::Text("Light Controls:");
// Light Position
ImGui::DragFloat3("Light Position", &lightSettings.position.x, 0.1F, -10.0F, 10.0F);
// Light Color
ImGui::ColorEdit3("Light Color", &lightSettings.color.x);
// Light Strengths
ImGui::SliderFloat("Ambient Strength", &lightSettings.ambient_strength, 0.0F, 1.0F);
ImGui::SliderFloat("Specular Strength", &lightSettings.specular_strength, 0.0F, 1.0F);
}

61
src/gui/imgui_manager.hpp Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_vulkan.h>
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include "../camera/camera.hpp"
#include "../structs/light_info.hpp"
class ImGuiManager {
public:
ImGuiManager() = default;
ImGuiManager(const ImGuiManager&) = delete;
ImGuiManager(ImGuiManager&&) = delete;
fn operator=(const ImGuiManager&)->ImGuiManager& = delete;
fn operator=(ImGuiManager&&)->ImGuiManager& = delete;
~ImGuiManager();
void init(
vk::Instance instance,
vk::PhysicalDevice physicalDevice,
vk::Device device,
uint32_t queueFamily,
vk::Queue queue,
vk::RenderPass renderPass,
uint32_t minImageCount,
uint32_t imageCount,
vk::SampleCountFlagBits msaaSamples,
GLFWwindow* window
);
fn cleanup() -> void;
static fn newFrame() -> void;
static fn render() -> void;
static fn renderControls(
float& cameraSpeed,
float& fieldOfView,
bool& wireframeMode,
float& lineWidth,
float maxLineWidth,
bool wideLineSupport,
Camera& camera,
LightInfo& lightSettings,
bool& needsPipelineRecreation
) -> void;
static fn renderMemoryUsage(size_t vertexSize, size_t indexSize, size_t vertexCount, size_t indexCount)
-> void;
private:
vk::UniqueDescriptorPool mDescriptorPool;
vk::Device mDevice = nullptr;
bool mInitialized = false;
static fn renderControlsHelp() -> void;
static fn renderFrameMetrics() -> void;
static fn renderCameraInfo(const Camera& camera) -> void;
static fn renderLightControls(LightInfo& lightSettings) -> void;
};

View file

@ -41,9 +41,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#include "window/window_manager.hpp" // Window manager
// ImGui headers for GUI
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_vulkan.h>
#include "gui/imgui_manager.hpp"
using namespace constants;
@ -76,9 +74,7 @@ class VulkanApp {
}
// Shut down ImGui
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
mImGuiManager.cleanup();
}
private:
@ -152,9 +148,8 @@ class VulkanApp {
std::vector<vk::UniqueDeviceMemory> mCameraUniformBuffersMemory; ///< Memory for camera uniform buffers
std::vector<void*> mCameraUniformBuffersMapped; ///< Mapped camera uniform buffers
vk::UniqueDescriptorPool mDescriptorPool; ///< Descriptor pool for the application
vk::UniqueDescriptorPool mImGuiDescriptorPool; ///< Separate descriptor pool for ImGui
std::vector<vk::DescriptorSet> mDescriptorSets; ///< Descriptor sets for binding resources
vk::UniqueDescriptorPool mDescriptorPool; ///< Descriptor pool for the application
std::vector<vk::DescriptorSet> mDescriptorSets; ///< Descriptor sets for binding resources
std::vector<vk::UniqueCommandBuffer> mCommandBuffers; ///< Command buffers for drawing commands
@ -193,6 +188,8 @@ class VulkanApp {
glm::mat4 mView; ///< View matrix
ImGuiManager mImGuiManager; ///< ImGui manager for GUI rendering
static fn processInput(vkfw::Window& window, Camera& camera, const f32& deltaTime, const f32& cameraSpeed)
-> void {
if (window.getKey(vkfw::Key::eW) == vkfw::eTrue)
@ -337,74 +334,20 @@ class VulkanApp {
createCommandBuffers(); // Create command buffers for rendering commands
createCrosshairBuffers(); // Create crosshair buffers
createSyncObjects(); // Create synchronization objects (semaphores and fences)
initImGui(); // Initialize Dear ImGui for GUI rendering
}
/**
* @brief Initializes the ImGui library for use with GLFW and Vulkan.
*
* This function sets up ImGui for rendering with Vulkan and GLFW. It creates the ImGui context,
* sets up the style, initializes ImGui for GLFW and Vulkan, and creates a descriptor pool for ImGui.
*/
fn initImGui() -> void {
// Create ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
// Remember to use a reference here, otherwise
// the ImGui::GetIO() function will return a
// copy and the changes won't be saved.
ImGuiIO& imGuiIO = ImGui::GetIO();
// Enable docking and viewports
imGuiIO.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
imGuiIO.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport
// Disable writing imgui.ini
imGuiIO.IniFilename = nullptr;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// Initialize ImGui for GLFW and Vulkan
ImGui_ImplGlfw_InitForVulkan(mWindow.get(), true);
vk::DescriptorPoolSize descriptorPoolSize = {
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
};
vk::DescriptorPoolCreateInfo poolInfo {
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = 1,
.poolSizeCount = 1,
.pPoolSizes = &descriptorPoolSize,
};
mImGuiDescriptorPool = mDevice->createDescriptorPoolUnique(poolInfo);
ImGui_ImplVulkan_InitInfo initInfo = {
.Instance = mInstance.get(),
.PhysicalDevice = mPhysicalDevice,
.Device = mDevice.get(),
.QueueFamily =
DeviceManager::findQueueFamilies(mPhysicalDevice, mSurface.get()).graphics_family.value(),
.Queue = mGraphicsQueue,
.DescriptorPool = mImGuiDescriptorPool.get(),
.RenderPass = mRenderPass.get(),
.MinImageCount = MAX_FRAMES_IN_FLIGHT,
.ImageCount = static_cast<u32>(mSwapChainImages.size()),
.MSAASamples = static_cast<VkSampleCountFlagBits>(mMsaaSamples),
.PipelineCache = VK_NULL_HANDLE,
.Subpass = 0,
.UseDynamicRendering = false,
.PipelineRenderingCreateInfo = {},
.Allocator = nullptr,
.CheckVkResultFn = nullptr,
.MinAllocationSize = 0,
};
ImGui_ImplVulkan_Init(&initInfo);
// Initialize ImGui
mImGuiManager.init(
mInstance.get(),
mPhysicalDevice,
mDevice.get(),
DeviceManager::findQueueFamilies(mPhysicalDevice, mSurface.get()).graphics_family.value(),
mGraphicsQueue,
mRenderPass.get(),
MAX_FRAMES_IN_FLIGHT,
static_cast<uint32_t>(mSwapChainImages.size()),
mMsaaSamples,
mWindow.get()
);
}
/**
@ -430,9 +373,25 @@ class VulkanApp {
updateFrameStats(lastFpsUpdate, frameCounter);
vkfw::pollEvents();
setupImGuiFrame();
renderImGuiControls();
finalizeImGuiFrame();
mImGuiManager.newFrame();
bool needsPipelineRecreation = false;
mImGuiManager.renderControls(
mCameraSpeed,
mFieldOfView,
mWireframeMode,
mLineWidth,
mMaxLineWidth,
mWideLineSupport,
mCamera,
mLightSettings,
needsPipelineRecreation
);
mImGuiManager.renderMemoryUsage(sizeof(Vertex), sizeof(uint32_t), mVertices.size(), mIndices.size());
if (needsPipelineRecreation) {
mDevice->waitIdle();
createGraphicsPipeline();
}
mImGuiManager.render();
drawFrame();
}
@ -440,106 +399,6 @@ class VulkanApp {
mDevice->waitIdle();
}
fn renderImGuiControls() -> void {
// Camera Settings
if (ImGui::CollapsingHeader("Camera Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::SliderFloat("Camera Speed", &mCameraSpeed, 0.1F, 10.0F, "%.1f");
ImGui::SliderFloat("Field of View", &mFieldOfView, 45.0F, 120.0F, "%.1f");
if (ImGui::Button("Reset Camera"))
mCamera = Camera();
}
// Rendering Settings
if (ImGui::CollapsingHeader("Rendering Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
if (ImGui::Checkbox("Wireframe Mode", &mWireframeMode))
recreateSwapChain();
if (mWireframeMode) {
if (mWideLineSupport) {
if (ImGui::SliderFloat("Line Width", &mLineWidth, 1.0F, mMaxLineWidth, "%.1f")) {
mDevice->waitIdle();
createGraphicsPipeline();
}
} else {
ImGui::TextColored(ImVec4(1.0F, 0.5F, 0.5F, 1.0F), "Wide lines not supported on this device");
mLineWidth = 1.0F;
}
}
}
renderControlsHelp();
renderPerformanceMetrics();
}
static fn renderControlsHelp() -> void {
if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::BulletText("Use mouse to look around");
ImGui::BulletText("WASD to move horizontally");
ImGui::BulletText("Space/Shift to move up/down");
ImGui::BulletText("ESC to toggle mouse capture");
}
}
fn renderPerformanceMetrics() -> void {
if (ImGui::CollapsingHeader("Performance", ImGuiTreeNodeFlags_DefaultOpen)) {
renderFrameMetrics();
renderMemoryUsage();
renderCameraInfo();
renderLightControls();
}
}
static fn renderFrameMetrics() -> void {
ImGui::Text(
"Application average %.3f ms/frame (%.1f FPS)",
static_cast<f64>(1000.0F / ImGui::GetIO().Framerate),
static_cast<f64>(ImGui::GetIO().Framerate)
);
}
fn renderMemoryUsage() -> void {
ImGui::Separator();
ImGui::Text("Memory Usage:");
ImGui::Text(
"Vertex Buffer: %.2f MB",
(static_cast<double>(mVertices.size()) * static_cast<double>(sizeof(Vertex))) / (1024.0 * 1024.0)
);
ImGui::Text(
"Index Buffer: %.2f MB",
(static_cast<double>(mIndices.size()) * static_cast<double>(sizeof(uint32_t))) / (1024.0 * 1024.0)
);
}
fn renderCameraInfo() -> void {
ImGui::Separator();
ImGui::Text("Camera Information:");
ImGui::Text(
"Position: (%.2f, %.2f, %.2f)",
mCamera.getPosition().x,
mCamera.getPosition().y,
mCamera.getPosition().z
);
ImGui::Text(
"Front Vector: (%.2f, %.2f, %.2f)", mCamera.getFront().x, mCamera.getFront().y, mCamera.getFront().z
);
ImGui::Text("Yaw: %.2f°, Pitch: %.2f°", mCamera.getYaw(), mCamera.getPitch());
}
fn renderLightControls() -> void {
ImGui::Separator();
ImGui::Text("Light Controls:");
// Light Position
ImGui::DragFloat3("Light Position", &mLightSettings.position.x, 0.1F, -10.0F, 10.0F);
// Light Color
ImGui::ColorEdit3("Light Color", &mLightSettings.color.x);
// Light Strengths
ImGui::SliderFloat("Ambient Strength", &mLightSettings.ambient_strength, 0.0F, 1.0F);
ImGui::SliderFloat("Specular Strength", &mLightSettings.specular_strength, 0.0F, 1.0F);
}
fn updateFrameStats(f64& lastFpsUpdate, i32& frameCounter) -> void {
f64 currentFrame = vkfw::getTime();
if (currentFrame - lastFpsUpdate > 1.0) {
@ -553,23 +412,6 @@ class VulkanApp {
++frameCounter;
}
static fn setupImGuiFrame() -> void {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Controls");
}
static fn finalizeImGuiFrame() -> void {
ImGui::End();
ImGui::Render();
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
}
/**
* @brief Cleans up the swap chain resources.
*