diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/app.hpp | 3 | ||||
-rw-r--r-- | editor/camera.cpp | 73 | ||||
-rw-r--r-- | editor/draw.cpp | 4 | ||||
-rw-r--r-- | editor/editor.cpp | 6 | ||||
-rw-r--r-- | editor/editor.hpp | 5 | ||||
-rw-r--r-- | editor/scenery-editor.cpp | 35 | ||||
-rw-r--r-- | editor/scenery-editor.hpp | 3 | ||||
-rw-r--r-- | editor/vobj-editor.cpp | 2 |
8 files changed, 100 insertions, 31 deletions
diff --git a/editor/app.hpp b/editor/app.hpp index b78037a0..51ea0296 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -58,6 +58,7 @@ struct app final : floormat_app #ifdef _WIN32 static void set_dpi_aware(); #endif + object_id object_at_cursor(); private: using key_set = enum_bitset<key, key_COUNT>; @@ -149,7 +150,7 @@ private: wireframe_mesh<wireframe::quad_wall_w> _wireframe_wall_w {_wireframe_texture}; wireframe_mesh<wireframe::box> _wireframe_box {_wireframe_texture}; wireframe_mesh<wireframe::quad> _wireframe_rect {_wireframe_texture}; - editor _editor; + editor _editor{this}; key_set keys; std::array<int, key_set::COUNT> key_modifiers = {}; std::vector<popup_target> inspectors; diff --git a/editor/camera.cpp b/editor/camera.cpp index fa933fcf..77e3a149 100644 --- a/editor/camera.cpp +++ b/editor/camera.cpp @@ -2,6 +2,9 @@ #include "src/global-coords.hpp" #include "shaders/shader.hpp" #include "floormat/main.hpp" +#include "src/RTree-search.hpp" +#include "src/world.hpp" +#include "src/camera-offset.hpp" #include <algorithm> namespace floormat { @@ -57,6 +60,76 @@ void app::reset_camera_offset() update_cursor_tile(cursor.pixel); } +object_id app::object_at_cursor() +{ + auto [z_min, z_max, z_cur, only] = get_z_bounds(); + if (only) + z_min = z_max = z_cur; + const auto [minx, maxx, miny, maxy] = M->get_draw_bounds(); + const auto sz = M->window_size(); + auto& world = M->world(); + auto& shader = M->shader(); + + using rtree_type = std::decay_t<decltype(*world[chunk_coords_{}].rtree())>; + using rect_type = typename rtree_type::Rect; + + if (cursor.pixel) + { + auto pos = tile_shader::project(Vector3d{0., 0., -_z_level*dTILE_SIZE[2]}); + auto pixel = Vector2d{*cursor.pixel} + pos; + auto coord = M->pixel_to_tile(pixel); + auto tile = global_coords{coord.chunk(), coord.local(), 0}; + + constexpr auto eps = 1e-6f; + constexpr auto m = TILE_SIZE2 * Vector2(1- eps, 1- eps); + const auto tile_ = Vector2(M->pixel_to_tile_(Vector2d(pixel))); + const auto curchunk = Vector2(tile.chunk()), curtile = Vector2(tile.local()); + const auto subpixel_ = Vector2(std::fmod(tile_[0], 1.f), std::fmod(tile_[1], 1.f)); + const auto subpixel = m * Vector2(curchunk[0] < 0 ? 1 + subpixel_[0] : subpixel_[0], + curchunk[1] < 0 ? 1 + subpixel_[1] : subpixel_[1]); + for (int16_t y = miny; y <= maxy; y++) + for (int16_t x = minx; x <= maxx; x++) + { + const chunk_coords_ c_pos{x, y, _z_level}; + auto* c_ = world.at(c_pos); + if (!c_) + continue; + auto& c = *c_; + c.ensure_passability(); + const with_shifted_camera_offset o{shader, c_pos, {minx, miny}, {maxx, maxy}}; + if (floormat_main::check_chunk_visible(shader.camera_offset(), sz)) + { + constexpr auto half_tile = TILE_SIZE2/2; + constexpr auto chunk_size = TILE_SIZE2 * TILE_MAX_DIM; + auto chunk_dist = (curchunk - Vector2(c_pos.x, c_pos.y))*chunk_size; + auto t0 = chunk_dist + curtile*TILE_SIZE2 + subpixel - half_tile; + auto t1 = t0+Vector2(1e-4f); + const auto* rtree = c.rtree(); + object_id ret = 0; + rtree->Search(t0.data(), t1.data(), [&](uint64_t data, const rect_type& rect) { + [[maybe_unused]] auto x = std::bit_cast<collision_data>(data); + if (x.tag == (uint64_t)collision_type::geometry) + return true; + Vector2 min(rect.m_min[0], rect.m_min[1]), max(rect.m_max[0], rect.m_max[1]); + if (t0 >= min && t0 <= max) + { + if (auto e_ = world.find_entity(x.data); + e_ && Vector2ui(e_->bbox_size).product() != 0) + { + ret = x.data; + return false; + } + } + return true; + }); + if (ret) + return ret; + } + } + } + return 0; +} + void app::update_cursor_tile(const Optional<Vector2i>& pixel) { cursor.pixel = pixel; diff --git a/editor/draw.cpp b/editor/draw.cpp index 124ca5d3..b6edf215 100644 --- a/editor/draw.cpp +++ b/editor/draw.cpp @@ -180,7 +180,9 @@ void app::draw() { if (_render_bboxes) draw_collision_boxes(); - if (_editor.current_tile_editor() || _editor.current_scenery_editor() || _editor.current_vobj_editor()) + if (_editor.current_tile_editor() || + _editor.current_scenery_editor() && _editor.current_scenery_editor()->is_anything_selected() || + _editor.current_vobj_editor()) draw_cursor(); draw_ui(); render_menu(); diff --git a/editor/editor.cpp b/editor/editor.cpp index b744f03c..3c470bf2 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -109,10 +109,10 @@ void editor::on_click_(world& world, global_coords pos, button b) default: break; case button::place: if (const auto& sel = mode->get_selected()) - mode->place_tile(world, pos, sel); + mode->place_tile(world, pos, sel, *_app); break; case button::remove: - mode->place_tile(world, pos, {}); + mode->place_tile(world, pos, {}, *_app); break; } } @@ -151,7 +151,7 @@ void editor::on_click(world& world, global_coords pos, int mods, button b) } } -editor::editor() = default; +editor::editor(app* a) : _app{a} {} void editor::set_mode(editor_mode mode) { diff --git a/editor/editor.hpp b/editor/editor.hpp index 868797fd..60e257d2 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -17,6 +17,7 @@ namespace floormat { struct world; struct anim_atlas; struct tile_atlas; +struct app; struct editor final { @@ -40,7 +41,7 @@ struct editor final void on_release(); void clear_selection(); - editor(); + editor(app* a); editor(editor&&) noexcept = default; editor& operator=(editor&&) noexcept = default; fm_DECLARE_DELETED_COPY_ASSIGNMENT(editor); @@ -53,6 +54,8 @@ private: snap_mode get_snap_value(snap_mode snap, int mods) const; static global_coords apply_snap(global_coords pos, global_coords last, snap_mode snap) noexcept; + app* _app; + tile_editor _floor{ editor_mode::floor, "floor"_s }; tile_editor _wall { editor_mode::walls, "wall"_s }; scenery_editor _scenery; diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp index b012af8d..66ff94bb 100644 --- a/editor/scenery-editor.cpp +++ b/editor/scenery-editor.cpp @@ -5,6 +5,8 @@ #include "src/world.hpp" #include "src/RTree-search.hpp" #include "rotation.inl" +#include "app.hpp" +#include <Magnum/Math/Range.h> namespace floormat { @@ -78,36 +80,23 @@ bool scenery_editor::is_anything_selected() const return _selected.proto.atlas != nullptr; } -void scenery_editor::place_tile(world& w, global_coords pos, const scenery_& s) +void scenery_editor::place_tile(world& w, global_coords pos, const scenery_& s, app& a) { if (!s) { auto [c, t] = w[pos]; - - // don't regen colliders - const auto es = c.entities(); - constexpr auto half_tile = TILE_SIZE2/2; - auto center = Vector2(pos.local())*TILE_SIZE2, - min = center - half_tile, max = min + half_tile; - for (auto i = es.size()-1; i != (size_t)-1; i--) + const auto& es = c.entities(); +start: while (auto id = a.object_at_cursor()) { - const auto& e = *es[i]; - if (e.type() != entity_type::scenery) - continue; - using rtree_type = std::decay_t<decltype(*w[chunk_coords_{}].rtree())>; - using rect_type = typename rtree_type::Rect; - bool do_remove = false; - c.rtree()->Search(min.data(), max.data(), [&](uint64_t data, const rect_type&) { - [[maybe_unused]] auto x = std::bit_cast<collision_data>(data); - if (e.id == x.data) + for (auto i = es.size()-1; i != (size_t)-1; i--) + { + if (es[i]->id == id) { - do_remove = true; - return false; + c.remove_entity(i); + goto start; } - return true; - }); - if (do_remove) - c.remove_entity(i); + } + break; } } else diff --git a/editor/scenery-editor.hpp b/editor/scenery-editor.hpp index c23c0c71..8b497015 100644 --- a/editor/scenery-editor.hpp +++ b/editor/scenery-editor.hpp @@ -9,6 +9,7 @@ namespace floormat { struct anim_atlas; struct global_coords; struct world; +struct app; struct scenery_editor final { @@ -31,7 +32,7 @@ struct scenery_editor final bool is_atlas_selected(const std::shared_ptr<anim_atlas>& atlas) const; bool is_item_selected(const scenery_& s) const; bool is_anything_selected() const; - static void place_tile(world& w, global_coords pos, const scenery_& s); + static void place_tile(world& w, global_coords pos, const scenery_& s, app& a); auto cbegin() const noexcept { return _atlases.cbegin(); } auto cend() const noexcept { return _atlases.cend(); } diff --git a/editor/vobj-editor.cpp b/editor/vobj-editor.cpp index 2693c44a..2cec6a5c 100644 --- a/editor/vobj-editor.cpp +++ b/editor/vobj-editor.cpp @@ -46,7 +46,7 @@ void vobj_editor::place_tile(world& w, global_coords pos, const vobj_* x) // don't regen colliders auto [c, t] = w[pos]; const auto px = Vector2(pos.local()) * TILE_SIZE2; - const auto es = c.entities(); + const auto& es = c.entities(); for (auto i = es.size()-1; i != (size_t)-1; i--) { const auto& e = *es[i]; |