diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-02-26 19:16:25 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-02-26 19:16:25 +0100 |
commit | 90d388665cfdb048a71fcadf0e142bb679f160ef (patch) | |
tree | ef5c8a5c01619a244cf6ebccfe806ae2a5c45baa | |
parent | e8dc8c27155afade10310c84678959f2d7456641 (diff) |
bbox rotation work
-rw-r--r-- | editor/app.hpp | 1 | ||||
-rw-r--r-- | editor/scenery-editor.cpp | 20 | ||||
-rw-r--r-- | editor/update.cpp | 44 | ||||
-rw-r--r-- | scenery/scenery.json | 4 | ||||
-rw-r--r-- | src/scenery.cpp | 45 | ||||
-rw-r--r-- | src/scenery.hpp | 4 |
6 files changed, 83 insertions, 35 deletions
diff --git a/editor/app.hpp b/editor/app.hpp index 64fdb587..d12a7001 100644 --- a/editor/app.hpp +++ b/editor/app.hpp @@ -108,6 +108,7 @@ private: void do_key(key k, int mods); void do_key(key k); + void do_rotate(bool backward); void apply_commands(const key_set& k); int get_key_modifiers(); void clear_keys(key min_inclusive, key max_exclusive); diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp index d8f74f7d..f9a0678e 100644 --- a/editor/scenery-editor.cpp +++ b/editor/scenery-editor.cpp @@ -21,11 +21,7 @@ scenery_editor::scenery_editor() noexcept void scenery_editor::set_rotation(rotation_ r) { - if (_selected.proto.atlas) - { - (void)_selected.proto.atlas->group(r); - _selected.proto.frame.r = r; - } + _selected.proto.frame.rotate(r); } rotation_ scenery_editor::rotation() const @@ -35,23 +31,21 @@ rotation_ scenery_editor::rotation() const void scenery_editor::next_rotation() { - if (_selected) - set_rotation(_selected.proto.atlas->next_rotation_from(_selected.proto.frame.r)); + set_rotation(_selected.proto.atlas->next_rotation_from(_selected.proto.frame.r)); } void scenery_editor::prev_rotation() { - if (_selected) - set_rotation(_selected.proto.atlas->next_rotation_from(_selected.proto.frame.r)); + set_rotation(_selected.proto.atlas->prev_rotation_from(_selected.proto.frame.r)); } void scenery_editor::select_tile(const scenery_& s) { - const auto rot = s.proto.atlas && s.proto.atlas->check_rotation(_selected.proto.frame.r) - ? _selected.proto.frame.r - : s.proto.frame.r; + const auto r = s.proto.atlas && s.proto.atlas->check_rotation(_selected.proto.frame.r) + ? _selected.proto.frame.r + : s.proto.frame.r; _selected = s; - _selected.proto.frame.r = rot; + set_rotation(r); } void scenery_editor::clear_selection() diff --git a/editor/update.cpp b/editor/update.cpp index 7423ef76..3481ea3b 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -83,6 +83,30 @@ void app::do_mouse_up_down(std::uint8_t button, bool is_down, int mods) _editor.on_release(); } +void app::do_rotate(bool backward) +{ + if (auto* ed = _editor.current_tile_editor()) + ed->toggle_rotation(); + else if (auto* ed = _editor.current_scenery_editor()) + { + if (ed->is_anything_selected()) + backward ? ed->prev_rotation() : ed->next_rotation(); + else if (cursor.tile) + { + auto [c, t] = M->world()[*cursor.tile]; + if (auto [atlas, s] = t.scenery(); atlas) + { + auto r = backward ? atlas->prev_rotation_from(s.r) : atlas->next_rotation_from(s.r); + if (r != s.r) + { + s.rotate(r); + c.mark_scenery_modified(); + } + } + } + } +} + void app::do_key(key k, int mods) { (void)mods; @@ -93,25 +117,7 @@ void app::do_key(key k, int mods) fm_warn("unhandled key: '%zu'", std::size_t(k)); return; case key_rotate_tile: - if (auto* ed = _editor.current_tile_editor()) - ed->toggle_rotation(); - else if (auto* ed = _editor.current_scenery_editor()) - { - if (ed->is_anything_selected()) - ed->next_rotation(); - else if (cursor.tile) - { - auto [c, t] = M->world()[*cursor.tile]; - if (auto [atlas, s] = t.scenery(); atlas) - { - auto old_r = s.r; - s.r = atlas->next_rotation_from(s.r); - if (s.r != old_r) - c.mark_scenery_modified(); - } - } - } - return; + return do_rotate(false); case key_mode_none: return _editor.set_mode(editor_mode::none); case key_mode_floor: diff --git a/scenery/scenery.json b/scenery/scenery.json index 12889bf6..48762ea4 100644 --- a/scenery/scenery.json +++ b/scenery/scenery.json @@ -2,7 +2,9 @@ { "name": "door1", "type": "door", - "atlas-name": "door-close" + "atlas-name": "door-close", + "bbox-offset": "0 x -32", + "bbox-size": "32 x 16" }, { "name": "control panel (wall) 1", diff --git a/src/scenery.cpp b/src/scenery.cpp index 47f5306f..0b250d7c 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -47,6 +47,30 @@ constexpr Pair<Vector2b, Vector2ub> rotate_bbox_to(Vector2b offset0, Vector2ub s }; } +constexpr Vector2b rotate_bbox_offset(Vector2b offset0, rotation r_old, rotation r_new) +{ + fm_assert(r_old < rotation_COUNT && (std::size_t)r_old % 2 == 0); + fm_assert(r_new < rotation_COUNT && (std::size_t)r_new % 2 == 0); + auto [m_offset0, i_offset0, i_size0] = symmetry_for_rot(r_old); + auto offset0_ = offset0 * m_offset0; + auto offset_n = Vector2b(offset0_[i_offset0[0]], offset0_[i_offset0[1]]); + //auto size_n = Vector2ub(size0[i_size0[0]], size0[i_size0[1]]); + //fm_debug_assert(r_old != rotation::N || offset_n == offset0 && size_n == size0); + auto [m_offset1, i_offset1, i_size1] = symmetry_for_rot(r_new); + return Vector2b{offset_n[i_offset1[0]], offset_n[i_offset1[1]]}*m_offset1; +} + +constexpr Vector2ub rotate_bbox_size(Vector2ub size0, rotation r_old, rotation r_new) +{ + fm_assert(r_old < rotation_COUNT && (std::size_t)r_old % 2 == 0); + fm_assert(r_new < rotation_COUNT && (std::size_t)r_new % 2 == 0); + auto [m_offset0, i_offset0, i_size0] = symmetry_for_rot(r_old); + auto size_n = Vector2ub(size0[i_size0[0]], size0[i_size0[1]]); + //fm_debug_assert(r_old != rotation::N || offset_n == offset0 && size_n == size0); + auto [m_offset1, i_offset1, i_size1] = symmetry_for_rot(r_new); + return Vector2ub{size_n[i_size1[0]], size_n[i_size1[1]]}; +} + constexpr Pair<Vector2b, Vector2ub> rot_for_door(rotation r) { constexpr Pair<Vector2b, Vector2ub> door_north = { @@ -79,6 +103,9 @@ static_assert(rotate_bbox_to({ 32, 16}, {16, 32}, rotation::E, rotation::S) == static_assert(rotate_bbox_to({ 32, 16}, {16, 32}, rotation::E, rotation::N) == Pair<Vector2b, Vector2ub>{{ 16, -32}, {32, 16}}); static_assert(rotate_bbox_to({-32, -16}, {16, 32}, rotation::W, rotation::S) == Pair<Vector2b, Vector2ub>{{-16, 32}, {32, 16}}); +static_assert(rotate_bbox_to({1, 2}, {3, 4}, rotation::E, rotation::E) == Pair<Vector2b, Vector2ub>{{1, 2}, {3, 4}}); +static_assert(rotate_bbox_to({1, 2}, {3, 4}, rotation::N, rotation::N) == Pair<Vector2b, Vector2ub>{{1, 2}, {3, 4}}); + } // namespace scenery_proto::scenery_proto() noexcept = default; @@ -108,7 +135,9 @@ scenery::scenery(generic_tag_t, const anim_atlas& atlas, rotation r, frame_t fra pass_mode passability, bool active, bool interactive, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) : frame{frame}, - offset{offset}, bbox_offset{bbox_offset}, bbox_size{bbox_size}, + offset{offset}, + bbox_offset{rotate_bbox_offset(bbox_offset, atlas.first_rotation(), r)}, + bbox_size{rotate_bbox_size(bbox_size, atlas.first_rotation(), r)}, r{r}, type{scenery_type::generic}, passability{passability}, active{active}, interactive{interactive} @@ -120,7 +149,9 @@ scenery::scenery(generic_tag_t, const anim_atlas& atlas, rotation r, frame_t fra scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) : frame{frame_t(is_open ? 0 : atlas.group(r).frames.size()-1)}, - offset{offset}, bbox_offset{bbox_offset}, bbox_size{bbox_size}, + offset{offset}, + bbox_offset{rotate_bbox_offset(bbox_offset, atlas.first_rotation(), r)}, + bbox_size{rotate_bbox_size(bbox_size, atlas.first_rotation(), r)}, r{r}, type{scenery_type::door}, passability{is_open ? pass_mode::pass : pass_mode::blocked}, interactive{true} @@ -129,6 +160,16 @@ scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open, fm_assert(atlas.group(r).frames.size() >= 2); } +Vector2b scenery::rotate_bbox_offset(Vector2b offset, rotation old_r, rotation r) { return floormat::rotate_bbox_offset(offset, old_r, r); } +Vector2ub scenery::rotate_bbox_size(Vector2ub size, rotation old_r, rotation r) { return floormat::rotate_bbox_size(size, old_r, r); } + +void scenery::rotate(rotation new_r) +{ + bbox_offset = scenery::rotate_bbox_offset(bbox_offset, r, new_r); + bbox_size = scenery::rotate_bbox_size(bbox_size, r, new_r); + r = new_r; +} + bool scenery::can_activate(const anim_atlas&) const noexcept { return interactive; diff --git a/src/scenery.hpp b/src/scenery.hpp index 962e53c5..3e950e90 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -59,6 +59,10 @@ struct scenery final 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); + + static Vector2b rotate_bbox_offset(Vector2b offset, rotation old_r, rotation r); + static Vector2ub rotate_bbox_size(Vector2ub size, rotation old_r, rotation r); }; constexpr scenery::scenery() noexcept : scenery{scenery::none_tag_t{}} {} |