summaryrefslogtreecommitdiffhomepage
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/app.hpp3
-rw-r--r--editor/camera.cpp73
-rw-r--r--editor/draw.cpp4
-rw-r--r--editor/editor.cpp6
-rw-r--r--editor/editor.hpp5
-rw-r--r--editor/scenery-editor.cpp35
-rw-r--r--editor/scenery-editor.hpp3
-rw-r--r--editor/vobj-editor.cpp2
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];