Add basic input system

This commit is contained in:
2020-05-16 00:56:22 +02:00
parent 3e3cbad9c4
commit fc529b0694
29 changed files with 1926 additions and 493 deletions

View File

@@ -1,6 +1,5 @@
#pragma once
#include <algorithm>
#include <functional>
#include <memory>
#include <mutex>

View 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;
};
}

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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";
}

View File

@@ -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;

View 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
}
}
};
}

View 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];
}
};
}
}

View 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
}
}
}

View 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);
}
}
};
}
}

View 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;
}
};
}
}

View 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;
}
};
}
}

View File

@@ -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)
{

View File

@@ -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!");
}
}

View File

@@ -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;
}
};
}

View 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);
}
};
}
}

View 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;
}
};
}
}

View 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;
}
};
}
}

View 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;
}
};
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include <string>
namespace openVulkanoCpp
{
namespace Input
{
enum class InputDeviceType : uint8_t
{
UNKNOWN, KEYBOARD, MOUSE, CONTROLLER
};
}
}

View 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; }
};
}
}

View 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;
};
}
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -35,6 +35,7 @@ namespace openVulkanoCpp
CreateRenderPass();
frameBuffer->InitRenderPass(this);
SetClearColor();
SetClearDepth();
}
void Close() override

View File

@@ -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);
}

View File

@@ -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{}

View File

@@ -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" />