25#define STB_IMAGE_IMPLEMENTATION
26#include <stb_image/stb_image.h>
30static std::list<EventHandler*>* handlers =
nullptr;
44 float lHandle, rHandle;
46 _WinGamePad(
unsigned int id) : id(id) {}
49static std::list<_WinGamePad> gamePads;
61 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
62 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
64 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
65 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
68 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
69 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
72 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
78 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
81 glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
88 glfwDestroyWindow(window);
93static void keyCallback(GLFWwindow* window,
int key,
int scancode,
int action,
int mods) {
94 if (handlers ==
nullptr)
return;
98 case GLFW_KEY_GRAVE_ACCENT: eKey = Key::Backtick;
break;
99 case GLFW_KEY_1: eKey = Key::One;
break;
100 case GLFW_KEY_2: eKey = Key::Two;
break;
101 case GLFW_KEY_3: eKey = Key::Three;
break;
102 case GLFW_KEY_4: eKey = Key::Four;
break;
103 case GLFW_KEY_5: eKey = Key::Five;
break;
104 case GLFW_KEY_6: eKey = Key::Six;
break;
105 case GLFW_KEY_7: eKey = Key::Seven;
break;
106 case GLFW_KEY_8: eKey = Key::Eight;
break;
107 case GLFW_KEY_9: eKey = Key::Nine;
break;
108 case GLFW_KEY_0: eKey = Key::Zero;
break;
109 case GLFW_KEY_MINUS: eKey = Key::Minus;
break;
110 case GLFW_KEY_EQUAL: eKey = Key::Equals;
break;
111 case GLFW_KEY_BACKSPACE:
case GLFW_KEY_DELETE: eKey = Key::Backspace;
break;
112 case GLFW_KEY_TAB: eKey = Key::Tab;
break;
113 case GLFW_KEY_LEFT_BRACKET: eKey = Key::LeftBracket;
break;
114 case GLFW_KEY_RIGHT_BRACKET: eKey = Key::RightBracket;
break;
115 case GLFW_KEY_BACKSLASH: eKey = Key::Backslash;
break;
116 case GLFW_KEY_ENTER: eKey = Key::Enter;
break;
117 case GLFW_KEY_LEFT_SHIFT: eKey = Key::LeftShift;
break;
118 case GLFW_KEY_COMMA: eKey = Key::Comma;
break;
119 case GLFW_KEY_PERIOD: eKey = Key::Period;
break;
120 case GLFW_KEY_SLASH: eKey = Key::Slash;
break;
121 case GLFW_KEY_RIGHT_SHIFT: eKey = Key::RightShift;
break;
122 case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_CONTROL: eKey = Key::Control;
break;
123 case GLFW_KEY_LEFT_ALT:
case GLFW_KEY_RIGHT_ALT: eKey = Key::Alt;
break;
124 case GLFW_KEY_SPACE: eKey = Key::Space;
break;
125 case GLFW_KEY_UP: eKey = Key::Up;
break;
126 case GLFW_KEY_DOWN: eKey = Key::Down;
break;
127 case GLFW_KEY_LEFT: eKey = Key::Left;
break;
128 case GLFW_KEY_RIGHT: eKey = Key::Right;
break;
129 case GLFW_KEY_Q: eKey = Key::Q;
break;
130 case GLFW_KEY_W: eKey = Key::W;
break;
131 case GLFW_KEY_E: eKey = Key::E;
break;
132 case GLFW_KEY_R: eKey = Key::R;
break;
133 case GLFW_KEY_T: eKey = Key::T;
break;
134 case GLFW_KEY_Y: eKey = Key::Y;
break;
135 case GLFW_KEY_U: eKey = Key::U;
break;
136 case GLFW_KEY_I: eKey = Key::I;
break;
137 case GLFW_KEY_O: eKey = Key::O;
break;
138 case GLFW_KEY_P: eKey = Key::P;
break;
139 case GLFW_KEY_A: eKey = Key::A;
break;
140 case GLFW_KEY_S: eKey = Key::S;
break;
141 case GLFW_KEY_D: eKey = Key::D;
break;
142 case GLFW_KEY_F: eKey = Key::F;
break;
143 case GLFW_KEY_G: eKey = Key::G;
break;
144 case GLFW_KEY_H: eKey = Key::H;
break;
145 case GLFW_KEY_J: eKey = Key::J;
break;
146 case GLFW_KEY_K: eKey = Key::K;
break;
147 case GLFW_KEY_L: eKey = Key::L;
break;
148 case GLFW_KEY_Z: eKey = Key::Z;
break;
149 case GLFW_KEY_X: eKey = Key::X;
break;
150 case GLFW_KEY_C: eKey = Key::C;
break;
151 case GLFW_KEY_V: eKey = Key::V;
break;
152 case GLFW_KEY_B: eKey = Key::B;
break;
153 case GLFW_KEY_N: eKey = Key::N;
break;
154 case GLFW_KEY_M: eKey = Key::M;
break;
158 if (action == GLFW_PRESS)
for (
auto handler : *handlers) handler->onKeyPress(eKey);
159 if (action == GLFW_RELEASE)
for (
auto handler : *handlers) handler->onKeyRelease(eKey);
162static void cursorCallback(GLFWwindow* window,
double x,
double y) {
163 if (handlers ==
nullptr)
return;
165 for (
auto handler : *handlers) handler->onMouseMove(pos);
168static void mouseButtonCallback(GLFWwindow* window,
int button,
int action,
int mods) {
169 if (handlers ==
nullptr)
return;
173 case GLFW_MOUSE_BUTTON_LEFT:
for (
auto handler : *handlers) handler->onLeftClick();
return;
174 case GLFW_MOUSE_BUTTON_MIDDLE:
for (
auto handler : *handlers) handler->onMiddleClick();
return;
175 case GLFW_MOUSE_BUTTON_RIGHT:
for (
auto handler : *handlers) handler->onRightClick();
return;
180 case GLFW_MOUSE_BUTTON_LEFT:
for (
auto handler : *handlers) handler->onLeftClickRelease();
return;
181 case GLFW_MOUSE_BUTTON_MIDDLE:
for (
auto handler : *handlers) handler->onMiddleClickRelease();
return;
182 case GLFW_MOUSE_BUTTON_RIGHT:
for (
auto handler : *handlers) handler->onRightClickRelease();
return;
189static void scrollCallback(GLFWwindow* window,
double xoffset,
double yoffset) {
190 if (handlers ==
nullptr)
return;
191 for (
auto handler : *handlers) handler->onMouseScroll(static_cast<float>(yoffset));
194static void resizeCallback(GLFWwindow* window,
int width,
int height) {
200 if (handlers ==
nullptr)
return;
201 for (
auto handler : *handlers) handler->onWindowResize(tmp_oldWinSize, size);
204static void focusCallback(GLFWwindow* window,
int focused) {
205 if (handlers ==
nullptr)
return;
206 if (focused)
for (
auto handler : *handlers) handler->onWindowGainedFocus();
207 else for (
auto handler : *handlers) handler->onWindowLostFocus();
210static void joystickCallback(
int jid,
int action) {
211 if (handlers ==
nullptr)
return;
214 for (
auto handler : *handlers) handler->onControllerConnect(jid);
215 gamePads.emplace_back(jid);
217 case GLFW_DISCONNECTED:
218 for (
auto handler : *handlers) handler->onControllerDisconnect(jid);
219 gamePads.remove_if([=] (_WinGamePad& gamepad) {
220 return gamepad.id == jid;
233void Window::create(
const char* title) {
235 window = glfwCreateWindow(oldWinSize.x, oldWinSize.y, title,
nullptr,
nullptr);
247 glfwMakeContextCurrent(window);
253 glfwGetWindowSize(window, &winSize.
x, &winSize.
y);
254 oldWinSize = winSize.
cast<
unsigned int>();
256 handlers = &eventHandlers;
257 glfwSetKeyCallback(window, keyCallback);
258 glfwSetCursorPosCallback(window, cursorCallback);
259 glfwSetMouseButtonCallback(window, mouseButtonCallback);
260 glfwSetScrollCallback(window, scrollCallback);
261 glfwSetWindowSizeCallback(window, resizeCallback);
262 glfwSetWindowFocusCallback(window, focusCallback);
263 glfwSetJoystickCallback(joystickCallback);
270bool Window::isOpen()
const {
271 return !glfwWindowShouldClose(window);
277void Window::lockCursor() {
278 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
284void Window::unlockCursor() {
285 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
299 return oldWinSize.
cast<
float>();
305Vector2ui Window::getFramebufferSize()
const {
307 glfwGetFramebufferSize(window, &size.
x, &size.
y);
308 return size.
cast<
unsigned int>();
314void Window::update() {
320 for (_WinGamePad& gamepad : gamePads) {
321 GLFWgamepadstate state;
322 if (!glfwGetGamepadState(gamepad.id, &state)) {
323 gamePads.remove_if([&] (_WinGamePad& gamepad2) {
324 return gamepad2.id == gamepad.id;
330 if (state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS && !gamepad.A) {
331 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
A);
334 if (state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS && !gamepad.B) {
335 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
B);
338 if (state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS && !gamepad.X) {
339 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
X);
342 if (state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS && !gamepad.Y) {
343 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
Y);
346 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS && !gamepad.DPadUp) {
347 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
DPadUp);
348 gamepad.DPadUp =
true;
350 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS && !gamepad.DPadRight) {
352 gamepad.DPadRight =
true;
354 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS && !gamepad.DPadDown) {
356 gamepad.DPadDown =
true;
358 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS && !gamepad.DPadLeft) {
360 gamepad.DPadLeft =
true;
362 if (state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS && !gamepad.R1) {
363 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
R1);
366 if (state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS && !gamepad.L1) {
367 for (
auto handler : eventHandlers) handler->onControllerButtonPress(gamepad.id,
ControllerButton::
L1);
370 if (state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS && !gamepad.RightJoystick) {
372 gamepad.RightJoystick =
true;
374 if (state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS && !gamepad.LeftJoystick) {
376 gamepad.LeftJoystick =
true;
378 if (state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS && !gamepad.RightMenu) {
380 gamepad.RightMenu =
true;
382 if (state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS && !gamepad.LeftMenu) {
384 gamepad.LeftMenu =
true;
388 if (state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_RELEASE && gamepad.A) {
389 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
A);
392 if (state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_RELEASE && gamepad.B) {
393 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
B);
396 if (state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_RELEASE && gamepad.X) {
397 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
X);
400 if (state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_RELEASE && gamepad.Y) {
401 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
Y);
404 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_RELEASE && gamepad.DPadUp) {
405 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
DPadUp);
406 gamepad.DPadUp =
false;
408 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_RELEASE && gamepad.DPadRight) {
410 gamepad.DPadRight =
false;
412 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_RELEASE && gamepad.DPadDown) {
414 gamepad.DPadDown =
false;
416 if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_RELEASE && gamepad.DPadLeft) {
418 gamepad.DPadLeft =
false;
420 if (state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_RELEASE && gamepad.R1) {
421 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
R1);
424 if (state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_RELEASE && gamepad.L1) {
425 for (
auto handler : eventHandlers) handler->onControllerButtonRelease(gamepad.id,
ControllerButton::
L1);
428 if (state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_RELEASE && gamepad.RightJoystick) {
430 gamepad.RightJoystick =
false;
432 if (state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_RELEASE && gamepad.LeftJoystick) {
434 gamepad.LeftJoystick =
false;
436 if (state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_RELEASE && gamepad.RightMenu) {
438 gamepad.RightMenu =
false;
440 if (state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_RELEASE && gamepad.LeftMenu) {
442 gamepad.LeftMenu =
false;
446 if (state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] != gamepad.lHandle) {
447 gamepad.lHandle = state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER];
448 for (
auto handler : eventHandlers) handler->onControllerHandle(gamepad.id,
ControllerAxis::
Left, gamepad.lHandle);
450 if (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] != gamepad.rHandle) {
451 gamepad.lHandle = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER];
452 for (
auto handler : eventHandlers) handler->onControllerHandle(gamepad.id,
ControllerAxis::
Right, gamepad.rHandle);
456 if (state.axes[GLFW_GAMEPAD_AXIS_LEFT_X] != gamepad.lJoystick.x || state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] != gamepad.lJoystick.y) {
457 gamepad.lJoystick.x = state.axes[GLFW_GAMEPAD_AXIS_LEFT_X];
458 gamepad.lJoystick.y = state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y];
459 for (
auto handler : eventHandlers) handler->onControllerJoystick(gamepad.id,
ControllerAxis::
Left, gamepad.lJoystick);
461 if (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] != gamepad.rJoystick.x || state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] != gamepad.rJoystick.y) {
462 gamepad.rJoystick.x = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X];
463 gamepad.rJoystick.y = state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y];
464 for (
auto handler : eventHandlers) handler->onControllerJoystick(gamepad.id,
ControllerAxis::
Right, gamepad.rJoystick);
473std::vector<const char*> Window::getInstanceExtensions()
const {
474 uint32_t glfwExtensionCount = 0;
475 const char** glfwExtensions;
476 glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
477 std::vector<const char*> requiredExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
478 return requiredExtensions;
489void Window::createWindowSurface(
const vk::UniqueInstance& instance, vk::UniqueSurfaceKHR& surface)
const {
490 VkSurfaceKHR tmpSurface;
491 if (glfwCreateWindowSurface(instance.get(), window,
nullptr, &tmpSurface) != VK_SUCCESS)
492 throw std::runtime_error(
"Unable to create window surface");
494 surface = vk::UniqueSurfaceKHR(tmpSurface, instance.get());
505void Window::setupGlad()
const {
506 if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
507 throw std::runtime_error(
"Unable to setup GLAD");
513void Window::swapBuffers() const noexcept {
514 glfwSwapBuffers(window);
522const char* Window::getTitle()
const {
530void Window::setIcon(
const std::string& filePath) {
534 image.pixels = stbi_load(filePath.c_str(), &image.width, &image.height,
nullptr, STBI_rgb_alpha);
535 glfwSetWindowIcon(window, 1, &image);
536 stbi_image_free(image.pixels);
538 console.
warn(
"Cannot set icon to " + filePath +
" - OSX does not support glfwSetWindowIcon");
std::string getAssetFolderPath() const
Vector2< A > cast() const