From 406eef79b9d5be87cb0e30d2031083899fcd2e58 Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Fri, 15 Apr 2022 16:01:29 +0100 Subject: [PATCH] ensure inputs on menu scene are handled correctly --- demo/main.cpp | 5 ++-- fggl/CMakeLists.txt | 2 ++ fggl/app.cpp | 3 ++- fggl/ecs3/module/module.cpp | 9 ++++--- fggl/gfx/window.cpp | 5 +++- fggl/input/input.cpp | 11 +++++++++ fggl/input/mouse.cpp | 13 ++++++++++ fggl/scenes/Scene.h | 4 ++++ fggl/scenes/menu.cpp | 29 +++++++++++++++++----- include/fggl/app.hpp | 2 +- include/fggl/ecs3/module/module.h | 7 ++++++ include/fggl/gfx/compat.hpp | 2 +- include/fggl/gfx/window.hpp | 6 +++-- include/fggl/gfx/window_input.hpp | 4 ++++ include/fggl/input/input.hpp | 12 +++------- include/fggl/input/keyboard.hpp | 40 +++++++++++++++++-------------- include/fggl/input/mouse.hpp | 16 ++++++++++--- include/fggl/scenes/menu.hpp | 16 ++++++++++++- include/fggl/util/states.hpp | 4 ++-- 19 files changed, 138 insertions(+), 52 deletions(-) create mode 100644 fggl/input/input.cpp create mode 100644 fggl/input/mouse.cpp diff --git a/demo/main.cpp b/demo/main.cpp index 857a63d..5ea7c1f 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -78,7 +78,7 @@ void process_camera(fggl::ecs3::World& ecs, const InputManager& input) { motion -= (forward * delta); camTransform->origin( camTransform->origin() + motion ); - if ( cam_mode == cam_arcball || input->mouse.button( fggl::input::MouseButton::MIDDLE ) ) { + if ( cam_mode == cam_arcball || input->mouse.down( fggl::input::MouseButton::MIDDLE ) ) { fggl::input::process_arcball(ecs, *input, cam); } else if ( cam_mode == cam_free ) { fggl::input::process_freecam(ecs, *input, cam); @@ -125,7 +125,7 @@ public: return; } - bool leftMouse = m_inputs->mouse.button(fggl::input::MouseButton::LEFT); + bool leftMouse = m_inputs->mouse.down(fggl::input::MouseButton::LEFT); if (leftMouse) { auto scenes = fggl::util::ServiceLocator::instance().providePtr<fggl::scenes::SceneManager>(); scenes->activate("game"); @@ -382,6 +382,7 @@ int main(int argc, const char* argv[]) { // and now our states auto menu = app.add_state<fggl::scenes::BasicMenu>("menu"); + menu->add("start", [&app]() { app.change_state("game"); }); // game state app.add_state<GameScene>("game"); diff --git a/fggl/CMakeLists.txt b/fggl/CMakeLists.txt index 20a6319..5cefcc8 100644 --- a/fggl/CMakeLists.txt +++ b/fggl/CMakeLists.txt @@ -20,6 +20,8 @@ target_sources(${PROJECT_NAME} scenes/menu.cpp ecs3/module/module.cpp input/camera_input.cpp + input/input.cpp + input/mouse.cpp data/heightmap.cpp ) diff --git a/fggl/app.cpp b/fggl/app.cpp index 11124cd..ee3c294 100644 --- a/fggl/app.cpp +++ b/fggl/app.cpp @@ -30,7 +30,8 @@ namespace fggl { while ( m_running ) { auto& state = m_states.active(); - + + m_modules->onUpdate(); state.update(); // window rendering to frame buffer diff --git a/fggl/ecs3/module/module.cpp b/fggl/ecs3/module/module.cpp index d1fd59c..85ce2e5 100644 --- a/fggl/ecs3/module/module.cpp +++ b/fggl/ecs3/module/module.cpp @@ -6,9 +6,8 @@ namespace fggl::ecs3 { - void Module::onFrameStart() { - } - - void Module::onFrameEnd() { - } + // default empty implementions + void Module::onUpdate() {} + void Module::onFrameStart() {} + void Module::onFrameEnd() {} } diff --git a/fggl/gfx/window.cpp b/fggl/gfx/window.cpp index 199ec90..4c6b21c 100644 --- a/fggl/gfx/window.cpp +++ b/fggl/gfx/window.cpp @@ -159,7 +159,7 @@ static void fggl_joystick(int jid, int state) { GlfwContext::GlfwContext( std::shared_ptr<fggl::input::Input> input ) { spdlog::debug("[glfw] context creation stated"); auto& glfwCallbacks = GlfwInputManager::instance(); - glfwCallbacks.setup(std::move(input) ); + glfwCallbacks.setup( std::move(input) ); glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE); glfwSetErrorCallback(glfw_error); @@ -183,6 +183,9 @@ GlfwContext::~GlfwContext() { } void GlfwContext::pollEvents() { + auto& glfwCallbacks = GlfwInputManager::instance(); + glfwCallbacks.frame(); + glfwPollEvents(); fggl_joystick_poll(); } diff --git a/fggl/input/input.cpp b/fggl/input/input.cpp new file mode 100644 index 0000000..ab6e2f5 --- /dev/null +++ b/fggl/input/input.cpp @@ -0,0 +1,11 @@ +#include <fggl/input/input.hpp> + +namespace fggl::input { + + void Input::frame(float dt) { + keyboard.frame(dt); + mouse.frame(dt); + gamepads.frame(dt); + } + +} // namespace fggl::input diff --git a/fggl/input/mouse.cpp b/fggl/input/mouse.cpp new file mode 100644 index 0000000..114aa5a --- /dev/null +++ b/fggl/input/mouse.cpp @@ -0,0 +1,13 @@ +#include <fggl/input/mouse.hpp> + +namespace fggl::input { + + void MouseState::operator=(const MouseState& rhs) { + for ( int i=0; i<4; i++ ) { + axis[i] = rhs.axis[i]; + } + buttons = rhs.buttons; + } + + +} // namespace fggl::input diff --git a/fggl/scenes/Scene.h b/fggl/scenes/Scene.h index d4c9daf..b749d91 100644 --- a/fggl/scenes/Scene.h +++ b/fggl/scenes/Scene.h @@ -14,6 +14,10 @@ namespace fggl::scenes { class Scene { public: virtual ~Scene() = default; + + // no copying + Scene(const Scene&) = delete; + Scene& operator=(const Scene&) = delete; virtual void setup() = 0; virtual void cleanup() = 0; diff --git a/fggl/scenes/menu.cpp b/fggl/scenes/menu.cpp index d99dc3c..8d9936e 100644 --- a/fggl/scenes/menu.cpp +++ b/fggl/scenes/menu.cpp @@ -1,7 +1,14 @@ #include <fggl/scenes/menu.hpp> +#include <fggl/util/service.h> + +#include <spdlog/spdlog.h> namespace fggl::scenes { + using fggl::input::MouseButton; + using fggl::input::MouseAxis; + + static void buttonBorder( gfx::Path2D& path, glm::vec2 pos, glm::vec2 size ) { // outer box path.colour( {1.0f, 0.0f, 0.0f} ); @@ -143,17 +150,23 @@ namespace fggl::scenes { makeBox( path, innerTop, innerBottom ); } - BasicMenu::BasicMenu(fggl::App& app) : AppState(app) { - + BasicMenu::BasicMenu(fggl::App& app) : AppState(app), m_inputs(nullptr), m_active() { + auto& locator = fggl::util::ServiceLocator::instance(); + m_inputs = locator.get<input::Input>(); } void BasicMenu::update() { + if ( m_inputs != nullptr ) { + m_cursorPos.x = m_inputs->mouse.axis( MouseAxis::X ); + m_cursorPos.y = m_inputs->mouse.axis( MouseAxis::Y ); + if ( m_inputs->mouse.pressed( MouseButton::LEFT ) ) { + spdlog::info("clicky clicky: ({}, {})", m_cursorPos.x, m_cursorPos.y); + } + } } void BasicMenu::render(gfx::Paint& paint) { - - const math::vec2 btnSize{ 150.0f, 30.0f }; const float spacing = 5; @@ -161,9 +174,9 @@ namespace fggl::scenes { const float padY = 50.0f; math::vec2 pos { 1920.0f - ( padX + btnSize.x ), padY }; - for (int i=0; i<10; i++) { + for ( const auto& item : m_items ) { gfx::Path2D btn( pos ); - makeButton( btn, pos, btnSize, i==2, i==1 ); + makeButton( btn, pos, btnSize, m_active == item.first, false ); paint.fill( btn ); pos.y += (btnSize.y + spacing); } @@ -196,4 +209,8 @@ namespace fggl::scenes { } + void BasicMenu::add(const std::string& name, callback cb) { + m_items[name] = cb; + } + }; diff --git a/include/fggl/app.hpp b/include/fggl/app.hpp index 34145ab..160a58e 100644 --- a/include/fggl/app.hpp +++ b/include/fggl/app.hpp @@ -102,7 +102,7 @@ namespace fggl { int run(int argc, const char** argv); template<typename T> - T& add_state(const Identifer& name) { + T* add_state(const Identifer& name) { static_assert( std::is_base_of<AppState,T>::value, "States must be AppStates"); return m_states.put<T>(name, *this); } diff --git a/include/fggl/ecs3/module/module.h b/include/fggl/ecs3/module/module.h index b38d1e3..a71ae98 100644 --- a/include/fggl/ecs3/module/module.h +++ b/include/fggl/ecs3/module/module.h @@ -21,6 +21,7 @@ namespace fggl::ecs3 { virtual void onLoad(ModuleManager& manager, TypeRegistry& tr) {}; + virtual void onUpdate(); virtual void onFrameStart(); virtual void onFrameEnd(); }; @@ -45,6 +46,12 @@ namespace fggl::ecs3 { m_types.callbackAdd( Component<C>::typeID(), cb); } + void onUpdate() { + for ( auto& [id,ptr] : m_modules ) { + ptr->onUpdate(); + } + } + void onFrameStart() { for ( auto& [id,ptr] : m_modules ) { ptr->onFrameStart(); diff --git a/include/fggl/gfx/compat.hpp b/include/fggl/gfx/compat.hpp index d1fcfa0..3a1b370 100644 --- a/include/fggl/gfx/compat.hpp +++ b/include/fggl/gfx/compat.hpp @@ -35,7 +35,7 @@ namespace fggl::gfx { return window; } - void onFrameStart() override { + void onUpdate() override { context.pollEvents(); } diff --git a/include/fggl/gfx/window.hpp b/include/fggl/gfx/window.hpp index fbb7900..3a4c6f2 100644 --- a/include/fggl/gfx/window.hpp +++ b/include/fggl/gfx/window.hpp @@ -28,7 +28,8 @@ namespace fggl::gfx { AutoIconify = GLFW_AUTO_ICONIFY, FocusOnShow = GLFW_FOCUS_ON_SHOW }; - enum WindowHint { + + enum WindowHint { Focused = GLFW_FOCUSED, Iconified = GLFW_ICONIFIED, Maximised = GLFW_MAXIMIZED, @@ -40,7 +41,8 @@ namespace fggl::gfx { GlDebugContext = GLFW_OPENGL_DEBUG_CONTEXT, NoError = GLFW_CONTEXT_NO_ERROR }; - class GlfwWindow : public Window { + + class GlfwWindow : public Window { public: GlfwWindow(); ~GlfwWindow(); diff --git a/include/fggl/gfx/window_input.hpp b/include/fggl/gfx/window_input.hpp index 6583efd..153fcd9 100644 --- a/include/fggl/gfx/window_input.hpp +++ b/include/fggl/gfx/window_input.hpp @@ -21,6 +21,10 @@ namespace fggl::gfx { m_inputs = input; } + inline void frame() { + m_inputs->frame(0.0f); + } + inline bool alive() { return m_inputs != nullptr; } diff --git a/include/fggl/input/input.hpp b/include/fggl/input/input.hpp index d570339..a2f0307 100644 --- a/include/fggl/input/input.hpp +++ b/include/fggl/input/input.hpp @@ -10,15 +10,9 @@ namespace fggl::input { class Input { public: - inline Input() : keyboard(), mouse(), gamepads() { - } - - inline void frame(float dt) { - keyboard.frame(dt); - mouse.frame(dt); - gamepads.frame(dt); - } - + Input() = default; + void frame(float dt); + KeyboardInput keyboard; MouseInput mouse; GamepadInput gamepads; diff --git a/include/fggl/input/keyboard.hpp b/include/fggl/input/keyboard.hpp index f4f6e82..853e652 100644 --- a/include/fggl/input/keyboard.hpp +++ b/include/fggl/input/keyboard.hpp @@ -3,33 +3,37 @@ #include <array> #include <vector> -#include <set> +#include <unordered_set> #include <iostream> namespace fggl::input { using scancode_t = int; - struct KeyboardState { - std::set<scancode_t> m_keys; + class KeyboardState { + public: + KeyboardState() = default; - inline void clear() { - m_keys.clear(); - } + inline void clear() { + m_keys.clear(); + } - inline void set(scancode_t code, bool state) { - if ( state ) { - m_keys.insert( code ); - } else { - m_keys.erase( code ); - } - } + inline void set(scancode_t code, bool state) { + if ( state ) { + m_keys.insert( code ); + } else { + m_keys.erase( code ); + } + } - inline bool down(scancode_t scancode) const { - if ( m_keys.empty() ) - return false; + inline bool down(scancode_t scancode) const { + if ( m_keys.empty() ) + return false; - return m_keys.find(scancode) != m_keys.end(); - } + return m_keys.count(scancode) > 0; + } + + private: + std::unordered_set<scancode_t> m_keys; }; class KeyboardInput { diff --git a/include/fggl/input/mouse.hpp b/include/fggl/input/mouse.hpp index d99160b..09af8e9 100644 --- a/include/fggl/input/mouse.hpp +++ b/include/fggl/input/mouse.hpp @@ -27,12 +27,12 @@ namespace fggl::input { struct MouseButtonRecord { MouseButton id; - char name[15]; + const char name[15]; }; struct MouseAxisRecord { MouseAxis id; - char name[15]; + const char name[15]; }; constexpr std::array<MouseButtonRecord, 8> MouseButtons = {{ @@ -56,10 +56,16 @@ namespace fggl::input { struct MouseState { float axis[MouseAxes.size()]; std::bitset<MouseButtons.size()> buttons; + + void operator=(const MouseState& rhs); }; class MouseInput { public: + MouseInput() = default; + MouseInput(const MouseInput& rhs) = delete; + void operator=(const MouseInput& rhs) = delete; + inline void frame(float dt) { m_prev = m_curr; } @@ -80,10 +86,14 @@ namespace fggl::input { m_curr.buttons[(int)btn] = state; } - inline bool button(MouseButton btn) const { + inline bool down(MouseButton btn) const { return m_curr.buttons[(int)btn]; } + inline bool downPrev(MouseButton btn) const { + return m_prev.buttons[(int)btn]; + } + inline bool pressed(MouseButton btn) const { return m_curr.buttons[(int)btn] && !m_prev.buttons[(int)btn]; } diff --git a/include/fggl/scenes/menu.hpp b/include/fggl/scenes/menu.hpp index c360401..14cd63e 100644 --- a/include/fggl/scenes/menu.hpp +++ b/include/fggl/scenes/menu.hpp @@ -1,11 +1,18 @@ #ifndef FGGL_SCENES_MENU_H #define FGGL_SCENES_MENU_H +#include <functional> +#include <map> +#include <memory> + #include <fggl/app.hpp> +#include <fggl/math/types.hpp> #include <fggl/input/input.hpp> namespace fggl::scenes { + using callback = std::function<void(void)>; + class BasicMenu : public AppState { public: BasicMenu(App& owner); @@ -16,8 +23,15 @@ namespace fggl::scenes { void activate() override; void deactivate() override; + void add(const std::string& label, callback cb); + private: - input::Input* m_inputs; + std::shared_ptr<input::Input> m_inputs; + std::map<const std::string, callback> m_items; + + // menu state + std::string m_active; + math::vec2 m_cursorPos; }; } // namepace fggl::scenes diff --git a/include/fggl/util/states.hpp b/include/fggl/util/states.hpp index a72fe31..29067a7 100644 --- a/include/fggl/util/states.hpp +++ b/include/fggl/util/states.hpp @@ -42,7 +42,7 @@ namespace fggl::util { StateMachine& operator=(StateMachine other) = delete; template<typename T, typename... Args> - T& put(const Identifer& name, Args&&... args) { + T* put(const Identifer& name, Args&&... args) { static_assert( std::is_base_of<StateType,T>::value, "States must be AppStates"); m_states[name] = std::make_unique<T>( std::forward<Args...>(args...) ); @@ -51,7 +51,7 @@ namespace fggl::util { m_active = name; } - return *(T*)(m_states[name].get()); + return (T*)(m_states[name].get()); } void change(const Identifer& name) { -- GitLab