diff options
-rw-r--r-- | draw/anim.cpp | 16 | ||||
-rw-r--r-- | draw/anim.hpp | 8 | ||||
-rw-r--r-- | editor/app.hpp | 5 | ||||
-rw-r--r-- | editor/draw.cpp | 13 | ||||
-rw-r--r-- | editor/scenery-editor.cpp | 6 | ||||
-rw-r--r-- | editor/update.cpp | 53 | ||||
-rw-r--r-- | floormat/main.hpp | 6 | ||||
-rw-r--r-- | main/clickable.hpp | 7 | ||||
-rw-r--r-- | main/draw.cpp | 4 | ||||
-rw-r--r-- | main/main-impl.hpp | 8 | ||||
-rw-r--r-- | src/scenery.cpp | 63 | ||||
-rw-r--r-- | src/scenery.hpp | 10 |
12 files changed, 108 insertions, 91 deletions
diff --git a/draw/anim.cpp b/draw/anim.cpp index 779c5a46..591d3801 100644 --- a/draw/anim.cpp +++ b/draw/anim.cpp @@ -27,21 +27,23 @@ std::array<UnsignedShort, 6> anim_mesh::make_index_array() void anim_mesh::add_clickable(tile_shader& shader, const Vector2i& win_size, chunk_coords c, std::uint8_t i, const std::shared_ptr<anim_atlas>& atlas, scenery& s, - std::vector<clickable_scenery>& clickable) + std::vector<clickable>& list) { const local_coords xy{i}; - const auto& g = atlas->group(s.r); - const auto& f = atlas->frame(s.r, s.frame); + const auto& a = *atlas; + const auto& g = a.group(s.r); + const auto& f = a.frame(s.r, s.frame); const auto world_pos = TILE_SIZE20 * Vector3(xy) + Vector3(g.offset) + Vector3(Vector2(s.offset), 0); const Vector2ui offset((Vector2(shader.camera_offset()) + Vector2(win_size)*.5f) + shader.project(world_pos) - Vector2(f.ground)); - clickable_scenery item = { - *atlas, s, + clickable item = { { f.offset, f.offset + f.size }, { offset, offset + f.size }, - atlas->bitmask(), tile_shader::depth_value(xy, tile_shader::scenery_depth_offset), c, xy, + a.bitmask(), tile_shader::depth_value(xy, tile_shader::scenery_depth_offset), + a.info().pixel_size[0], + c, xy, !g.mirror_from.isEmpty(), }; - clickable.push_back(item); + list.push_back(item); } void anim_mesh::draw(tile_shader& shader, chunk& c) diff --git a/draw/anim.hpp b/draw/anim.hpp index 1ce38d08..ccb03403 100644 --- a/draw/anim.hpp +++ b/draw/anim.hpp @@ -17,21 +17,19 @@ namespace floormat { struct tile_shader; struct anim_atlas; struct chunk; -template<typename Atlas, typename T> struct clickable; +struct clickable; struct scenery; struct anim_mesh final { - using clickable_scenery = clickable<anim_atlas, scenery>; - anim_mesh(); void draw(tile_shader& shader, chunk& c); void draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, const Vector3& pos, float depth); void draw(tile_shader& shader, anim_atlas& atlas, rotation r, std::size_t frame, local_coords xy, Vector2b offset); static void add_clickable(tile_shader& shader, const Vector2i& win_size, - chunk_coords c, std::uint8_t i, const std::shared_ptr<anim_atlas>& atlas, scenery& s, - std::vector<clickable_scenery>& clickable); + chunk_coords c, std::uint8_t i, const std::shared_ptr<anim_atlas>& atlas, scenery& s, + std::vector<clickable>& list); private: struct vertex_data final { diff --git a/editor/app.hpp b/editor/app.hpp index ff98ce99..c958fdf4 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -31,8 +31,7 @@ struct cursor_state final { bool in_imgui = false; }; -template<typename Atlas, typename T> struct clickable; -using clickable_scenery = clickable<anim_atlas, scenery>; +struct clickable; enum class Cursor: std::uint32_t { Arrow, TextInput, Wait, Crosshair, WaitArrow, @@ -86,7 +85,7 @@ private: void do_camera(float dt, const key_set& cmds, int mods); void reset_camera_offset(); - clickable_scenery* find_clickable_scenery(const Optional<Vector2i>& pixel); + clickable* find_clickable_scenery(const Optional<Vector2i>& pixel); void do_quicksave(); void do_quickload(); diff --git a/editor/draw.cpp b/editor/draw.cpp index 41a5c713..77d3f665 100644 --- a/editor/draw.cpp +++ b/editor/draw.cpp @@ -144,25 +144,22 @@ void app::draw() render_menu(); } -clickable_scenery* app::find_clickable_scenery(const Optional<Vector2i>& pixel_) +clickable* app::find_clickable_scenery(const Optional<Vector2i>& pixel_) { if (!pixel_ || _editor.mode() != editor_mode::none) return nullptr; const auto pixel = Vector2ui(*pixel_); - clickable_scenery* item = nullptr; + clickable* item = nullptr; float depth = -1; const auto array = M->clickable_scenery(); - for (clickable_scenery& c : array) + for (clickable& c : array) if (c.depth > depth && c.dest.contains(pixel)) { const auto pos_ = pixel - c.dest.min() + c.src.min(); - const auto pos = c.atlas.group(c.item.r).mirror_from.isEmpty() - ? pos_ - : Vector2ui(c.src.sizeX() - 1 - pos_[0], pos_[1]); - const auto stride = c.atlas.info().pixel_size[0]; - std::size_t idx = pos.y() * stride + pos.x(); + const auto pos = !c.mirrored ? pos_ : Vector2ui(c.src.sizeX() - 1 - pos_[0], pos_[1]); + std::size_t idx = pos.y() * c.stride + pos.x(); fm_debug_assert(idx < c.bitmask.size()); if (c.bitmask[idx]) { diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp index f9a0678e..1d0635a6 100644 --- a/editor/scenery-editor.cpp +++ b/editor/scenery-editor.cpp @@ -3,6 +3,7 @@ #include "loader/loader.hpp" #include "compat/assert.hpp" #include "src/world.hpp" +#include "rotation.inl" namespace floormat { @@ -21,7 +22,10 @@ scenery_editor::scenery_editor() noexcept void scenery_editor::set_rotation(rotation_ r) { - _selected.proto.frame.rotate(r); + auto& s = _selected.proto.frame; + s.bbox_offset = rotate_point(s.bbox_offset, s.r, r); + s.bbox_size = rotate_size(s.bbox_size, s.r, r); + s.r = r; } rotation_ scenery_editor::rotation() const diff --git a/editor/update.cpp b/editor/update.cpp index afc3b6cc..35170ffc 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -49,6 +49,7 @@ void app::do_mouse_move(int mods) void app::do_mouse_up_down(std::uint8_t button, bool is_down, int mods) { + auto& w = M->world(); update_cursor_tile(cursor.pixel); if (is_down && cursor.tile && !cursor.in_imgui) @@ -59,13 +60,18 @@ void app::do_mouse_up_down(std::uint8_t button, bool is_down, int mods) break; case editor_mode::none: if (button == mouse_button_left) - if (auto* s = find_clickable_scenery(*cursor.pixel); s && s->item.can_activate(s->atlas)) - return (void)s->item.activate(s->atlas); + { + if (auto* cl = find_clickable_scenery(*cursor.pixel)) + { + auto [c, t] = w[{cl->chunk, cl->pos}]; + if (auto s = t.scenery()) + return (void)s.activate(); + } + } break; case editor_mode::floor: case editor_mode::walls: case editor_mode::scenery: - auto& w = M->world(); auto pos = *cursor.tile; switch (button) { @@ -94,12 +100,13 @@ void app::do_rotate(bool backward) else if (cursor.tile) { auto [c, t] = M->world()[*cursor.tile]; - if (auto [atlas, s] = t.scenery(); atlas) + if (auto sc = t.scenery()) { + auto [atlas, s] = sc; auto r = backward ? atlas->prev_rotation_from(s.r) : atlas->next_rotation_from(s.r); if (r != s.r) { - s.rotate(r); + sc.rotate(r); c.mark_scenery_modified(); } } @@ -157,15 +164,16 @@ void app::update_world(float dt) for (std::int16_t y = miny; y <= maxy; y++) for (std::int16_t x = minx; x <= maxx; x++) for (auto& c = world[chunk_coords{x, y}]; auto [x, k, pt] : c) - if (auto [atlas, scenery] = x.scenery(); atlas != nullptr) + if (auto sc = x.scenery()) { - auto pass0 = scenery.passability; - auto offset0 = scenery.offset; - auto bb_offset0 = scenery.bbox_offset; - auto bb_size0 = scenery.bbox_size; - scenery.update(dt, *atlas); - if (pass0 != scenery.passability || offset0 != scenery.offset || - bb_offset0 != scenery.bbox_offset || bb_size0 != scenery.bbox_size) + auto [atlas, s] = x.scenery(); + auto pass0 = s.passability; + auto offset0 = s.offset; + auto bb_offset0 = s.bbox_offset; + auto bb_size0 = s.bbox_size; + sc.update(dt); + if (pass0 != s.passability || offset0 != s.offset || + bb_offset0 != s.bbox_offset || bb_size0 != s.bbox_size) c.mark_scenery_modified(); } } @@ -179,12 +187,19 @@ void app::update(float dt) if (!cursor.in_imgui) { - auto* s = find_clickable_scenery(cursor.pixel); - - if (s && s->item.can_activate(s->atlas)) - M->set_cursor(std::uint32_t(Cursor::Hand)); - else - set_cursor_from_imgui(); + if (auto* cl = find_clickable_scenery(cursor.pixel)) + { + auto& w = M->world(); + auto [c, t] = w[{cl->chunk, cl->pos}]; + if (auto sc = t.scenery()) + { + auto [atlas, s] = sc; + if (sc && sc.can_activate()) + M->set_cursor(std::uint32_t(Cursor::Hand)); + else + set_cursor_from_imgui(); + } + } } M->world().maybe_collect(); diff --git a/floormat/main.hpp b/floormat/main.hpp index b729e9a2..08d94404 100644 --- a/floormat/main.hpp +++ b/floormat/main.hpp @@ -16,7 +16,7 @@ struct tile_shader; struct world; struct scenery; struct anim_atlas; -template<typename Atlas, typename T> struct clickable; +struct clickable; struct floor_mesh; struct wall_mesh; struct anim_mesh; @@ -53,8 +53,8 @@ struct floormat_main virtual void start_text_input() noexcept = 0; virtual void stop_text_input() noexcept = 0; - virtual ArrayView<const clickable<anim_atlas, scenery>> clickable_scenery() const noexcept = 0; - virtual ArrayView<clickable<anim_atlas, scenery>> clickable_scenery() noexcept = 0; + virtual ArrayView<const clickable> clickable_scenery() const noexcept = 0; + virtual ArrayView<clickable> clickable_scenery() noexcept = 0; virtual void set_cursor(std::uint32_t cursor) noexcept = 0; virtual std::uint32_t cursor() const noexcept = 0; diff --git a/main/clickable.hpp b/main/clickable.hpp index 3eee243f..92b8dd49 100644 --- a/main/clickable.hpp +++ b/main/clickable.hpp @@ -5,17 +5,14 @@ namespace floormat { -template<typename Atlas, typename T> struct clickable final { - - Atlas& atlas; - T& item; Math::Range2D<UnsignedInt> src, dest; BitArrayView bitmask; float depth = 0; + std::uint32_t stride; chunk_coords chunk; local_coords pos; - bool mirrored = false; + bool mirrored; }; } // namespace floormat diff --git a/main/draw.cpp b/main/draw.cpp index 957d3217..28bd1fdd 100644 --- a/main/draw.cpp +++ b/main/draw.cpp @@ -215,12 +215,12 @@ void main_impl::drawEvent() timeline.nextFrame(); } -ArrayView<const clickable<anim_atlas, scenery>> main_impl::clickable_scenery() const noexcept +ArrayView<const clickable> main_impl::clickable_scenery() const noexcept { return { _clickable_scenery.data(), _clickable_scenery.size() }; } -ArrayView<clickable<anim_atlas, scenery>> main_impl::clickable_scenery() noexcept +ArrayView<clickable> main_impl::clickable_scenery() noexcept { return { _clickable_scenery.data(), _clickable_scenery.size() }; } diff --git a/main/main-impl.hpp b/main/main-impl.hpp index 3ec6b8a5..deb5d73e 100644 --- a/main/main-impl.hpp +++ b/main/main-impl.hpp @@ -19,7 +19,7 @@ namespace floormat { struct floormat_app; struct scenery; struct anim_atlas; -template<typename Atlas, typename T> struct clickable; +struct clickable; struct main_impl final : Platform::Sdl2Application, floormat_main { @@ -41,8 +41,8 @@ struct main_impl final : Platform::Sdl2Application, floormat_main global_coords pixel_to_tile(Vector2d position) const noexcept override; Vector2d pixel_to_tile_(Vector2d position) const noexcept override; - ArrayView<const clickable<anim_atlas, scenery>> clickable_scenery() const noexcept override; - ArrayView<clickable<anim_atlas, scenery>> clickable_scenery() noexcept override; + ArrayView<const clickable> clickable_scenery() const noexcept override; + ArrayView<clickable> clickable_scenery() noexcept override; Platform::Sdl2Application& application() noexcept override; const Platform::Sdl2Application& application() const noexcept override; @@ -77,7 +77,7 @@ private: [[maybe_unused]] char _dummy = maybe_register_debug_callback(s.gpu_debug); floormat_app& app; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) tile_shader _shader; - std::vector<clickable<anim_atlas, scenery>> _clickable_scenery; + std::vector<clickable> _clickable_scenery; struct world _world{}; Magnum::Timeline timeline; floor_mesh _floor_mesh; diff --git a/src/scenery.cpp b/src/scenery.cpp index 7c32248b..86ebea73 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -64,72 +64,77 @@ scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open, fm_assert(atlas.group(r).frames.size() >= 2); } -void scenery::rotate(rotation new_r) +void scenery_ref::rotate(rotation new_r) { - bbox_offset = rotate_point(bbox_offset, r, new_r); - bbox_size = rotate_size(bbox_size, r, new_r); - r = new_r; + auto& s = frame; + s.bbox_offset = rotate_point(s.bbox_offset, s.r, new_r); + s.bbox_size = rotate_size(s.bbox_size, s.r, new_r); + s.r = new_r; } -bool scenery::can_activate(const anim_atlas&) const noexcept +bool scenery_ref::can_activate() noexcept { - return interactive; + return frame.interactive; } -void scenery::update(float dt, const anim_atlas& anim) +void scenery_ref::update(float dt) { - if (!active) + auto& s = frame; + if (!s.active) return; - switch (type) + switch (s.type) { default: case scenery_type::none: case scenery_type::generic: break; case scenery_type::door: - const auto hz = std::uint8_t(anim.info().fps); + fm_assert(atlas); + auto& anim = *atlas; + const auto hz = std::uint8_t(atlas->info().fps); const auto nframes = (int)anim.info().nframes; fm_debug_assert(anim.info().fps > 0 && anim.info().fps <= 0xff); - auto delta_ = int(delta) + int(65535u * dt); + auto delta_ = int(s.delta) + int(65535u * dt); delta_ = std::min(65535, delta_); const auto frame_time = int(1.f/hz * 65535); const auto n = (std::uint8_t)std::clamp(delta_ / frame_time, 0, 255); - delta = (std::uint16_t)std::clamp(delta_ - frame_time*n, 0, 65535); - fm_debug_assert(delta >= 0); - const std::int8_t dir = closing ? 1 : -1; - const int fr = frame + dir*n; - active = fr > 0 && fr < nframes-1; + s.delta = (std::uint16_t)std::clamp(delta_ - frame_time*n, 0, 65535); + fm_debug_assert(s.delta >= 0); + const std::int8_t dir = s.closing ? 1 : -1; + const int fr = s.frame + dir*n; + s.active = fr > 0 && fr < nframes-1; if (fr <= 0) - passability = pass_mode::pass; + s.passability = pass_mode::pass; else if (fr >= nframes-1) - passability = pass_mode::blocked; + s.passability = pass_mode::blocked; else - passability = pass_mode::see_through; - frame = (frame_t)std::clamp(fr, 0, nframes-1); - if (!active) - delta = closing = 0; + s.passability = pass_mode::see_through; + s.frame = (scenery::frame_t)std::clamp(fr, 0, nframes-1); + if (!s.active) + s.delta = s.closing = 0; break; } } -bool scenery::activate(const anim_atlas& atlas) +bool scenery_ref::activate() { - if (active) + auto& s = frame; + if (!*this || s.active) return false; - switch (type) + switch (s.type) { default: case scenery_type::none: case scenery_type::generic: break; case scenery_type::door: - fm_assert(frame == 0 || frame == atlas.info().nframes-1); - closing = frame == 0; - frame += closing ? 1 : -1; - active = true; + fm_assert(s.frame == 0 || s.frame == atlas->info().nframes-1); + s.closing = s.frame == 0; + s.frame += s.closing ? 1 : -1; + s.active = true; return true; } return false; diff --git a/src/scenery.hpp b/src/scenery.hpp index 5fe2f043..7d2cb502 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -49,11 +49,6 @@ struct scenery final Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); bool operator==(const scenery&) const noexcept; - - bool can_activate(const anim_atlas& anim) const noexcept; - bool activate(const anim_atlas& atlas); - void update(float dt, const anim_atlas& anim); - void rotate(rotation r); }; constexpr scenery::scenery() noexcept : scenery{scenery::none_tag_t{}} {} @@ -100,6 +95,11 @@ struct scenery_ref final { std::shared_ptr<anim_atlas>& atlas; scenery& frame; + bool can_activate() noexcept; + bool activate(); + void update(float dt); + void rotate(rotation r); + private: struct chunk* c; std::uint8_t idx; |