summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--draw/anim.cpp16
-rw-r--r--draw/anim.hpp8
-rw-r--r--editor/app.hpp5
-rw-r--r--editor/draw.cpp13
-rw-r--r--editor/scenery-editor.cpp6
-rw-r--r--editor/update.cpp53
-rw-r--r--floormat/main.hpp6
-rw-r--r--main/clickable.hpp7
-rw-r--r--main/draw.cpp4
-rw-r--r--main/main-impl.hpp8
-rw-r--r--src/scenery.cpp63
-rw-r--r--src/scenery.hpp10
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;