summaryrefslogtreecommitdiffhomepage
path: root/editor/ground-editor.cpp
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-01-11 13:54:53 +0100
committerStanislaw Halik <sthalik@misaki.pl>2024-01-11 14:11:47 +0100
commit7867213a01fcabb1f05b1836c2ca59dc3bb2132f (patch)
tree44af754bed0278c8bf3435df6278bd291c3043e5 /editor/ground-editor.cpp
parent74cf06b6b217eff32a547cf73f051f27e6b80919 (diff)
rename tile_atlas -> ground_atlas
Diffstat (limited to 'editor/ground-editor.cpp')
-rw-r--r--editor/ground-editor.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/editor/ground-editor.cpp b/editor/ground-editor.cpp
new file mode 100644
index 00000000..0f67853e
--- /dev/null
+++ b/editor/ground-editor.cpp
@@ -0,0 +1,166 @@
+#include "ground-editor.hpp"
+#include "src/ground-atlas.hpp"
+#include "src/world.hpp"
+#include "src/random.hpp"
+#include "keys.hpp"
+#include "loader/loader.hpp"
+#include "compat/exception.hpp"
+#include <Corrade/Containers/PairStl.h>
+#include <Corrade/Utility/Path.h>
+
+namespace floormat {
+
+ground_editor::ground_editor()
+{
+ load_atlases();
+}
+
+void ground_editor::load_atlases()
+{
+ for (const auto& atlas : loader.ground_atlases("floor.json"_s))
+ {
+ auto& [_, vec] = _permutation;
+ vec.reserve(atlas->num_tiles());
+ _atlases[atlas->name()] = atlas;
+ }
+}
+
+std::shared_ptr<ground_atlas> ground_editor::maybe_atlas(StringView str)
+{
+ if (auto it = _atlases.find(str); it != _atlases.end())
+ return it->second;
+ else
+ return nullptr;
+}
+
+std::shared_ptr<ground_atlas> ground_editor::atlas(StringView str)
+{
+ if (auto ptr = maybe_atlas(str))
+ return ptr;
+ else
+ fm_throw("no such atlas: {}"_cf, str);
+}
+
+StringView ground_editor::name() const noexcept { return "floor"_s; }
+
+void ground_editor::clear_selection()
+{
+ _selected_tile = {};
+ _permutation = {};
+ _selection_mode = sel_none;
+}
+
+void ground_editor::select_tile(const std::shared_ptr<ground_atlas>& atlas, size_t variant)
+{
+ fm_assert(atlas);
+ clear_selection();
+ _selection_mode = sel_tile;
+ _selected_tile = { atlas, variant_t(variant % atlas->num_tiles()) };
+}
+
+void ground_editor::select_tile_permutation(const std::shared_ptr<ground_atlas>& atlas)
+{
+ fm_assert(atlas);
+ clear_selection();
+ _selection_mode = sel_perm;
+ _permutation = { atlas, {} };
+}
+
+bool ground_editor::is_tile_selected(const std::shared_ptr<const ground_atlas>& atlas, size_t variant) const
+{
+ return atlas && _selection_mode == sel_tile && _selected_tile &&
+ atlas == _selected_tile.atlas && variant == _selected_tile.variant;
+}
+
+bool ground_editor::is_permutation_selected(const std::shared_ptr<const ground_atlas>& atlas) const
+{
+ const auto& [perm, _] = _permutation;
+ return atlas && _selection_mode == sel_perm && perm == atlas;
+}
+
+bool ground_editor::is_atlas_selected(const std::shared_ptr<const ground_atlas>& atlas) const
+{
+ switch (_selection_mode)
+ {
+ default:
+ case sel_none:
+ return false;
+ case sel_perm:
+ return is_permutation_selected(atlas);
+ case sel_tile:
+ return atlas && _selected_tile && atlas == _selected_tile.atlas;
+ }
+}
+
+bool ground_editor::is_anything_selected() const
+{
+ return _selection_mode != sel_none;
+}
+
+template<std::random_access_iterator T>
+void fisher_yates(T begin, T end)
+{
+ const auto N = std::distance(begin, end);
+ for (auto i = N-1; i >= 1; i--)
+ {
+ const auto j = random(i+1);
+ using std::swap;
+ swap(begin[i], begin[j]);
+ }
+}
+
+tile_image_proto ground_editor::get_selected_perm()
+{
+ auto& [atlas, vec] = _permutation;
+ const auto N = (variant_t)atlas->num_tiles();
+ if (N == 0)
+ return {};
+ if (vec.empty())
+ {
+ for (variant_t i = 0; i < N; i++)
+ vec.push_back(i);
+ fisher_yates(vec.begin(), vec.end());
+ }
+ const auto idx = vec.back();
+ vec.pop_back();
+ return {atlas, idx};
+}
+
+tile_image_proto ground_editor::get_selected()
+{
+ switch (_selection_mode)
+ {
+ default:
+ fm_warn_once("invalid editor mode '%u'", (unsigned)_selection_mode);
+ [[fallthrough]];
+ case sel_none:
+ return {};
+ case sel_tile:
+ return _selected_tile;
+ case sel_perm:
+ return get_selected_perm();
+ }
+}
+
+void ground_editor::place_tile(world& world, global_coords pos, const tile_image_proto& img)
+{
+ auto [c, t] = world[pos];
+ c.mark_ground_modified();
+ t.ground() = img;
+}
+
+auto ground_editor::check_snap(int mods) const -> editor_snap_mode
+{
+ const bool ctrl = mods & kmod_ctrl, shift = mods & kmod_shift;
+
+ if (!(ctrl | shift))
+ return editor_snap_mode::none;
+
+ if (shift)
+ return editor_snap_mode::horizontal;
+ if (ctrl)
+ return editor_snap_mode::vertical;
+ return editor_snap_mode::none;
+}
+
+} // namespace floormat