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