generated from AfonsoCMSousa/CPP-OpenGLTemplate
117 lines
3.1 KiB
C
117 lines
3.1 KiB
C
#pragma once
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
struct Camera {
|
|
glm::vec3 position;
|
|
glm::vec3 front;
|
|
glm::vec3 up;
|
|
glm::vec3 right;
|
|
glm::vec3 world_up;
|
|
|
|
float yaw; // horizontal angle, degrees
|
|
float pitch; // vertical angle, degrees
|
|
float fov;
|
|
float speed;
|
|
float sensitivity;
|
|
|
|
// Mouse state
|
|
float last_x, last_y;
|
|
bool first_mouse;
|
|
bool cursor_captured;
|
|
};
|
|
|
|
inline Camera camera_init(glm::vec3 position, float scr_width, float scr_height) {
|
|
Camera c;
|
|
c.position = position;
|
|
c.world_up = glm::vec3(0.0f, 1.0f, 0.0f);
|
|
c.yaw = -90.0f; // face -Z by default
|
|
c.pitch = -20.0f;
|
|
c.fov = 60.0f;
|
|
c.speed = 5.0f;
|
|
c.sensitivity = 0.1f;
|
|
c.last_x = scr_width * 0.5f;
|
|
c.last_y = scr_height * 0.5f;
|
|
c.first_mouse = true;
|
|
c.cursor_captured = false;
|
|
|
|
// Compute initial vectors from yaw/pitch
|
|
glm::vec3 front;
|
|
front.x = cos(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
|
front.y = sin(glm::radians(c.pitch));
|
|
front.z = sin(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
|
c.front = glm::normalize(front);
|
|
c.right = glm::normalize(glm::cross(c.front, c.world_up));
|
|
c.up = glm::normalize(glm::cross(c.right, c.front));
|
|
return c;
|
|
}
|
|
|
|
inline glm::mat4 camera_view(const Camera &c) {
|
|
return glm::lookAt(c.position, c.position + c.front, c.up);
|
|
}
|
|
|
|
inline glm::mat4 camera_projection(const Camera &c, float aspect) {
|
|
return glm::perspective(glm::radians(c.fov), aspect, 0.1f, 1000.0f);
|
|
}
|
|
|
|
// Call every frame with GLFW window
|
|
inline void camera_keyboard(Camera &c, GLFWwindow *window, float dt) {
|
|
if (!c.cursor_captured)
|
|
return;
|
|
float vel = c.speed * dt;
|
|
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
|
c.position += c.front * vel;
|
|
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
|
c.position -= c.front * vel;
|
|
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
|
c.position -= c.right * vel;
|
|
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
|
c.position += c.right * vel;
|
|
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
|
|
c.position += c.world_up * vel;
|
|
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
|
c.position -= c.world_up * vel;
|
|
}
|
|
|
|
// Call from your GLFW cursor position callback
|
|
inline void camera_mouse(Camera &c, double xpos, double ypos) {
|
|
if (!c.cursor_captured)
|
|
return;
|
|
|
|
if (c.first_mouse) {
|
|
c.last_x = (float)xpos;
|
|
c.last_y = (float)ypos;
|
|
c.first_mouse = false;
|
|
}
|
|
|
|
float dx = ((float)xpos - c.last_x) * c.sensitivity;
|
|
float dy = (c.last_y - (float)ypos) * c.sensitivity; // inverted Y
|
|
c.last_x = (float)xpos;
|
|
c.last_y = (float)ypos;
|
|
|
|
c.yaw += dx;
|
|
c.pitch += dy;
|
|
if (c.pitch > 89.0f)
|
|
c.pitch = 89.0f;
|
|
if (c.pitch < -89.0f)
|
|
c.pitch = -89.0f;
|
|
|
|
glm::vec3 front;
|
|
front.x = cos(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
|
front.y = sin(glm::radians(c.pitch));
|
|
front.z = sin(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
|
c.front = glm::normalize(front);
|
|
c.right = glm::normalize(glm::cross(c.front, c.world_up));
|
|
c.up = glm::normalize(glm::cross(c.right, c.front));
|
|
}
|
|
|
|
// Call from scroll callback
|
|
inline void camera_scroll(Camera &c, double yoffset) {
|
|
c.fov -= (float)yoffset;
|
|
if (c.fov < 10.0f)
|
|
c.fov = 10.0f;
|
|
if (c.fov > 90.0f)
|
|
c.fov = 90.0f;
|
|
}
|