Add basic input system
This commit is contained in:
@@ -4,11 +4,15 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020methods/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020public_0020fields/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Enum_0020members/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Global_0020functions/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Local_0020variables/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Namespaces/@EntryIndexedValue"><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></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Parameters/@EntryIndexedValue"><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></s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=AABB/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=BORDERLESS/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=gamepad/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=GLFW/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=SPDLOG/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unregister/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vulkan/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vulkano/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
21
openVulkanoCpp/Base/IPlatform.hpp
Normal file
21
openVulkanoCpp/Base/IPlatform.hpp
Normal file
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -10,4 +10,5 @@ namespace openVulkanoCpp
|
||||
std::shared_ptr<spdlog::logger> Logger::AUDIO = nullptr;
|
||||
std::shared_ptr<spdlog::logger> Logger::DATA = nullptr;
|
||||
std::shared_ptr<spdlog::logger> Logger::SCENE = nullptr;
|
||||
std::shared_ptr<spdlog::logger> Logger::INPUT = nullptr;
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace openVulkanoCpp
|
||||
static std::shared_ptr<spdlog::logger> AUDIO;
|
||||
static std::shared_ptr<spdlog::logger> DATA;
|
||||
static std::shared_ptr<spdlog::logger> SCENE;
|
||||
static std::shared_ptr<spdlog::logger> 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));
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#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;
|
||||
|
||||
76
openVulkanoCpp/Host/GLFW/InputDeviceGLFW.hpp
Normal file
76
openVulkanoCpp/Host/GLFW/InputDeviceGLFW.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Base/ITickable.hpp"
|
||||
#include "../../Input/InputDeviceKeyboard.hpp"
|
||||
#include "../../Input/InputDeviceMouse.hpp"
|
||||
#include "../../Input/InputDeviceController.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
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<Input::InputKey::Controller::Axis>(i), state.axes[i]);
|
||||
}
|
||||
|
||||
uint32_t buttonStates = 0;
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
buttonStates |= static_cast<uint32_t>(state.buttons[i] != 0) << i;
|
||||
}
|
||||
SetButtons(buttonStates);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Joysticks currently are not supported
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
93
openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp
Normal file
93
openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include "../../Input/InputKey.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
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];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
61
openVulkanoCpp/Host/GLFW/InputProviderGLFW.cpp
Normal file
61
openVulkanoCpp/Host/GLFW/InputProviderGLFW.cpp
Normal file
@@ -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<Input::InputKey::Keyboard::Key>(keyboardMapping.Map(key)), action == GLFW_PRESS);
|
||||
}
|
||||
//TODO handle keyboard notifications
|
||||
}
|
||||
}
|
||||
}
|
||||
92
openVulkanoCpp/Host/GLFW/InputProviderGLFW.hpp
Normal file
92
openVulkanoCpp/Host/GLFW/InputProviderGLFW.hpp
Normal file
@@ -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 <GLFW/glfw3.h>
|
||||
#include <array>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace GLFW
|
||||
{
|
||||
class WindowGLFW;
|
||||
|
||||
class InputProviderGLFW final : public IInitable, public ITickable, public ICloseable
|
||||
{
|
||||
friend WindowGLFW;
|
||||
static InputProviderGLFW* INSTANCE;
|
||||
|
||||
std::array<ControllerGLFW, GLFW_JOYSTICK_LAST> 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
63
openVulkanoCpp/Host/GLFW/PlatformGLFW.hpp
Normal file
63
openVulkanoCpp/Host/GLFW/PlatformGLFW.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include "../../Base/IPlatform.hpp"
|
||||
#include "WindowGLFW.hpp"
|
||||
#include "InputProviderGLFW.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace GLFW
|
||||
{
|
||||
class PlatformGLFW final : public IPlatform
|
||||
{
|
||||
std::vector<WindowGLFW*> 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
456
openVulkanoCpp/Host/GLFW/WindowGLFW.hpp
Normal file
456
openVulkanoCpp/Host/GLFW/WindowGLFW.hpp
Normal file
@@ -0,0 +1,456 @@
|
||||
#pragma once
|
||||
#include <GLFW/glfw3.h>
|
||||
#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<GLFWmonitor*> GetMonitors()
|
||||
{
|
||||
int count;
|
||||
GLFWmonitor** monitorsArray = glfwGetMonitors(&count);
|
||||
std::vector<GLFWmonitor*> 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<vk::Result>(glfwCreateWindowSurface(static_cast<VkInstance>(instance), window, reinterpret_cast<const VkAllocationCallbacks*>(pAllocator), &rawSurface));
|
||||
return createResultValue(result, rawSurface, "vk::CommandBuffer::begin");
|
||||
}
|
||||
|
||||
std::vector<std::string> 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<WindowGLFW*>(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<std::string> GetVulkanRequiredInstanceExtensions()
|
||||
{
|
||||
std::vector<std::string> 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;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<IGraphicsAppManager*>(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)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#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<int>(renderApi));
|
||||
Logger::MANAGER->error("Unsupported render api requested! Requested %d", static_cast<int>(renderApi));
|
||||
throw std::runtime_error("Unsupported render api requested!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
#pragma once
|
||||
#include <GLFW/glfw3.h>
|
||||
#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<GLFWmonitor*> GetMonitors()
|
||||
{
|
||||
int count;
|
||||
GLFWmonitor** monitorsArray = glfwGetMonitors(&count);
|
||||
std::vector<GLFWmonitor*> 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<vk::Result>(glfwCreateWindowSurface(static_cast<VkInstance>(instance), window, reinterpret_cast<const VkAllocationCallbacks*>(pAllocator), &rawSurface));
|
||||
return createResultValue(result, rawSurface, "vk::CommandBuffer::begin");
|
||||
}
|
||||
|
||||
std::vector<std::string> 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<WindowGLFW*>(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<std::string> GetVulkanRequiredInstanceExtensions()
|
||||
{
|
||||
std::vector<std::string> 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;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
103
openVulkanoCpp/Input/InputDevice.hpp
Normal file
103
openVulkanoCpp/Input/InputDevice.hpp
Normal file
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
110
openVulkanoCpp/Input/InputDeviceController.hpp
Normal file
110
openVulkanoCpp/Input/InputDeviceController.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Base/Logger.hpp"
|
||||
#include "InputDevice.hpp"
|
||||
#include <cstring>
|
||||
|
||||
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<InputKey::Controller::Axis>(key));
|
||||
}
|
||||
|
||||
bool ReadButton(int16_t key) const override final
|
||||
{
|
||||
return GetButton(static_cast<InputKey::Controller::Button>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonUp(int16_t key) const override final
|
||||
{
|
||||
return GetButtonUp(static_cast<InputKey::Controller::Button>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonDown(int16_t key) const override final
|
||||
{
|
||||
return GetButtonDown(static_cast<InputKey::Controller::Button>(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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
87
openVulkanoCpp/Input/InputDeviceKeyboard.hpp
Normal file
87
openVulkanoCpp/Input/InputDeviceKeyboard.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include "InputDevice.hpp"
|
||||
#include <bitset>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
class IWindow;
|
||||
|
||||
namespace Input
|
||||
{
|
||||
class InputDeviceKeyboard : public InputDevice
|
||||
{
|
||||
std::bitset<InputKey::Keyboard::KEY_LAST + 1> keyState;
|
||||
std::bitset<InputKey::Keyboard::KEY_LAST + 1> 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<InputKey::Keyboard::Key>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonUp(int16_t key) const override final
|
||||
{
|
||||
return GetButtonUp(static_cast<InputKey::Keyboard::Key>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonDown(int16_t key) const override final
|
||||
{
|
||||
return GetButtonDown(static_cast<InputKey::Keyboard::Key>(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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
180
openVulkanoCpp/Input/InputDeviceMouse.hpp
Normal file
180
openVulkanoCpp/Input/InputDeviceMouse.hpp
Normal file
@@ -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<float>(posX - mousePosX);
|
||||
axes[InputKey::Mouse::AXIS_Y] = static_cast<float>(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<InputKey::Mouse::Axis>(key));
|
||||
}
|
||||
|
||||
bool ReadButton(int16_t key) const override final
|
||||
{
|
||||
return GetButton(static_cast<InputKey::Mouse::Button>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonUp(int16_t key) const override final
|
||||
{
|
||||
return GetButtonUp(static_cast<InputKey::Mouse::Button>(key));
|
||||
}
|
||||
|
||||
bool ReadButtonDown(int16_t key) const override final
|
||||
{
|
||||
return GetButtonDown(static_cast<InputKey::Mouse::Button>(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<float>::quiet_NaN(), std::numeric_limits<float>::quiet_NaN() };
|
||||
}
|
||||
|
||||
void GetMousePosition(const IWindow* window, double& posX, double& posY) const
|
||||
{
|
||||
if (window == lastWindow)
|
||||
{
|
||||
posX = mousePosX;
|
||||
posY = mousePosY;
|
||||
}
|
||||
else
|
||||
{
|
||||
posX = std::numeric_limits<double>::quiet_NaN();
|
||||
posY = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
|
||||
IWindow* GetActiveWindow() const
|
||||
{
|
||||
return lastWindow;
|
||||
}
|
||||
|
||||
bool IsInWindow(const IWindow* window) const
|
||||
{
|
||||
return window == lastWindow;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
14
openVulkanoCpp/Input/InputDeviceType.hpp
Normal file
14
openVulkanoCpp/Input/InputDeviceType.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Input
|
||||
{
|
||||
enum class InputDeviceType : uint8_t
|
||||
{
|
||||
UNKNOWN, KEYBOARD, MOUSE, CONTROLLER
|
||||
};
|
||||
}
|
||||
}
|
||||
273
openVulkanoCpp/Input/InputKey.hpp
Normal file
273
openVulkanoCpp/Input/InputKey.hpp
Normal file
@@ -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; }
|
||||
};
|
||||
}
|
||||
}
|
||||
182
openVulkanoCpp/Input/InputManager.hpp
Normal file
182
openVulkanoCpp/Input/InputManager.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputKey.hpp"
|
||||
#include "InputDevice.hpp"
|
||||
#include "../Base/Utils.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
namespace Input
|
||||
{
|
||||
class BaseInputAction
|
||||
{
|
||||
std::string name;
|
||||
std::vector<InputDevice*> 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<InputDevice*>& GetDevices() const
|
||||
{
|
||||
return devices;
|
||||
}
|
||||
|
||||
bool IsEnabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void SetEnabled(bool enabled)
|
||||
{
|
||||
this->enabled = enabled;
|
||||
}
|
||||
};
|
||||
|
||||
class InputAction : public BaseInputAction
|
||||
{
|
||||
std::vector<InputKey> keys;
|
||||
std::vector<std::pair<InputKey, InputKey>> axisButtons;
|
||||
|
||||
public:
|
||||
InputAction(const std::string& name) : BaseInputAction(name)
|
||||
{}
|
||||
|
||||
const std::vector<InputKey>& GetKeys() const
|
||||
{
|
||||
return keys;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<InputKey, InputKey>>& 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<InputDevice*> devices;
|
||||
std::vector<std::vector<InputKey>> 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<InputDevice*>& 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<InputDevice*>& 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<InputKey, std::vector<InputAction*>> inputActionMapping;
|
||||
std::unordered_map<std::string, InputAction*> actionNameMapping;
|
||||
std::vector<InputDevice*> devices;
|
||||
InputDevice* lastActiveDevice = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace openVulkanoCpp
|
||||
CreateRenderPass();
|
||||
frameBuffer->InitRenderPass(this);
|
||||
SetClearColor();
|
||||
SetClearDepth();
|
||||
}
|
||||
|
||||
void Close() override
|
||||
|
||||
@@ -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<uint32_t>(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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
#include "Scene/Scene.hpp"
|
||||
#include "Scene/Shader.hpp"
|
||||
#include "Base/EngineConfiguration.hpp"
|
||||
#include "Input/InputManager.hpp"
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
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<Drawable*> drawablesPool;
|
||||
std::vector<Node*> 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{}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
<AdditionalIncludeDirectories>$(VULKAN_SDK)\Include;$(SolutionDir)\external\spdlog\include;C:\Program Files\Assimp\include</AdditionalIncludeDirectories>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);DEBUG</PreprocessorDefinitions>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -98,6 +99,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"</Command>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Base\Logger.cpp" />
|
||||
<ClCompile Include="Host\GLFW\InputProviderGLFW.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="Scene\Drawable.cpp" />
|
||||
<ClCompile Include="Scene\Node.cpp" />
|
||||
@@ -110,6 +112,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"</Command>
|
||||
<ClInclude Include="Base\IGraphicsApp.hpp" />
|
||||
<ClInclude Include="Base\IGraphicsAppManager.hpp" />
|
||||
<ClInclude Include="Base\IInitable.hpp" />
|
||||
<ClInclude Include="Base\IPlatform.hpp" />
|
||||
<ClInclude Include="Base\Logger.hpp" />
|
||||
<ClInclude Include="Base\PlatformEnums.hpp" />
|
||||
<ClInclude Include="Base\ITickable.hpp" />
|
||||
@@ -120,6 +123,17 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"</Command>
|
||||
<ClInclude Include="Base\Utils.hpp" />
|
||||
<ClInclude Include="Data\ReadOnlyAtomicArrayQueue.hpp" />
|
||||
<ClInclude Include="Base\EngineConfiguration.hpp" />
|
||||
<ClInclude Include="Host\GLFW\InputDeviceGLFW.hpp" />
|
||||
<ClInclude Include="Host\GLFW\InputMappingGLFW.hpp" />
|
||||
<ClInclude Include="Host\GLFW\InputProviderGLFW.hpp" />
|
||||
<ClInclude Include="Host\GLFW\PlatformGLFW.hpp" />
|
||||
<ClInclude Include="Input\InputDevice.hpp" />
|
||||
<ClInclude Include="Input\InputDeviceController.hpp" />
|
||||
<ClInclude Include="Input\InputDeviceKeyboard.hpp" />
|
||||
<ClInclude Include="Input\InputDeviceMouse.hpp" />
|
||||
<ClInclude Include="Input\InputDeviceType.hpp" />
|
||||
<ClInclude Include="Input\InputKey.hpp" />
|
||||
<ClInclude Include="Input\InputManager.hpp" />
|
||||
<ClInclude Include="Scene\AABB.hpp" />
|
||||
<ClInclude Include="Scene\Drawable.hpp" />
|
||||
<ClInclude Include="Scene\Material.hpp" />
|
||||
@@ -129,7 +143,7 @@ xcopy /y "$(ProjectDir)Shader\*.spv" "$(OutDir)\Shader\"</Command>
|
||||
<ClInclude Include="Scene\Vertex.hpp" />
|
||||
<ClInclude Include="Host\GraphicsAppManager.hpp" />
|
||||
<ClInclude Include="Host\PlatformProducer.hpp" />
|
||||
<ClInclude Include="Host\WindowGLFW.hpp" />
|
||||
<ClInclude Include="Host\GLFW\WindowGLFW.hpp" />
|
||||
<ClInclude Include="Vulkan\Buffer.hpp" />
|
||||
<ClInclude Include="Vulkan\CommandHelper.hpp" />
|
||||
<ClInclude Include="Vulkan\Context.hpp" />
|
||||
|
||||
Reference in New Issue
Block a user