diff --git a/openVulkanoCpp.sln.DotSettings b/openVulkanoCpp.sln.DotSettings
index 9ad4899..81d6aa3 100644
--- a/openVulkanoCpp.sln.DotSettings
+++ b/openVulkanoCpp.sln.DotSettings
@@ -4,11 +4,15 @@
<NamingElement Priority="9"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="member function" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement>
<NamingElement Priority="11"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="PUBLIC"><type Name="class field" /><type Name="struct field" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></NamingElement>
<NamingElement Priority="13"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="scoped enumerator" /><type Name="unscoped enumerator" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></NamingElement>
+ <NamingElement Priority="9"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="global function" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement>
+ <NamingElement Priority="7"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="local variable" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></NamingElement>
<NamingElement Priority="16"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="namespace" /><type Name="namespace alias" /></Descriptor><Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /></NamingElement>
<NamingElement Priority="5"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="function parameter" /><type Name="lambda parameter" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></NamingElement>
True
True
+ True
True
True
+ True
True
True
\ No newline at end of file
diff --git a/openVulkanoCpp/Base/Event.hpp b/openVulkanoCpp/Base/Event.hpp
index 722e16d..59b586d 100644
--- a/openVulkanoCpp/Base/Event.hpp
+++ b/openVulkanoCpp/Base/Event.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include
#include
#include
#include
diff --git a/openVulkanoCpp/Base/IPlatform.hpp b/openVulkanoCpp/Base/IPlatform.hpp
new file mode 100644
index 0000000..94c6380
--- /dev/null
+++ b/openVulkanoCpp/Base/IPlatform.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "IInitable.hpp"
+#include "ITickable.hpp"
+#include "ICloseable.hpp"
+#include "UI/IWindow.hpp"
+
+namespace openVulkanoCpp
+{
+ class PlatformInitFailedException : public std::runtime_error
+ {
+ public:
+ PlatformInitFailedException(char const* const message) : runtime_error(message) {}
+ };
+
+ class IPlatform : public IInitable, public ITickable, public ICloseable
+ {
+ public:
+ virtual IWindow* MakeWindow() = 0;
+ };
+}
diff --git a/openVulkanoCpp/Base/Logger.cpp b/openVulkanoCpp/Base/Logger.cpp
index c362e0b..7cdd5b7 100644
--- a/openVulkanoCpp/Base/Logger.cpp
+++ b/openVulkanoCpp/Base/Logger.cpp
@@ -10,4 +10,5 @@ namespace openVulkanoCpp
std::shared_ptr Logger::AUDIO = nullptr;
std::shared_ptr Logger::DATA = nullptr;
std::shared_ptr Logger::SCENE = nullptr;
+ std::shared_ptr Logger::INPUT = nullptr;
}
\ No newline at end of file
diff --git a/openVulkanoCpp/Base/Logger.hpp b/openVulkanoCpp/Base/Logger.hpp
index 26dbe31..e1d547b 100644
--- a/openVulkanoCpp/Base/Logger.hpp
+++ b/openVulkanoCpp/Base/Logger.hpp
@@ -28,6 +28,7 @@ namespace openVulkanoCpp
static std::shared_ptr AUDIO;
static std::shared_ptr DATA;
static std::shared_ptr SCENE;
+ static std::shared_ptr INPUT;
static void SetupLogger(std::string logFolder = "logs", std::string logFile = "openVulkano.log")
{
@@ -59,6 +60,7 @@ namespace openVulkanoCpp
AUDIO = CreateLogger("audio");
DATA = CreateLogger("data");
SCENE = CreateLogger("scene");
+ INPUT = CreateLogger("input");
spdlog::flush_every(std::chrono::seconds(5));
diff --git a/openVulkanoCpp/Base/PlatformEnums.hpp b/openVulkanoCpp/Base/PlatformEnums.hpp
index a0588af..e74b3b7 100644
--- a/openVulkanoCpp/Base/PlatformEnums.hpp
+++ b/openVulkanoCpp/Base/PlatformEnums.hpp
@@ -10,6 +10,7 @@ namespace openVulkanoCpp
//OpenGL,
//DirectX11,
//DirectX12,
+ //Metal,
MAX_VALUE
};
@@ -27,7 +28,7 @@ namespace openVulkanoCpp
{
enum Platform
{
- Windows = 0, MacOS, Linux, Android, MAX_VALUE
+ Windows = 0, MacOS, Linux, Android, iOS, MAX_VALUE
};
inline std::string ToString(Platform os)
@@ -35,9 +36,10 @@ namespace openVulkanoCpp
switch (os)
{
case Windows: return "Windows";
- case MacOS: return "Windows";
- case Linux: return "Windows";
- case Android: return "Windows";
+ case MacOS: return "MacOS";
+ case Linux: return "Linux";
+ case Android: return "Android";
+ case iOS: return "iOS";
}
return "Invalid";
}
diff --git a/openVulkanoCpp/Base/UI/IWindow.hpp b/openVulkanoCpp/Base/UI/IWindow.hpp
index 22a7181..c21e5df 100644
--- a/openVulkanoCpp/Base/UI/IWindow.hpp
+++ b/openVulkanoCpp/Base/UI/IWindow.hpp
@@ -4,7 +4,6 @@
#include
#include
#include "../PlatformEnums.hpp"
-#include "../ITickable.hpp"
#include "../ICloseable.hpp"
namespace openVulkanoCpp
@@ -29,7 +28,7 @@ namespace openVulkanoCpp
WindowMode windowMode = WINDOWED;
};
- class IWindow : public ITickable, public ICloseable
+ class IWindow : public ICloseable
{
public:
virtual ~IWindow() = default;
diff --git a/openVulkanoCpp/Host/GLFW/InputDeviceGLFW.hpp b/openVulkanoCpp/Host/GLFW/InputDeviceGLFW.hpp
new file mode 100644
index 0000000..43be00e
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/InputDeviceGLFW.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "../../Base/ITickable.hpp"
+#include "../../Input/InputDeviceKeyboard.hpp"
+#include "../../Input/InputDeviceMouse.hpp"
+#include "../../Input/InputDeviceController.hpp"
+#include
+
+namespace openVulkanoCpp
+{
+ class KeyboardGLFW final : public Input::InputDeviceKeyboard
+ {
+ public:
+ KeyboardGLFW() = default;
+
+ using Input::InputDeviceKeyboard::Init;
+ using Input::InputDeviceKeyboard::PreTick;
+ using Input::InputDeviceKeyboard::UpdateKey;
+ using Input::InputDeviceKeyboard::UpdateActiveWindow;
+ };
+
+ class MouseGLFW final : public Input::InputDeviceMouse
+ {
+ public:
+ MouseGLFW() = default;
+
+ using Input::InputDeviceMouse::Init;
+ using Input::InputDeviceMouse::ClearAxes;
+ using Input::InputDeviceMouse::UpdateButtons;
+ using Input::InputDeviceMouse::UpdatePosition;
+ using Input::InputDeviceMouse::UpdateWheel;
+ using Input::InputDeviceMouse::UpdateActiveWindow;
+ };
+
+ class ControllerGLFW final : public Input::InputDeviceController, public ITickable
+ {
+ bool gamepad = false;;
+ public:
+ ControllerGLFW() = default;
+
+ void Init(int joystickId)
+ {
+ if (GetIndex() != -1) return;
+ gamepad = glfwJoystickIsGamepad(joystickId);
+ std::string name = glfwGetJoystickName(joystickId);
+ if (gamepad) name += " - " + std::string(glfwGetGamepadName(joystickId));
+ InputDeviceController::Init(joystickId, name);
+ if (!gamepad) Logger::INPUT->warn("Joysticks currently are not supported");
+ }
+
+ void Tick() override
+ {
+ if (GetIndex() == -1) return;
+ if (gamepad)
+ {
+ GLFWgamepadstate state;
+ glfwGetGamepadState(GetIndex(), &state);
+ for (int i = 0; i < 6; i++)
+ {
+ SetAxis(static_cast(i), state.axes[i]);
+ }
+
+ uint32_t buttonStates = 0;
+ for (int i = 0; i < 15; i++)
+ {
+ buttonStates |= static_cast(state.buttons[i] != 0) << i;
+ }
+ SetButtons(buttonStates);
+ }
+ else
+ {
+ // Joysticks currently are not supported
+ }
+ }
+ };
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp b/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp
new file mode 100644
index 0000000..e62b4fa
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp
@@ -0,0 +1,93 @@
+#pragma once
+#include "../../Input/InputKey.hpp"
+#include
+
+namespace openVulkanoCpp
+{
+ namespace GLFW
+ {
+ struct KeyboardInputMapping
+ {
+ int mapping[GLFW_KEY_LAST + 1];
+
+ constexpr KeyboardInputMapping() : mapping()
+ {
+ for (int i = 0; i <= GLFW_KEY_LAST; i++)
+ {
+ int remappedKey = -1;
+
+ if (i == GLFW_KEY_SPACE)
+ {
+ remappedKey = i;
+ }
+ else if (i >= GLFW_KEY_COMMA && i <= GLFW_KEY_RIGHT_BRACKET)
+ {
+ if (i != 58 && i != 60 && i != 62 && i != 63 && i != 64)
+ {
+ remappedKey = i;
+ }
+ }
+ else if (i == GLFW_KEY_GRAVE_ACCENT)
+ {
+ remappedKey = 64;
+ }
+ else if (i == GLFW_KEY_WORLD_1)
+ {
+ remappedKey = 58;
+ }
+ else if (i == GLFW_KEY_WORLD_2)
+ {
+ remappedKey = 60;
+ }
+ else if (i >= GLFW_KEY_KP_0 && i <= GLFW_KEY_KP_EQUAL)
+ {
+ remappedKey = i - 320;
+ }
+ else if (i >= GLFW_KEY_NUM_LOCK)
+ {
+ remappedKey = 17;
+ }
+ else if (i == GLFW_KEY_SPACE)
+ {
+ remappedKey = 62;
+ }
+ else if (i == GLFW_KEY_APOSTROPHE)
+ {
+ remappedKey = 63;
+ }
+ else if (i >= GLFW_KEY_ESCAPE && i <= GLFW_KEY_END)
+ {
+ remappedKey = i - 238;
+ }
+ else if (i >= GLFW_KEY_CAPS_LOCK && i <= GLFW_KEY_SCROLL_LOCK)
+ {
+ remappedKey = i - 248;
+ }
+ else if (i >= GLFW_KEY_PRINT_SCREEN && i <= GLFW_KEY_PAUSE)
+ {
+ remappedKey = i - 249;
+ }
+ else if (i >= GLFW_KEY_LEFT_SHIFT && i <= GLFW_KEY_RIGHT_SUPER)
+ {
+ remappedKey = i - 304;
+ }
+ else if (i == GLFW_KEY_MENU)
+ {
+ remappedKey = 99;
+ }
+ else if (i >= GLFW_KEY_F1 && i <= GLFW_KEY_F25)
+ {
+ remappedKey = i - 189;
+ }
+ mapping[i] = remappedKey;
+ }
+ }
+
+ constexpr int Map(int glfwKey) const
+ {
+ if (glfwKey < 0) return -1;
+ return mapping[glfwKey];
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Host/GLFW/InputProviderGLFW.cpp b/openVulkanoCpp/Host/GLFW/InputProviderGLFW.cpp
new file mode 100644
index 0000000..dc4695e
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/InputProviderGLFW.cpp
@@ -0,0 +1,61 @@
+#include "InputProviderGLFW.hpp"
+#include "InputMappingGLFW.hpp"
+#include "../../Input/InputManager.hpp"
+
+namespace openVulkanoCpp
+{
+ namespace GLFW
+ {
+ constexpr KeyboardInputMapping keyboardMapping = KeyboardInputMapping();
+
+ InputProviderGLFW* InputProviderGLFW::INSTANCE = nullptr;
+
+ void InputProviderGLFW::Init()
+ {
+ if (INSTANCE) throw PlatformInitFailedException("An instance of the GLFW input provider has already been initialized!");
+ INSTANCE = this;
+ glfwSetJoystickCallback(&JoystickCallback);
+
+ // register already connected controller
+ for (int i = 0; i < GLFW_JOYSTICK_LAST; i++)
+ {
+ if (glfwJoystickPresent(i) == GLFW_TRUE)
+ {
+ OnJoystickConnect(i);
+ }
+ }
+ mouseButtons = 0;
+
+ keyboard.Init(0, "Keyboard");
+ mouse.Init(0, "Mouse");
+ Input::InputManager::GetInstace()->RegisterInputDevice(&mouse);
+ Input::InputManager::GetInstace()->RegisterInputDevice(&keyboard);
+ }
+
+ void InputProviderGLFW::OnJoystickConnect(int joystickId)
+ {
+ controllers[joystickId].Init(joystickId);
+ Input::InputManager::GetInstace()->RegisterInputDevice(&controllers[joystickId]);
+ }
+
+ void InputProviderGLFW::OnJoystickDisconnect(int joystickId)
+ {
+ Input::InputManager::GetInstace()->UnregisterInputDevice(&controllers[joystickId]);
+
+ controllers[joystickId].Close();
+ }
+
+ void InputProviderGLFW::SetKeyboardKey(IWindow* window, int key, int scanCode, int action, int mods)
+ {
+ if (action == GLFW_REPEAT)
+ {
+ //TODO handle repeat for text inputs
+ }
+ else
+ {
+ keyboard.UpdateKey(static_cast(keyboardMapping.Map(key)), action == GLFW_PRESS);
+ }
+ //TODO handle keyboard notifications
+ }
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Host/GLFW/InputProviderGLFW.hpp b/openVulkanoCpp/Host/GLFW/InputProviderGLFW.hpp
new file mode 100644
index 0000000..3a80443
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/InputProviderGLFW.hpp
@@ -0,0 +1,92 @@
+#pragma once
+#include "../../Base/IInitable.hpp"
+#include "../../Base/ITickable.hpp"
+#include "../../Base/ICloseable.hpp"
+#include "../../Base/IPlatform.hpp"
+#include "InputDeviceGLFW.hpp"
+#include
+#include
+
+namespace openVulkanoCpp
+{
+ namespace GLFW
+ {
+ class WindowGLFW;
+
+ class InputProviderGLFW final : public IInitable, public ITickable, public ICloseable
+ {
+ friend WindowGLFW;
+ static InputProviderGLFW* INSTANCE;
+
+ std::array controllers = {};
+ MouseGLFW mouse;
+ KeyboardGLFW keyboard;
+ uint8_t mouseButtons = 0;
+
+ public:
+ void Init() override;
+
+ void Close() override
+ {
+ glfwSetJoystickCallback(NULL);
+ INSTANCE = nullptr;
+ }
+
+ void PreTick()
+ {
+ mouse.ClearAxes();
+ keyboard.PreTick();
+ }
+
+ void Tick() override
+ {
+ for(ControllerGLFW& controller : controllers)
+ {
+ controller.Tick();
+ }
+ mouse.UpdateButtons(mouseButtons);
+ }
+
+ void SetMouseButton(int button, bool state)
+ {
+ uint8_t bit = 1 << button;
+ if (state)
+ {
+ mouseButtons |= bit;
+ }
+ else
+ {
+ mouseButtons ^= bit;
+ }
+ }
+
+ void SetKeyboardKey(IWindow* window, int key, int scanCode, int action, int mods);
+
+ void MouseEnterExitWindow(IWindow* window)
+ {
+ mouse.UpdateActiveWindow(window);
+ keyboard.UpdateActiveWindow(window);
+ }
+
+ void OnJoystickConnect(int joystickId);
+
+ void OnJoystickDisconnect(int joystickId);
+
+ static void JoystickCallback(int joystickId, int joystickEvent)
+ {
+ if (joystickEvent == GLFW_CONNECTED)
+ {
+ INSTANCE->OnJoystickConnect(joystickId);
+ }
+ else if (joystickEvent == GLFW_DISCONNECTED)
+ {
+ INSTANCE->OnJoystickDisconnect(joystickId);
+ }
+ else
+ {
+ Logger::INPUT->warn("Unknown GLFW joystick event {0} for joystick {1}", joystickEvent, joystickId);
+ }
+ }
+ };
+ }
+}
diff --git a/openVulkanoCpp/Host/GLFW/PlatformGLFW.hpp b/openVulkanoCpp/Host/GLFW/PlatformGLFW.hpp
new file mode 100644
index 0000000..4d035ac
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/PlatformGLFW.hpp
@@ -0,0 +1,63 @@
+#pragma once
+#include "../../Base/IPlatform.hpp"
+#include "WindowGLFW.hpp"
+#include "InputProviderGLFW.hpp"
+#include
+
+namespace openVulkanoCpp
+{
+ namespace GLFW
+ {
+ class PlatformGLFW final : public IPlatform
+ {
+ std::vector windows;
+ InputProviderGLFW inputProvider;
+ bool initialized = false;
+
+ public:
+ PlatformGLFW() = default;
+
+ ~PlatformGLFW() override
+ {
+ if (initialized)
+ {
+ Close();
+ }
+ }
+
+ bool IsInitialized() const { return initialized; }
+
+ void Init() override
+ {
+ if (!glfwInit()) throw PlatformInitFailedException("Failed to initialize glfw");
+ inputProvider.Init();
+ initialized = true;
+ }
+
+ void Tick() override
+ {
+ inputProvider.PreTick();
+ glfwPollEvents();
+ inputProvider.Tick();
+ }
+
+ void Close() override
+ {
+ for(const IWindow* window : windows)
+ {
+ delete window;
+ }
+ windows.clear();
+ inputProvider.Close();
+ glfwTerminate();
+ }
+
+ IWindow* MakeWindow() override
+ {
+ WindowGLFW* window = new WindowGLFW(inputProvider);
+ windows.push_back(window);
+ return window;
+ }
+ };
+ }
+}
diff --git a/openVulkanoCpp/Host/GLFW/WindowGLFW.hpp b/openVulkanoCpp/Host/GLFW/WindowGLFW.hpp
new file mode 100644
index 0000000..492d5c6
--- /dev/null
+++ b/openVulkanoCpp/Host/GLFW/WindowGLFW.hpp
@@ -0,0 +1,456 @@
+#pragma once
+#include
+#include "../../Base/UI/BaseWindow.hpp"
+#include "../../Base/Logger.hpp"
+#include "../../Base/IPlatform.hpp"
+#include "InputProviderGLFW.hpp"
+
+namespace openVulkanoCpp
+{
+ namespace GLFW
+ {
+ class WindowGLFW final : public BaseWindow, virtual public IVulkanWindow, virtual public IOpenGlWindow
+ {
+ private:
+ InputProviderGLFW& inputProvider;
+ GLFWwindow* window = nullptr;
+ IWindowHandler* handler = nullptr;
+
+ public:
+ WindowGLFW(InputProviderGLFW& inputProvider): inputProvider(inputProvider) {}
+
+ virtual ~WindowGLFW() override
+ {
+ if (window != nullptr) Close();
+ }
+
+ protected:
+ GLFWmonitor* GetCurrentMonitor() const
+ {
+ int monitorCount = 0;
+ GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
+ for (int i = 0; i < monitorCount; i++)
+ {
+ int posX, posY, sizeX, sizeY;
+ glfwGetMonitorWorkarea(monitors[i], &posX, &posY, &sizeX, &sizeY);
+ if (windowConfig.posX >= posX && windowConfig.posX < posX + sizeX &&
+ windowConfig.posY >= posY && windowConfig.posY < posY + sizeY)
+ {
+ return monitors[i];
+ }
+ }
+ return nullptr;
+ }
+
+ GLFWmonitor* GetTargetMonitor() const
+ {
+ if (windowConfig.windowMode == FULLSCREEN)
+ {
+ // TODO add config to control used display
+ return GetPrimaryMonitor();
+ }
+ return nullptr;
+ }
+
+ void Create()
+ {
+ glfwWindowHint(GLFW_DECORATED, (~windowConfig.windowMode) & 1);
+ //TODO handle full screen resolutions
+ window = glfwCreateWindow(windowConfig.width, windowConfig.height, windowConfig.title.c_str(), GetTargetMonitor(), nullptr);
+ if (!window) return;
+ glfwSetWindowUserPointer(window, this);
+ RegisterCallbacks();
+ }
+
+ void RegisterCallbacks() const
+ {
+ glfwSetErrorCallback(ErrorCallback);
+
+ glfwSetDropCallback(window, DropCallback);
+ glfwSetFramebufferSizeCallback(window, ResizeCallback);
+ glfwSetWindowFocusCallback(window, FocusCallback);
+ glfwSetWindowRefreshCallback(window, RefreshCallback);
+ glfwSetWindowIconifyCallback(window, MinimizeCallback);
+ glfwSetWindowPosCallback(window, WindowMoveCallback);
+ glfwSetWindowCloseCallback(window, CloseCallback);
+
+ // Input Callbacks
+ glfwSetKeyCallback(window, KeyboardCallback);
+ glfwSetMouseButtonCallback(window, MouseButtonCallback);
+ glfwSetCursorPosCallback(window, MouseMoveCallback);
+ glfwSetScrollCallback(window, MouseScrollCallback);
+ glfwSetCursorEnterCallback(window, MouseEnterExitCallback);
+ //glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
+ //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+ }
+
+ static GLFWmonitor* GetPrimaryMonitor()
+ {
+ return glfwGetPrimaryMonitor();
+ }
+
+ static std::vector GetMonitors()
+ {
+ int count;
+ GLFWmonitor** monitorsArray = glfwGetMonitors(&count);
+ std::vector monitors;
+ monitors.reserve(count);
+ for (int i = 0; i < count; i++)
+ {
+ monitors[i] = monitorsArray[i];
+ }
+ return monitors;
+ }
+
+ public: // IWindow implementation
+ void Init(RenderAPI::RenderApi renderApi) override
+ {
+ if (renderApi == RenderAPI::VULKAN) glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ Create();
+ if (!window)
+ {
+ throw WindowInitFailedException("Failed to initialize window");
+ }
+ if (renderApi != RenderAPI::VULKAN) MakeCurrentThread();
+ Logger::WINDOW->info("GLFW Window created (id: {0})", GetWindowId());
+ }
+
+ void Close() override
+ {
+ glfwDestroyWindow(window);
+ window = nullptr;
+ Logger::WINDOW->info("GLFW Window destroyed (id: {0})", GetWindowId());
+ }
+
+ void Present() const override
+ {
+ glfwSwapBuffers(window);
+ }
+
+ void Show() override
+ {
+ glfwShowWindow(window);
+ }
+
+ void Hide() override
+ {
+ glfwHideWindow(window);
+ }
+
+ void SetTitle(const std::string& title) override
+ {
+ windowConfig.title = title;
+ glfwSetWindowTitle(window, title.c_str());
+ }
+
+ void SetSize(uint32_t width, uint32_t height) override
+ {
+ windowConfig.width = width;
+ windowConfig.height = height;
+ if (window)
+ {
+ glfwSetWindowSize(window, width, height);
+ }
+ }
+
+ void SetPosition(int posX, int posY) override
+ {
+ windowConfig.posX = posX;
+ windowConfig.posY = posY;
+ if (window)
+ {
+ glfwSetWindowPos(window, posX, posY);
+ }
+ }
+
+ void SetSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight) override
+ {
+ minWidth = (minWidth < 0) ? GLFW_DONT_CARE : minWidth;
+ minHeight = (minHeight < 0) ? GLFW_DONT_CARE : minHeight;
+ maxWidth = (maxWidth < 0) ? GLFW_DONT_CARE : maxWidth;
+ maxHeight = (maxHeight < 0) ? GLFW_DONT_CARE : maxHeight;
+ glfwSetWindowSizeLimits(window, minWidth, minHeight, maxWidth, maxHeight);
+ }
+
+ void MakeCurrentThread() override
+ {
+ glfwMakeContextCurrent(window);
+ }
+
+ void SetWindowMode(WindowMode windowMode) override
+ {
+ if (windowMode == this->windowConfig.windowMode) return; // Nothing to change here
+ if (!window) return; // Window not yet created
+ this->windowConfig.windowMode = windowMode;
+ uint32_t sizeX = 0, sizeY = 0;
+ int posX = 0, posY = 0;
+ GLFWmonitor* monitor = nullptr;
+ glfwWindowHint(GLFW_DECORATED, (~windowMode) & 1);
+ if (windowMode == WINDOWED || windowMode == BORDERLESS)
+ {
+ sizeX = windowConfig.width;
+ sizeY = windowConfig.height;
+ posX = windowConfig.posX;
+ posY = windowConfig.posY;
+ monitor = nullptr;
+ if (windowMode == WINDOWED)
+ {
+ Logger::WINDOW->info("Switching to Windowed mode");
+ }
+ else
+ {
+ Logger::WINDOW->info("Switching to Borderless Windowed mode");
+ }
+ }
+ else
+ { // Fullscreen
+ GetPosition(&windowConfig.posX, &windowConfig.posY); // Backup current window position
+ monitor = GetCurrentMonitor();
+ if (!monitor) monitor = GetPrimaryMonitor();
+ if (!monitor) return; // We don't have a monitor to set the fullscreen window to
+ const GLFWvidmode* videoMode = glfwGetVideoMode(monitor ? monitor : GetPrimaryMonitor());
+ sizeX = videoMode->width;
+ sizeY = videoMode->height;
+ if (windowMode == FULLSCREEN)
+ {
+ // TODO find video mode that best matches user settings
+ Logger::WINDOW->info("Switching to Fullscreen mode");
+ }
+ else if (windowMode == BORDERLESS_FULLSCREEN)
+ {
+ int sX, sY;
+ glfwGetMonitorWorkarea(monitor, &posX, &posY, &sX, &sY);
+ monitor = nullptr;
+ Logger::WINDOW->info("Switching to Borderless Fullscreen mode");
+ }
+ }
+ glfwSetWindowMonitor(this->window, monitor, posX, posY, sizeX, sizeY, GLFW_DONT_CARE);
+ }
+
+ void SetWindowHandler(IWindowHandler* handler) override
+ {
+ this->handler = handler;
+ }
+
+ IVulkanWindow* GetVulkanWindow() override
+ {
+ return this;
+ }
+
+ IOpenGlWindow* GetOpenGlWindow() override
+ {
+ return this;
+ }
+
+ // Status getter
+ void GetSize(int* width, int* height) override
+ {
+ glfwGetWindowSize(window, width, height);
+ }
+
+ void GetPosition(int* x, int* y) override
+ {
+ glfwGetWindowPos(window, x, y);
+ }
+
+ IWindowHandler* GetWindowHandler() override
+ {
+ return handler;
+ }
+
+ //IVulkanWindow stuff
+ vk::SurfaceKHR CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator) override
+ {
+ VkSurfaceKHR rawSurface;
+ const auto result = static_cast(glfwCreateWindowSurface(static_cast(instance), window, reinterpret_cast(pAllocator), &rawSurface));
+ return createResultValue(result, rawSurface, "vk::CommandBuffer::begin");
+ }
+
+ std::vector GetRequiredInstanceExtensions() override
+ {
+ return GetVulkanRequiredInstanceExtensions();
+ }
+
+ public: // Window events
+ void OnResize(const uint32_t newWidth, const uint32_t newHeight)
+ {
+ Logger::WINDOW->debug("Window (id: {0}) resized (width: {1}, height: {2})", GetWindowId(), newWidth, newHeight);
+ handler->OnWindowResize(this, newWidth, newHeight);
+ }
+
+ void OnMinimize()
+ {
+ Logger::WINDOW->debug("Window (id: {0}) minimized", GetWindowId());
+ handler->OnWindowMinimize(this);
+ }
+
+ void OnRestore()
+ {
+ Logger::WINDOW->debug("Window (id: {0}) restored", GetWindowId());
+ handler->OnWindowRestore(this);
+ }
+
+ void OnFocusLost()
+ {
+ Logger::WINDOW->debug("Window (id: {0}) focus lost", GetWindowId());
+ handler->OnWindowFocusLost(this);
+ }
+
+ void OnFocusGained()
+ {
+ Logger::WINDOW->debug("Window (id: {0}) focus gained", GetWindowId());
+ handler->OnWindowFocusGained(this);
+ }
+
+ void OnMove(const int posX, const int posY)
+ {
+ Logger::WINDOW->debug("Window (id: {0}) moved (x: {1}, y: {2})", GetWindowId(), posX, posY);
+ if (windowConfig.windowMode == WINDOWED || windowConfig.windowMode == BORDERLESS)
+ { // Don't save window position for fullscreen
+ windowConfig.posX = posX;
+ windowConfig.posY = posY;
+ }
+ handler->OnWindowMove(this, posX, posY);
+ }
+
+ void OnClose()
+ {
+ Logger::WINDOW->debug("Window (id: {0}) closed", GetWindowId());
+ handler->OnWindowClose(this);
+ }
+
+ protected:
+ virtual void OnKeyEvent(int key, int scanCode, int action, int mods)
+ {
+ if (key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT)
+ {
+ WindowMode newMode = FULLSCREEN;
+ switch (windowConfig.windowMode)
+ {
+ case WINDOWED: newMode = FULLSCREEN; break;
+ case BORDERLESS: newMode = BORDERLESS_FULLSCREEN; break;
+ case FULLSCREEN: newMode = WINDOWED; break;
+ case BORDERLESS_FULLSCREEN: newMode = BORDERLESS; break;
+ }
+ SetWindowMode(newMode);
+ }
+ switch (action)
+ {
+ case GLFW_PRESS:// OnKeyPressed(key, mods);
+ Logger::INPUT->info("Key Pressed: {0} Mod: {1} ScanCode: {2}", key, mods, scanCode);
+ break;
+ case GLFW_RELEASE:// OnKeyReleased(key, mods);
+ Logger::INPUT->info("Key Released: {0} Mod: {1} ScanCode: {2}", key, mods, scanCode);
+ break;
+ case GLFW_REPEAT:
+ Logger::INPUT->info("Key Repeat: {0} Mod: {1} ScanCode: {2}", key, mods, scanCode);
+ break;
+
+ default: break;
+ }
+ }
+
+ private: // Callbacks
+ static WindowGLFW* GetWindow(GLFWwindow* window)
+ {
+ return static_cast(glfwGetWindowUserPointer(window));
+ }
+
+ static void KeyboardCallback(GLFWwindow* window, int key, int scanCode, int action, int mods)
+ {
+ GetWindow(window)->OnKeyEvent(key, scanCode, action, mods);
+ const auto windowInstance = GetWindow(window);
+ windowInstance->inputProvider.SetKeyboardKey(windowInstance, key, scanCode, action, mods);
+ }
+
+ static void MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
+ {
+ GetWindow(window)->inputProvider.SetMouseButton(button, action != GLFW_RELEASE);
+ }
+
+ static void MouseMoveCallback(GLFWwindow* window, double posX, double posY)
+ {
+ GetWindow(window)->inputProvider.mouse.UpdatePosition(posX, posY);
+ }
+
+ static void MouseScrollCallback(GLFWwindow* window, double xOffset, double yOffset)
+ {
+ GetWindow(window)->inputProvider.mouse.UpdateWheel(xOffset, yOffset);
+ }
+
+ static void MouseEnterExitCallback(GLFWwindow* window, int entered)
+ {
+ const auto windowInstance = GetWindow(window);
+ windowInstance->inputProvider.MouseEnterExitWindow(windowInstance);
+ Logger::INPUT->info("Mouse enter/exit: {}", entered);
+ }
+
+ static void ResizeCallback(GLFWwindow* window, int width, int height)
+ {
+ GetWindow(window)->OnResize(width, height);
+ }
+
+ static void FocusCallback(GLFWwindow* window, const int focused)
+ {
+ if (focused == GLFW_TRUE)
+ GetWindow(window)->OnFocusGained();
+ else
+ GetWindow(window)->OnFocusLost();
+ }
+
+ static void MinimizeCallback(GLFWwindow* window, const int minimized)
+ {
+ if (minimized == GLFW_TRUE)
+ GetWindow(window)->OnMinimize();
+ else
+ GetWindow(window)->OnRestore();
+ }
+
+ static void RefreshCallback(GLFWwindow* window)
+ {
+ //TODO is there really anything to do? or is it ok if the window is only redrawn on the next frame?
+ }
+
+ static void WindowMoveCallback(GLFWwindow* window, const int posX, const int posY)
+ {
+ GetWindow(window)->OnMove(posX, posY);
+ }
+
+ static void CloseCallback(GLFWwindow* window)
+ {
+ GetWindow(window)->OnClose();
+ }
+
+ static void DropCallback(GLFWwindow* window, const int count, const char** paths)
+ {
+ //TODO something useful
+ }
+
+ static void ErrorCallback(const int error, const char* description)
+ {
+ Logger::WINDOW->error("GLFW error (e{0}): {1}", error, description);
+ }
+
+
+
+
+ public:
+ static std::vector GetVulkanRequiredInstanceExtensions()
+ {
+ std::vector result;
+ uint32_t count = 0;
+ const char** names = glfwGetRequiredInstanceExtensions(&count);
+ if (names && count)
+ {
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ result.emplace_back(names[i]);
+ }
+ }
+ return result;
+ }
+
+
+ };
+ }
+}
diff --git a/openVulkanoCpp/Host/GraphicsAppManager.hpp b/openVulkanoCpp/Host/GraphicsAppManager.hpp
index ad149e0..c3ea2c1 100644
--- a/openVulkanoCpp/Host/GraphicsAppManager.hpp
+++ b/openVulkanoCpp/Host/GraphicsAppManager.hpp
@@ -15,11 +15,12 @@
namespace openVulkanoCpp
{
/**
- * \brief A simple GraphicsAppManager. It can only handle on window.
+ * \brief A simple GraphicsAppManager. It can only handle one window.
*/
- class GraphicsAppManager : virtual public IGraphicsAppManager, virtual public IWindowHandler
+ class GraphicsAppManager final : virtual public IGraphicsAppManager, virtual public IWindowHandler
{
private:
+ IPlatform* platform;
IWindow* window;
IGraphicsApp* app;
IRenderer* renderer;
@@ -27,7 +28,7 @@ namespace openVulkanoCpp
bool paused = false, running = false;
float fpsTimer = 0, avgFps = 0, avgFrameTime = 0;
uint64_t frameCount = 0, lastFrameCount = 0;
- Timer* frameTimer;
+ Timer frameTimer;
std::string windowTitleFormat;
public:
@@ -37,22 +38,21 @@ namespace openVulkanoCpp
Logger::SetupLogger();
if (!app)
{
- const auto msg = "The app must not be null!";
+ constexpr auto msg = "The app must not be null!";
Logger::MANAGER->error(msg);
throw std::runtime_error(msg);
}
- window = PlatformProducer::CreateBestWindow(renderApi);
+ platform = PlatformProducer::CreatePlatform(renderApi);
+ window = platform->MakeWindow();
renderer = PlatformProducer::CreateRenderManager(renderApi);
app->SetGraphicsAppManager(this);
window->SetWindowHandler(this);
- frameTimer = new Timer();
}
~GraphicsAppManager() override
{
delete renderer;
- delete window;
- delete frameTimer;
+ delete platform;
}
public: // Getter
@@ -91,14 +91,14 @@ namespace openVulkanoCpp
void Pause() override
{
paused = true;
- frameTimer->Stop();
+ frameTimer.Stop();
Logger::MANAGER->info("Graphics application paused");
}
void Resume() override
{
paused = false;
- frameTimer->Start();
+ frameTimer.Start();
Logger::MANAGER->info("Graphics application resumed");
}
@@ -107,7 +107,7 @@ namespace openVulkanoCpp
{
running = true;
StartUp();
- frameTimer->Reset();
+ frameTimer.Reset();
Loop(); // Runs the rendering loop
ShutDown();
}
@@ -119,9 +119,10 @@ namespace openVulkanoCpp
{
Logger::MANAGER->info("Initializing ...");
app->Init();
+ platform->Init();
window->Init(renderApi);
//TODO restore window settings if there are any set
- renderer->Init((IGraphicsAppManager*)this, window);
+ renderer->Init(static_cast(this), window);
windowTitleFormat = app->GetAppName() + " " + app->GetAppVersion() + " - " + renderer->GetMainRenderDeviceName() + " - {:.1f} fps ({:.1f} ms)";
Logger::MANAGER->info("Initialized");
}
@@ -139,7 +140,7 @@ namespace openVulkanoCpp
{
while (running)
{
- window->Tick();
+ platform->Tick();
if (paused)
{ // The rendering is paused
// No need to burn cpu time if the app is paused
@@ -149,7 +150,7 @@ namespace openVulkanoCpp
{
app->Tick();
renderer->Tick();
- frameTimer->Tick();
+ frameTimer.Tick();
UpdateFps();
}
}
@@ -160,6 +161,7 @@ namespace openVulkanoCpp
Logger::MANAGER->info("Shutting down ...");
renderer->Close();
window->Close();
+ platform->Close();
app->Close();
Logger::MANAGER->info("Shutdown complete");
}
@@ -167,7 +169,7 @@ namespace openVulkanoCpp
void UpdateFps()
{
frameCount++;
- fpsTimer += frameTimer->GetTickSeconds();
+ fpsTimer += frameTimer.GetTickSeconds();
if(fpsTimer > 1.0f)
{
diff --git a/openVulkanoCpp/Host/PlatformProducer.hpp b/openVulkanoCpp/Host/PlatformProducer.hpp
index 539d6e8..382d549 100644
--- a/openVulkanoCpp/Host/PlatformProducer.hpp
+++ b/openVulkanoCpp/Host/PlatformProducer.hpp
@@ -1,9 +1,10 @@
#pragma once
#include
#include "../Base/Logger.hpp"
-#include "../Vulkan/Renderer.hpp"
#include "../Base/PlatformEnums.hpp"
-#include "WindowGLFW.hpp"
+#include "../Base/IPlatform.hpp"
+#include "../Vulkan/Renderer.hpp"
+#include "GLFW/PlatformGLFW.hpp"
namespace openVulkanoCpp
{
@@ -32,18 +33,18 @@ namespace openVulkanoCpp
}
/**
- * \brief Creates a window that fits best for the current environment
- * \param renderApi The render api that should be used when searching for the best suited window
- * \return The created window. nullptr if no window is supported on the current platform
+ * \brief Creates a platform that fits best for the current environment
+ * \param renderApi The render api that should be used when searching for the best suited platform provider
+ * \return The created platform
* \throws std::runtime_error if the render api is not supported
*/
- static IWindow* CreateBestWindow(RenderAPI::RenderApi renderApi)
- { //TODO add more windows to chose from
- switch(renderApi)
+ static IPlatform* CreatePlatform(RenderAPI::RenderApi renderApi)
+ {
+ switch (renderApi)
{
- case RenderAPI::VULKAN: return new WindowGLFW();
+ case RenderAPI::VULKAN: return new GLFW::PlatformGLFW();
default:
- Logger::RENDER->error("Unsupported render api requested! Requested %d", static_cast(renderApi));
+ Logger::MANAGER->error("Unsupported render api requested! Requested %d", static_cast(renderApi));
throw std::runtime_error("Unsupported render api requested!");
}
}
diff --git a/openVulkanoCpp/Host/WindowGLFW.hpp b/openVulkanoCpp/Host/WindowGLFW.hpp
deleted file mode 100644
index c65d616..0000000
--- a/openVulkanoCpp/Host/WindowGLFW.hpp
+++ /dev/null
@@ -1,456 +0,0 @@
-#pragma once
-#include
-#include "../Base/UI/BaseWindow.hpp"
-#include "../Base/Logger.hpp"
-
-namespace openVulkanoCpp
-{
- class WindowGLFW : public BaseWindow, virtual public IVulkanWindow, virtual public IOpenGlWindow
- {
- private:
- GLFWwindow* window = nullptr;
- IWindowHandler* handler = nullptr;
-
- public:
- WindowGLFW() = default;
-
- virtual ~WindowGLFW() override
- {
- if (window != nullptr) Close();
- }
-
- protected:
- GLFWmonitor* GetCurrentMonitor() const
- {
- int monitorCount = 0;
- GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
- for(int i = 0; i < monitorCount; i++)
- {
- int posX, posY, sizeX, sizeY;
- glfwGetMonitorWorkarea(monitors[i], &posX, &posY, &sizeX, &sizeY);
- if (windowConfig.posX >= posX && windowConfig.posX < posX + sizeX &&
- windowConfig.posY >= posY && windowConfig.posY < posY + sizeY)
- {
- return monitors[i];
- }
- }
- return nullptr;
- }
-
- GLFWmonitor* GetTargetMonitor() const
- {
- if(windowConfig.windowMode == FULLSCREEN)
- {
- // TODO add config to control used display
- return GetPrimaryMonitor();
- }
- return nullptr;
- }
-
- void Create()
- {
- glfwWindowHint(GLFW_DECORATED, (~windowConfig.windowMode) & 1);
- //TODO handle full screen resolutions
- window = glfwCreateWindow(windowConfig.width, windowConfig.height, windowConfig.title.c_str(), GetTargetMonitor(), nullptr);
- if(!window) return;
- glfwSetWindowUserPointer(window, this);
- RegisterCallbacks();
- }
-
- void RegisterCallbacks() const
- {
- glfwSetErrorCallback(ErrorCallback);
-
- glfwSetDropCallback(window, DropCallback);
- glfwSetFramebufferSizeCallback(window, ResizeCallback);
- glfwSetWindowFocusCallback(window, FocusCallback);
- glfwSetWindowRefreshCallback(window, RefreshCallback);
- glfwSetWindowIconifyCallback(window, MinimizeCallback);
- glfwSetWindowPosCallback(window, WindowMoveCallback);
- glfwSetWindowCloseCallback(window, CloseCallback);
-
- // Input Callbacks
- glfwSetKeyCallback(window, KeyboardCallback);
- glfwSetMouseButtonCallback(window, MouseButtonCallback);
- glfwSetCursorPosCallback(window, MouseMoveCallback);
- glfwSetScrollCallback(window, MouseScrollCallback);
- }
-
- static GLFWmonitor* GetPrimaryMonitor()
- {
- return glfwGetPrimaryMonitor();
- }
-
- static std::vector GetMonitors()
- {
- int count;
- GLFWmonitor** monitorsArray = glfwGetMonitors(&count);
- std::vector monitors;
- monitors.reserve(count);
- for (int i = 0; i < count; i++)
- {
- monitors[i] = monitorsArray[i];
- }
- return monitors;
- }
-
- public: // IWindow implementation
- void Init(RenderAPI::RenderApi renderApi) override
- {
- if (!glfwInit()) throw WindowInitFailedException("Failed to initialize glfw");
- if(renderApi == RenderAPI::VULKAN) glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- Create();
- if(!window)
- {
- glfwTerminate();
- throw WindowInitFailedException("Failed to initialize window");
- }
- if (renderApi != RenderAPI::VULKAN) MakeCurrentThread();
- Logger::WINDOW->info("GLFW Window created (id: {0})", GetWindowId());
- }
-
- void Close() override
- {
- glfwDestroyWindow(window);
- window = nullptr;
- glfwTerminate();
- Logger::WINDOW->info("GLFW Window destroyed (id: {0})", GetWindowId());
- }
-
- void Present() const override
- {
- glfwSwapBuffers(window);
- }
-
- void Show() override
- {
- glfwShowWindow(window);
- }
-
- void Hide() override
- {
- glfwHideWindow(window);
- }
-
- void Tick() override
- {
- glfwPollEvents();
- }
-
- void SetTitle(const std::string& title) override
- {
- windowConfig.title = title;
- glfwSetWindowTitle(window, title.c_str());
- }
-
- void SetSize(uint32_t width, uint32_t height) override
- {
- windowConfig.width = width;
- windowConfig.height = height;
- if (window)
- {
- glfwSetWindowSize(window, width, height);
- }
- }
-
- void SetPosition(int posX, int posY) override
- {
- windowConfig.posX = posX;
- windowConfig.posY = posY;
- if(window)
- {
- glfwSetWindowPos(window, posX, posY);
- }
- }
-
- void SetSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight) override
- {
- minWidth = (minWidth < 0) ? GLFW_DONT_CARE : minWidth;
- minHeight = (minHeight < 0) ? GLFW_DONT_CARE : minHeight;
- maxWidth = (maxWidth < 0) ? GLFW_DONT_CARE : maxWidth;
- maxHeight = (maxHeight < 0) ? GLFW_DONT_CARE : maxHeight;
- glfwSetWindowSizeLimits(window, minWidth, minHeight, maxWidth, maxHeight);
- }
-
- void MakeCurrentThread() override
- {
- glfwMakeContextCurrent(window);
- }
-
- void SetWindowMode(WindowMode windowMode) override
- {
- if (windowMode == this->windowConfig.windowMode) return; // Nothing to change here
- if (!window) return; // Window not yet created
- this->windowConfig.windowMode = windowMode;
- uint32_t sizeX = 0, sizeY = 0;
- int posX = 0, posY = 0;
- GLFWmonitor* monitor = nullptr;
- glfwWindowHint(GLFW_DECORATED, (~windowMode) & 1);
- if(windowMode == WINDOWED || windowMode == BORDERLESS)
- {
- sizeX = windowConfig.width;
- sizeY = windowConfig.height;
- posX = windowConfig.posX;
- posY = windowConfig.posY;
- monitor = nullptr;
- if(windowMode == WINDOWED)
- {
- Logger::WINDOW->info("Switching to Windowed mode");
- }
- else
- {
- Logger::WINDOW->info("Switching to Borderless Windowed mode");
- }
- }
- else
- { // Fullscreen
- GetPosition(&windowConfig.posX, &windowConfig.posY); // Backup current window position
- monitor = GetCurrentMonitor();
- if (!monitor) monitor = GetPrimaryMonitor();
- if (!monitor) return; // We don't have a monitor to set the fullscreen window to
- const GLFWvidmode* videoMode = glfwGetVideoMode(monitor ? monitor : GetPrimaryMonitor());
- sizeX = videoMode->width;
- sizeY = videoMode->height;
- if (windowMode == FULLSCREEN)
- {
- // TODO find video mode that best matches user settings
- Logger::WINDOW->info("Switching to Fullscreen mode");
- }
- else if (windowMode == BORDERLESS_FULLSCREEN)
- {
- int sX, sY;
- glfwGetMonitorWorkarea(monitor, &posX, &posY, &sX, &sY);
- monitor = nullptr;
- Logger::WINDOW->info("Switching to Borderless Fullscreen mode");
- }
- }
- glfwSetWindowMonitor(this->window, monitor, posX, posY, sizeX, sizeY, GLFW_DONT_CARE);
- }
-
- void SetWindowHandler(IWindowHandler* handler) override
- {
- this->handler = handler;
- }
-
- IVulkanWindow* GetVulkanWindow() override
- {
- return this;
- }
-
- IOpenGlWindow* GetOpenGlWindow() override
- {
- return this;
- }
-
- // Status getter
- void GetSize(int* width, int* height) override
- {
- glfwGetWindowSize(window, width, height);
- }
-
- void GetPosition(int* x, int* y) override
- {
- glfwGetWindowPos(window, x, y);
- }
-
- IWindowHandler* GetWindowHandler() override
- {
- return handler;
- }
-
- //IVulkanWindow stuff
- vk::SurfaceKHR CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator) override
- {
- VkSurfaceKHR rawSurface;
- const auto result = static_cast(glfwCreateWindowSurface(static_cast(instance), window, reinterpret_cast(pAllocator), &rawSurface));
- return createResultValue(result, rawSurface, "vk::CommandBuffer::begin");
- }
-
- std::vector GetRequiredInstanceExtensions() override
- {
- return GetVulkanRequiredInstanceExtensions();
- }
-
- public: // Window events
- void OnResize(const uint32_t newWidth, const uint32_t newHeight)
- {
- Logger::WINDOW->debug("Window (id: {0}) resized (width: {1}, height: {2})", GetWindowId(), newWidth, newHeight);
- handler->OnWindowResize(this, newWidth, newHeight);
- }
-
- void OnMinimize()
- {
- Logger::WINDOW->debug("Window (id: {0}) minimized", GetWindowId());
- handler->OnWindowMinimize(this);
- }
-
- void OnRestore()
- {
- Logger::WINDOW->debug("Window (id: {0}) restored", GetWindowId());
- handler->OnWindowRestore(this);
- }
-
- void OnFocusLost()
- {
- Logger::WINDOW->debug("Window (id: {0}) focus lost", GetWindowId());
- handler->OnWindowFocusLost(this);
- }
-
- void OnFocusGained()
- {
- Logger::WINDOW->debug("Window (id: {0}) focus gained", GetWindowId());
- handler->OnWindowFocusGained(this);
- }
-
- void OnMove(const int posX, const int posY)
- {
- Logger::WINDOW->debug("Window (id: {0}) moved (x: {1}, y: {2})", GetWindowId(), posX, posY);
- if (windowConfig.windowMode == WINDOWED || windowConfig.windowMode == BORDERLESS)
- { // Don't save window position for fullscreen
- windowConfig.posX = posX;
- windowConfig.posY = posY;
- }
- handler->OnWindowMove(this, posX, posY);
- }
-
- void OnClose()
- {
- Logger::WINDOW->debug("Window (id: {0}) closed", GetWindowId());
- handler->OnWindowClose(this);
- }
-
- public: // Input events TODO
- virtual void OnKeyPressed(int key, int mods) {}
- virtual void OnKeyReleased(int key, int mods) {}
- virtual void OnMousePressed(int button, int mods) {}
- virtual void OnMouseReleased(int button, int mods) {}
- virtual void OnMouseMoved(double posX, double posY) {}
- virtual void OnMouseScrolled(double delta) {}
-
- protected:
- virtual void OnKeyEvent(int key, int scanCode, int action, int mods)
- {
- if (key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT)
- {
- WindowMode newMode = FULLSCREEN;
- switch (windowConfig.windowMode)
- {
- case WINDOWED: newMode = FULLSCREEN; break;
- case BORDERLESS: newMode = BORDERLESS_FULLSCREEN; break;
- case FULLSCREEN: newMode = WINDOWED; break;
- case BORDERLESS_FULLSCREEN: newMode = BORDERLESS; break;
- }
- SetWindowMode(newMode);
- }
- switch (action)
- {
- case GLFW_PRESS: OnKeyPressed(key, mods); break;
- case GLFW_RELEASE: OnKeyReleased(key, mods); break;
- default: break;
- }
- }
-
- virtual void OnMouseButtonEvent(int button, int action, int mods)
- {
- switch (action)
- {
- case GLFW_PRESS: OnMousePressed(button, mods); break;
- case GLFW_RELEASE: OnMouseReleased(button, mods); break;
- default: break;
- }
- }
-
- private: // Callbacks
- static WindowGLFW* GetWindow(GLFWwindow* window)
- {
- return static_cast(glfwGetWindowUserPointer(window));
- }
-
- static void KeyboardCallback(GLFWwindow* window, int key, int scanCode, int action, int mods)
- {
- GetWindow(window)->OnKeyEvent(key, scanCode, action, mods);
- }
-
- static void MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
- {
- GetWindow(window)->OnMouseButtonEvent(button, action, mods);
- }
-
- static void MouseMoveCallback(GLFWwindow* window, double posX, double posY)
- {
- GetWindow(window)->OnMouseMoved(posX, posY);
- }
-
- static void MouseScrollCallback(GLFWwindow* window, double xOffset, double yOffset)
- {
- GetWindow(window)->OnMouseScrolled(yOffset);
- }
-
- static void ResizeCallback(GLFWwindow* window, int width, int height)
- {
- GetWindow(window)->OnResize(width, height);
- }
-
- static void FocusCallback(GLFWwindow* window, const int focused)
- {
- if (focused == GLFW_TRUE)
- GetWindow(window)->OnFocusGained();
- else
- GetWindow(window)->OnFocusLost();
- }
-
- static void MinimizeCallback(GLFWwindow* window, const int minimized)
- {
- if(minimized == GLFW_TRUE)
- GetWindow(window)->OnMinimize();
- else
- GetWindow(window)->OnRestore();
- }
-
- static void RefreshCallback(GLFWwindow* window)
- {
- //TODO is there really anything to do? or is it ok if the window is only redrawn on the next frame?
- }
-
- static void WindowMoveCallback(GLFWwindow* window, const int posX, const int posY)
- {
- GetWindow(window)->OnMove(posX, posY);
- }
-
- static void CloseCallback(GLFWwindow* window)
- {
- GetWindow(window)->OnClose();
- }
-
- static void DropCallback(GLFWwindow* window, const int count, const char** paths)
- {
- //TODO something useful
- }
-
- static void ErrorCallback(const int error, const char* description)
- {
- Logger::WINDOW->error("GLFW error (e{0}): {1}", error, description);
- }
-
-
-
-
- public:
- static std::vector GetVulkanRequiredInstanceExtensions()
- {
- std::vector result;
- uint32_t count = 0;
- const char** names = glfwGetRequiredInstanceExtensions(&count);
- if (names && count)
- {
- for (uint32_t i = 0; i < count; ++i)
- {
- result.emplace_back(names[i]);
- }
- }
- return result;
- }
-
-
- };
-}
diff --git a/openVulkanoCpp/Input/InputDevice.hpp b/openVulkanoCpp/Input/InputDevice.hpp
new file mode 100644
index 0000000..0e4d7f6
--- /dev/null
+++ b/openVulkanoCpp/Input/InputDevice.hpp
@@ -0,0 +1,103 @@
+#pragma once
+#include "../Base/ICloseable.hpp"
+#include "InputKey.hpp"
+
+namespace openVulkanoCpp
+{
+ namespace Input
+ {
+ class InputDevice : public ICloseable
+ {
+ InputDeviceType deviceType = InputDeviceType::UNKNOWN;
+ int index = -1;
+ std::string name;
+ float axisAsButtonThreshold = 0.5f;
+ float buttonAsAxisValue = 1.0f;
+
+ protected:
+ InputDevice() = default;
+
+ void Init(InputDeviceType type, int index, const std::string& name)
+ {
+ this->deviceType = type;
+ this->index = index;
+ this->name = name;
+ }
+
+ virtual float ReadAxis(int16_t key) const = 0;
+
+ virtual bool ReadButton(int16_t key) const = 0;
+
+ virtual bool ReadButtonUp(int16_t key) const = 0;
+
+ virtual bool ReadButtonDown(int16_t key) const = 0;
+
+ public:
+ virtual ~InputDevice() = default;
+
+ virtual void Close() override
+ {
+ this->deviceType = InputDeviceType::UNKNOWN;
+ this->index = -1;
+ this->name = "";
+ }
+
+ InputDeviceType GetType() const { return deviceType; }
+ int GetIndex() const { return index; }
+ const std::string& GetName() const { return name; }
+
+ float GetAxisAsButtonThreshold() const { return axisAsButtonThreshold; }
+ void SetAxisAsButtonThreshold(float value) { axisAsButtonThreshold = value; }
+
+ float GetButtonAsAxisValue() const { return buttonAsAxisValue; }
+ void SetButtonAsAxisValue(float value) { buttonAsAxisValue = value; }
+
+ bool GetButton(InputKey key) const
+ {
+ if (key.GetInputDeviceType() != deviceType) return false;
+ if (key.GetInputType() == InputKey::InputType::AXIS)
+ {
+ return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
+ }
+ return ReadButton(key.GetInputKey());
+ }
+
+ bool GetButtonUp(InputKey key) const
+ {
+ if (key.GetInputDeviceType() != deviceType) return false;
+ if (key.GetInputType() == InputKey::InputType::AXIS)
+ {
+ //TODO handle
+ return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
+ }
+ return ReadButtonUp(key.GetInputKey());
+ }
+
+ bool GetButtonDown(InputKey key) const
+ {
+ if (key.GetInputDeviceType() != deviceType) return false;
+ if (key.GetInputType() == InputKey::InputType::AXIS)
+ {
+ //TODO handle
+ return ReadAxis(key.GetInputKey()) > axisAsButtonThreshold;
+ }
+ return ReadButtonDown(key.GetInputKey());
+ }
+
+ float GetAxis(InputKey key) const
+ {
+ if (key.GetInputDeviceType() != deviceType) return 0;
+ if (key.GetInputType() == InputKey::InputType::BUTTON)
+ {
+ return ReadButton(key.GetInputKey()) ? buttonAsAxisValue : 0;
+ }
+ return ReadAxis(key.GetInputKey());
+ }
+
+ float GetAxis(InputKey keyPositive, InputKey keyNegative) const
+ {
+ return GetAxis(keyPositive) - GetAxis(keyNegative);
+ }
+ };
+ }
+}
diff --git a/openVulkanoCpp/Input/InputDeviceController.hpp b/openVulkanoCpp/Input/InputDeviceController.hpp
new file mode 100644
index 0000000..332e1d8
--- /dev/null
+++ b/openVulkanoCpp/Input/InputDeviceController.hpp
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "../Base/Logger.hpp"
+#include "InputDevice.hpp"
+#include
+
+namespace openVulkanoCpp
+{
+ namespace Input
+ {
+ class ControllerType
+ {
+ public:
+ enum Type { GENERIC_JOYSTICK, XBOX, DUAL_SHOCK, DUAL_SENSE };
+
+ private:
+ Type type;
+
+ public:
+ ControllerType(Type type) : type(type) {}
+ };
+
+ class InputDeviceController : public InputDevice
+ {
+ float axes[InputKey::Controller::Axis::AXIS_LAST + 1] = {0};
+ uint32_t pressedButtons = 0, lastPressedButtons = 0;
+ const ControllerType controllerType = ControllerType::GENERIC_JOYSTICK;
+
+ bool GetLastButton(InputKey::Controller::Button button) const
+ {
+ return lastPressedButtons & (1 << button);
+ }
+
+ protected:
+ InputDeviceController() = default;
+
+ void Init(const int index, const std::string& name)
+ {
+ InputDevice::Init(InputDeviceType::CONTROLLER, index, name);
+
+ pressedButtons = 0;
+ lastPressedButtons = 0;
+ for(float& axis : axes)
+ {
+ axis = 0;
+ }
+
+ // TODO find controller type from name
+ Logger::INPUT->info("Initialized controller: id: {0}, name: {1}", index, name);
+ }
+
+ void SetAxis(InputKey::Controller::Axis axisId, float value)
+ {
+ axes[axisId] = value;
+ }
+
+ void SetButtons(uint32_t buttonStates)
+ {
+ lastPressedButtons = pressedButtons;
+ pressedButtons = buttonStates;
+ }
+
+ float ReadAxis(int16_t key) const override final
+ {
+ return GetAxis(static_cast(key));
+ }
+
+ bool ReadButton(int16_t key) const override final
+ {
+ return GetButton(static_cast(key));
+ }
+
+ bool ReadButtonUp(int16_t key) const override final
+ {
+ return GetButtonUp(static_cast(key));
+ }
+
+ bool ReadButtonDown(int16_t key) const override final
+ {
+ return GetButtonDown(static_cast(key));
+ }
+
+ public:
+ bool GetButton(const InputKey::Controller::Button button) const
+ {
+ return pressedButtons & (1 << button);
+ }
+
+ bool GetButtonUp(const InputKey::Controller::Button button) const
+ {
+ return !GetButton(button) && GetLastButton(button);
+ }
+
+ bool GetButtonDown(const InputKey::Controller::Button button) const
+ {
+ return GetButton(button) && !GetLastButton(button);
+ }
+
+ float GetAxis(const InputKey::Controller::Axis axis) const
+ {
+ return axes[axis];
+ }
+
+ ControllerType GetControllerType() const
+ {
+ return controllerType;
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Input/InputDeviceKeyboard.hpp b/openVulkanoCpp/Input/InputDeviceKeyboard.hpp
new file mode 100644
index 0000000..34d3652
--- /dev/null
+++ b/openVulkanoCpp/Input/InputDeviceKeyboard.hpp
@@ -0,0 +1,87 @@
+#pragma once
+#include "InputDevice.hpp"
+#include
+
+namespace openVulkanoCpp
+{
+ class IWindow;
+
+ namespace Input
+ {
+ class InputDeviceKeyboard : public InputDevice
+ {
+ std::bitset keyState;
+ std::bitset lastKeyState;
+ IWindow* lastWindow;
+
+ protected:
+ InputDeviceKeyboard() = default;
+
+ void Init(int index, const std::string& name)
+ {
+ InputDevice::Init(InputDeviceType::KEYBOARD, index, name);
+ }
+
+ void PreTick()
+ {
+ lastKeyState = keyState;
+ }
+
+ void UpdateKey(InputKey::Keyboard::Key key, bool state)
+ {
+ keyState[key] = state;
+ }
+
+ void UpdateActiveWindow(IWindow* window)
+ {
+ lastWindow = window;
+ }
+
+ float ReadAxis(int16_t key) const override final
+ {
+ return 0;
+ }
+
+ bool ReadButton(int16_t key) const override final
+ {
+ return GetButton(static_cast(key));
+ }
+
+ bool ReadButtonUp(int16_t key) const override final
+ {
+ return GetButtonUp(static_cast(key));
+ }
+
+ bool ReadButtonDown(int16_t key) const override final
+ {
+ return GetButtonDown(static_cast(key));
+ }
+
+ public:
+ bool GetButton(const InputKey::Keyboard::Key button) const
+ {
+ return keyState[button] > 0;
+ }
+
+ bool GetButtonUp(const InputKey::Keyboard::Key button) const
+ {
+ return !keyState[button] && lastKeyState[button];
+ }
+
+ bool GetButtonDown(const InputKey::Keyboard::Key button) const
+ {
+ return keyState[button] && !lastKeyState[button];
+ }
+
+ IWindow* GetActiveWindow() const
+ {
+ return lastWindow;
+ }
+
+ bool IsInWindow(const IWindow* window) const
+ {
+ return window == lastWindow;
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Input/InputDeviceMouse.hpp b/openVulkanoCpp/Input/InputDeviceMouse.hpp
new file mode 100644
index 0000000..64b464d
--- /dev/null
+++ b/openVulkanoCpp/Input/InputDeviceMouse.hpp
@@ -0,0 +1,180 @@
+#pragma once
+#include "InputDevice.hpp"
+#include "../Base/Logger.hpp"
+
+namespace openVulkanoCpp
+{
+ class IWindow;
+
+ namespace Input
+ {
+ class InputDeviceMouse : public InputDevice
+ {
+ float axes[InputKey::Mouse::Axis::AXIS_LAST + 2] = { 0 };
+ uint8_t pressedButtons = 0, lastPressedButtons = 0;
+ double mousePosX = 0, mousePosY = 0;
+ IWindow* lastWindow = nullptr;
+
+ protected:
+ InputDeviceMouse() = default;
+
+ void Init(const int index, const std::string& name)
+ {
+ InputDevice::Init(InputDeviceType::MOUSE, index, name);
+
+ ClearAxes();
+ pressedButtons = 0;
+ lastPressedButtons = 0;
+ mousePosX = 0;
+ mousePosY = 0;
+ lastWindow = nullptr;
+ }
+
+ void UpdateButtons(uint8_t newPressedButtons)
+ {
+ lastPressedButtons = pressedButtons;
+ pressedButtons = newPressedButtons;
+ if (lastPressedButtons != pressedButtons)
+ Logger::INPUT->info("Mouse button state changed {0:08b}", pressedButtons);
+ }
+
+ void UpdatePosition(double posX, double posY)
+ {
+ axes[InputKey::Mouse::AXIS_X] = static_cast(posX - mousePosX);
+ axes[InputKey::Mouse::AXIS_Y] = static_cast(posY - mousePosY);
+ mousePosX = posX;
+ mousePosY = posY;
+ Logger::INPUT->info("Mouse moved posX: {0} posY: {1}, relativeX: {2}, relativeY: {3}", posX, posY, axes[InputKey::Mouse::AXIS_X], axes[InputKey::Mouse::AXIS_Y]);
+ }
+
+ void UpdateWheel(float wheelX, float wheelY)
+ {
+ axes[InputKey::Mouse::AXIS_WHEEL_X] = wheelX;
+ axes[InputKey::Mouse::AXIS_WHEEL_Y] = wheelY;
+ Logger::INPUT->info("Mouse scrolled x: {0} y: {1}", wheelX, wheelY);
+ }
+
+ void UpdateActiveWindow(IWindow* window)
+ {
+ axes[InputKey::Mouse::AXIS_X] = 0;
+ axes[InputKey::Mouse::AXIS_Y] = 0;
+ lastWindow = window;
+ }
+
+ void ClearAxes()
+ {
+ for (float& axis : axes)
+ {
+ axis = 0;
+ }
+ }
+
+ private:
+ bool GetLastButton(InputKey::Mouse::Button button) const
+ {
+ return lastPressedButtons & (1 << button);
+ }
+
+ protected:
+ float ReadAxis(int16_t key) const override final
+ {
+ return GetAxis(static_cast(key));
+ }
+
+ bool ReadButton(int16_t key) const override final
+ {
+ return GetButton(static_cast(key));
+ }
+
+ bool ReadButtonUp(int16_t key) const override final
+ {
+ return GetButtonUp(static_cast(key));
+ }
+
+ bool ReadButtonDown(int16_t key) const override final
+ {
+ return GetButtonDown(static_cast(key));
+ }
+
+ public:
+ bool GetButton(const InputKey::Mouse::Button button) const
+ {
+ return pressedButtons & (1 << button);
+ }
+
+ bool GetButtonUp(const InputKey::Mouse::Button button) const
+ {
+ return !GetButton(button) && GetLastButton(button);
+ }
+
+ bool GetButtonDown(const InputKey::Mouse::Button button) const
+ {
+ return GetButton(button) && !GetLastButton(button);
+ }
+
+ float GetAxis(const InputKey::Mouse::Axis axis) const
+ {
+ return axes[axis];
+ }
+
+ float GetWheel() const
+ {
+ return GetAxis(InputKey::Mouse::Axis::AXIS_WHEEL_Y);
+ }
+
+ float GetWheelX() const
+ {
+ return GetAxis(InputKey::Mouse::Axis::AXIS_WHEEL_X);
+ }
+
+ float GetWheelY() const
+ {
+ return GetAxis(InputKey::Mouse::Axis::AXIS_WHEEL_Y);
+ }
+
+ glm::vec2 GetMousePosition() const
+ {
+ return { mousePosX, mousePosY };
+ }
+
+ void GetMousePosition(double& posX, double& posY) const
+ {
+ posX = mousePosX;
+ posY = mousePosY;
+ }
+
+ glm::vec2 GetMousePosition(const IWindow* window) const
+ {
+ if (window == lastWindow)
+ {
+ return { mousePosX, mousePosY };
+ }
+ return { std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN() };
+ }
+
+ void GetMousePosition(const IWindow* window, double& posX, double& posY) const
+ {
+ if (window == lastWindow)
+ {
+ posX = mousePosX;
+ posY = mousePosY;
+ }
+ else
+ {
+ posX = std::numeric_limits::quiet_NaN();
+ posY = std::numeric_limits::quiet_NaN();
+ }
+ }
+
+ IWindow* GetActiveWindow() const
+ {
+ return lastWindow;
+ }
+
+ bool IsInWindow(const IWindow* window) const
+ {
+ return window == lastWindow;
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Input/InputDeviceType.hpp b/openVulkanoCpp/Input/InputDeviceType.hpp
new file mode 100644
index 0000000..d2f8bd6
--- /dev/null
+++ b/openVulkanoCpp/Input/InputDeviceType.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+#include
+
+namespace openVulkanoCpp
+{
+ namespace Input
+ {
+ enum class InputDeviceType : uint8_t
+ {
+ UNKNOWN, KEYBOARD, MOUSE, CONTROLLER
+ };
+ }
+}
\ No newline at end of file
diff --git a/openVulkanoCpp/Input/InputKey.hpp b/openVulkanoCpp/Input/InputKey.hpp
new file mode 100644
index 0000000..713bf66
--- /dev/null
+++ b/openVulkanoCpp/Input/InputKey.hpp
@@ -0,0 +1,273 @@
+#pragma once
+#include "InputDeviceType.hpp"
+
+namespace openVulkanoCpp
+{
+ namespace Input
+ {
+ class InputKey
+ {
+ public:
+ enum class InputType : uint8_t
+ {
+ BUTTON = 0, AXIS
+ };
+
+ class Keyboard
+ {
+ public:
+ enum Key : int16_t
+ {
+ UNKNOWN = -1,
+ // Numpad
+ KEY_NUMPAD_0 = 0,
+ KEY_NUMPAD_1 = 1,
+ KEY_NUMPAD_2 = 2,
+ KEY_NUMPAD_3 = 3,
+ KEY_NUMPAD_4 = 4,
+ KEY_NUMPAD_5 = 5,
+ KEY_NUMPAD_6 = 6,
+ KEY_NUMPAD_7 = 7,
+ KEY_NUMPAD_8 = 8,
+ KEY_NUMPAD_9 = 9,
+ KEY_NUMPAD_DECIMAL = 10,
+ KEY_NUMPAD_DIVIDE = 11,
+ KEY_NUMPAD_MULTIPLY = 12,
+ KEY_NUMPAD_SUBTRACT = 13,
+ KEY_NUMPAD_ADD = 14,
+ KEY_NUMPAD_ENTER = 15,
+ KEY_NUMPAD_EQUAL = 16,
+ KEY_NUM_LOCK = 17,
+
+ KEY_ESCAPE = 18,
+ KEY_ENTER = 19,
+ KEY_TAB = 20,
+ KEY_BACKSPACE = 21,
+ KEY_INSERT = 22,
+ KEY_DELETE = 23,
+ KEY_RIGHT = 24,
+ KEY_LEFT = 25,
+ KEY_DOWN = 26,
+ KEY_UP = 27,
+ KEY_PAGE_UP = 28,
+ KEY_PAGE_DOWN = 29,
+ KEY_HOME = 30,
+ KEY_END = 31,
+ KEY_CAPS_LOCK = 32,
+ KEY_SCROLL_LOCK = 33,
+ KEY_PRINT_SCREEN = 34,
+ KEY_PAUSE = 35,
+ KEY_LEFT_SHIFT = 36,
+ KEY_LEFT_CONTROL = 37,
+ KEY_LEFT_ALT = 38,
+ KEY_LEFT_SUPER = 39,
+ KEY_RIGHT_SHIFT = 40,
+ KEY_RIGHT_CONTROL = 41,
+ KEY_RIGHT_ALT = 42,
+ KEY_RIGHT_SUPER = 43,
+
+ // Printable keys, most of them are mapped to their ascii codes
+ KEY_COMMA = 44,
+ KEY_MINUS = 45,
+ KEY_PERIOD = 46,
+ KEY_SLASH = 47,
+ KEY_0 = 48,
+ KEY_1 = 49,
+ KEY_2 = 50,
+ KEY_3 = 51,
+ KEY_4 = 52,
+ KEY_5 = 53,
+ KEY_6 = 54,
+ KEY_7 = 55,
+ KEY_8 = 56,
+ KEY_9 = 57,
+ KEY_WORLD_1 = 58,
+ KEY_SEMICOLON = 59,
+ KEY_WORLD_2 = 60,
+ KEY_EQUAL = 61,
+ KEY_SPACE = 62,
+ KEY_APOSTROPHE = 63, //'
+ KEY_GRAVE_ACCENT = 64, // `
+ KEY_A = 65,
+ KEY_B = 66,
+ KEY_C = 67,
+ KEY_D = 68,
+ KEY_E = 69,
+ KEY_F = 70,
+ KEY_G = 71,
+ KEY_H = 72,
+ KEY_I = 73,
+ KEY_J = 74,
+ KEY_K = 75,
+ KEY_L = 76,
+ KEY_M = 77,
+ KEY_N = 78,
+ KEY_O = 79,
+ KEY_P = 80,
+ KEY_Q = 81,
+ KEY_R = 82,
+ KEY_S = 83,
+ KEY_T = 84,
+ KEY_U = 85,
+ KEY_V = 86,
+ KEY_W = 87,
+ KEY_X = 88,
+ KEY_Y = 89,
+ KEY_Z = 90,
+ KEY_LEFT_BRACKET = 91, // [
+ KEY_BACKSLASH = 92,
+ KEY_RIGHT_BRACKET = 93, // ]
+
+ KEY_MENU = 99,
+
+ // Function keys
+ KEY_F1 = 101,
+ KEY_F2 = 102,
+ KEY_F3 = 103,
+ KEY_F4 = 104,
+ KEY_F5 = 105,
+ KEY_F6 = 106,
+ KEY_F7 = 107,
+ KEY_F8 = 108,
+ KEY_F9 = 109,
+ KEY_F10 = 110,
+ KEY_F11 = 111,
+ KEY_F12 = 112,
+ KEY_F13 = 113,
+ KEY_F14 = 114,
+ KEY_F15 = 115,
+ KEY_F16 = 116,
+ KEY_F17 = 117,
+ KEY_F18 = 118,
+ KEY_F19 = 119,
+ KEY_F20 = 120,
+ KEY_F21 = 121,
+ KEY_F22 = 122,
+ KEY_F23 = 123,
+ KEY_F24 = 124,
+ KEY_F25 = 125,
+
+ KEY_LAST = KEY_F25
+ };
+ };
+
+ class Mouse
+ {
+ public:
+ enum Button : int16_t
+ {
+ BUTTON_1 = 0,
+ BUTTON_2,
+ BUTTON_3,
+ BUTTON_4,
+ BUTTON_5,
+ BUTTON_6,
+ BUTTON_7,
+ BUTTON_8,
+ BUTTON_LAST = BUTTON_8,
+ BUTTON_LEFT = BUTTON_1,
+ BUTTON_RIGHT = BUTTON_2,
+ BUTTON_MIDDLE = BUTTON_3
+ };
+
+ enum Axis : int16_t
+ {
+ AXIS_X = 0,
+ AXIS_Y,
+ AXIS_WHEEL_X,
+ AXIS_WHEEL_Y,
+ AXIS_LAST = AXIS_WHEEL_Y
+ };
+ };
+
+ class Controller
+ {
+ public:
+ enum Button : int16_t
+ {
+ JOY_1 = 0,
+ JOY_2,
+ JOY_3,
+ JOY_4,
+ JOY_5,
+ JOY_6,
+ JOY_7,
+ JOY_8,
+ JOY_9,
+ JOY_10,
+ JOY_11,
+ JOY_12,
+ JOY_13,
+ JOY_14,
+ JOY_15,
+ JOY_16,
+ JOY_LAST = JOY_16,
+
+ BUTTON_A = JOY_1,
+ BUTTON_B = JOY_2,
+ BUTTON_X = JOY_3,
+ BUTTON_Y = JOY_4,
+ BUTTON_LEFT_BUMPER = JOY_5,
+ BUTTON_RIGHT_BUMPER = JOY_6,
+ BUTTON_BACK = JOY_7,
+ BUTTON_START = JOY_8,
+ BUTTON_GUIDE = JOY_9,
+ BUTTON_LEFT_THUMB = JOY_10,
+ BUTTON_RIGHT_THUMB = JOY_11,
+ BUTTON_DPAD_UP = JOY_12,
+ BUTTON_DPAD_RIGHT = JOY_13,
+ BUTTON_DPAD_DOWN = JOY_14,
+ BUTTON_DPAD_LEFT = JOY_15,
+
+ PS_BUTTON_CROSS = BUTTON_A,
+ PS_BUTTON_CIRCLE = BUTTON_B,
+ PS_BUTTON_SQUARE = BUTTON_X,
+ PS_BUTTON_TRIANGLE = BUTTON_Y
+ };
+
+ enum Axis : int16_t
+ {
+ AXIS_LEFT_X = 0,
+ AXIS_LEFT_Y,
+ AXIS_RIGHT_X,
+ AXIS_RIGHT_Y,
+ AXIS_LEFT_TRIGGER,
+ AXIS_RIGHT_TRIGGER,
+ AXIS_LAST = AXIS_RIGHT_TRIGGER
+ };
+ };
+
+ private:
+ InputDeviceType deviceType;
+ InputType type;
+ int16_t key;
+
+ public:
+ InputKey(Keyboard::Key keyboardKey) :
+ deviceType(InputDeviceType::KEYBOARD), type(InputType::BUTTON), key(keyboardKey)
+ {}
+
+ InputKey(Mouse::Button mouseButton) :
+ deviceType(InputDeviceType::MOUSE), type(InputType::BUTTON), key(mouseButton)
+ {}
+
+ InputKey(Mouse::Axis mouseAxis) :
+ deviceType(InputDeviceType::MOUSE), type(InputType::AXIS), key(mouseAxis)
+ {}
+
+ InputKey(Controller::Button controllerButton) :
+ deviceType(InputDeviceType::CONTROLLER), type(InputType::BUTTON), key(controllerButton)
+ {}
+
+ InputKey(Controller::Axis controllerAxis) :
+ deviceType(InputDeviceType::CONTROLLER), type(InputType::AXIS), key(controllerAxis)
+ {}
+
+ InputDeviceType GetInputDeviceType() const { return deviceType; }
+
+ InputType GetInputType() const { return type; }
+
+ int16_t GetInputKey() const { return key; }
+ };
+ }
+}
diff --git a/openVulkanoCpp/Input/InputManager.hpp b/openVulkanoCpp/Input/InputManager.hpp
new file mode 100644
index 0000000..8bf08ba
--- /dev/null
+++ b/openVulkanoCpp/Input/InputManager.hpp
@@ -0,0 +1,182 @@
+#pragma once
+
+#include "InputKey.hpp"
+#include "InputDevice.hpp"
+#include "../Base/Utils.hpp"
+
+#include
+#include
+#include
+
+namespace openVulkanoCpp
+{
+ namespace Input
+ {
+ class BaseInputAction
+ {
+ std::string name;
+ std::vector devices;
+ bool enabled;
+
+ protected:
+ BaseInputAction(const std::string& name) : name(name), enabled(true) {}
+
+ public:
+ virtual ~BaseInputAction() = default;
+
+ const std::string& GetName() const
+ {
+ return name;
+ }
+
+ const std::vector& GetDevices() const
+ {
+ return devices;
+ }
+
+ bool IsEnabled() const
+ {
+ return enabled;
+ }
+
+ void SetEnabled(bool enabled)
+ {
+ this->enabled = enabled;
+ }
+ };
+
+ class InputAction : public BaseInputAction
+ {
+ std::vector keys;
+ std::vector> axisButtons;
+
+ public:
+ InputAction(const std::string& name) : BaseInputAction(name)
+ {}
+
+ const std::vector& GetKeys() const
+ {
+ return keys;
+ }
+
+ const std::vector>& GetAxisButtons() const
+ {
+ return axisButtons;
+ }
+
+ void BindKey(InputKey key)
+ {
+ keys.push_back(key);
+ }
+
+ void BindAxisButtons(InputKey keyPositive, InputKey keyNegative)
+ {
+ axisButtons.emplace_back(keyPositive, keyNegative);
+ }
+ };
+
+ class InputShortcut : public BaseInputAction
+ {
+ std::string name;
+ std::vector devices;
+ std::vector> buttonBindings;
+
+ public:
+ InputShortcut(const std::string& name) : BaseInputAction(name)
+ {}
+ };
+
+ class InputManager
+ {
+ InputManager() = default;
+ public:
+ static InputManager* GetInstace()
+ {
+ static InputManager* instance = new InputManager();
+ return instance;
+ }
+
+ void RegisterInputDevice(InputDevice* device)
+ {
+ devices.push_back(device);
+ if (!lastActiveDevice) lastActiveDevice = device;
+ }
+
+ void UnregisterInputDevice(InputDevice* device)
+ {
+ Utils::Remove(devices, device);
+ }
+
+ InputAction* GetAction(const std::string& actionName)
+ {
+ InputAction*& action = actionNameMapping[actionName];
+ if(!action)
+ {
+ action = new InputAction(actionName);
+ }
+ return action;
+ }
+
+ float GetAxis(const InputAction* action) const
+ {
+ float value = 0;
+ const std::vector& testDevices = action->GetDevices().empty() ? devices : action->GetDevices();
+ for (const InputDevice* device : testDevices)
+ {
+ for(InputKey key : action->GetKeys())
+ {
+ value += device->GetAxis(key);
+ }
+ for(const auto& keys : action->GetAxisButtons())
+ {
+ value += GetAxis(keys.first) - GetAxis(keys.second);
+ }
+ }
+ return value;
+ }
+
+ float GetAxis(InputKey key) const
+ {
+ float value = 0;
+ for (const InputDevice* device : devices)
+ {
+ value += device->GetAxis(key);
+ }
+ return value;
+ }
+
+ bool GetButton(InputAction* action) const
+ {
+ const std::vector& testDevices = action->GetDevices().empty() ? devices : action->GetDevices();
+ for (const InputDevice* device : testDevices)
+ {
+ for (const InputKey key : action->GetKeys())
+ {
+ if (device->GetButton(key)) return true;
+ }
+ }
+ return false;
+ }
+
+ bool GetButton(InputKey key) const
+ {
+ for(const InputDevice* device : devices)
+ {
+ if (device->GetButton(key)) return true;
+ }
+ return false;
+ }
+
+ InputDevice* GetLastActiveDevice() const
+ {
+ return lastActiveDevice;
+ }
+
+ private:
+ //std::unordered_map> inputActionMapping;
+ std::unordered_map actionNameMapping;
+ std::vector devices;
+ InputDevice* lastActiveDevice = nullptr;
+ };
+ }
+}
diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp
index e695f1c..d159454 100644
--- a/openVulkanoCpp/Scene/Camera.hpp
+++ b/openVulkanoCpp/Scene/Camera.hpp
@@ -3,6 +3,7 @@
#include
#include
#include "Node.hpp"
+#define GLM_FORECE_DEPTH_ZERO_TO_ONE
namespace openVulkanoCpp
{
@@ -17,7 +18,7 @@ namespace openVulkanoCpp
glm::mat4x4 projection, view, viewProjection;
Camera() = default;
- virtual ~Camera() = default;
+ virtual ~Camera() override = default;
public:
void Init(float width, float height, float nearPlane, float farPlane)
diff --git a/openVulkanoCpp/Scene/Geometry.hpp b/openVulkanoCpp/Scene/Geometry.hpp
index 9020f2f..968f108 100644
--- a/openVulkanoCpp/Scene/Geometry.hpp
+++ b/openVulkanoCpp/Scene/Geometry.hpp
@@ -131,7 +131,7 @@ namespace openVulkanoCpp
20, 21, 22, 20, 22, 23 // right face index data
}, indexCount);
x *= 0.5f; y *= 0.5f; z *= 0.5f;
- int i = 0;
+ uint32_t i = 0;
// front face vertex data
vertices[i++].Set(-x, +y, -z, +0, +0, -1, +0, +0);
vertices[i++].Set(-x, -y, -z, +0, +0, -1, +0, +1);
diff --git a/openVulkanoCpp/Vulkan/RenderPass.hpp b/openVulkanoCpp/Vulkan/RenderPass.hpp
index 7003f71..10e6423 100644
--- a/openVulkanoCpp/Vulkan/RenderPass.hpp
+++ b/openVulkanoCpp/Vulkan/RenderPass.hpp
@@ -35,6 +35,7 @@ namespace openVulkanoCpp
CreateRenderPass();
frameBuffer->InitRenderPass(this);
SetClearColor();
+ SetClearDepth();
}
void Close() override
diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp
index 2d7395c..46de025 100644
--- a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp
+++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp
@@ -63,7 +63,8 @@ namespace openVulkanoCpp
vk::PipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.cullMode = vk::CullModeFlagBits::eBack;
vk::PipelineMultisampleStateCreateInfo msaa = {};
- vk::PipelineDepthStencilStateCreateInfo depth = { {}, 1, 1, vk::CompareOp::eGreater };
+ vk::PipelineDepthStencilStateCreateInfo depth = { {}, 1, 1, vk::CompareOp::eLess };
+ depth.maxDepthBounds = 1;
vk::PipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eA | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eR;
vk::PipelineColorBlendStateCreateInfo colorInfo = {};
@@ -74,7 +75,7 @@ namespace openVulkanoCpp
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfos.size()), shaderStageCreateInfos.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly,
nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass };
- pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value;
+ pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo);
}
diff --git a/openVulkanoCpp/main.cpp b/openVulkanoCpp/main.cpp
index ebfbdf3..d23a6d2 100644
--- a/openVulkanoCpp/main.cpp
+++ b/openVulkanoCpp/main.cpp
@@ -2,8 +2,13 @@
#include "Scene/Scene.hpp"
#include "Scene/Shader.hpp"
#include "Base/EngineConfiguration.hpp"
+#include "Input/InputManager.hpp"
+
+#include
+#include
using namespace openVulkanoCpp::Scene;
+using namespace openVulkanoCpp::Input;
uint32_t GEOS = 3000, OBJECTS = 10000, DYNAMIC = 1000;
@@ -16,6 +21,11 @@ class ExampleApp : public openVulkanoCpp::IGraphicsApp
std::vector drawablesPool;
std::vector nodesPool;
+ InputAction* actionForward;
+ InputAction* actionSide;
+ InputAction* actionLookUp;
+ InputAction* actionLookSide;
+
public:
std::string GetAppName() override { return "ExampleApp"; }
std::string GetAppVersion() override { return "v1.0"; }
@@ -51,14 +61,55 @@ public:
scene.shader = &shader;
GetGraphicsAppManager()->GetRenderer()->SetScene(&scene);
+
+ auto input = InputManager::GetInstace();
+ actionForward = input->GetAction("forward");
+ actionSide = input->GetAction("side");
+ actionLookUp = input->GetAction("look up");
+ actionLookSide = input->GetAction("look side");
+
+ actionForward->BindKey(InputKey(InputKey::Controller::AXIS_LEFT_Y));
+ actionForward->BindAxisButtons(InputKey(InputKey::Keyboard::KEY_S), InputKey(InputKey::Keyboard::KEY_W));
+ actionSide->BindKey(InputKey(InputKey::Controller::AXIS_LEFT_X));
+ actionSide->BindAxisButtons(InputKey(InputKey::Keyboard::KEY_D), InputKey(InputKey::Keyboard::KEY_A));
+ actionLookUp->BindKey(InputKey(InputKey::Controller::AXIS_RIGHT_Y));
+ actionLookSide->BindKey(InputKey(InputKey::Controller::AXIS_RIGHT_X));
+ actionLookUp->BindAxisButtons(InputKey(InputKey::Keyboard::KEY_DOWN), InputKey(InputKey::Keyboard::KEY_UP));
+ actionLookSide->BindAxisButtons(InputKey(InputKey::Keyboard::KEY_RIGHT), InputKey(InputKey::Keyboard::KEY_LEFT));
+ actionLookUp->BindKey(InputKey(InputKey::Mouse::AXIS_Y));
+ actionLookSide->BindKey(InputKey(InputKey::Mouse::AXIS_X));
}
+ float yaw = 0, pitch = 0;
+ glm::vec3 position = {0,0,10};
+
void Tick() override
{
for(int i = 0; i < DYNAMIC; i++)
{
nodesPool[i]->SetMatrix(glm::translate(glm::mat4x4(1), glm::vec3((std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5)));
}
+
+ auto input = InputManager::GetInstace();
+ glm::vec3 vec(input->GetAxis(actionSide), 0, -input->GetAxis(actionForward));
+ if(glm::length2(vec) > 1)
+ {
+ vec = glm::normalize(vec);
+ }
+
+ float tiemScale = 0.004f;
+
+ vec = vec * tiemScale; // scale vector
+
+ yaw += input->GetAxis(actionLookSide) * tiemScale * 0.5f;
+ pitch += input->GetAxis(actionLookUp) * tiemScale * 0.5f;
+
+ glm::quat rot(glm::vec3(pitch, yaw, 0));
+ glm::mat4 rotMat = glm::toMat4(rot);
+
+ vec = glm::vec3(rot * glm::vec4(vec, 1));
+ position += vec;
+ cam.SetMatrix(glm::translate(glm::mat4(1), position) * rotMat);
}
void Close() override{}
diff --git a/openVulkanoCpp/openVulkanoCpp.vcxproj b/openVulkanoCpp/openVulkanoCpp.vcxproj
index 2299cf0..c4d7e1d 100644
--- a/openVulkanoCpp/openVulkanoCpp.vcxproj
+++ b/openVulkanoCpp/openVulkanoCpp.vcxproj
@@ -51,6 +51,7 @@
$(VULKAN_SDK)\Include;$(SolutionDir)\external\spdlog\include;C:\Program Files\Assimp\include
true
_MBCS;%(PreprocessorDefinitions);DEBUG
+ stdcpp17
Console
@@ -98,6 +99,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"
+
@@ -110,6 +112,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"
+
@@ -120,6 +123,17 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"
+
+
+
+
+
+
+
+
+
+
+
@@ -129,7 +143,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"
-
+