bit of a refactoring

This commit is contained in:
Mars 2024-11-17 18:49:23 -05:00
parent 4c82bbe275
commit cf7b42b95c
4 changed files with 227 additions and 166 deletions

View file

@ -1,3 +1,8 @@
[fmt] [fmt]
src.github = "fmtlib/fmt" src.github = "fmtlib/fmt"
fetch.github = "fmtlib/fmt" fetch.github = "fmtlib/fmt"
[imgui]
src.git = "https://github.com/ocornut/imgui.git"
src.branch = "docking"
fetch.github = "ocornut/imgui"

View file

@ -23,6 +23,7 @@
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
// Include custom utility headers // Include custom utility headers
#include "util/constants.hpp" // Constants definitions
#include "util/crosshair.hpp" // Crosshair definitions #include "util/crosshair.hpp" // Crosshair definitions
#include "util/shaders.hpp" // Compiled shader code #include "util/shaders.hpp" // Compiled shader code
#include "util/types.hpp" // Custom type definitions #include "util/types.hpp" // Custom type definitions
@ -38,34 +39,7 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#define VKFW_NO_STRUCT_CONSTRUCTORS // Use aggregate initialization for GLFW structs #define VKFW_NO_STRUCT_CONSTRUCTORS // Use aggregate initialization for GLFW structs
#include "vkfw.hpp" // Include GLFW C++ bindings #include "vkfw.hpp" // Include GLFW C++ bindings
// Constants for window dimensions using namespace constants;
constexpr i32 WIDTH = 1920;
constexpr i32 HEIGHT = 1080;
// CAMERA_SPEED of camera movement
constexpr f64 CAMERA_SPEED = 1.0;
// Maximum number of frames that can be processed concurrently
constexpr i32 MAX_FRAMES_IN_FLIGHT = 2;
// Shader file paths
constexpr const char* VERTEX_SHADER_PATH = "shaders/vertex.glsl";
constexpr const char* FRAGMENT_SHADER_PATH = "shaders/fragment.glsl";
constexpr const char* CROSSHAIR_VERTEX_SHADER_PATH = "shaders/crosshair_vertex.glsl";
constexpr const char* CROSSHAIR_FRAGMENT_SHADER_PATH = "shaders/crosshair_fragment.glsl";
// Validation layers for debug builds
#ifndef NDEBUG
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
#endif
// Required device extensions (platform-specific)
#ifdef __APPLE__
constexpr std::array<const char*, 2> deviceExtensions = { vk::KHRSwapchainExtensionName,
vk::KHRPortabilitySubsetExtensionName };
#else
constexpr std::array<const char*, 1> deviceExtensions = { vk::KHRSwapchainExtensionName };
#endif
/** /**
* @brief The Vulkan application class. * @brief The Vulkan application class.
@ -207,6 +181,9 @@ class VulkanApp {
f32 mCameraSpeed = CAMERA_SPEED; ///< Current camera speed f32 mCameraSpeed = CAMERA_SPEED; ///< Current camera speed
f32 mFieldOfView = 90.0F; ///< Current field of view f32 mFieldOfView = 90.0F; ///< Current field of view
bool mWireframeMode = false; ///< Wireframe rendering mode bool mWireframeMode = false; ///< Wireframe rendering mode
f32 mLineWidth = 1.0F; ///< Line width for wireframe mode
f32 mMaxLineWidth = 1.0F; ///< Maximum supported line width
bool mWideLineSupport = false; ///< Whether wide lines are supported
/** /**
* @brief Struct to store queue family indices. * @brief Struct to store queue family indices.
@ -551,6 +528,10 @@ class VulkanApp {
// copy and the changes won't be saved. // copy and the changes won't be saved.
ImGuiIO& imGuiIO = ImGui::GetIO(); 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 // Disable writing imgui.ini
imGuiIO.IniFilename = nullptr; imGuiIO.IniFilename = nullptr;
@ -617,55 +598,53 @@ class VulkanApp {
processInput(mWindow.get(), mCamera, static_cast<f32>(deltaTime), mCameraSpeed); processInput(mWindow.get(), mCamera, static_cast<f32>(deltaTime), mCameraSpeed);
mView = mCamera.getViewMatrix(); mView = mCamera.getViewMatrix();
if (currentFrame - lastFpsUpdate > 1.0) { updateFrameStats(lastFpsUpdate, frameCounter);
mWindow->setTitle(
fmt::format("Vulkan - {:.0f}FPS", static_cast<f32>(frameCounter / (currentFrame - lastFpsUpdate)))
);
lastFpsUpdate = currentFrame;
frameCounter = 0;
}
++frameCounter;
vkfw::pollEvents(); vkfw::pollEvents();
// Start the ImGui frame setupImGuiFrame();
ImGui_ImplVulkan_NewFrame(); renderImGuiControls();
ImGui_ImplGlfw_NewFrame(); finalizeImGuiFrame();
ImGui::NewFrame();
// Create ImGui window with controls drawFrame();
ImGui::Begin("Controls"); }
// Camera Position mDevice->waitIdle();
auto pos = mCamera.getPosition(); }
ImGui::Text("Camera Position: (%.2f, %.2f, %.2f)", pos.x, pos.y, pos.z);
fn renderImGuiControls() -> void {
// Camera Settings // Camera Settings
if (ImGui::CollapsingHeader("Camera Settings", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Camera Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::SliderFloat("Camera Speed", &mCameraSpeed, 0.1F, 10.0F, "%.1f"); ImGui::SliderFloat("Camera Speed", &mCameraSpeed, 0.1F, 10.0F, "%.1f");
ImGui::SliderFloat("Field of View", &mFieldOfView, 45.0F, 120.0F, "%.1f"); ImGui::SliderFloat("Field of View", &mFieldOfView, 45.0F, 120.0F, "%.1f");
if (ImGui::Button("Reset Camera")) { if (ImGui::Button("Reset Camera")) {
mCamera = Camera(); // Reset to default position mCamera = Camera();
} }
} }
// Rendering Settings // Rendering Settings
if (ImGui::CollapsingHeader("Rendering Settings", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Rendering Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
// Wireframe Mode
if (ImGui::Checkbox("Wireframe Mode", &mWireframeMode)) { if (ImGui::Checkbox("Wireframe Mode", &mWireframeMode)) {
recreateSwapChain(); recreateSwapChain();
} }
// Line Width (only in wireframe mode)
static float LineWidth = 1.0F;
if (mWireframeMode) { if (mWireframeMode) {
if (ImGui::SliderFloat("Line Width", &LineWidth, 1.0F, 5.0F, "%.1f")) { if (mWideLineSupport) {
// TODO: Update line width in pipeline 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;
} }
} }
} }
// Controls Help renderControlsHelp();
renderPerformanceMetrics();
}
static fn renderControlsHelp() -> void {
if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::BulletText("Use mouse to look around"); ImGui::BulletText("Use mouse to look around");
ImGui::BulletText("WASD to move horizontally"); ImGui::BulletText("WASD to move horizontally");
@ -673,16 +652,26 @@ class VulkanApp {
ImGui::BulletText("ESC to toggle mouse capture"); ImGui::BulletText("ESC to toggle mouse capture");
ImGui::BulletText("Tab to toggle this menu"); ImGui::BulletText("Tab to toggle this menu");
} }
}
// Performance Metrics fn renderPerformanceMetrics() -> void {
if (ImGui::CollapsingHeader("Performance", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::CollapsingHeader("Performance", ImGuiTreeNodeFlags_DefaultOpen)) {
renderFrameMetrics();
renderMemoryUsage();
renderCameraInfo();
renderLightControls();
}
}
static fn renderFrameMetrics() -> void {
ImGui::Text( ImGui::Text(
"Application average %.3f ms/frame (%.1f FPS)", "Application average %.3f ms/frame (%.1f FPS)",
static_cast<f64>(1000.0F / ImGui::GetIO().Framerate), static_cast<f64>(1000.0F / ImGui::GetIO().Framerate),
static_cast<f64>(ImGui::GetIO().Framerate) static_cast<f64>(ImGui::GetIO().Framerate)
); );
}
// Memory Usage fn renderMemoryUsage() -> void {
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Memory Usage:"); ImGui::Text("Memory Usage:");
ImGui::Text( ImGui::Text(
@ -693,8 +682,9 @@ class VulkanApp {
"Index Buffer: %.2f MB", "Index Buffer: %.2f MB",
(static_cast<double>(mIndices.size()) * static_cast<double>(sizeof(uint32_t))) / (1024.0 * 1024.0) (static_cast<double>(mIndices.size()) * static_cast<double>(sizeof(uint32_t))) / (1024.0 * 1024.0)
); );
}
// Camera Information fn renderCameraInfo() -> void {
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Camera Information:"); ImGui::Text("Camera Information:");
ImGui::Text( ImGui::Text(
@ -707,8 +697,9 @@ class VulkanApp {
"Front Vector: (%.2f, %.2f, %.2f)", mCamera.getFront().x, mCamera.getFront().y, mCamera.getFront().z "Front Vector: (%.2f, %.2f, %.2f)", mCamera.getFront().x, mCamera.getFront().y, mCamera.getFront().z
); );
ImGui::Text("Yaw: %.2f°, Pitch: %.2f°", mCamera.getYaw(), mCamera.getPitch()); ImGui::Text("Yaw: %.2f°, Pitch: %.2f°", mCamera.getYaw(), mCamera.getPitch());
}
// Light Controls fn renderLightControls() -> void {
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Light Controls:"); ImGui::Text("Light Controls:");
@ -723,15 +714,33 @@ class VulkanApp {
ImGui::SliderFloat("Specular Strength", &mLightSettings.specular_strength, 0.0F, 1.0F); ImGui::SliderFloat("Specular Strength", &mLightSettings.specular_strength, 0.0F, 1.0F);
} }
ImGui::End(); fn updateFrameStats(f64& lastFpsUpdate, i32& frameCounter) -> void {
f64 currentFrame = vkfw::getTime();
// Render ImGui if (currentFrame - lastFpsUpdate > 1.0) {
ImGui::Render(); mWindow->setTitle(
fmt::format("Vulkan - {:.0f}FPS", static_cast<f32>(frameCounter / (currentFrame - lastFpsUpdate)))
drawFrame(); );
lastFpsUpdate = currentFrame;
frameCounter = 0;
}
++frameCounter;
} }
mDevice->waitIdle(); 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();
}
} }
/** /**
@ -912,6 +921,16 @@ class VulkanApp {
if (isDeviceSuitable(device)) { if (isDeviceSuitable(device)) {
mPhysicalDevice = device; mPhysicalDevice = device;
mMsaaSamples = getMaxUsableSampleCount(); mMsaaSamples = getMaxUsableSampleCount();
// Get the device properties for line width limits
vk::PhysicalDeviceProperties deviceProperties = device.getProperties();
mMaxLineWidth = deviceProperties.limits.lineWidthRange[1];
mWideLineSupport = deviceProperties.limits.lineWidthRange[1] > 1.0F;
#ifndef NDEBUG
fmt::println("Maximum supported line width: {}", mMaxLineWidth);
fmt::println("Wide lines supported: {}", mWideLineSupport ? "yes" : "no");
#endif
break; break;
} }
} }
@ -1249,7 +1268,7 @@ class VulkanApp {
.cullMode = vk::CullModeFlagBits::eBack, .cullMode = vk::CullModeFlagBits::eBack,
.frontFace = vk::FrontFace::eCounterClockwise, .frontFace = vk::FrontFace::eCounterClockwise,
.depthBiasEnable = vk::False, .depthBiasEnable = vk::False,
.lineWidth = mWireframeMode ? 2.0F : 1.0F, // Thicker lines in wireframe mode .lineWidth = mWireframeMode ? mLineWidth : 1.0F, // Thicker lines in wireframe mode
}; };
vk::PipelineMultisampleStateCreateInfo multisampling { vk::PipelineMultisampleStateCreateInfo multisampling {
@ -2045,7 +2064,7 @@ class VulkanApp {
attrib.vertices[static_cast<u32>((3 * index.vertex_index) + 2)], attrib.vertices[static_cast<u32>((3 * index.vertex_index) + 2)],
}, },
.color = { 1.0F, 1.0F, 1.0F }, .color = { 1.0F, 1.0F, 1.0F },
.texCoord = { .tex_coord = {
attrib.texcoords[static_cast<u32>((2 * index.texcoord_index) + 0)], attrib.texcoords[static_cast<u32>((2 * index.texcoord_index) + 0)],
1.0F - attrib.texcoords[static_cast<u32>((2 * index.texcoord_index) + 1)], 1.0F - attrib.texcoords[static_cast<u32>((2 * index.texcoord_index) + 1)],
}, },

37
src/util/constants.hpp Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include <array>
#include <vulkan/vulkan.hpp>
#include "types.hpp"
namespace constants {
// Window dimensions
constexpr i32 WIDTH = 1920;
constexpr i32 HEIGHT = 1080;
// Camera settings
constexpr f64 CAMERA_SPEED = 1.0;
// Frame processing
constexpr i32 MAX_FRAMES_IN_FLIGHT = 2;
// Shader paths
constexpr const char* VERTEX_SHADER_PATH = "shaders/vertex.glsl";
constexpr const char* FRAGMENT_SHADER_PATH = "shaders/fragment.glsl";
constexpr const char* CROSSHAIR_VERTEX_SHADER_PATH = "shaders/crosshair_vertex.glsl";
constexpr const char* CROSSHAIR_FRAGMENT_SHADER_PATH = "shaders/crosshair_fragment.glsl";
// Validation layers
#ifndef NDEBUG
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
#endif
// Device extensions
#ifdef __APPLE__
constexpr std::array<const char*, 2> deviceExtensions = { vk::KHRSwapchainExtensionName,
vk::KHRPortabilitySubsetExtensionName };
#else
constexpr std::array<const char*, 1> deviceExtensions = { vk::KHRSwapchainExtensionName };
#endif
}

View file

@ -27,7 +27,7 @@
struct Vertex { struct Vertex {
glm::vec3 pos; ///< Position of the vertex in 3D space (x, y, z) glm::vec3 pos; ///< Position of the vertex in 3D space (x, y, z)
glm::vec3 color; ///< RGB color values, each component in range [0, 1] glm::vec3 color; ///< RGB color values, each component in range [0, 1]
glm::vec2 texCoord; ///< Texture coordinates (u, v) for texture mapping glm::vec2 tex_coord; ///< Texture coordinates (u, v) for texture mapping
glm::vec3 normal; ///< Normal vector of the vertex glm::vec3 normal; ///< Normal vector of the vertex
/** /**
@ -51,7 +51,8 @@ struct Vertex {
/** /**
* @brief Provides attribute descriptions for vertex data interpretation. * @brief Provides attribute descriptions for vertex data interpretation.
* *
* @return std::array<vk::VertexInputAttributeDescription, 4> Array of descriptions for position, color, texture coordinates, and normal. * @return std::array<vk::VertexInputAttributeDescription, 4> Array of descriptions for position, color,
* texture coordinates, and normal.
* *
* The attribute descriptions specify: * The attribute descriptions specify:
* - Location indices (0 for position, 1 for color, 2 for texture coordinates, 3 for normal) * - Location indices (0 for position, 1 for color, 2 for texture coordinates, 3 for normal)
@ -77,7 +78,7 @@ struct Vertex {
.location = 2, .location = 2,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, texCoord), .offset = offsetof(Vertex, tex_coord),
}, },
vk::VertexInputAttributeDescription { vk::VertexInputAttributeDescription {
.location = 3, .location = 3,
@ -95,7 +96,7 @@ struct Vertex {
* @return bool True if vertices are identical in position, color, texture coordinates, and normal. * @return bool True if vertices are identical in position, color, texture coordinates, and normal.
*/ */
fn operator==(const Vertex& other) const->bool { fn operator==(const Vertex& other) const->bool {
return pos == other.pos && color == other.color && texCoord == other.texCoord && normal == other.normal; return pos == other.pos && color == other.color && tex_coord == other.tex_coord && normal == other.normal;
} }
}; };
@ -117,8 +118,7 @@ namespace std {
*/ */
fn operator()(Vertex const& vertex) const->size_t { fn operator()(Vertex const& vertex) const->size_t {
return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^ return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
(hash<glm::vec2>()(vertex.texCoord) << 1) ^ (hash<glm::vec2>()(vertex.tex_coord) << 1) ^ (hash<glm::vec3>()(vertex.normal) << 2);
(hash<glm::vec3>()(vertex.normal) << 2);
} }
}; };
} }