summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-02-26 19:16:25 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-02-26 19:16:25 +0100
commit90d388665cfdb048a71fcadf0e142bb679f160ef (patch)
treeef5c8a5c01619a244cf6ebccfe806ae2a5c45baa
parente8dc8c27155afade10310c84678959f2d7456641 (diff)
bbox rotation work
-rw-r--r--editor/app.hpp1
-rw-r--r--editor/scenery-editor.cpp20
-rw-r--r--editor/update.cpp44
-rw-r--r--scenery/scenery.json4
-rw-r--r--src/scenery.cpp45
-rw-r--r--src/scenery.hpp4
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{}} {}