window management in its own files
This commit is contained in:
parent
a6fa5b0570
commit
0f4d0d72d9
|
@ -42,6 +42,7 @@ executable(
|
|||
'src/camera/camera.cpp',
|
||||
'src/init/vulkan_instance.cpp',
|
||||
'src/init/debug_messenger.cpp',
|
||||
'src/window/window_manager.cpp',
|
||||
],
|
||||
include_directories: include_directories('include', is_system: true),
|
||||
dependencies: deps,
|
||||
|
|
172
src/main.cpp
172
src/main.cpp
|
@ -28,12 +28,13 @@
|
|||
#include "structs/queue_family_indices.hpp"
|
||||
#include "structs/swap_chain_support_details.hpp"
|
||||
#include "structs/uniform_buffer_object.hpp"
|
||||
#include "util/constants.hpp" // Constants definitions
|
||||
#include "util/crosshair.hpp" // Crosshair definitions
|
||||
#include "util/shaders.hpp" // Compiled shader code
|
||||
#include "util/types.hpp" // Custom type definitions
|
||||
#include "util/unique_image.hpp" // Custom image handling utilities
|
||||
#include "util/vertex.hpp" // Custom vertex structure definition
|
||||
#include "util/constants.hpp" // Constants definitions
|
||||
#include "util/crosshair.hpp" // Crosshair definitions
|
||||
#include "util/shaders.hpp" // Compiled shader code
|
||||
#include "util/types.hpp" // Custom type definitions
|
||||
#include "util/unique_image.hpp" // Custom image handling utilities
|
||||
#include "util/vertex.hpp" // Custom vertex structure definition
|
||||
#include "window/window_manager.hpp" // Window manager
|
||||
|
||||
// ImGui headers for GUI
|
||||
#include <imgui.h>
|
||||
|
@ -213,100 +214,74 @@ class VulkanApp {
|
|||
* The window is created without a default OpenGL context, as we'll be using Vulkan.
|
||||
*/
|
||||
fn initWindow() -> void {
|
||||
// Initialize GLFW
|
||||
mVKFWInstance = vkfw::initUnique();
|
||||
// Initialize GLFW and create window
|
||||
std::tie(mVKFWInstance, mWindow) = WindowManager::create(
|
||||
"Vulkan",
|
||||
{
|
||||
.on_cursor_move = [this](const vkfw::Window& /*window*/, f64 mouseX, f64 mouseY) -> void {
|
||||
if (!mCursorCaptured)
|
||||
return; // Skip camera movement when cursor is not captured
|
||||
|
||||
// Set window creation hints
|
||||
vkfw::WindowHints hints { .clientAPI = vkfw::ClientAPI::eNone }; // No OpenGL context
|
||||
if (mFirstMouse) {
|
||||
mLastX = mouseX;
|
||||
mLastY = mouseY;
|
||||
mFirstMouse = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the primary monitor and its resolution
|
||||
vkfw::Monitor primaryMonitor = vkfw::getPrimaryMonitor();
|
||||
const GLFWvidmode* videoMode = primaryMonitor.getVideoMode();
|
||||
f64 xoffset = mouseX - mLastX;
|
||||
f64 yoffset = mLastY - mouseY; // Reversed since y-coordinates range from bottom to top
|
||||
|
||||
// Calculate window position to center it
|
||||
i32 xpos = (videoMode->width - WIDTH) / 2;
|
||||
i32 ypos = (videoMode->height - HEIGHT) / 2;
|
||||
mLastX = mouseX;
|
||||
mLastY = mouseY;
|
||||
|
||||
// Create the window
|
||||
mWindow = vkfw::createWindowUnique(WIDTH, HEIGHT, "Vulkan", hints);
|
||||
mCamera.rotate(-xoffset, yoffset); // Invert xoffset for correct horizontal movement
|
||||
},
|
||||
.on_key = [this](
|
||||
const vkfw::Window& window,
|
||||
const vkfw::Key& key,
|
||||
const i32& /*scancode*/,
|
||||
const vkfw::KeyAction& action,
|
||||
const vkfw::ModifierKeyFlags& /*mods*/
|
||||
) -> void {
|
||||
if (key == vkfw::Key::eEscape && action == vkfw::KeyAction::ePress) {
|
||||
mCursorCaptured = false;
|
||||
window.set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eNormal);
|
||||
}
|
||||
|
||||
// Set window position
|
||||
mWindow->setPos(xpos, ypos);
|
||||
|
||||
// Set the user pointer to this instance, allowing us to access it in callbacks
|
||||
mWindow->setUserPointer(this);
|
||||
|
||||
// Configure cursor for FPS-style camera control
|
||||
mWindow->set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eDisabled);
|
||||
|
||||
// Set up mouse callback
|
||||
mWindow->callbacks()->on_cursor_move =
|
||||
[this](const vkfw::Window& /*window*/, f64 mouseX, f64 mouseY) -> void {
|
||||
if (!mCursorCaptured)
|
||||
return; // Skip camera movement when cursor is not captured
|
||||
|
||||
if (mFirstMouse) {
|
||||
mLastX = mouseX;
|
||||
mLastY = mouseY;
|
||||
mFirstMouse = false;
|
||||
return;
|
||||
if (key == vkfw::Key::eR && action == vkfw::KeyAction::ePress) {
|
||||
try {
|
||||
mDevice->waitIdle();
|
||||
createGraphicsPipeline();
|
||||
fmt::println("Shaders reloaded successfully!");
|
||||
} catch (const std::exception& e) {
|
||||
fmt::println(stderr, "Failed to reload shaders: {}", e.what());
|
||||
}
|
||||
}
|
||||
},
|
||||
.on_mouse_button = [this](
|
||||
const vkfw::Window& window,
|
||||
const vkfw::MouseButton& button,
|
||||
const vkfw::MouseButtonAction& action,
|
||||
const vkfw::ModifierKeyFlags& /*mods*/
|
||||
) -> void {
|
||||
if (button == vkfw::MouseButton::eLeft && action == vkfw::MouseButtonAction::ePress &&
|
||||
!mCursorCaptured) {
|
||||
// Only capture cursor if click is not on ImGui window
|
||||
if (!ImGui::GetIO().WantCaptureMouse) {
|
||||
mCursorCaptured = true;
|
||||
mFirstMouse = true; // Reset first mouse flag to avoid jumps
|
||||
window.set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eDisabled);
|
||||
}
|
||||
}
|
||||
},
|
||||
.on_window_resize =
|
||||
[this](const vkfw::Window& /*window*/, usize /*width*/, usize /*height*/) -> void {
|
||||
// Set the framebuffer resized flag when the window is resized
|
||||
mFramebufferResized = true;
|
||||
},
|
||||
}
|
||||
|
||||
f64 xoffset = mouseX - mLastX;
|
||||
f64 yoffset = mLastY - mouseY; // Reversed since y-coordinates range from bottom to top
|
||||
|
||||
mLastX = mouseX;
|
||||
mLastY = mouseY;
|
||||
|
||||
mCamera.rotate(-xoffset, yoffset); // Invert xoffset for correct horizontal movement
|
||||
};
|
||||
|
||||
// Set up key callback for escape
|
||||
mWindow->callbacks()->on_key = [this](
|
||||
const vkfw::Window& window,
|
||||
const vkfw::Key& key,
|
||||
const i32& /*scancode*/,
|
||||
const vkfw::KeyAction& action,
|
||||
const vkfw::ModifierKeyFlags& /*mods*/
|
||||
) -> void {
|
||||
if (key == vkfw::Key::eEscape && action == vkfw::KeyAction::ePress) {
|
||||
mCursorCaptured = false;
|
||||
window.set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eNormal);
|
||||
}
|
||||
|
||||
if (key == vkfw::Key::eR && action == vkfw::KeyAction::ePress) {
|
||||
try {
|
||||
mDevice->waitIdle();
|
||||
createGraphicsPipeline();
|
||||
fmt::println("Shaders reloaded successfully!");
|
||||
} catch (const std::exception& e) { fmt::println(stderr, "Failed to reload shaders: {}", e.what()); }
|
||||
}
|
||||
};
|
||||
|
||||
// Set up mouse button callback for re-capture
|
||||
mWindow->callbacks()->on_mouse_button = [this](
|
||||
const vkfw::Window& window,
|
||||
const vkfw::MouseButton& button,
|
||||
const vkfw::MouseButtonAction& action,
|
||||
const vkfw::ModifierKeyFlags& /*mods*/
|
||||
) -> void {
|
||||
if (button == vkfw::MouseButton::eLeft && action == vkfw::MouseButtonAction::ePress &&
|
||||
!mCursorCaptured) {
|
||||
// Only capture cursor if click is not on ImGui window
|
||||
if (!ImGui::GetIO().WantCaptureMouse) {
|
||||
mCursorCaptured = true;
|
||||
mFirstMouse = true; // Reset first mouse flag to avoid jumps
|
||||
window.set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eDisabled);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Set up the window resize callback
|
||||
mWindow->callbacks()->on_window_resize =
|
||||
[this](const vkfw::Window& /*window*/, usize /*width*/, usize /*height*/) -> void {
|
||||
// Set the framebuffer resized flag when the window is resized
|
||||
mFramebufferResized = true;
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -437,7 +412,7 @@ class VulkanApp {
|
|||
f64 lastFpsUpdate = 0.0;
|
||||
i32 frameCounter = 0;
|
||||
|
||||
while (!mWindow->shouldClose()) {
|
||||
while (!WindowManager::shouldClose(mWindow.get())) {
|
||||
f64 currentFrame = vkfw::getTime();
|
||||
deltaTime = currentFrame - lastFrame;
|
||||
lastFrame = currentFrame;
|
||||
|
@ -561,7 +536,8 @@ class VulkanApp {
|
|||
fn updateFrameStats(f64& lastFpsUpdate, i32& frameCounter) -> void {
|
||||
f64 currentFrame = vkfw::getTime();
|
||||
if (currentFrame - lastFpsUpdate > 1.0) {
|
||||
mWindow->setTitle(
|
||||
WindowManager::setTitle(
|
||||
mWindow.get(),
|
||||
fmt::format("Vulkan - {:.0f}FPS", static_cast<f32>(frameCounter / (currentFrame - lastFpsUpdate)))
|
||||
);
|
||||
lastFpsUpdate = currentFrame;
|
||||
|
@ -608,7 +584,7 @@ class VulkanApp {
|
|||
fn recreateSwapChain() -> void {
|
||||
i32 width = 0, height = 0;
|
||||
while (width == 0 || height == 0) {
|
||||
std::tie(width, height) = mWindow->getFramebufferSize();
|
||||
std::tie(width, height) = WindowManager::getFramebufferSize(mWindow.get());
|
||||
vkfw::waitEvents();
|
||||
}
|
||||
|
||||
|
@ -2688,7 +2664,7 @@ class VulkanApp {
|
|||
|
||||
// Get the window's resolution
|
||||
u32 width = 0, height = 0;
|
||||
std::tie(width, height) = mWindow->getFramebufferSize();
|
||||
std::tie(width, height) = WindowManager::getFramebufferSize(mWindow.get());
|
||||
|
||||
// Return the resolution clamped to the supported range
|
||||
return {
|
||||
|
|
78
src/window/window_manager.cpp
Normal file
78
src/window/window_manager.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <vkfw.hpp>
|
||||
|
||||
#include "window_manager.hpp"
|
||||
|
||||
#include "../util/constants.hpp"
|
||||
|
||||
using namespace constants;
|
||||
|
||||
fn WindowManager::create(const char* title, const WindowCallbacks& callbacks)
|
||||
-> std::tuple<vkfw::UniqueInstance, vkfw::UniqueWindow> {
|
||||
// Initialize GLFW
|
||||
vkfw::UniqueInstance instance = vkfw::initUnique();
|
||||
|
||||
// Don't create an OpenGL context
|
||||
vkfw::WindowHints hints;
|
||||
hints.clientAPI = vkfw::ClientAPI::eNone;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Required for macOS
|
||||
hints.cocoaRetinaFramebuffer = true;
|
||||
#endif
|
||||
|
||||
// Create window
|
||||
vkfw::UniqueWindow window = vkfw::createWindowUnique(WIDTH, HEIGHT, title, hints);
|
||||
|
||||
// Get the primary monitor and its resolution
|
||||
vkfw::Monitor primaryMonitor = vkfw::getPrimaryMonitor();
|
||||
const GLFWvidmode* videoMode = primaryMonitor.getVideoMode();
|
||||
|
||||
// Calculate window position to center it
|
||||
i32 xpos = (videoMode->width - WIDTH) / 2;
|
||||
i32 ypos = (videoMode->height - HEIGHT) / 2;
|
||||
|
||||
// Set window position
|
||||
window->setPos(xpos, ypos);
|
||||
|
||||
// Configure cursor for FPS-style camera control
|
||||
window->set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eDisabled);
|
||||
|
||||
// Set up callbacks
|
||||
if (callbacks.on_cursor_move)
|
||||
window->callbacks()->on_cursor_move = callbacks.on_cursor_move;
|
||||
|
||||
if (callbacks.on_key)
|
||||
window->callbacks()->on_key = callbacks.on_key;
|
||||
|
||||
if (callbacks.on_mouse_button)
|
||||
window->callbacks()->on_mouse_button = callbacks.on_mouse_button;
|
||||
|
||||
if (callbacks.on_window_resize)
|
||||
window->callbacks()->on_window_resize = callbacks.on_window_resize;
|
||||
|
||||
return std::make_tuple(std::move(instance), std::move(window));
|
||||
}
|
||||
|
||||
fn WindowManager::getRequiredExtensions() -> std::vector<const char*> {
|
||||
// Get the required extensions from GLFW
|
||||
std::span<const char*> extensionsSpan = vkfw::getRequiredInstanceExtensions();
|
||||
return { extensionsSpan.begin(), extensionsSpan.end() };
|
||||
}
|
||||
|
||||
fn WindowManager::getFramebufferSize(const vkfw::Window& window) -> std::pair<i32, i32> {
|
||||
return window.getFramebufferSize();
|
||||
}
|
||||
|
||||
fn WindowManager::shouldClose(const vkfw::Window& window) -> bool { return window.shouldClose(); }
|
||||
|
||||
fn WindowManager::setTitle(const vkfw::Window& window, const std::string& title) -> void {
|
||||
window.setTitle(title);
|
||||
}
|
||||
|
||||
fn WindowManager::setCursorMode(const vkfw::Window& window, vkfw::CursorMode mode) -> void {
|
||||
window.set<vkfw::InputMode::eCursor>(mode);
|
||||
}
|
||||
|
||||
fn WindowManager::setPosition(const vkfw::Window& window, i32 xpos, i32 ypos) -> void {
|
||||
window.setPos(xpos, ypos);
|
||||
}
|
81
src/window/window_manager.hpp
Normal file
81
src/window/window_manager.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
|
||||
#define VKFW_NO_STRUCT_CONSTRUCTORS // Use aggregate initialization for GLFW structs
|
||||
#include <vkfw.hpp>
|
||||
|
||||
#include "../util/types.hpp"
|
||||
|
||||
struct WindowCallbacks {
|
||||
std::function<void(const vkfw::Window&, f64, f64)> on_cursor_move;
|
||||
std::function<
|
||||
void(const vkfw::Window&, const vkfw::Key&, i32, const vkfw::KeyAction&, const vkfw::ModifierKeyFlags&)>
|
||||
on_key;
|
||||
std::function<
|
||||
void(const vkfw::Window&, const vkfw::MouseButton&, const vkfw::MouseButtonAction&, const vkfw::ModifierKeyFlags&)>
|
||||
on_mouse_button;
|
||||
std::function<void(const vkfw::Window&, usize, usize)> on_window_resize;
|
||||
};
|
||||
|
||||
class WindowManager {
|
||||
public:
|
||||
WindowManager() = default;
|
||||
|
||||
/**
|
||||
* @brief Creates a window with the specified dimensions and title.
|
||||
*
|
||||
* @param title Window title
|
||||
* @param callbacks Window callbacks
|
||||
* @return vkfw::UniqueWindow Unique pointer to the created window
|
||||
*/
|
||||
static fn create(const char* title, const WindowCallbacks& callbacks)
|
||||
-> std::tuple<vkfw::UniqueInstance, vkfw::UniqueWindow>;
|
||||
|
||||
/**
|
||||
* @brief Gets the required instance extensions for window surface creation.
|
||||
*
|
||||
* @return std::vector<const char*> List of required extensions
|
||||
*/
|
||||
static fn getRequiredExtensions() -> std::vector<const char*>;
|
||||
|
||||
/**
|
||||
* @brief Gets the framebuffer size of the window.
|
||||
*
|
||||
* @param window GLFW window
|
||||
* @return std::pair<i32, i32> Width and height of the framebuffer
|
||||
*/
|
||||
static fn getFramebufferSize(const vkfw::Window& window) -> std::pair<i32, i32>;
|
||||
|
||||
/**
|
||||
* @brief Checks if the window should close.
|
||||
*
|
||||
* @param window GLFW window
|
||||
* @return true Window should close
|
||||
* @return false Window should stay open
|
||||
*/
|
||||
static fn shouldClose(const vkfw::Window& window) -> bool;
|
||||
|
||||
/**
|
||||
* @brief Sets the window title.
|
||||
*
|
||||
* @param window GLFW window
|
||||
* @param title New window title
|
||||
*/
|
||||
static fn setTitle(const vkfw::Window& window, const std::string& title) -> void;
|
||||
|
||||
/**
|
||||
* @brief Sets the cursor mode.
|
||||
*
|
||||
* @param window GLFW window
|
||||
* @param mode Cursor mode (Normal or Disabled)
|
||||
*/
|
||||
static fn setCursorMode(const vkfw::Window& window, vkfw::CursorMode mode) -> void;
|
||||
|
||||
/**
|
||||
* @brief Sets the window position.
|
||||
*
|
||||
* @param window GLFW window
|
||||
* @param xpos X position
|
||||
* @param ypos Y position
|
||||
*/
|
||||
static fn setPosition(const vkfw::Window& window, i32 xpos, i32 ypos) -> void;
|
||||
};
|
Loading…
Reference in a new issue