ADD: Window mode system
This commit is contained in:
@@ -188,6 +188,23 @@ void VulkanEngine::init()
|
|||||||
window_flags
|
window_flags
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_windowMode = WindowMode::Windowed;
|
||||||
|
_windowDisplayIndex = SDL_GetWindowDisplayIndex(_window);
|
||||||
|
if (_windowDisplayIndex < 0) _windowDisplayIndex = 0;
|
||||||
|
{
|
||||||
|
int wx = 0, wy = 0, ww = 0, wh = 0;
|
||||||
|
SDL_GetWindowPosition(_window, &wx, &wy);
|
||||||
|
SDL_GetWindowSize(_window, &ww, &wh);
|
||||||
|
if (ww > 0 && wh > 0)
|
||||||
|
{
|
||||||
|
_windowedRect.x = wx;
|
||||||
|
_windowedRect.y = wy;
|
||||||
|
_windowedRect.w = ww;
|
||||||
|
_windowedRect.h = wh;
|
||||||
|
_windowedRect.valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_deviceManager = std::make_shared<DeviceManager>();
|
_deviceManager = std::make_shared<DeviceManager>();
|
||||||
_deviceManager->init_vulkan(_window);
|
_deviceManager->init_vulkan(_window);
|
||||||
|
|
||||||
@@ -332,6 +349,125 @@ void VulkanEngine::init()
|
|||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanEngine::set_window_mode(WindowMode mode, int display_index)
|
||||||
|
{
|
||||||
|
if (!_window) return;
|
||||||
|
|
||||||
|
const int num_displays = SDL_GetNumVideoDisplays();
|
||||||
|
int current_display = SDL_GetWindowDisplayIndex(_window);
|
||||||
|
if (current_display < 0) current_display = 0;
|
||||||
|
|
||||||
|
if (num_displays <= 0)
|
||||||
|
{
|
||||||
|
display_index = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (display_index < 0) display_index = current_display;
|
||||||
|
display_index = std::clamp(display_index, 0, num_displays - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const WindowMode prev_mode = _windowMode;
|
||||||
|
const bool entering_fullscreen = (prev_mode == WindowMode::Windowed) && (mode != WindowMode::Windowed);
|
||||||
|
|
||||||
|
if (entering_fullscreen)
|
||||||
|
{
|
||||||
|
int wx = 0, wy = 0, ww = 0, wh = 0;
|
||||||
|
SDL_GetWindowPosition(_window, &wx, &wy);
|
||||||
|
SDL_GetWindowSize(_window, &ww, &wh);
|
||||||
|
if (ww > 0 && wh > 0)
|
||||||
|
{
|
||||||
|
_windowedRect.x = wx;
|
||||||
|
_windowedRect.y = wy;
|
||||||
|
_windowedRect.w = ww;
|
||||||
|
_windowedRect.h = wh;
|
||||||
|
_windowedRect.valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are currently in any fullscreen mode, leave fullscreen first so we can safely
|
||||||
|
// move the window to the target display before re-entering fullscreen.
|
||||||
|
if (prev_mode != WindowMode::Windowed)
|
||||||
|
{
|
||||||
|
if (SDL_SetWindowFullscreen(_window, 0) != 0)
|
||||||
|
{
|
||||||
|
fmt::println("[Window] SDL_SetWindowFullscreen(0) failed: {}", SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the window to the selected display (applies to both windowed and fullscreen).
|
||||||
|
SDL_SetWindowPosition(_window,
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(display_index),
|
||||||
|
SDL_WINDOWPOS_CENTERED_DISPLAY(display_index));
|
||||||
|
|
||||||
|
if (mode == WindowMode::Windowed)
|
||||||
|
{
|
||||||
|
SDL_SetWindowBordered(_window, SDL_TRUE);
|
||||||
|
SDL_SetWindowResizable(_window, SDL_TRUE);
|
||||||
|
|
||||||
|
int target_w = 0, target_h = 0;
|
||||||
|
if (_windowedRect.valid)
|
||||||
|
{
|
||||||
|
target_w = _windowedRect.w;
|
||||||
|
target_h = _windowedRect.h;
|
||||||
|
}
|
||||||
|
if (target_w <= 0 || target_h <= 0)
|
||||||
|
{
|
||||||
|
SDL_GetWindowSize(_window, &target_w, &target_h);
|
||||||
|
}
|
||||||
|
if (target_w > 0 && target_h > 0)
|
||||||
|
{
|
||||||
|
SDL_SetWindowSize(_window, target_w, target_h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SDL_SetWindowBordered(_window, SDL_FALSE);
|
||||||
|
|
||||||
|
const Uint32 fullscreen_flag =
|
||||||
|
(mode == WindowMode::FullscreenDesktop) ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
|
||||||
|
|
||||||
|
if (mode == WindowMode::FullscreenExclusive)
|
||||||
|
{
|
||||||
|
SDL_DisplayMode desktop{};
|
||||||
|
if (SDL_GetDesktopDisplayMode(display_index, &desktop) == 0)
|
||||||
|
{
|
||||||
|
// Request desktop mode by default. Future UI can add explicit mode selection.
|
||||||
|
SDL_SetWindowDisplayMode(_window, &desktop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_SetWindowFullscreen(_window, fullscreen_flag) != 0)
|
||||||
|
{
|
||||||
|
fmt::println("[Window] SDL_SetWindowFullscreen({}) failed: {}",
|
||||||
|
static_cast<unsigned>(fullscreen_flag),
|
||||||
|
SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_windowMode = mode;
|
||||||
|
_windowDisplayIndex = SDL_GetWindowDisplayIndex(_window);
|
||||||
|
if (_windowDisplayIndex < 0) _windowDisplayIndex = display_index;
|
||||||
|
|
||||||
|
// Make sure SDL has processed the fullscreen/move requests before we query drawable size for swapchain recreation.
|
||||||
|
SDL_PumpEvents();
|
||||||
|
|
||||||
|
// Recreate swapchain immediately so the very next draw uses correct extent.
|
||||||
|
if (_swapchainManager)
|
||||||
|
{
|
||||||
|
_swapchainManager->resize_swapchain(_window);
|
||||||
|
if (_swapchainManager->resize_requested)
|
||||||
|
{
|
||||||
|
resize_requested = true;
|
||||||
|
_last_resize_event_ms = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resize_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanEngine::set_logical_render_extent(VkExtent2D extent)
|
void VulkanEngine::set_logical_render_extent(VkExtent2D extent)
|
||||||
{
|
{
|
||||||
extent = clamp_nonzero_extent(extent);
|
extent = clamp_nonzero_extent(extent);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <cstdint>
|
||||||
#include "vk_mem_alloc.h"
|
#include "vk_mem_alloc.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -62,6 +63,13 @@ struct MeshNode : public Node
|
|||||||
class VulkanEngine
|
class VulkanEngine
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class WindowMode : uint8_t
|
||||||
|
{
|
||||||
|
Windowed = 0,
|
||||||
|
FullscreenDesktop = 1, // borderless fullscreen ("fullscreen windowed")
|
||||||
|
FullscreenExclusive = 2 // exclusive fullscreen (may change display mode)
|
||||||
|
};
|
||||||
|
|
||||||
bool _isInitialized{false};
|
bool _isInitialized{false};
|
||||||
int _frameNumber{0};
|
int _frameNumber{0};
|
||||||
|
|
||||||
@@ -80,6 +88,9 @@ public:
|
|||||||
|
|
||||||
struct SDL_Window *_window{nullptr};
|
struct SDL_Window *_window{nullptr};
|
||||||
|
|
||||||
|
WindowMode _windowMode{WindowMode::Windowed};
|
||||||
|
int _windowDisplayIndex{0};
|
||||||
|
|
||||||
FrameResources _frames[FRAME_OVERLAP];
|
FrameResources _frames[FRAME_OVERLAP];
|
||||||
|
|
||||||
FrameResources &get_current_frame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
|
FrameResources &get_current_frame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
|
||||||
@@ -204,6 +215,9 @@ public:
|
|||||||
//run main loop
|
//run main loop
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
// Window controls (runtime)
|
||||||
|
void set_window_mode(WindowMode mode, int display_index);
|
||||||
|
|
||||||
// Rendering resolution controls:
|
// Rendering resolution controls:
|
||||||
// - logicalRenderExtent controls camera aspect and picking (letterboxed view).
|
// - logicalRenderExtent controls camera aspect and picking (letterboxed view).
|
||||||
// - renderScale controls the internal render target pixel count (logical * scale).
|
// - renderScale controls the internal render target pixel count (logical * scale).
|
||||||
@@ -258,6 +272,15 @@ public:
|
|||||||
bool freeze_rendering{false};
|
bool freeze_rendering{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct WindowedRect
|
||||||
|
{
|
||||||
|
int x{0};
|
||||||
|
int y{0};
|
||||||
|
int w{0};
|
||||||
|
int h{0};
|
||||||
|
bool valid{false};
|
||||||
|
} _windowedRect;
|
||||||
|
|
||||||
void init_frame_resources();
|
void init_frame_resources();
|
||||||
|
|
||||||
void init_pipelines();
|
void init_pipelines();
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
|
#include "SDL2/SDL.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "ImGuizmo.h"
|
#include "ImGuizmo.h"
|
||||||
|
|
||||||
@@ -23,12 +25,93 @@
|
|||||||
#include "device/images.h"
|
#include "device/images.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include <core/types.h>
|
#include <core/types.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "mesh_bvh.h"
|
#include "mesh_bvh.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
static void ui_window(VulkanEngine *eng)
|
||||||
|
{
|
||||||
|
if (!eng || !eng->_window) return;
|
||||||
|
|
||||||
|
int num_displays = SDL_GetNumVideoDisplays();
|
||||||
|
if (num_displays <= 0)
|
||||||
|
{
|
||||||
|
ImGui::Text("No displays reported by SDL (%s)", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int current_display = SDL_GetWindowDisplayIndex(eng->_window);
|
||||||
|
if (current_display < 0) current_display = eng->_windowDisplayIndex;
|
||||||
|
current_display = std::clamp(current_display, 0, num_displays - 1);
|
||||||
|
|
||||||
|
const char *cur_display_name = SDL_GetDisplayName(current_display);
|
||||||
|
if (!cur_display_name) cur_display_name = "Unknown";
|
||||||
|
|
||||||
|
ImGui::Text("Current: %s on display %d (%s)",
|
||||||
|
(eng->_windowMode == VulkanEngine::WindowMode::Windowed)
|
||||||
|
? "Windowed"
|
||||||
|
: (eng->_windowMode == VulkanEngine::WindowMode::FullscreenDesktop)
|
||||||
|
? "Borderless Fullscreen"
|
||||||
|
: "Exclusive Fullscreen",
|
||||||
|
current_display,
|
||||||
|
cur_display_name);
|
||||||
|
|
||||||
|
static int pending_display = -1;
|
||||||
|
static int pending_mode = -1; // 0 windowed, 1 borderless, 2 exclusive
|
||||||
|
if (pending_display < 0) pending_display = current_display;
|
||||||
|
if (pending_mode < 0) pending_mode = static_cast<int>(eng->_windowMode);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::BeginCombo("Monitor", cur_display_name))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num_displays; ++i)
|
||||||
|
{
|
||||||
|
const char *name = SDL_GetDisplayName(i);
|
||||||
|
if (!name) name = "Unknown";
|
||||||
|
const bool selected = (pending_display == i);
|
||||||
|
if (ImGui::Selectable(name, selected))
|
||||||
|
{
|
||||||
|
pending_display = i;
|
||||||
|
}
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *mode_labels[] = {
|
||||||
|
"Windowed",
|
||||||
|
"Borderless (Fullscreen Desktop)",
|
||||||
|
"Exclusive Fullscreen"
|
||||||
|
};
|
||||||
|
ImGui::Combo("Mode", &pending_mode, mode_labels, 3);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Apply triggers immediate swapchain recreation.");
|
||||||
|
if (ImGui::Button("Apply"))
|
||||||
|
{
|
||||||
|
auto mode = static_cast<VulkanEngine::WindowMode>(std::clamp(pending_mode, 0, 2));
|
||||||
|
eng->set_window_mode(mode, pending_display);
|
||||||
|
|
||||||
|
// Re-sync pending selections with what SDL actually applied.
|
||||||
|
pending_display = SDL_GetWindowDisplayIndex(eng->_window);
|
||||||
|
if (pending_display < 0) pending_display = eng->_windowDisplayIndex;
|
||||||
|
pending_display = std::clamp(pending_display, 0, num_displays - 1);
|
||||||
|
pending_mode = static_cast<int>(eng->_windowMode);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Use Current"))
|
||||||
|
{
|
||||||
|
pending_display = current_display;
|
||||||
|
pending_mode = static_cast<int>(eng->_windowMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Background / compute playground
|
// Background / compute playground
|
||||||
static void ui_background(VulkanEngine *eng)
|
static void ui_background(VulkanEngine *eng)
|
||||||
{
|
{
|
||||||
@@ -1364,6 +1447,11 @@ void vk_engine_draw_debug_ui(VulkanEngine *eng)
|
|||||||
ui_overview(eng);
|
ui_overview(eng);
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
if (ImGui::BeginTabItem("Window"))
|
||||||
|
{
|
||||||
|
ui_window(eng);
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
if (ImGui::BeginTabItem("Background"))
|
if (ImGui::BeginTabItem("Background"))
|
||||||
{
|
{
|
||||||
ui_background(eng);
|
ui_background(eng);
|
||||||
|
|||||||
Reference in New Issue
Block a user