init
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
/* Copyright (c) 2019-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "glfw_window.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <fmt/format.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
#include "core/util/logging.hpp"
|
||||
#include "platform/platform.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void error_callback(int error, const char *description)
|
||||
{
|
||||
LOGE("GLFW Error (code {}): {}", error, description);
|
||||
}
|
||||
|
||||
void window_close_callback(GLFWwindow *window)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
void window_size_callback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
if (auto platform = reinterpret_cast<Platform *>(glfwGetWindowUserPointer(window)))
|
||||
{
|
||||
platform->resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void window_focus_callback(GLFWwindow *window, int focused)
|
||||
{
|
||||
if (auto platform = reinterpret_cast<Platform *>(glfwGetWindowUserPointer(window)))
|
||||
{
|
||||
platform->set_focus(focused);
|
||||
}
|
||||
}
|
||||
|
||||
inline KeyCode translate_key_code(int key)
|
||||
{
|
||||
static const std::unordered_map<int, KeyCode> key_lookup =
|
||||
{
|
||||
{GLFW_KEY_SPACE, KeyCode::Space},
|
||||
{GLFW_KEY_APOSTROPHE, KeyCode::Apostrophe},
|
||||
{GLFW_KEY_COMMA, KeyCode::Comma},
|
||||
{GLFW_KEY_MINUS, KeyCode::Minus},
|
||||
{GLFW_KEY_PERIOD, KeyCode::Period},
|
||||
{GLFW_KEY_SLASH, KeyCode::Slash},
|
||||
{GLFW_KEY_0, KeyCode::_0},
|
||||
{GLFW_KEY_1, KeyCode::_1},
|
||||
{GLFW_KEY_2, KeyCode::_2},
|
||||
{GLFW_KEY_3, KeyCode::_3},
|
||||
{GLFW_KEY_4, KeyCode::_4},
|
||||
{GLFW_KEY_5, KeyCode::_5},
|
||||
{GLFW_KEY_6, KeyCode::_6},
|
||||
{GLFW_KEY_7, KeyCode::_7},
|
||||
{GLFW_KEY_8, KeyCode::_8},
|
||||
{GLFW_KEY_9, KeyCode::_9},
|
||||
{GLFW_KEY_SEMICOLON, KeyCode::Semicolon},
|
||||
{GLFW_KEY_EQUAL, KeyCode::Equal},
|
||||
{GLFW_KEY_A, KeyCode::A},
|
||||
{GLFW_KEY_B, KeyCode::B},
|
||||
{GLFW_KEY_C, KeyCode::C},
|
||||
{GLFW_KEY_D, KeyCode::D},
|
||||
{GLFW_KEY_E, KeyCode::E},
|
||||
{GLFW_KEY_F, KeyCode::F},
|
||||
{GLFW_KEY_G, KeyCode::G},
|
||||
{GLFW_KEY_H, KeyCode::H},
|
||||
{GLFW_KEY_I, KeyCode::I},
|
||||
{GLFW_KEY_J, KeyCode::J},
|
||||
{GLFW_KEY_K, KeyCode::K},
|
||||
{GLFW_KEY_L, KeyCode::L},
|
||||
{GLFW_KEY_M, KeyCode::M},
|
||||
{GLFW_KEY_N, KeyCode::N},
|
||||
{GLFW_KEY_O, KeyCode::O},
|
||||
{GLFW_KEY_P, KeyCode::P},
|
||||
{GLFW_KEY_Q, KeyCode::Q},
|
||||
{GLFW_KEY_R, KeyCode::R},
|
||||
{GLFW_KEY_S, KeyCode::S},
|
||||
{GLFW_KEY_T, KeyCode::T},
|
||||
{GLFW_KEY_U, KeyCode::U},
|
||||
{GLFW_KEY_V, KeyCode::V},
|
||||
{GLFW_KEY_W, KeyCode::W},
|
||||
{GLFW_KEY_X, KeyCode::X},
|
||||
{GLFW_KEY_Y, KeyCode::Y},
|
||||
{GLFW_KEY_Z, KeyCode::Z},
|
||||
{GLFW_KEY_LEFT_BRACKET, KeyCode::LeftBracket},
|
||||
{GLFW_KEY_BACKSLASH, KeyCode::Backslash},
|
||||
{GLFW_KEY_RIGHT_BRACKET, KeyCode::RightBracket},
|
||||
{GLFW_KEY_GRAVE_ACCENT, KeyCode::GraveAccent},
|
||||
{GLFW_KEY_ESCAPE, KeyCode::Escape},
|
||||
{GLFW_KEY_ENTER, KeyCode::Enter},
|
||||
{GLFW_KEY_TAB, KeyCode::Tab},
|
||||
{GLFW_KEY_BACKSPACE, KeyCode::Backspace},
|
||||
{GLFW_KEY_INSERT, KeyCode::Insert},
|
||||
{GLFW_KEY_DELETE, KeyCode::DelKey},
|
||||
{GLFW_KEY_RIGHT, KeyCode::Right},
|
||||
{GLFW_KEY_LEFT, KeyCode::Left},
|
||||
{GLFW_KEY_DOWN, KeyCode::Down},
|
||||
{GLFW_KEY_UP, KeyCode::Up},
|
||||
{GLFW_KEY_PAGE_UP, KeyCode::PageUp},
|
||||
{GLFW_KEY_PAGE_DOWN, KeyCode::PageDown},
|
||||
{GLFW_KEY_HOME, KeyCode::Home},
|
||||
{GLFW_KEY_END, KeyCode::End},
|
||||
{GLFW_KEY_CAPS_LOCK, KeyCode::CapsLock},
|
||||
{GLFW_KEY_SCROLL_LOCK, KeyCode::ScrollLock},
|
||||
{GLFW_KEY_NUM_LOCK, KeyCode::NumLock},
|
||||
{GLFW_KEY_PRINT_SCREEN, KeyCode::PrintScreen},
|
||||
{GLFW_KEY_PAUSE, KeyCode::Pause},
|
||||
{GLFW_KEY_F1, KeyCode::F1},
|
||||
{GLFW_KEY_F2, KeyCode::F2},
|
||||
{GLFW_KEY_F3, KeyCode::F3},
|
||||
{GLFW_KEY_F4, KeyCode::F4},
|
||||
{GLFW_KEY_F5, KeyCode::F5},
|
||||
{GLFW_KEY_F6, KeyCode::F6},
|
||||
{GLFW_KEY_F7, KeyCode::F7},
|
||||
{GLFW_KEY_F8, KeyCode::F8},
|
||||
{GLFW_KEY_F9, KeyCode::F9},
|
||||
{GLFW_KEY_F10, KeyCode::F10},
|
||||
{GLFW_KEY_F11, KeyCode::F11},
|
||||
{GLFW_KEY_F12, KeyCode::F12},
|
||||
{GLFW_KEY_KP_0, KeyCode::KP_0},
|
||||
{GLFW_KEY_KP_1, KeyCode::KP_1},
|
||||
{GLFW_KEY_KP_2, KeyCode::KP_2},
|
||||
{GLFW_KEY_KP_3, KeyCode::KP_3},
|
||||
{GLFW_KEY_KP_4, KeyCode::KP_4},
|
||||
{GLFW_KEY_KP_5, KeyCode::KP_5},
|
||||
{GLFW_KEY_KP_6, KeyCode::KP_6},
|
||||
{GLFW_KEY_KP_7, KeyCode::KP_7},
|
||||
{GLFW_KEY_KP_8, KeyCode::KP_8},
|
||||
{GLFW_KEY_KP_9, KeyCode::KP_9},
|
||||
{GLFW_KEY_KP_DECIMAL, KeyCode::KP_Decimal},
|
||||
{GLFW_KEY_KP_DIVIDE, KeyCode::KP_Divide},
|
||||
{GLFW_KEY_KP_MULTIPLY, KeyCode::KP_Multiply},
|
||||
{GLFW_KEY_KP_SUBTRACT, KeyCode::KP_Subtract},
|
||||
{GLFW_KEY_KP_ADD, KeyCode::KP_Add},
|
||||
{GLFW_KEY_KP_ENTER, KeyCode::KP_Enter},
|
||||
{GLFW_KEY_KP_EQUAL, KeyCode::KP_Equal},
|
||||
{GLFW_KEY_LEFT_SHIFT, KeyCode::LeftShift},
|
||||
{GLFW_KEY_LEFT_CONTROL, KeyCode::LeftControl},
|
||||
{GLFW_KEY_LEFT_ALT, KeyCode::LeftAlt},
|
||||
{GLFW_KEY_RIGHT_SHIFT, KeyCode::RightShift},
|
||||
{GLFW_KEY_RIGHT_CONTROL, KeyCode::RightControl},
|
||||
{GLFW_KEY_RIGHT_ALT, KeyCode::RightAlt},
|
||||
};
|
||||
|
||||
auto key_it = key_lookup.find(key);
|
||||
|
||||
if (key_it == key_lookup.end())
|
||||
{
|
||||
return KeyCode::Unknown;
|
||||
}
|
||||
|
||||
return key_it->second;
|
||||
}
|
||||
|
||||
inline KeyAction translate_key_action(int action)
|
||||
{
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
return KeyAction::Down;
|
||||
}
|
||||
else if (action == GLFW_RELEASE)
|
||||
{
|
||||
return KeyAction::Up;
|
||||
}
|
||||
else if (action == GLFW_REPEAT)
|
||||
{
|
||||
return KeyAction::Repeat;
|
||||
}
|
||||
|
||||
return KeyAction::Unknown;
|
||||
}
|
||||
|
||||
void key_callback(GLFWwindow *window, int key, int /*scancode*/, int action, int /*mods*/)
|
||||
{
|
||||
KeyCode key_code = translate_key_code(key);
|
||||
KeyAction key_action = translate_key_action(action);
|
||||
|
||||
if (auto platform = reinterpret_cast<Platform *>(glfwGetWindowUserPointer(window)))
|
||||
{
|
||||
platform->input_event(KeyInputEvent{key_code, key_action});
|
||||
}
|
||||
}
|
||||
|
||||
inline MouseButton translate_mouse_button(int button)
|
||||
{
|
||||
if (button < GLFW_MOUSE_BUTTON_6)
|
||||
{
|
||||
return static_cast<MouseButton>(button);
|
||||
}
|
||||
|
||||
return MouseButton::Unknown;
|
||||
}
|
||||
|
||||
inline MouseAction translate_mouse_action(int action)
|
||||
{
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
return MouseAction::Down;
|
||||
}
|
||||
else if (action == GLFW_RELEASE)
|
||||
{
|
||||
return MouseAction::Up;
|
||||
}
|
||||
|
||||
return MouseAction::Unknown;
|
||||
}
|
||||
|
||||
void cursor_position_callback(GLFWwindow *window, double xpos, double ypos)
|
||||
{
|
||||
if (auto *platform = reinterpret_cast<Platform *>(glfwGetWindowUserPointer(window)))
|
||||
{
|
||||
platform->input_event(MouseButtonInputEvent{
|
||||
MouseButton::Unknown,
|
||||
MouseAction::Move,
|
||||
static_cast<float>(xpos),
|
||||
static_cast<float>(ypos)});
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_button_callback(GLFWwindow *window, int button, int action, int /*mods*/)
|
||||
{
|
||||
MouseAction mouse_action = translate_mouse_action(action);
|
||||
|
||||
if (auto *platform = reinterpret_cast<Platform *>(glfwGetWindowUserPointer(window)))
|
||||
{
|
||||
double xpos, ypos;
|
||||
glfwGetCursorPos(window, &xpos, &ypos);
|
||||
|
||||
platform->input_event(MouseButtonInputEvent{
|
||||
translate_mouse_button(button),
|
||||
mouse_action,
|
||||
static_cast<float>(xpos),
|
||||
static_cast<float>(ypos)});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GlfwWindow::GlfwWindow(Platform *platform, const Window::Properties &properties) :
|
||||
Window(properties)
|
||||
{
|
||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
glfwInitHint(GLFW_X11_XCB_VULKAN_SURFACE, false);
|
||||
#endif
|
||||
|
||||
if (!glfwInit())
|
||||
{
|
||||
throw std::runtime_error("GLFW couldn't be initialized.");
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
switch (properties.mode)
|
||||
{
|
||||
case Window::Mode::Fullscreen:
|
||||
{
|
||||
auto *monitor = glfwGetPrimaryMonitor();
|
||||
const auto *mode = glfwGetVideoMode(monitor);
|
||||
handle = glfwCreateWindow(mode->width, mode->height, properties.title.c_str(), monitor, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case Window::Mode::FullscreenBorderless:
|
||||
{
|
||||
auto *monitor = glfwGetPrimaryMonitor();
|
||||
const auto *mode = glfwGetVideoMode(monitor);
|
||||
glfwWindowHint(GLFW_RED_BITS, mode->redBits);
|
||||
glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
|
||||
glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
|
||||
glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
|
||||
handle = glfwCreateWindow(mode->width, mode->height, properties.title.c_str(), monitor, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case Window::Mode::FullscreenStretch:
|
||||
{
|
||||
throw std::runtime_error("Cannot support stretch mode on this platform.");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
handle = glfwCreateWindow(properties.extent.width, properties.extent.height, properties.title.c_str(), NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
resize(Extent{properties.extent.width, properties.extent.height});
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
throw std::runtime_error("Couldn't create glfw window.");
|
||||
}
|
||||
|
||||
glfwSetWindowUserPointer(handle, platform);
|
||||
|
||||
glfwSetWindowCloseCallback(handle, window_close_callback);
|
||||
glfwSetWindowSizeCallback(handle, window_size_callback);
|
||||
glfwSetWindowFocusCallback(handle, window_focus_callback);
|
||||
glfwSetKeyCallback(handle, key_callback);
|
||||
glfwSetCursorPosCallback(handle, cursor_position_callback);
|
||||
glfwSetMouseButtonCallback(handle, mouse_button_callback);
|
||||
|
||||
glfwSetInputMode(handle, GLFW_STICKY_KEYS, 1);
|
||||
glfwSetInputMode(handle, GLFW_STICKY_MOUSE_BUTTONS, 1);
|
||||
}
|
||||
|
||||
GlfwWindow::~GlfwWindow()
|
||||
{
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
VkSurfaceKHR GlfwWindow::create_surface(vkb::core::InstanceC &instance)
|
||||
{
|
||||
return create_surface(instance.get_handle(), VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
VkSurfaceKHR GlfwWindow::create_surface(VkInstance instance, VkPhysicalDevice)
|
||||
{
|
||||
if (instance == VK_NULL_HANDLE || !handle)
|
||||
{
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
VkResult errCode = glfwCreateWindowSurface(instance, handle, NULL, &surface);
|
||||
|
||||
if (errCode != VK_SUCCESS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
bool GlfwWindow::should_close()
|
||||
{
|
||||
return glfwWindowShouldClose(handle);
|
||||
}
|
||||
|
||||
void GlfwWindow::process_events()
|
||||
{
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
void GlfwWindow::close()
|
||||
{
|
||||
glfwSetWindowShouldClose(handle, GLFW_TRUE);
|
||||
}
|
||||
|
||||
/// @brief It calculates the dpi factor using the density from GLFW physical size
|
||||
/// <a href="https://www.glfw.org/docs/latest/monitor_guide.html#monitor_size">GLFW docs for dpi</a>
|
||||
float GlfwWindow::get_dpi_factor() const
|
||||
{
|
||||
auto primary_monitor = glfwGetPrimaryMonitor();
|
||||
auto vidmode = glfwGetVideoMode(primary_monitor);
|
||||
|
||||
int width_mm, height_mm;
|
||||
glfwGetMonitorPhysicalSize(primary_monitor, &width_mm, &height_mm);
|
||||
|
||||
// As suggested by the GLFW monitor guide
|
||||
static const float inch_to_mm = 25.0f;
|
||||
static const float win_base_density = 96.0f;
|
||||
|
||||
auto dpi = static_cast<uint32_t>(vidmode->width / (width_mm / inch_to_mm));
|
||||
auto dpi_factor = dpi / win_base_density;
|
||||
return dpi_factor;
|
||||
}
|
||||
|
||||
float GlfwWindow::get_content_scale_factor() const
|
||||
{
|
||||
int fb_width, fb_height;
|
||||
glfwGetFramebufferSize(handle, &fb_width, &fb_height);
|
||||
int win_width, win_height;
|
||||
glfwGetWindowSize(handle, &win_width, &win_height);
|
||||
|
||||
// We could return a 2D result here instead of a scalar,
|
||||
// but non-uniform scaling is very unlikely, and would
|
||||
// require significantly more changes in the IMGUI integration
|
||||
return static_cast<float>(fb_width) / win_width;
|
||||
}
|
||||
|
||||
std::vector<const char *> GlfwWindow::get_required_surface_extensions() const
|
||||
{
|
||||
uint32_t glfw_extension_count{0};
|
||||
const char **names = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
||||
return {names, names + glfw_extension_count};
|
||||
}
|
||||
|
||||
} // namespace vkb
|
||||
Reference in New Issue
Block a user