From 0485661fd05af686acf886cb2c96dd4a5e38bb4d Mon Sep 17 00:00:00 2001 From: vimene Date: Fri, 3 Jan 2025 08:19:05 +0100 Subject: improved keyboard and mouse controls --- src/ctrl/keyboard.h | 43 +++++++- src/ctrl/mouse.h | 13 ++- src/engine.cpp | 297 ++++++++++++++++++++++++++++------------------------ 3 files changed, 208 insertions(+), 145 deletions(-) diff --git a/src/ctrl/keyboard.h b/src/ctrl/keyboard.h index de7297c..4f3b4ef 100644 --- a/src/ctrl/keyboard.h +++ b/src/ctrl/keyboard.h @@ -1,15 +1,50 @@ #ifndef CTRL_KEYBOARD_H #define CTRL_KEYBOARD_H +#include +#include "math/vector.h" + +using engine::math::Vector2; + namespace engine::controllers { +enum class KeyboardKey { + fw, + bw, + key_left, + key_right, + zoom, +}; + +static constexpr std::size_t keyboard_key_count = 5; + +template class Keyboard { public: - bool fw_down, bw_down, left_down, right_down, zoom_down; + constexpr Keyboard(KeyDownCallback key_down_cb, KeyUpCallback key_up_cb) : + key_down_cb{key_down_cb}, key_up_cb{key_up_cb}, key_down_list{{{}}} {} + + void key_down_event(KeyboardKey key) { + key_down_list[static_cast(key) / (sizeof(std::size_t) * 8)] + |= 1 << (static_cast(key) % (sizeof(std::size_t) * 8)); + key_down_cb(key); + } + + void key_up_event(KeyboardKey key) { + key_down_list[static_cast(key) / (sizeof(std::size_t) * 8)] + &= ~(1 << (static_cast(key) % (sizeof(std::size_t) * 8))); + key_up_cb(key); + } + + constexpr bool is_down(KeyboardKey key) const & { + return (key_down_list[static_cast(key) / (sizeof(std::size_t) * 8)] + & (1 << (static_cast(key) % (sizeof(std::size_t) * 8)))) != 0; + } - constexpr Keyboard() : - fw_down{false}, bw_down{false}, left_down{false}, - right_down{false}, zoom_down{false} {} + private: + KeyDownCallback key_down_cb; + KeyUpCallback key_up_cb; + std::array key_down_list; }; } diff --git a/src/ctrl/mouse.h b/src/ctrl/mouse.h index 8b66cee..521b0a4 100644 --- a/src/ctrl/mouse.h +++ b/src/ctrl/mouse.h @@ -3,16 +3,19 @@ #include "math/vector.h" -using engine::math::Vector2; - namespace engine::controllers { +template class Mouse { public: - bool moved; - Vector2 rel_motion; + constexpr Mouse(MouseMotionCallback mouse_motion_cb) : mouse_motion_cb{mouse_motion_cb} {} + + void mouse_motion_event(Vector2 rel) const & { + mouse_motion_cb(rel); + } - constexpr Mouse() : moved{false}, rel_motion{0.f, 0.f} {} + private: + MouseMotionCallback mouse_motion_cb; }; } diff --git a/src/engine.cpp b/src/engine.cpp index 6e05d7f..453f8c5 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef ENABLE_NCURSES #include @@ -51,6 +52,7 @@ using engine::math::Matrix4, engine::math::Quaternion, engine::controllers::Keyboard, + engine::controllers::KeyboardKey, engine::controllers::Mouse; #define FPS 60 @@ -129,9 +131,19 @@ static void scene_main(Renderer& renderer, const Matrix4& final_tra } }; - Keyboard kb{}; - Mouse mouse{}; float rx = 0.f, ry = 0.f; + Keyboard kb{[&](KeyboardKey key) { + (void) key; + }, [&](KeyboardKey key) { + (void) key; + }}; + Mouse mouse{[&](Vector2 rel) { + rx += -rel.y; + ry += -rel.x; + if (rx < -PI / 2.f) rx = -PI / 2.f; + if (rx > PI / 2.f) rx = PI / 2.f; + scene.camera.transform.rot = Quaternion::euler_zxy(rx, ry, 0.f); + }}; camera = &scene.camera; @@ -157,22 +169,15 @@ static void scene_main(Renderer& renderer, const Matrix4& final_tra } cont = update_frame(scene, kb, mouse); - if (mouse.moved) { - rx += -mouse.rel_motion.y; - ry += -mouse.rel_motion.x; - if (rx < -PI / 2.f) rx = -PI / 2.f; - if (rx > PI / 2.f) rx = PI / 2.f; - scene.camera.transform.rot = Quaternion::euler_zxy(rx, ry, 0.f); - } - Vector3 movement(0.f, 0.f, 0.f); - if (kb.fw_down) movement.z += -1.f; - if (kb.left_down) movement.x += -1.f; - if (kb.bw_down) movement.z += +1.f; - if (kb.right_down) movement.x += +1.f; - if (kb.fw_down || kb.left_down || kb.bw_down || kb.right_down) movement.normalize(); + if (kb.is_down(KeyboardKey::fw)) movement.z += -1.f; + if (kb.is_down(KeyboardKey::key_left)) movement.x += -1.f; + if (kb.is_down(KeyboardKey::bw)) movement.z += +1.f; + if (kb.is_down(KeyboardKey::key_right)) movement.x += +1.f; + if (kb.is_down(KeyboardKey::fw) || kb.is_down(KeyboardKey::key_left) + || kb.is_down(KeyboardKey::bw) || kb.is_down(KeyboardKey::key_right)) movement.normalize(); scene.camera.transform.loc += movement.rot(Quaternion::rot_y(ry)) * .05f; - scene.camera.fov = (kb.zoom_down ? 40.f : 80.f) * PI / 180.f; + scene.camera.fov = (kb.is_down(KeyboardKey::zoom) ? 40.f : 80.f) * PI / 180.f; } } @@ -194,64 +199,85 @@ static int main_term() { getmaxyx(stdscr, h, w); Renderer renderer{CharacterFrameBuffer{static_cast(w), static_cast(h)}}; - scene_main(renderer, Matrix4::scale(Vector3(2.f, 1.f, 1.f)), [&](Scene& scene, Keyboard& kb, Mouse& mouse) { - (void) scene; - mvaddnstr(0, 0, renderer.fb.chars(), renderer.width() * renderer.height()); - - bool cont = true; - //timeout(1000 / FPS); - timeout(10); - int c = getch(); - - kb.fw_down = false; - kb.left_down = false; - kb.bw_down = false; - kb.right_down = false; - - mouse.moved = false; - mouse.rel_motion = Vector2(0.f, 0.f); - - switch (c) { - case 'z': - kb.fw_down = true; - break; - case 'q': - kb.left_down = true; - break; - case 's': - kb.bw_down = true; - break; - case 'd': - kb.right_down = true; - break; - case 'p': - kb.zoom_down = !kb.zoom_down; - break; - case KEY_UP: - mouse.moved = true; - mouse.rel_motion = Vector2(0.f, -.1f); - break; - case KEY_LEFT: - mouse.moved = true; - mouse.rel_motion = Vector2(-.1f, 0.f); - break; - case KEY_DOWN: - mouse.moved = true; - mouse.rel_motion = Vector2(0.f, +.1f); - break; - case KEY_RIGHT: - mouse.moved = true; - mouse.rel_motion = Vector2(+.1f, 0.f); - break; - case MKEY_ESC: - return false; - } + scene_main(renderer, Matrix4::scale(Vector3(2.f, 1.f, 1.f)), + [&](Scene& scene, auto& kb, auto& mouse) { + (void) scene; + mvaddnstr(0, 0, renderer.fb.chars(), renderer.width() * renderer.height()); + + bool cont = true; + std::optional key; + std::optional rel; + //timeout(1000 / FPS); + timeout(10); + int c = getch(); + + switch (c) { + case 'z': + key = KeyboardKey::fw; + break; + case 'q': + key = KeyboardKey::key_left; + break; + case 's': + key = KeyboardKey::bw; + break; + case 'd': + key = KeyboardKey::key_right; + break; + case 'p': + key = KeyboardKey::zoom; + break; + case KEY_UP: + rel = Vector2(0.f, -.1f); + break; + case KEY_LEFT: + rel = Vector2(-.1f, 0.f); + break; + case KEY_DOWN: + rel = Vector2(0.f, +.1f); + break; + case KEY_RIGHT: + rel = Vector2(+.1f, 0.f); + break; + case MKEY_ESC: + return false; + } + + if (key && *key == KeyboardKey::fw) { + if (!kb.is_down(KeyboardKey::fw)) kb.key_down_event(KeyboardKey::fw); + } else { + if (kb.is_down(KeyboardKey::fw)) kb.key_up_event(KeyboardKey::fw); + } + if (key && *key == KeyboardKey::key_left) { + if (!kb.is_down(KeyboardKey::key_left)) kb.key_down_event(KeyboardKey::key_left); + } else { + if (kb.is_down(KeyboardKey::key_left)) kb.key_up_event(KeyboardKey::key_left); + } + if (key && *key == KeyboardKey::bw) { + if (!kb.is_down(KeyboardKey::bw)) kb.key_down_event(KeyboardKey::bw); + } else { + if (kb.is_down(KeyboardKey::bw)) kb.key_up_event(KeyboardKey::bw); + } + if (key && *key == KeyboardKey::key_right) { + if (!kb.is_down(KeyboardKey::key_right)) kb.key_down_event(KeyboardKey::key_right); + } else { + if (kb.is_down(KeyboardKey::key_right)) kb.key_up_event(KeyboardKey::key_right); + } + + if (key && *key == KeyboardKey::zoom) { + if (kb.is_down(KeyboardKey::zoom)) kb.key_up_event(KeyboardKey::zoom); + else kb.key_down_event(KeyboardKey::zoom); + } - getmaxyx(stdscr, h, w); - renderer.resize(static_cast(w), static_cast(h)); + if (rel) + mouse.mouse_motion_event(*rel); - return cont; - }); + getmaxyx(stdscr, h, w); + renderer.resize(static_cast(w), static_cast(h)); + + return cont; + } + ); // terminate endwin(); @@ -285,76 +311,75 @@ static int main_graphical() { SDL_Event e; - scene_main(engine_renderer, Matrix4::idty(), [&](Scene& scene, Keyboard& kb, Mouse& mouse) { - (void) scene; - SDL_UpdateTexture(texture, nullptr, engine_renderer.fb.pixels(), SCREEN_WIDTH * 4); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, nullptr, nullptr); - SDL_RenderPresent(renderer); - SDL_UpdateWindowSurface(window); - SDL_SetRelativeMouseMode(SDL_TRUE); - bool cont = true; - mouse.moved = false; - mouse.rel_motion = Vector2(0.f, 0.f); - if (SDL_WaitEventTimeout(&e, 10)) { - do { - switch (e.type) { - case SDL_QUIT: - cont = false; - break; - case SDL_KEYDOWN: - switch (e.key.keysym.sym) { - case SDLK_z: - kb.fw_down = true; - break; - case SDLK_q: - kb.left_down = true; - break; - case SDLK_s: - kb.bw_down = true; - break; - case SDLK_d: - kb.right_down = true; - break; - case SDLK_LCTRL: - kb.zoom_down = true; - break; - } - break; - case SDL_KEYUP: - switch (e.key.keysym.sym) { - case SDLK_z: - kb.fw_down = false; - break; - case SDLK_q: - kb.left_down = false; - break; - case SDLK_s: - kb.bw_down = false; + scene_main(engine_renderer, Matrix4::idty(), + [&](Scene& scene, auto& kb, auto& mouse) { + (void) scene; + SDL_UpdateTexture(texture, nullptr, engine_renderer.fb.pixels(), SCREEN_WIDTH * 4); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, nullptr, nullptr); + SDL_RenderPresent(renderer); + SDL_UpdateWindowSurface(window); + SDL_SetRelativeMouseMode(SDL_TRUE); + bool cont = true; + if (SDL_WaitEventTimeout(&e, 10)) { + do { + switch (e.type) { + case SDL_QUIT: + cont = false; break; - case SDLK_d: - kb.right_down = false; + case SDL_KEYDOWN: + switch (e.key.keysym.sym) { + case SDLK_z: + kb.key_down_event(KeyboardKey::fw); + break; + case SDLK_q: + kb.key_down_event(KeyboardKey::key_left); + break; + case SDLK_s: + kb.key_down_event(KeyboardKey::bw); + break; + case SDLK_d: + kb.key_down_event(KeyboardKey::key_right); + break; + case SDLK_LCTRL: + kb.key_down_event(KeyboardKey::zoom); + break; + } break; - case SDLK_LCTRL: - kb.zoom_down = false; + case SDL_KEYUP: + switch (e.key.keysym.sym) { + case SDLK_z: + kb.key_up_event(KeyboardKey::fw); + break; + case SDLK_q: + kb.key_up_event(KeyboardKey::key_left); + break; + case SDLK_s: + kb.key_up_event(KeyboardKey::bw); + break; + case SDLK_d: + kb.key_up_event(KeyboardKey::key_right); + break; + case SDLK_LCTRL: + kb.key_up_event(KeyboardKey::zoom); + break; + case SDLK_ESCAPE: + cont = false; + break; + } break; - case SDLK_ESCAPE: - cont = false; + case SDL_MOUSEMOTION: + mouse.mouse_motion_event(Vector2( + static_cast(e.motion.xrel) * .01f, + static_cast(e.motion.yrel) * .01f)); break; } - break; - case SDL_MOUSEMOTION: - mouse.moved = true; - mouse.rel_motion += Vector2( - static_cast(e.motion.xrel) * .01f, - static_cast(e.motion.yrel) * .01f); - break; - } - } while (SDL_PollEvent(&e)); - } + } while (SDL_PollEvent(&e)); + } - return cont; - }); + return cont; + } + ); // terminate SDL_DestroyTexture(texture); -- cgit v1.2.3