aa
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
// Minimal GLFW-compatible Win32 backend for cross-compiling the example.
|
||||
// It implements only the subset used by src/render.cpp.
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_win32.h>
|
||||
|
||||
struct GLFWwindow {
|
||||
HWND handle = nullptr;
|
||||
void* user_pointer = nullptr;
|
||||
bool should_close = false;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
GLFWkeyfun key_callback = nullptr;
|
||||
GLFWmousebuttonfun mouse_button_callback = nullptr;
|
||||
GLFWcursorposfun cursor_pos_callback = nullptr;
|
||||
GLFWscrollfun scroll_callback = nullptr;
|
||||
|
||||
std::array<unsigned char, 1024> key_state{};
|
||||
std::array<unsigned char, 8> mouse_button_state{};
|
||||
double cursor_x = 0.0;
|
||||
double cursor_y = 0.0;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr wchar_t kWindowClassName[] = L"OpenCGE_GLFWStub";
|
||||
HINSTANCE g_instance = nullptr;
|
||||
bool g_initialized = false;
|
||||
bool g_resizable = true;
|
||||
|
||||
int map_key(WPARAM vk) {
|
||||
if (vk >= 'A' && vk <= 'Z') {
|
||||
return GLFW_KEY_A + static_cast<int>(vk - 'A');
|
||||
}
|
||||
if (vk >= '0' && vk <= '9') {
|
||||
return GLFW_KEY_0 + static_cast<int>(vk - '0');
|
||||
}
|
||||
switch (vk) {
|
||||
case VK_ESCAPE:
|
||||
return GLFW_KEY_ESCAPE;
|
||||
case VK_LEFT:
|
||||
return GLFW_KEY_LEFT;
|
||||
case VK_RIGHT:
|
||||
return GLFW_KEY_RIGHT;
|
||||
case VK_UP:
|
||||
return GLFW_KEY_UP;
|
||||
case VK_DOWN:
|
||||
return GLFW_KEY_DOWN;
|
||||
case VK_SPACE:
|
||||
return GLFW_KEY_SPACE;
|
||||
case VK_RETURN:
|
||||
return GLFW_KEY_ENTER;
|
||||
case VK_TAB:
|
||||
return GLFW_KEY_TAB;
|
||||
case VK_BACK:
|
||||
return GLFW_KEY_BACKSPACE;
|
||||
case VK_DELETE:
|
||||
return GLFW_KEY_DELETE;
|
||||
case VK_LSHIFT:
|
||||
return GLFW_KEY_LEFT_SHIFT;
|
||||
case VK_RSHIFT:
|
||||
return GLFW_KEY_RIGHT_SHIFT;
|
||||
case VK_LCONTROL:
|
||||
return GLFW_KEY_LEFT_CONTROL;
|
||||
case VK_RCONTROL:
|
||||
return GLFW_KEY_RIGHT_CONTROL;
|
||||
case VK_LMENU:
|
||||
return GLFW_KEY_LEFT_ALT;
|
||||
case VK_RMENU:
|
||||
return GLFW_KEY_RIGHT_ALT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
int current_mods() {
|
||||
int mods = 0;
|
||||
if (GetKeyState(VK_SHIFT) & 0x8000) {
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
}
|
||||
if (GetKeyState(VK_CONTROL) & 0x8000) {
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
}
|
||||
if (GetKeyState(VK_MENU) & 0x8000) {
|
||||
mods |= GLFW_MOD_ALT;
|
||||
}
|
||||
if ((GetKeyState(VK_LWIN) & 0x8000) || (GetKeyState(VK_RWIN) & 0x8000)) {
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
}
|
||||
return mods;
|
||||
}
|
||||
|
||||
void handle_key(GLFWwindow* window, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
if (window == nullptr || window->key_callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int key = map_key(wparam);
|
||||
const int scancode = static_cast<int>((lparam >> 16) & 0x1ff);
|
||||
const int action = message == WM_KEYDOWN || message == WM_SYSKEYDOWN
|
||||
? (((lparam & (1U << 30)) != 0) ? GLFW_REPEAT : GLFW_PRESS)
|
||||
: GLFW_RELEASE;
|
||||
|
||||
if (key >= 0 && key < static_cast<int>(window->key_state.size())) {
|
||||
window->key_state[key] = action == GLFW_RELEASE ? GLFW_RELEASE : GLFW_PRESS;
|
||||
}
|
||||
|
||||
window->key_callback(window, key, scancode, action, current_mods());
|
||||
}
|
||||
|
||||
int map_mouse_button(UINT message, WPARAM wparam) {
|
||||
switch (message) {
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
return GLFW_MOUSE_BUTTON_LEFT;
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
return GLFW_MOUSE_BUTTON_RIGHT;
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
return GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
case WM_XBUTTONDOWN:
|
||||
case WM_XBUTTONUP:
|
||||
return GET_XBUTTON_WPARAM(wparam) == XBUTTON1 ? GLFW_MOUSE_BUTTON_4
|
||||
: GLFW_MOUSE_BUTTON_5;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_mouse_button(GLFWwindow* window, UINT message, WPARAM wparam) {
|
||||
if (window == nullptr || window->mouse_button_callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int button = map_mouse_button(message, wparam);
|
||||
if (button < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_down = message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
|
||||
message == WM_MBUTTONDOWN || message == WM_XBUTTONDOWN;
|
||||
window->mouse_button_state[button] = is_down ? GLFW_PRESS : GLFW_RELEASE;
|
||||
window->mouse_button_callback(window, button, is_down ? GLFW_PRESS : GLFW_RELEASE,
|
||||
current_mods());
|
||||
}
|
||||
|
||||
LRESULT CALLBACK window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
auto* window = reinterpret_cast<GLFWwindow*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
|
||||
|
||||
switch (message) {
|
||||
case WM_CLOSE:
|
||||
if (window != nullptr) {
|
||||
window->should_close = true;
|
||||
}
|
||||
return 0;
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
handle_key(window, message, wparam, lparam);
|
||||
return 0;
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_XBUTTONDOWN:
|
||||
case WM_XBUTTONUP:
|
||||
handle_mouse_button(window, message, wparam);
|
||||
return 0;
|
||||
case WM_MOUSEMOVE:
|
||||
if (window != nullptr) {
|
||||
window->cursor_x = static_cast<double>(GET_X_LPARAM(lparam));
|
||||
window->cursor_y = static_cast<double>(GET_Y_LPARAM(lparam));
|
||||
if (window->cursor_pos_callback != nullptr) {
|
||||
window->cursor_pos_callback(window, window->cursor_x, window->cursor_y);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case WM_MOUSEWHEEL:
|
||||
if (window != nullptr && window->scroll_callback != nullptr) {
|
||||
const double delta = static_cast<double>(GET_WHEEL_DELTA_WPARAM(wparam)) /
|
||||
static_cast<double>(WHEEL_DELTA);
|
||||
window->scroll_callback(window, 0.0, delta);
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProcW(hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
int glfwInit(void) {
|
||||
if (g_initialized) {
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
g_instance = GetModuleHandleW(nullptr);
|
||||
|
||||
WNDCLASSEXW wc{};
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wc.lpfnWndProc = window_proc;
|
||||
wc.hInstance = g_instance;
|
||||
wc.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512));
|
||||
wc.lpszClassName = kWindowClassName;
|
||||
if (RegisterClassExW(&wc) == 0) {
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
g_initialized = true;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void glfwTerminate(void) {
|
||||
g_initialized = false;
|
||||
}
|
||||
|
||||
void glfwWindowHint(int hint, int value) {
|
||||
if (hint == GLFW_RESIZABLE) {
|
||||
g_resizable = value != GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor*, GLFWwindow*) {
|
||||
if (!g_initialized) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int wide_length = MultiByteToWideChar(CP_UTF8, 0, title, -1, nullptr, 0);
|
||||
std::vector<wchar_t> wide_title(wide_length);
|
||||
MultiByteToWideChar(CP_UTF8, 0, title, -1, wide_title.data(), wide_length);
|
||||
|
||||
DWORD style = WS_OVERLAPPEDWINDOW;
|
||||
if (!g_resizable) {
|
||||
style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||
}
|
||||
|
||||
RECT rect{0, 0, width, height};
|
||||
AdjustWindowRectEx(&rect, style, FALSE, 0);
|
||||
|
||||
HWND hwnd = CreateWindowExW(
|
||||
0, kWindowClassName, wide_title.data(), style, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, g_instance, nullptr);
|
||||
if (hwnd == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* window = new GLFWwindow();
|
||||
window->handle = hwnd;
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window));
|
||||
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
return window;
|
||||
}
|
||||
|
||||
void glfwDestroyWindow(GLFWwindow* window) {
|
||||
if (window == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (window->handle != nullptr) {
|
||||
DestroyWindow(window->handle);
|
||||
}
|
||||
delete window;
|
||||
}
|
||||
|
||||
void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer) {
|
||||
if (window != nullptr) {
|
||||
window->user_pointer = pointer;
|
||||
}
|
||||
}
|
||||
|
||||
void* glfwGetWindowUserPointer(GLFWwindow* window) {
|
||||
return window != nullptr ? window->user_pointer : nullptr;
|
||||
}
|
||||
|
||||
GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback) {
|
||||
if (window == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
GLFWkeyfun previous = window->key_callback;
|
||||
window->key_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback) {
|
||||
if (window == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
GLFWmousebuttonfun previous = window->mouse_button_callback;
|
||||
window->mouse_button_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback) {
|
||||
if (window == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
GLFWcursorposfun previous = window->cursor_pos_callback;
|
||||
window->cursor_pos_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback) {
|
||||
if (window == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
GLFWscrollfun previous = window->scroll_callback;
|
||||
window->scroll_callback = callback;
|
||||
return previous;
|
||||
}
|
||||
|
||||
void glfwPollEvents(void) {
|
||||
MSG msg{};
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
int glfwWindowShouldClose(GLFWwindow* window) {
|
||||
return window != nullptr && window->should_close ? GLFW_TRUE : GLFW_FALSE;
|
||||
}
|
||||
|
||||
int glfwGetKey(GLFWwindow* window, int key) {
|
||||
if (window == nullptr || key < 0 || key >= static_cast<int>(window->key_state.size())) {
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
return window->key_state[key] != 0 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
}
|
||||
|
||||
int glfwGetMouseButton(GLFWwindow* window, int button) {
|
||||
if (window == nullptr || button < 0 ||
|
||||
button >= static_cast<int>(window->mouse_button_state.size())) {
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
return window->mouse_button_state[button] != 0 ? GLFW_PRESS : GLFW_RELEASE;
|
||||
}
|
||||
|
||||
void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos) {
|
||||
if (xpos != nullptr) {
|
||||
*xpos = window != nullptr ? window->cursor_x : 0.0;
|
||||
}
|
||||
if (ypos != nullptr) {
|
||||
*ypos = window != nullptr ? window->cursor_y : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height) {
|
||||
if (window == nullptr || window->handle == nullptr) {
|
||||
return;
|
||||
}
|
||||
RECT client{};
|
||||
GetClientRect(window->handle, &client);
|
||||
if (width != nullptr) {
|
||||
*width = client.right - client.left;
|
||||
}
|
||||
if (height != nullptr) {
|
||||
*height = client.bottom - client.top;
|
||||
}
|
||||
}
|
||||
|
||||
const char** glfwGetRequiredInstanceExtensions(uint32_t* count) {
|
||||
static const char* extensions[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
if (count != nullptr) {
|
||||
*count = static_cast<uint32_t>(sizeof(extensions) / sizeof(extensions[0]));
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface) {
|
||||
if (instance == VK_NULL_HANDLE || window == nullptr || surface == nullptr) {
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
auto create_surface = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
|
||||
vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"));
|
||||
if (create_surface == nullptr) {
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
info.hinstance = g_instance;
|
||||
info.hwnd = window->handle;
|
||||
return create_surface(instance, &info, allocator, surface);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user