diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2021-01-28 18:51:30 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2021-01-28 18:51:30 +0000 |
commit | 235f128136c7c23a64fa5f0424edf05879b8ee9b (patch) | |
tree | f703d173de2e55fdbdf9723cc5993df63bcff200 | |
parent | Generate some random terrain with a water layer (diff) | |
download | ilt-235f128136c7c23a64fa5f0424edf05879b8ee9b.tar.bz2 ilt-235f128136c7c23a64fa5f0424edf05879b8ee9b.tar.xz ilt-235f128136c7c23a64fa5f0424edf05879b8ee9b.zip |
Input stack and logical split of camera controller
-rw-r--r-- | application/inputHandler.h | 13 | ||||
-rw-r--r-- | application/main.cpp | 118 | ||||
-rw-r--r-- | application/manualCameraController.cpp | 65 | ||||
-rw-r--r-- | application/manualCameraController.h | 25 | ||||
-rw-r--r-- | gfx/camera_controller.h | 14 | ||||
-rw-r--r-- | gfx/gl/camera.cpp | 4 | ||||
-rw-r--r-- | gfx/gl/camera.h | 5 | ||||
-rw-r--r-- | utility/collection.hpp | 37 |
8 files changed, 192 insertions, 89 deletions
diff --git a/application/inputHandler.h b/application/inputHandler.h new file mode 100644 index 0000000..bcb900b --- /dev/null +++ b/application/inputHandler.h @@ -0,0 +1,13 @@ +#ifndef INPUT_HANDLER_H +#define INPUT_HANDLER_H + +union SDL_Event; + +class InputHandler { +public: + virtual ~InputHandler() = default; + + virtual bool handleInput(SDL_Event &) = 0; +}; + +#endif diff --git a/application/main.cpp b/application/main.cpp index 912fa4f..0685d5e 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -1,5 +1,7 @@ #include "game/terrain.h" #include "gfx/window.h" +#include "inputHandler.h" +#include "manualCameraController.h" #include <SDL2/SDL.h> #include <chrono> #include <cmath> @@ -7,6 +9,7 @@ #include <game/physical.h> #include <game/world.h> #include <game/worldobject.h> +#include <gfx/camera_controller.h> #include <gfx/gl/camera.h> #include <gfx/gl/shader.h> #include <gfx/gl/transform.h> @@ -15,6 +18,7 @@ #include <memory> #include <numbers> #include <special_members.hpp> +#include <vector> #include <worker.h> static const int DISPLAY_WIDTH = 800; @@ -36,7 +40,7 @@ private: float counter {}; }; -class SDL_Application { +class SDL_Application : public InputHandler, public std::enable_shared_from_this<SDL_Application> { public: SDL_Application() { @@ -50,13 +54,26 @@ public: SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); } - ~SDL_Application() + + ~SDL_Application() override { SDL_Quit(); } + NO_COPY(SDL_Application); NO_MOVE(SDL_Application); + bool + handleInput(SDL_Event & e) override + { + switch (e.type) { + case SDL_QUIT: + isRunning = false; + return true; + } + return false; + } + void run() { @@ -65,7 +82,6 @@ public: Worker w; - World world; world.create<Monkey>(); world.create<Terrain>(); @@ -76,90 +92,19 @@ public: shader.Bind(); shader.setView(camera.GetViewProjection()); - SDL_Event e; - bool isRunning = true; - auto t_start = std::chrono::high_resolution_clock::now(); const auto framelen = std::chrono::milliseconds {1000} / 120; - bool mrb {false}, ctrl {false}; - while (isRunning) { - while (SDL_PollEvent(&e)) { - switch (e.type) { - case SDL_QUIT: - isRunning = false; - break; - case SDL_KEYDOWN: - switch (e.key.keysym.sym) { - case SDLK_KP_8: - camera.MoveForward(1); - break; - case SDLK_KP_2: - camera.MoveForward(-1); - break; - case SDLK_KP_4: - camera.MoveRight(1); - break; - case SDLK_KP_6: - camera.MoveRight(-1); - break; - case SDLK_KP_7: - camera.RotateY(0.04); - break; - case SDLK_KP_9: - camera.RotateY(-0.04); - break; - case SDLK_LCTRL: - case SDLK_RCTRL: - ctrl = true; - break; - } - shader.setView(camera.GetViewProjection()); - break; - case SDL_KEYUP: - switch (e.key.keysym.sym) { - case SDLK_LCTRL: - case SDLK_RCTRL: - ctrl = false; - break; - } - break; - case SDL_MOUSEBUTTONDOWN: - switch (e.button.button) { - case SDL_BUTTON_RIGHT: - SDL_SetRelativeMouseMode(SDL_TRUE); - mrb = true; - break; - } - break; - case SDL_MOUSEBUTTONUP: - switch (e.button.button) { - case SDL_BUTTON_RIGHT: - SDL_SetRelativeMouseMode(SDL_FALSE); - mrb = false; - break; - } - break; - case SDL_MOUSEMOTION: - if (mrb) { - if (ctrl) { - camera.RotateY(-0.01F * e.motion.xrel); - camera.Pitch(-0.01F * e.motion.yrel); - } - else { - camera.MoveRight(e.motion.xrel); - camera.SlideForward(e.motion.yrel); - } - shader.setView(camera.GetViewProjection()); - } - break; - } - } + inputStack.objects.push_back(shared_from_this()); + inputStack.objects.insert(inputStack.objects.begin(), world.create<ManualCameraController>()); + while (isRunning) { + processInputs(); const auto t_end = std::chrono::high_resolution_clock::now(); const auto t_passed = std::chrono::duration_cast<std::chrono::milliseconds>(t_end - t_start); world.apply(&WorldObject::tick, t_passed); + world.apply<CameraController>(&CameraController::updateCamera, &camera, &shader); windows.apply(&Window::Clear, 0.0F, 0.0F, 0.0F, 1.0F); world.apply<Renderable>(&Renderable::render, shader); windows.apply(&Window::SwapBuffers); @@ -170,12 +115,25 @@ public: t_start = t_end; } } + +private: + void + processInputs() + { + for (SDL_Event e; SDL_PollEvent(&e);) { + inputStack.applyOne(&InputHandler::handleInput, e); + } + } + + bool isRunning {true}; + Collection<InputHandler> inputStack; + World world; }; int main(int, char **) { - SDL_Application().run(); + std::make_shared<SDL_Application>()->run(); return 0; } diff --git a/application/manualCameraController.cpp b/application/manualCameraController.cpp new file mode 100644 index 0000000..36f3312 --- /dev/null +++ b/application/manualCameraController.cpp @@ -0,0 +1,65 @@ +#include "manualCameraController.h" +#include <gfx/gl/camera.h> +#include <gfx/gl/shader.h> + +bool +ManualCameraController::handleInput(SDL_Event & e) +{ + switch (e.type) { + case SDL_KEYDOWN: + switch (e.key.keysym.sym) { + case SDLK_LCTRL: + case SDLK_RCTRL: + ctrl = true; + return true; + } + break; + case SDL_KEYUP: + switch (e.key.keysym.sym) { + case SDLK_LCTRL: + case SDLK_RCTRL: + ctrl = false; + return true; + } + break; + case SDL_MOUSEBUTTONDOWN: + switch (e.button.button) { + case SDL_BUTTON_RIGHT: + SDL_SetRelativeMouseMode(SDL_TRUE); + mrb = true; + return true; + } + break; + case SDL_MOUSEBUTTONUP: + switch (e.button.button) { + case SDL_BUTTON_RIGHT: + SDL_SetRelativeMouseMode(SDL_FALSE); + mrb = false; + return true; + } + break; + case SDL_MOUSEMOTION: + if (mrb) { + motion = e.motion; + } + return true; + } + return false; +} + +void +ManualCameraController::updateCamera(Camera * camera, Shader * shader) const +{ + if (motion) { + if (ctrl) { + camera->RotateY(-0.01F * motion->xrel); + camera->Pitch(-0.01F * motion->yrel); + } + else { + camera->MoveRight(motion->xrel); + camera->SlideForward(motion->yrel); + } + shader->setView(camera->GetViewProjection()); + motion.reset(); + } +} diff --git a/application/manualCameraController.h b/application/manualCameraController.h new file mode 100644 index 0000000..112ec5c --- /dev/null +++ b/application/manualCameraController.h @@ -0,0 +1,25 @@ +#ifndef MANUAL_CAMERA_CONTROLLER_H +#define MANUAL_CAMERA_CONTROLLER_H + +#include "game/worldobject.h" +#include "inputHandler.h" +#include <SDL2/SDL.h> +#include <gfx/camera_controller.h> +#include <optional> + +class Camera; +class Shader; + +class ManualCameraController : public CameraController, public InputHandler { +public: + bool handleInput(SDL_Event & e) override; + + void tick(TickDuration) override { } + + void updateCamera(Camera * camera, Shader * shader) const override; + +private: + bool ctrl {false}, mrb {false}; + mutable std::optional<SDL_MouseMotionEvent> motion; +}; +#endif diff --git a/gfx/camera_controller.h b/gfx/camera_controller.h new file mode 100644 index 0000000..cdc70d2 --- /dev/null +++ b/gfx/camera_controller.h @@ -0,0 +1,14 @@ +#ifndef CAMERA_CONTROLLER_H +#define CAMERA_CONTROLLER_H + +#include <game/worldobject.h> + +class Camera; +class Shader; + +class CameraController : public WorldObject { +public: + virtual void updateCamera(Camera *, Shader *) const = 0; +}; + +#endif diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp index 2f48ca5..c98ff70 100644 --- a/gfx/gl/camera.cpp +++ b/gfx/gl/camera.cpp @@ -2,8 +2,8 @@ #include <glm/gtx/transform.hpp> Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) : - projection {glm::perspective(fov, aspect, zNear, zFar)}, pos {pos}, forward {0.0F, 0.0F, 1.0F}, up {0.0F, 1.0F, - 0.0F} + pos {pos}, forward {0.0F, 0.0F, 1.0F}, up {0.0F, 1.0F, 0.0F}, projection { + glm::perspective(fov, aspect, zNear, zFar)} { } diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h index 90d88a3..3d8ece4 100644 --- a/gfx/gl/camera.h +++ b/gfx/gl/camera.h @@ -15,11 +15,12 @@ public: void Pitch(float angle);
void RotateY(float angle);
-private:
- glm::mat4 projection;
glm::vec3 pos;
glm::vec3 forward;
glm::vec3 up;
+
+private:
+ glm::mat4 projection;
};
#endif
diff --git a/utility/collection.hpp b/utility/collection.hpp index 1422a84..a9ddb78 100644 --- a/utility/collection.hpp +++ b/utility/collection.hpp @@ -6,26 +6,53 @@ template<typename Object> class Collection { public: - using Ptr = std::unique_ptr<Object>; + using Ptr = std::shared_ptr<Object>; std::vector<Ptr> objects; template<typename T = Object, typename... Params> - const auto & + auto create(Params &&... params) { - return objects.emplace_back(std::make_unique<T>(std::forward<Params>(params)...)); + auto obj = std::make_shared<T>(std::forward<Params>(params)...); + objects.emplace_back(obj); + return obj; } template<typename T = Object, typename M = void, typename... Params> - void + auto apply(const M & m, Params &&... params) const { - std::for_each(objects.cbegin(), objects.cend(), [&m, ¶ms...](auto && op) { + return std::count_if(objects.begin(), objects.end(), [&m, ¶ms...](auto && op) { if (auto o = dynamic_cast<T *>(op.get())) { std::invoke(m, o, std::forward<Params>(params)...); + return true; + } + return false; + }); + } + + template<typename T = Object, typename M = void, typename... Params> + auto + applyOne(const M & m, Params &&... params) const + { + return std::find_if(objects.begin(), objects.end(), [&m, ¶ms...](auto && op) { + if (auto o = dynamic_cast<T *>(op.get())) { + return std::invoke(m, o, std::forward<Params>(params)...); } + return false; }); } + + template<typename T = Object> + void + removeAll() + { + objects.erase(std::remove_if(objects.begin(), objects.end(), + [](auto && op) { + return dynamic_cast<T *>(op.get()); + }), + objects.end()); + } }; #endif |