summaryrefslogtreecommitdiffhomepage
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/app.hpp51
-rw-r--r--editor/camera.cpp16
-rw-r--r--editor/draw.cpp4
-rw-r--r--editor/editor.cpp102
-rw-r--r--editor/editor.hpp21
-rw-r--r--editor/events.cpp107
-rw-r--r--editor/imgui.cpp16
-rw-r--r--editor/keys.hpp24
-rw-r--r--editor/update.cpp54
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