diff options
Diffstat (limited to 'src/camera.hpp')
| -rw-r--r-- | src/camera.hpp | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/camera.hpp b/src/camera.hpp new file mode 100644 index 0000000..59e6180 --- /dev/null +++ b/src/camera.hpp @@ -0,0 +1,217 @@ +/* +* Basic camera class +* +* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#define GLM_FORCE_RADIANS +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include <glm/glm.hpp> +#include <glm/gtc/quaternion.hpp> +#include <glm/gtc/matrix_transform.hpp> + +class Camera +{ + float fov; + float znear, zfar; + + void updateViewMatrix() + { + glm::mat4 rotM = glm::mat4(1.0f); + glm::mat4 transM; + + rotM = glm::rotate(rotM, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); + rotM = glm::rotate(rotM, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + rotM = glm::rotate(rotM, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + + transM = glm::translate(glm::mat4(1.0f), position); + + if (type == CameraType::firstperson) + matrices.view = rotM * transM; + else + matrices.view = transM * rotM; + } +public: + enum CameraType { lookat, firstperson }; + CameraType type = CameraType::lookat; + + glm::vec3 rotation = glm::vec3(); + glm::vec3 position = glm::vec3(); + + float rotationSpeed = 1.0f; + float movementSpeed = 1.0f; + float zoomSpeed = 0.5f; + + struct + { + glm::mat4 perspective; + glm::mat4 view; + } matrices; + + struct { + bool left = false; + bool right = false; + bool up = false; + bool down = false; + } keys; + + bool moving() + { + return keys.left || keys.right || keys.up || keys.down; + } + + float getNearClip() { + return znear; + } + + float getFarClip() { + return zfar; + } + + glm::vec3 getViewDirection () { + glm::vec3 camFront; + camFront.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y)); + camFront.y = sin(glm::radians(rotation.x)); + camFront.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y)); + camFront = glm::normalize(camFront); + return camFront; + } + + void setPerspective(float fov, float aspect, float znear, float zfar) + { + this->fov = fov; + this->znear = znear; + this->zfar = zfar; + matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar); + } + + void updateAspectRatio(float aspect) + { + matrices.perspective = glm::perspective(glm::radians(fov), aspect, znear, zfar); + } + + void setPosition(glm::vec3 position) + { + this->position = position; + updateViewMatrix(); + } + + void setRotation(glm::vec3 rotation) + { + this->rotation = rotation; + updateViewMatrix(); + } + + void rotate(glm::vec3 delta) + { + this->rotation += delta; + updateViewMatrix(); + } + + void setTranslation(glm::vec3 translation) + { + this->position = translation; + updateViewMatrix(); + } + + void translate(glm::vec3 delta) + { + this->position += delta; + updateViewMatrix(); + } + + void update(float deltaTime) + { + if (type == CameraType::firstperson) + { + if (moving()) + { + glm::vec3 camFront; + camFront.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y)); + camFront.y = sin(glm::radians(rotation.x)); + camFront.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y)); + camFront = glm::normalize(camFront); + + float moveSpeed = deltaTime * movementSpeed; + + if (keys.up) + position += camFront * moveSpeed; + if (keys.down) + position -= camFront * moveSpeed; + if (keys.left) + position -= glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * moveSpeed; + if (keys.right) + position += glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * moveSpeed; + + updateViewMatrix(); + } + } + } + + // Update camera passing separate axis data (gamepad) + // Returns true if view or position has been changed + bool updatePad(glm::vec2 axisLeft, glm::vec2 axisRight, float deltaTime) + { + bool retVal = false; + + if (type == CameraType::firstperson) + { + // Use the common console thumbstick layout + // Left = view, right = move + + const float deadZone = 0.0015f; + const float range = 1.0f - deadZone; + + glm::vec3 camFront; + camFront.x = -cos(glm::radians(rotation.x)) * sin(glm::radians(rotation.y)); + camFront.y = sin(glm::radians(rotation.x)); + camFront.z = cos(glm::radians(rotation.x)) * cos(glm::radians(rotation.y)); + camFront = glm::normalize(camFront); + + float moveSpeed = deltaTime * movementSpeed * 2.0f; + float rotSpeed = deltaTime * rotationSpeed * 50.0f; + + // Move + if (fabsf(axisLeft.y) > deadZone) + { + float pos = (fabsf(axisLeft.y) - deadZone) / range; + position -= camFront * pos * ((axisLeft.y < 0.0f) ? -1.0f : 1.0f) * moveSpeed; + retVal = true; + } + if (fabsf(axisLeft.x) > deadZone) + { + float pos = (fabsf(axisLeft.x) - deadZone) / range; + position += glm::normalize(glm::cross(camFront, glm::vec3(0.0f, 1.0f, 0.0f))) * pos * ((axisLeft.x < 0.0f) ? -1.0f : 1.0f) * moveSpeed; + retVal = true; + } + + // Rotate + if (fabsf(axisRight.x) > deadZone) + { + float pos = (fabsf(axisRight.x) - deadZone) / range; + rotation.y += pos * ((axisRight.x < 0.0f) ? -1.0f : 1.0f) * rotSpeed; + retVal = true; + } + if (fabsf(axisRight.y) > deadZone) + { + float pos = (fabsf(axisRight.y) - deadZone) / range; + rotation.x -= pos * ((axisRight.y < 0.0f) ? -1.0f : 1.0f) * rotSpeed; + retVal = true; + } + } + else + { + // todo: move code from example base class for look-at + } + + if (retVal) + { + updateViewMatrix(); + } + + return retVal; + } + +}; |