From 33346e9a5c58e92e4d7cc7cb542cf5abb7ffeb25 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 7 Mar 2016 17:46:10 +0100 Subject: [PATCH] controllable camera --- src/app/keymap.cpp | 44 ++++++++++++++ src/app/keymap.hpp | 51 ++++++++++++++++ src/graphics/camera.cpp | 30 +++++++--- src/graphics/camera.hpp | 22 +++++-- src/graphics/viewport.cpp | 2 +- src/tacos.cpp | 120 +++++++++++++++++++++++++++++++++++++- 6 files changed, 252 insertions(+), 17 deletions(-) create mode 100644 src/app/keymap.cpp create mode 100644 src/app/keymap.hpp diff --git a/src/app/keymap.cpp b/src/app/keymap.cpp new file mode 100644 index 0000000..6fa41a1 --- /dev/null +++ b/src/app/keymap.cpp @@ -0,0 +1,44 @@ +#include "keymap.hpp" + +#include + + +namespace tacos { + +Keymap::Keymap() +: codemap{ NONE } { + +} + +void Keymap::Map(SDL_Scancode scancode, Action action) { + if (scancode > MAX_SCANCODE) { + throw std::runtime_error("cannot map out of bounds scancode"); + } + codemap[scancode] = action; +} + +Keymap::Action Keymap::Lookup(SDL_Scancode scancode) const { + if (scancode < NUM_SCANCODES) { + return codemap[scancode]; + } else { + return NONE; + } +} + +void Keymap::LoadDefault() { + Map(SDL_SCANCODE_ESCAPE, EXIT); + Map(SDL_SCANCODE_W, CAMERA_FORWARD); + Map(SDL_SCANCODE_S, CAMERA_BACK); + Map(SDL_SCANCODE_A, CAMERA_LEFT); + Map(SDL_SCANCODE_D, CAMERA_RIGHT); + Map(SDL_SCANCODE_Q, CAMERA_YAW_CW); + Map(SDL_SCANCODE_E, CAMERA_YAW_CCW); + Map(SDL_SCANCODE_INSERT, CAMERA_PITCH_CCW); + Map(SDL_SCANCODE_DELETE, CAMERA_PITCH_CW); + Map(SDL_SCANCODE_HOME, CAMERA_UP); + Map(SDL_SCANCODE_END, CAMERA_DOWN); + Map(SDL_SCANCODE_PAGEUP, CAMERA_NEARER); + Map(SDL_SCANCODE_PAGEDOWN, CAMERA_FARTHER); +} + +} diff --git a/src/app/keymap.hpp b/src/app/keymap.hpp new file mode 100644 index 0000000..34aa8d9 --- /dev/null +++ b/src/app/keymap.hpp @@ -0,0 +1,51 @@ +#ifndef TACOS_APP_KEYMAP_HPP +#define TACOS_APP_KEYMAP_HPP + +#include + + +namespace tacos { + +class Keymap { + +public: + enum Action { + NONE, + + CAMERA_RIGHT, + CAMERA_LEFT, + CAMERA_UP, + CAMERA_DOWN, + CAMERA_BACK, + CAMERA_FORWARD, + CAMERA_NEARER, + CAMERA_FARTHER, + CAMERA_PITCH_CCW, + CAMERA_PITCH_CW, + CAMERA_YAW_CCW, + CAMERA_YAW_CW, + + EXIT, + }; + + static constexpr unsigned int MAX_SCANCODE = 0xFF; + static constexpr unsigned int NUM_SCANCODES = MAX_SCANCODE + 1; + +public: + Keymap(); + + void Map(SDL_Scancode scancode, Action); + Action Lookup(SDL_Scancode scancode) const; + Action Lookup(const SDL_Keysym &s) const { return Lookup(s.scancode); } + Action Lookup(const SDL_KeyboardEvent &e) const { return Lookup(e.keysym); } + + void LoadDefault(); + +private: + Action codemap[NUM_SCANCODES]; + +}; + +} + +#endif diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index bc43e04..d9b8e84 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -5,21 +5,33 @@ namespace tacos { -Camera::Camera(const glm::vec3 &f) -: focus(&f) +Camera::Camera() +: focus(0.0f) , distance(100.0f) -, pitch(1.04719755119659774614f) // π/3 -, yaw(0.0f) { +, orientation(0.52359877559829887307f, 0.0f) { // π/6 } -void Camera::Focus(const glm::vec3 &f) noexcept { - focus = &f; +glm::mat4 Camera::View() const noexcept { + // zero yaw is into the screen, so -Z is the base view direction we're transforming from + // pitch needs to be inverted because we're projecting the distance back + const glm::vec3 position(focus - distance * rotateY(rotateX(glm::vec3(0.0f, 0.0f, -1.0f), -orientation.x), orientation.y)); + return glm::lookAt(position, focus, glm::vec3(0.0f, 1.0f, 0.0f)); } -glm::mat4 Camera::View() const noexcept { - const glm::vec3 position(*focus - distance * rotateY(rotateX(glm::vec3(0.0f, 0.0f, 1.0f), pitch), yaw)); - return glm::lookAt(position, *focus, glm::vec3(0.0f, 1.0f, 0.0f)); +void Camera::Move(const glm::vec3 &delta) noexcept { + focus += rotateY(delta, orientation.y); +} + +void Camera::Rotate(const glm::vec2 &delta) noexcept { + orientation += delta; + orientation.x = glm::clamp(orientation.x, -1.55f, 1.55f); + while (orientation.y > 3.14159265358979323844f) { // π + orientation.y -= 6.28318530717958647688f; // 2π + } + while (orientation.y < -3.14159265358979323844f) { + orientation.y += 6.28318530717958647688f; + } } } diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index a1660ca..9d1953a 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -13,17 +13,29 @@ namespace tacos { class Camera { public: - explicit Camera(const glm::vec3 &focus); + Camera(); glm::mat4 View() const noexcept; - void Focus(const glm::vec3 &) noexcept; + /// set focal point to given position + void Warp(const glm::vec3 &position) noexcept { focus = position; } + /// move focal point by given delta + void Move(const glm::vec3 &delta) noexcept; + + /// set distance of camera to focal point + void Distance(float dist) noexcept { distance = dist; } + /// adjust distance of camera to focal point + void BackOff(float delta) noexcept { distance += delta; } + + /// set pitch and yaw + void Orient(const glm::vec2 &orient) noexcept { orientation = orient; } + /// change pitch and yaw + void Rotate(const glm::vec2 &delta) noexcept; private: - const glm::vec3 *focus; + glm::vec3 focus; float distance; - float pitch; - float yaw; + glm::vec2 orientation; }; diff --git a/src/graphics/viewport.cpp b/src/graphics/viewport.cpp index 4ee85c8..17c99c7 100644 --- a/src/graphics/viewport.cpp +++ b/src/graphics/viewport.cpp @@ -12,7 +12,7 @@ Viewport::Viewport(int w, int h) , fov(0.78539816339744830961f) // π/4 , aspect(float(w) / float(h)) , near(0.1f) -, far(100.0f) +, far(256.0f) , perspective(glm::perspective(fov, aspect, near, far)) , ortho(glm::ortho(0.0f, float(width), float(height), 0.0f, near, far)) { diff --git a/src/tacos.cpp b/src/tacos.cpp index 580becb..0e47e6e 100644 --- a/src/tacos.cpp +++ b/src/tacos.cpp @@ -1,6 +1,7 @@ #include "app/assets.hpp" #include "app/config.hpp" #include "app/init.hpp" +#include "app/keymap.hpp" #include "graphics/camera.hpp" #include "graphics/shader.hpp" #include "graphics/viewport.hpp" @@ -24,6 +25,9 @@ int main(int argc, char *argv[]) { Window window(1440, 900); Viewport viewport(1440, 900); + Keymap keymap; + keymap.LoadDefault(); + constexpr float noise_scale = 1.0f/64.0f; constexpr float height_scale = 5.0f; @@ -46,21 +50,123 @@ int main(int argc, char *argv[]) { } floor.GenerateVertices(); - glm::vec3 focus(20.0f, 0.0f, 20.0f); - Camera camera(focus); + Camera camera; + camera.Warp(glm::vec3(20.0f, 0.0f, 20.0f)); glm::mat4 M; glm::mat4 V; glm::mat4 MV; glm::mat4 MVP; + constexpr float cam_speed = 15.0f; // units per second + constexpr float cam_rot_speed = 2.0f; // radians per second + + glm::vec3 cam_fwd(0.0f); + glm::vec3 cam_rev(0.0f); + float cam_near = 0.0f; + float cam_far = 0.0f; + glm::vec2 cam_rot_ccw(0.0f); + glm::vec2 cam_rot_cw(0.0f); + floor_program.Use(); bool running = true; + Uint32 last = SDL_GetTicks(); SDL_Event event; while (running) { + Uint32 now = SDL_GetTicks(); + // handle while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_KEYDOWN: + switch (keymap.Lookup(event.key)) { + case Keymap::CAMERA_RIGHT: + cam_fwd.x = 1.0f; + break; + case Keymap::CAMERA_LEFT: + cam_rev.x = 1.0f; + break; + case Keymap::CAMERA_UP: + cam_fwd.y = 1.0f; + break; + case Keymap::CAMERA_DOWN: + cam_rev.y = 1.0f; + break; + case Keymap::CAMERA_BACK: + cam_fwd.z = 1.0f; + break; + case Keymap::CAMERA_FORWARD: + cam_rev.z = 1.0f; + break; + case Keymap::CAMERA_NEARER: + cam_near = 1.0f; + break; + case Keymap::CAMERA_FARTHER: + cam_far = 1.0f; + break; + case Keymap::CAMERA_PITCH_CCW: + cam_rot_ccw.x = 1.0f; + break; + case Keymap::CAMERA_PITCH_CW: + cam_rot_cw.x = 1.0f; + break; + case Keymap::CAMERA_YAW_CCW: + cam_rot_ccw.y = 1.0f; + break; + case Keymap::CAMERA_YAW_CW: + cam_rot_cw.y = 1.0f; + break; + case Keymap::EXIT: + running = false; + break; + default: + case Keymap::NONE: + break; + } + break; + case SDL_KEYUP: + switch (keymap.Lookup(event.key)) { + case Keymap::CAMERA_RIGHT: + cam_fwd.x = 0.0f; + break; + case Keymap::CAMERA_LEFT: + cam_rev.x = 0.0f; + break; + case Keymap::CAMERA_UP: + cam_fwd.y = 0.0f; + break; + case Keymap::CAMERA_DOWN: + cam_rev.y = 0.0f; + break; + case Keymap::CAMERA_BACK: + cam_fwd.z = 0.0f; + break; + case Keymap::CAMERA_FORWARD: + cam_rev.z = 0.0f; + break; + case Keymap::CAMERA_NEARER: + cam_near = 0.0f; + break; + case Keymap::CAMERA_FARTHER: + cam_far = 0.0f; + break; + case Keymap::CAMERA_PITCH_CCW: + cam_rot_ccw.x = 0.0f; + break; + case Keymap::CAMERA_PITCH_CW: + cam_rot_cw.x = 0.0f; + break; + case Keymap::CAMERA_YAW_CCW: + cam_rot_ccw.y = 0.0f; + break; + case Keymap::CAMERA_YAW_CW: + cam_rot_cw.y = 0.0f; + break; + default: + case Keymap::NONE: + break; + } + break; case SDL_QUIT: running = false; break; @@ -73,6 +179,14 @@ int main(int argc, char *argv[]) { break; } } + + // update + float dt = (now - last) * 0.001f; + camera.Move((cam_fwd - cam_rev) * cam_speed * dt); + camera.BackOff((cam_far - cam_near) * cam_speed * dt); + camera.Rotate((cam_rot_ccw - cam_rot_cw) * cam_rot_speed * dt); + + // render V = camera.View(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (int z = 0; z < floor.VAODepth(); ++z) { @@ -86,6 +200,8 @@ int main(int argc, char *argv[]) { } } window.Flip(); + + last = now; } return 0; -- 2.39.2