parent
dda4ec2fe5
commit
95527a5a55
10 changed files with 225 additions and 14 deletions
@ -0,0 +1,28 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <glm/mat4x4.hpp> |
||||||
|
#include <glm/gtc/quaternion.hpp> |
||||||
|
#include <vulkan/vulkan_core.h> |
||||||
|
#include "input.hpp" |
||||||
|
|
||||||
|
class Camera : private MouseListener { |
||||||
|
private: |
||||||
|
glm::vec3 position {0, 0, 0}; |
||||||
|
|
||||||
|
float phi = 0; |
||||||
|
float theta = 0; |
||||||
|
|
||||||
|
float fov = 45; |
||||||
|
float near = 0.1; |
||||||
|
float far = 100; |
||||||
|
|
||||||
|
VkExtent2D& extent; |
||||||
|
public: |
||||||
|
explicit Camera(VkExtent2D& extent); |
||||||
|
void update(float dt); |
||||||
|
glm::mat4 view() const; |
||||||
|
glm::mat4 projection() const; |
||||||
|
glm::vec3 localToWorld(const glm::vec3& direction) const; |
||||||
|
protected: |
||||||
|
void mouseMoved(float deltaX, float deltaY) override; |
||||||
|
}; |
@ -0,0 +1,44 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <GLFW/glfw3.h> |
||||||
|
#include <map> |
||||||
|
#include <set> |
||||||
|
|
||||||
|
class Listener; |
||||||
|
class MouseListener; |
||||||
|
|
||||||
|
class Input { |
||||||
|
friend Listener; |
||||||
|
friend MouseListener; |
||||||
|
public: |
||||||
|
explicit Input(GLFWwindow* window); |
||||||
|
static Input* instance; |
||||||
|
static std::map<int, bool> KeyIsDown; |
||||||
|
static std::map<int, bool> MouseButtonIsDown; |
||||||
|
private: |
||||||
|
GLFWwindow* window; |
||||||
|
std::set<Listener*> listeners; |
||||||
|
|
||||||
|
void keyPressed(int key); |
||||||
|
void keyReleased(int key); |
||||||
|
|
||||||
|
void mouseButtonPressed(int button); |
||||||
|
void mouseButtonReleased(int button); |
||||||
|
void mouseMoved(double newX, double newY); |
||||||
|
double oldX {}, oldY {}; |
||||||
|
}; |
||||||
|
|
||||||
|
class Listener { |
||||||
|
public: |
||||||
|
Listener(); |
||||||
|
virtual ~Listener(); |
||||||
|
}; |
||||||
|
|
||||||
|
class KeyListener : Listener { |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
class MouseListener : public Listener { |
||||||
|
public: |
||||||
|
virtual void mouseMoved(float deltaX, float deltaY) {}; |
||||||
|
}; |
@ -0,0 +1,60 @@ |
|||||||
|
#include "camera.hpp" |
||||||
|
#include "application.hpp" |
||||||
|
#include "vulkan/instance.hpp" |
||||||
|
#include "input.hpp" |
||||||
|
#include <glm/gtc/matrix_transform.hpp> |
||||||
|
|
||||||
|
const std::map<int, glm::vec3> moveDirections { |
||||||
|
{GLFW_KEY_A, {-1, 0, 0}}, |
||||||
|
{GLFW_KEY_D, {1, 0, 0}}, |
||||||
|
{GLFW_KEY_S, {0, 0, 1}}, |
||||||
|
{GLFW_KEY_W, {0, 0, -1}}, |
||||||
|
{GLFW_KEY_E, {0, 1, 0}}, |
||||||
|
{GLFW_KEY_Q, {0, -1, 0}}, |
||||||
|
}; |
||||||
|
|
||||||
|
void Camera::update(float dt) { |
||||||
|
glm::vec3 add {}; |
||||||
|
|
||||||
|
for (const auto &[key, dir] : moveDirections) |
||||||
|
if (Input::KeyIsDown[key]) |
||||||
|
add += dir; |
||||||
|
|
||||||
|
position += localToWorld(add) * dt; |
||||||
|
} |
||||||
|
|
||||||
|
glm::mat4 Camera::view() const { |
||||||
|
glm::vec3 forward = localToWorld({0, 0, -1}); |
||||||
|
return glm::lookAt(position, position + forward, glm::vec3(0, 1, 0)); |
||||||
|
} |
||||||
|
|
||||||
|
glm::mat4 Camera::projection() const { |
||||||
|
float aspect = static_cast<float>(extent.width) / static_cast<float>(extent.height); |
||||||
|
return glm::perspective(glm::radians(fov), aspect, near, far); |
||||||
|
} |
||||||
|
|
||||||
|
glm::vec3 Camera::localToWorld(const glm::vec3& direction) const { |
||||||
|
float x = glm::sin(phi) * glm::cos(theta); |
||||||
|
float y = glm::sin(theta); |
||||||
|
float z = -glm::cos(phi) * glm::cos(theta); |
||||||
|
glm::vec3 forward {x, y, z}; |
||||||
|
glm::qua rotation = glm::quatLookAt(forward, glm::vec3(0, 1, 0)); |
||||||
|
return rotation * direction; |
||||||
|
} |
||||||
|
|
||||||
|
Camera::Camera(VkExtent2D &extent) : extent(extent) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void Camera::mouseMoved(float deltaX, float deltaY) { |
||||||
|
if (!Input::MouseButtonIsDown[GLFW_MOUSE_BUTTON_RIGHT]) |
||||||
|
return; |
||||||
|
|
||||||
|
const float div = 300; |
||||||
|
|
||||||
|
phi += deltaX / div; |
||||||
|
theta += -deltaY / div; |
||||||
|
|
||||||
|
float margin = 0.1; |
||||||
|
theta = glm::clamp(theta, -glm::half_pi<float>() + margin, glm::half_pi<float>() - margin); |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
#include "input.hpp" |
||||||
|
|
||||||
|
std::map<int, bool> Input::KeyIsDown; |
||||||
|
std::map<int, bool> Input::MouseButtonIsDown; |
||||||
|
|
||||||
|
Input* Input::instance; |
||||||
|
|
||||||
|
Input::Input(GLFWwindow *window) : window(window) { |
||||||
|
instance = this; |
||||||
|
|
||||||
|
glfwSetWindowUserPointer(window, this); |
||||||
|
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods){ |
||||||
|
auto inputManager = reinterpret_cast<Input*>(glfwGetWindowUserPointer(window)); |
||||||
|
if (action == GLFW_PRESS) |
||||||
|
inputManager->keyPressed(key); |
||||||
|
if (action == GLFW_RELEASE) |
||||||
|
inputManager->keyReleased(key); |
||||||
|
}); |
||||||
|
|
||||||
|
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos){ |
||||||
|
auto inputManager = reinterpret_cast<Input*>(glfwGetWindowUserPointer(window)); |
||||||
|
inputManager->mouseMoved(xpos, ypos); |
||||||
|
}); |
||||||
|
glfwGetCursorPos(window, &oldX, &oldY); |
||||||
|
|
||||||
|
glfwSetMouseButtonCallback(window, [](GLFWwindow* window, int button, int action, int mods){ |
||||||
|
auto inputManager = reinterpret_cast<Input*>(glfwGetWindowUserPointer(window)); |
||||||
|
if (action == GLFW_PRESS) |
||||||
|
inputManager->mouseButtonPressed(button); |
||||||
|
if (action == GLFW_RELEASE) |
||||||
|
inputManager->mouseButtonReleased(button); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
void Input::keyPressed(int key) { |
||||||
|
Input::KeyIsDown[key] = true; |
||||||
|
} |
||||||
|
|
||||||
|
void Input::keyReleased(int key) { |
||||||
|
Input::KeyIsDown[key] = false; |
||||||
|
} |
||||||
|
|
||||||
|
void Input::mouseButtonPressed(int button) { |
||||||
|
Input::MouseButtonIsDown[button] = true; |
||||||
|
if (button == GLFW_MOUSE_BUTTON_RIGHT) |
||||||
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); |
||||||
|
} |
||||||
|
|
||||||
|
void Input::mouseButtonReleased(int button) { |
||||||
|
Input::MouseButtonIsDown[button] = false; |
||||||
|
if (button == GLFW_MOUSE_BUTTON_RIGHT) |
||||||
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); |
||||||
|
} |
||||||
|
|
||||||
|
void Input::mouseMoved(double newX, double newY) { |
||||||
|
float deltaX = static_cast<float>(newX - oldX); |
||||||
|
float deltaY = static_cast<float>(newY - oldY); |
||||||
|
for (auto listener : listeners){ |
||||||
|
if (auto mouseListener = dynamic_cast<MouseListener*>(listener)){ |
||||||
|
mouseListener->mouseMoved(deltaX, deltaY); |
||||||
|
} |
||||||
|
} |
||||||
|
oldX = newX; |
||||||
|
oldY = newY; |
||||||
|
} |
||||||
|
|
||||||
|
Listener::Listener() { |
||||||
|
Input::instance->listeners.insert(this); |
||||||
|
} |
||||||
|
|
||||||
|
Listener::~Listener() { |
||||||
|
Input::instance->listeners.erase(this); |
||||||
|
} |
Loading…
Reference in new issue