diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/app.hpp | 51 | ||||
-rw-r--r-- | editor/camera.cpp | 16 | ||||
-rw-r--r-- | editor/draw.cpp | 4 | ||||
-rw-r--r-- | editor/editor.cpp | 102 | ||||
-rw-r--r-- | editor/editor.hpp | 21 | ||||
-rw-r--r-- | editor/events.cpp | 107 | ||||
-rw-r--r-- | editor/imgui.cpp | 16 | ||||
-rw-r--r-- | editor/keys.hpp | 24 | ||||
-rw-r--r-- | editor/update.cpp | 54 |
9 files changed, 280 insertions, 115 deletions
diff --git a/editor/app.hpp b/editor/app.hpp index ccc4d8bf..e7808dcc 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -9,6 +9,7 @@ #include "draw/quad-wall-w.hpp" #include "draw/box.hpp" #include "floormat/app.hpp" +#include "keys.hpp" #include <memory> #include <optional> @@ -33,26 +34,23 @@ struct cursor_state final { struct app final : floormat_app { static int run_from_argv(int argv, const char* const* argc); + ~app() override; private: + using key_set = enum_bitset<key, key_COUNT>; + app(fm_settings&& opts); - ~app() override; fm_DECLARE_DELETED_COPY_ASSIGNMENT(app); fm_DECLARE_DEPRECATED_MOVE_ASSIGNMENT(app); - enum class key : unsigned { - noop, - camera_up, camera_left, camera_right, camera_down, camera_reset, - rotate_tile, - mode_none, mode_floor, mode_walls, - quit, - quicksave, quickload, - COUNT, MIN = noop, NO_REPEAT = rotate_tile, GLOBAL = quicksave, - }; + int exec(); void update(float dt) override; + void update_cursor_tile(const std::optional<Vector2i>& pixel); void maybe_initialize_chunk(const chunk_coords& pos, chunk& c) override; + void maybe_initialize_chunk_(const chunk_coords& pos, chunk& c); + void draw_msaa() override; void draw() override; @@ -69,32 +67,32 @@ private: void on_mouse_leave() noexcept override; void on_mouse_enter() noexcept override; - int exec(); + void do_mouse_move(int modifiers); + void do_mouse_up_down(std::uint8_t button, bool is_down, int modifiers); - void maybe_initialize_chunk_(const chunk_coords& pos, chunk& c); - - void do_mouse_move(); - void do_mouse_up_down(std::uint8_t button, bool is_down); - - void do_camera(float dt, const enum_bitset<key>& cmds); + void do_camera(float dt, const key_set& cmds, int mods); + void reset_camera_offset(); void do_quicksave(); void do_quickload(); - void reset_camera_offset(); - void update_cursor_tile(const std::optional<Vector2i>& pixel); - void draw_cursor_tile(); - + void draw_editor_pane(tile_editor& type, float main_menu_height); + void draw_cursor(); void init_imgui(Vector2i size); void draw_ui(); float draw_main_menu(); void draw_fps(); - void draw_cursor_tile_text(); + void draw_tile_under_cursor(); void render_menu(); - void apply_commands(const enum_bitset<key>& k); - void clear_non_global_keys(); - void draw_editor_pane(tile_editor& type, float main_menu_height); + void do_key(key k, int mods); + void do_key(key k); + void apply_commands(const key_set& k); + static int get_key_modifiers(); + void clear_keys(key min_inclusive, key max_exclusive); + void clear_keys(); + void clear_non_global_keys() { clear_keys(key_noop, key_GLOBAL); } + void clear_non_repeated_keys() { clear_keys(key_NO_REPEAT, key_COUNT); } Containers::Pointer<floormat_main> M; ImGuiIntegration::Context _imgui{NoCreate}; @@ -104,7 +102,8 @@ private: wireframe_mesh<wireframe::quad_wall_w> _wireframe_wall_w; wireframe_mesh<wireframe::box> _wireframe_box; editor _editor; - enum_bitset<key> keys; + key_set keys; + std::array<int, key_set::COUNT> key_modifiers; cursor_state cursor; }; diff --git a/editor/camera.cpp b/editor/camera.cpp index c03808d7..e10a995c 100644 --- a/editor/camera.cpp +++ b/editor/camera.cpp @@ -5,25 +5,25 @@ namespace floormat { -void app::do_camera(float dt, const enum_bitset<key>& cmds) +void app::do_camera(float dt, const key_set& cmds, int mods) { - if (cmds[key::camera_reset]) + if (cmds[key_camera_reset]) { reset_camera_offset(); update_cursor_tile(cursor.pixel); - do_mouse_move(); + do_mouse_move(mods); return; } Vector2d dir{}; - if (cmds[key::camera_up]) + if (cmds[key_camera_up]) dir += Vector2d{0, -1}; - else if (cmds[key::camera_down]) + else if (cmds[key_camera_down]) dir += Vector2d{0, 1}; - if (cmds[key::camera_left]) + if (cmds[key_camera_left]) dir += Vector2d{-1, 0}; - else if (cmds[key::camera_right]) + else if (cmds[key_camera_right]) dir += Vector2d{1, 0}; if (dir != Vector2d{}) @@ -43,7 +43,7 @@ void app::do_camera(float dt, const enum_bitset<key>& cmds) shader.set_camera_offset(camera_offset); update_cursor_tile(cursor.pixel); - do_mouse_move(); + do_mouse_move(mods); } } diff --git a/editor/draw.cpp b/editor/draw.cpp index 654c484e..ee11edd3 100644 --- a/editor/draw.cpp +++ b/editor/draw.cpp @@ -7,7 +7,7 @@ namespace floormat { -void app::draw_cursor_tile() +void app::draw_cursor() { constexpr float LINE_WIDTH = 2; @@ -36,7 +36,7 @@ void app::draw_cursor_tile() void app::draw_msaa() { - draw_cursor_tile(); + draw_cursor(); } void app::draw() diff --git a/editor/editor.cpp b/editor/editor.cpp index 58b20e68..7f9ba11d 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -7,14 +7,15 @@ #include "compat/unreachable.hpp" #include "src/tile-defs.hpp" #include "src/world.hpp" +#include "keys.hpp" + #include <Corrade/Containers/StringView.h> -#include <filesystem> + #include <vector> +#include <filesystem> namespace floormat { -static const std::filesystem::path image_path{IMAGE_PATH, std::filesystem::path::generic_format}; - tile_editor::tile_editor(editor_mode mode, StringView name) : _name{ name}, _mode{ mode} { load_atlases(); @@ -22,6 +23,7 @@ tile_editor::tile_editor(editor_mode mode, StringView name) : _name{ name}, _mod void tile_editor::load_atlases() { + static const std::filesystem::path image_path{IMAGE_PATH, std::filesystem::path::generic_format}; using atlas_array = std::vector<std::shared_ptr<tile_atlas>>; for (auto& atlas : json_helper::from_json<atlas_array>(image_path/(_name + ".json"))) { @@ -195,6 +197,40 @@ void tile_editor::set_rotation(editor_wall_rotation r) } } +auto tile_editor::check_snap(int mods) const -> snap_mode +{ + enum : int { + KMOD_CTRL = 0x0040 | 0x0080, + KMOD_SHIFT = 0x0001 | 0x0002, + }; + const bool ctrl = mods & kmod_ctrl, shift = mods & kmod_shift; + + if (!(ctrl | shift)) + return snap_mode::none; + + switch (_mode) + { + default: + case editor_mode::none: + return snap_mode::none; + case editor_mode::walls: + switch (_rotation) + { + case editor_wall_rotation::N: + return snap_mode::horizontal; + case editor_wall_rotation::W: + return snap_mode::vertical; + default: return snap_mode::none; + } + case editor_mode::floor: + if (shift) + return snap_mode::horizontal; + if (ctrl) + return snap_mode::vertical; + return snap_mode::none; + } +} + editor::editor() { } @@ -231,28 +267,60 @@ void editor::on_release() _last_pos = std::nullopt; } -void editor::on_mouse_move(world& world, const global_coords pos) +auto editor::get_snap_value(snap_mode snap, int mods) const -> snap_mode { - if (_last_pos && *_last_pos != pos) - { - _last_pos = pos; - on_click(world, pos); - } + if (snap != snap_mode::none) + return snap; + else if (const auto* mode = current(); mode != nullptr) + return mode->check_snap(mods); + else + return snap_mode::none; } -void editor::on_click(world& world, global_coords pos) +void editor::on_mouse_move(world& world, global_coords pos, int mods) { - if (auto* mode = current(); mode) + if (!current()) + return; + + if (_last_pos) { - auto opt = mode->get_selected(); - if (opt) + auto& last_pos = *_last_pos; + const snap_mode snap = get_snap_value(last_pos.snap, mods); + switch (snap) { - _last_pos = pos; - mode->place_tile(world, pos, opt); + default: + case snap_mode::none: + break; + case snap_mode::horizontal: + pos.y = last_pos.coord.y; + break; + case snap_mode::vertical: + pos.x = last_pos.coord.x; + break; } - else - on_release(); + last_pos = { pos, snap }; + on_click(world, pos, mods); } } +void editor::on_click(world& world, global_coords pos, int mods) +{ + if (!current()) + return; + auto& mode = *current(); + + if (auto opt = mode.get_selected(); opt) + { + if (!_last_pos) + _last_pos = { pos, snap_mode::none }; + auto snap = _last_pos->snap; + if (snap == snap_mode::none) + snap = mode.check_snap(mods); + _last_pos = { pos, snap }; + mode.place_tile(world, pos, opt); + } + else + on_release(); +} + } // namespace floormat diff --git a/editor/editor.hpp b/editor/editor.hpp index 113cb915..c3b4d2ec 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -44,6 +44,13 @@ private: tile_image get_selected_perm(); public: + enum class snap_mode : std::uint8_t { + none = 0, + horizontal = 1 << 0, + vertical = 1 << 1, + both = horizontal | vertical, + }; + tile_editor(editor_mode mode, StringView name); std::shared_ptr<tile_atlas> maybe_atlas(StringView str); std::shared_ptr<tile_atlas> atlas(StringView str); @@ -65,6 +72,7 @@ public: void place_tile(world& world, global_coords pos, tile_image& img); void toggle_rotation(); void set_rotation(editor_wall_rotation r); + snap_mode check_snap(int mods) const; }; struct editor final @@ -77,8 +85,8 @@ struct editor final tile_editor* current() noexcept; const tile_editor* current() const noexcept; - void on_click(world& world, global_coords pos); - void on_mouse_move(world& world, global_coords pos); + void on_click(world& world, global_coords pos, int mods); + void on_mouse_move(world& world, global_coords pos, int modifiers); void on_release(); editor(); @@ -88,12 +96,19 @@ struct editor final static constexpr inline auto rotation_N = editor_wall_rotation::N; static constexpr inline auto rotation_W = editor_wall_rotation::W; + using snap_mode = tile_editor::snap_mode; private: + snap_mode get_snap_value(snap_mode snap, int mods) const; + tile_editor _floor{ editor_mode::floor, "floor" }; tile_editor _wall { editor_mode::walls, "wall" }; - std::optional<global_coords> _last_pos; + struct drag_pos final { + global_coords coord; + snap_mode snap = snap_mode::none; + }; + std::optional<drag_pos> _last_pos; editor_mode _mode = editor_mode::none; bool _dirty = false; }; diff --git a/editor/events.cpp b/editor/events.cpp index 8a665c64..fc8693af 100644 --- a/editor/events.cpp +++ b/editor/events.cpp @@ -3,12 +3,16 @@ #include "floormat/main.hpp" #include "floormat/events.hpp" #include "src/world.hpp" +#include "keys.hpp" #include <utility> #include <Magnum/Platform/Sdl2Application.h> #include <Magnum/ImGuiIntegration/Context.hpp> +#include <SDL_keycode.h> +#include <SDL_events.h> + namespace floormat { void app::on_focus_in() noexcept {} @@ -18,11 +22,21 @@ void app::on_any_event(const any_event&) noexcept {} #define accessor(type, name) \ type m_##name = {}; auto name() const noexcept { return m_##name; } -void app::clear_non_global_keys() +void app::clear_keys(key min_inclusive, key max_exclusive) { using key_type = decltype(keys)::value_type; - for (key i = key::MIN; i < key::GLOBAL; i = key{key_type(i) + 1}) - keys[i] = false; + for (key_type i = key_type(min_inclusive); i < key_type(max_exclusive); i++) + { + const auto idx = key(i); + keys[idx] = false; + key_modifiers[i] = kmod_none; + } +} + +void app::clear_keys() +{ + keys.reset(); + key_modifiers = {}; } void app::on_mouse_move(const mouse_move_event& event) noexcept @@ -33,7 +47,7 @@ void app::on_mouse_move(const mouse_move_event& event) noexcept cursor.in_imgui = _imgui.handleMouseMoveEvent(e); update_cursor_tile(event.position); - do_mouse_move(); + do_mouse_move(event.mods); } void app::on_mouse_up_down(const mouse_button_event& event, bool is_down) noexcept @@ -50,9 +64,7 @@ void app::on_mouse_up_down(const mouse_button_event& event, bool is_down) noexce } e = {event.position, Button(event.button)}; if (!(cursor.in_imgui = is_down ? _imgui.handleMousePressEvent(e) : _imgui.handleMouseReleaseEvent(e))) - do_mouse_up_down(event.button, is_down); - else - clear_non_global_keys(); + do_mouse_up_down(event.button, is_down, event.mods); } void app::on_mouse_scroll(const mouse_scroll_event& event) noexcept @@ -64,6 +76,21 @@ void app::on_mouse_scroll(const mouse_scroll_event& event) noexcept _imgui.handleMouseScrollEvent(e); } +static constexpr int fixup_mods_(int mods, int value, int mask) +{ + return !!(mods & mask) * value; +} + +static constexpr int fixup_mods(int mods) +{ + int ret = 0; + ret |= fixup_mods_(mods, kmod_ctrl, KMOD_CTRL); + ret |= fixup_mods_(mods, kmod_shift, KMOD_SHIFT); + ret |= fixup_mods_(mods, kmod_alt, KMOD_ALT); + ret |= fixup_mods_(mods, kmod_super, KMOD_GUI); + return ret; +} + void app::on_key_up_down(const key_event& event, bool is_down) noexcept { using KeyEvent = Platform::Sdl2Application::KeyEvent; @@ -75,29 +102,39 @@ void app::on_key_up_down(const key_event& event, bool is_down) noexcept accessor(Modifiers, modifiers) } e = {Ev::Key(event.key), Ev::Modifier(event.mods)}; - if (!(is_down ? _imgui.handleKeyPressEvent(e) : _imgui.handleKeyReleaseEvent(e))) - { - // todo put it into a separate function - const key x = fm_begin(switch (event.key) { - default: return key::COUNT; - case SDLK_w: return key::camera_up; - case SDLK_a: return key::camera_left; - case SDLK_s: return key::camera_down; - case SDLK_d: return key::camera_right; - case SDLK_HOME: return key::camera_reset; - case SDLK_r: return key::rotate_tile; - case SDLK_1: return key::mode_none; - case SDLK_2: return key::mode_floor; - case SDLK_3: return key::mode_walls; - case SDLK_F5: return key::quicksave; - case SDLK_F9: return key::quickload; - case SDLK_ESCAPE: return key::quit; - }); - if (x != key::COUNT && (!event.is_repeated || (key)x < key::NO_REPEAT)) - keys[x] = is_down; - } - else + [[maybe_unused]] constexpr int CTRL = kmod_ctrl; + [[maybe_unused]] constexpr int SHIFT = kmod_shift; + [[maybe_unused]] constexpr int ALT = kmod_alt; + [[maybe_unused]] constexpr int SUPER = kmod_super; + + const auto mods = fixup_mods(event.mods); + + const key x = fm_begin(switch (auto k = event.key | mods) { + default: return key_COUNT; + case SDLK_w: return key_camera_up; + case SDLK_a: return key_camera_left; + case SDLK_s: return key_camera_down; + case SDLK_d: return key_camera_right; + case SDLK_HOME: return key_camera_reset; + case SDLK_r: return key_rotate_tile; + case SDLK_1: return key_mode_none; + case SDLK_2: return key_mode_floor; + case SDLK_3: return key_mode_walls; + case SDLK_F5: return key_quicksave; + case SDLK_F9: return key_quickload; + case SDLK_q | CTRL: return key_quit; + }); + + if (x == key_COUNT) + void(); + else if (x >= key_NO_REPEAT) + !event.is_repeated ? do_key(x, mods) : void(); + else if (is_down ? _imgui.handleKeyPressEvent(e) : _imgui.handleKeyReleaseEvent(e)) clear_non_global_keys(); + else { + keys[x] = is_down; + key_modifiers[std::size_t(x)] = event.mods; + } } void app::on_text_input_event(const text_input_event& event) noexcept @@ -117,7 +154,7 @@ void app::on_viewport_event(const Math::Vector2<int>& size) noexcept void app::on_focus_out() noexcept { update_cursor_tile(std::nullopt); - keys = {}; + clear_keys(); } void app::on_mouse_leave() noexcept @@ -125,4 +162,14 @@ void app::on_mouse_leave() noexcept update_cursor_tile(std::nullopt); } +void app::do_key(floormat::key k) +{ + do_key(k, SDL_GetModState()); +} + +int app::get_key_modifiers() +{ + return fixup_mods(SDL_GetModState()); +} + } // namespace floormat diff --git a/editor/imgui.cpp b/editor/imgui.cpp index 588f4031..2edcd9d4 100644 --- a/editor/imgui.cpp +++ b/editor/imgui.cpp @@ -50,11 +50,11 @@ float app::draw_main_menu() ImGui::MenuItem("Floor", "2", &b_floor); ImGui::MenuItem("Walls", "3", &b_walls); if (b_none) - keys[key::mode_none] = true; - if (b_floor) - keys[key::mode_floor] = true; - if (b_walls) - keys[key::mode_walls] = true; + keys[key_mode_none] = true; + else if (b_floor) + keys[key_mode_floor] = true; + else if (b_walls) + keys[key_mode_walls] = true; } main_menu_height = ImGui::GetContentRegionMax().y; @@ -72,8 +72,8 @@ void app::draw_ui() if (auto* ed = _editor.current(); ed != nullptr) draw_editor_pane(*ed, main_menu_height); draw_fps(); - draw_cursor_tile(); - draw_cursor_tile_text(); + draw_cursor(); + draw_tile_under_cursor(); ImGui::EndFrame(); } @@ -191,7 +191,7 @@ void app::draw_fps() draw.AddText({M->window_size()[0] - size.x - 4, 3}, ImGui::ColorConvertFloat4ToU32({0, 1, 0, 1}), buf); } -void app::draw_cursor_tile_text() +void app::draw_tile_under_cursor() { if (!cursor.tile) return; diff --git a/editor/keys.hpp b/editor/keys.hpp new file mode 100644 index 00000000..a94e771e --- /dev/null +++ b/editor/keys.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "compat/integer-types.hpp" + +namespace floormat { + +enum kmod : int { + kmod_none = 0x0000, + kmod_shift = 0x0001 << 8, + kmod_ctrl = 0x0040 << 8, + kmod_alt = 0x0100 << 8, + kmod_super = 0x0400 << 8, +}; + +enum key : std::uint32_t { + key_noop, + key_camera_up, key_camera_left, key_camera_right, key_camera_down, key_camera_reset, + key_rotate_tile, + key_mode_none, key_mode_floor, key_mode_walls, + key_quit, + key_quicksave, key_quickload, + key_COUNT, key_MIN = key_noop, key_NO_REPEAT = key_rotate_tile, key_GLOBAL = key_quit, +}; + +} // namespace floormat diff --git a/editor/update.cpp b/editor/update.cpp index b26c783b..ea3e554a 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -35,49 +35,61 @@ void app::maybe_initialize_chunk([[maybe_unused]] const chunk_coords& pos, [[may //maybe_initialize_chunk_(pos, c); } -void app::do_mouse_move() +void app::do_mouse_move(int mods) { if (cursor.tile && !cursor.in_imgui) - _editor.on_mouse_move(M->world(), *cursor.tile); + _editor.on_mouse_move(M->world(), *cursor.tile, mods); } -void app::do_mouse_up_down(std::uint8_t button, bool is_down) +void app::do_mouse_up_down(std::uint8_t button, bool is_down, int mods) { if (cursor.tile && !cursor.in_imgui && button == mouse_button_left && is_down) - _editor.on_click(M->world(), *cursor.tile); + _editor.on_click(M->world(), *cursor.tile, mods); else _editor.on_release(); } -void app::apply_commands(const enum_bitset<key>& k) +void app::do_key(key k, int mods) { - if (keys[key::quit]) + (void)mods; + switch (k) { - M->quit(0); + default: + fm_warn("unhandled key: '%zu'", std::size_t(k)); return; - } - - if (k[key::mode_none]) - _editor.set_mode(editor_mode::none); - if (k[key::mode_floor]) - _editor.set_mode(editor_mode::floor); - if (k[key::mode_walls]) - _editor.set_mode(editor_mode::walls); - if (k[key::rotate_tile]) + case key_rotate_tile: if (auto* ed = _editor.current(); ed) ed->toggle_rotation(); + return; + case key_mode_none: + return _editor.set_mode(editor_mode::none); + case key_mode_floor: + return _editor.set_mode(editor_mode::floor); + case key_mode_walls: + return _editor.set_mode(editor_mode::walls); + case key_quicksave: + return do_quicksave(); + case key_quickload: + return do_quickload(); + case key_quit: + return M->quit(0); + } +} - if (k[key::quicksave]) - do_quicksave(); - if (k[key::quickload]) - do_quickload(); +void app::apply_commands(const key_set& keys) +{ + using value_type = key_set::value_type; + for (value_type i = key_NO_REPEAT; i < key_COUNT; i++) + if (const auto k = key(i); keys[k]) + do_key(k, key_modifiers[i]); } void app::update(float dt) { draw_ui(); apply_commands(keys); - do_camera(dt, keys); + do_camera(dt, keys, get_key_modifiers()); + clear_non_repeated_keys(); } } // namespace floormat |