summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--editor/CMakeLists.txt4
-rw-r--r--editor/app.cpp25
-rw-r--r--editor/app.hpp13
-rw-r--r--editor/camera.cpp5
-rw-r--r--editor/events.cpp2
-rw-r--r--editor/scenery-editor.cpp2
-rw-r--r--editor/tests-private.hpp43
-rw-r--r--editor/tests.cpp80
-rw-r--r--editor/tests/path.cpp77
-rw-r--r--editor/vobj-editor.cpp2
-rw-r--r--floormat/main.hpp2
-rw-r--r--main/main-impl.cpp1
-rw-r--r--main/main-impl.hpp2
-rw-r--r--src/object.cpp5
-rw-r--r--src/object.hpp1
-rw-r--r--src/path-search-dijkstra.cpp10
17 files changed, 222 insertions, 53 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33a63e45..b3118d5f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -204,6 +204,7 @@ fm_run_hook(fm-userconfig-src)
if(CMAKE_COMPILER_IS_GNUCXX)
add_compile_options(-Wno-float-equal)
+ add_compile_options(-Wreturn-type -Werror=return-type)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt
index 74da3536..5f4f17d3 100644
--- a/editor/CMakeLists.txt
+++ b/editor/CMakeLists.txt
@@ -1,6 +1,6 @@
set(self floormat-editor)
-file(GLOB sources "*.cpp" CONFIGURE_ARGS)
+file(GLOB sources "*.cpp" "tests/*.cpp" CONFIGURE_ARGS)
corrade_add_resource(res "../resources.conf")
if(MSVC)
@@ -23,7 +23,7 @@ if(NOT SDL2_INCLUDE_DIRS)
get_target_property(SDL2_INCLUDE_DIRS SDL2::SDL2 INTERFACE_INCLUDE_DIRECTORIES)
endif()
endif()
-set_property(SOURCE "events.cpp" APPEND PROPERTY INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}")
+set_property(SOURCE "events.cpp" "tests.cpp" APPEND PROPERTY INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}")
add_executable(${self} dummy.cc)
if (FLOORMAT_ASAN)
diff --git a/editor/app.cpp b/editor/app.cpp
index a2ffc9f4..7c42e98c 100644
--- a/editor/app.cpp
+++ b/editor/app.cpp
@@ -17,6 +17,17 @@
namespace floormat {
+struct Optional<point> cursor_state::point() const
+{
+ if (tile)
+ return {InPlaceInit, *tile, *subpixel};
+ else
+ return {};
+}
+
+floormat_main& app::main() { return *M; }
+const cursor_state& app::cursor_state() { return cursor; }
+
app::app(fm_settings&& opts) :
M{floormat_main::create(*this, Utility::move(opts))},
_tests{tests_data_::make()}
@@ -40,15 +51,17 @@ void app::reset_world()
reset_world(world{});
}
-void app::ensure_player_character(world& w)
+std::shared_ptr<critter> app::ensure_player_character(world& w)
{
if (_character_id)
if (auto C = w.find_object(_character_id); C && C->type() == object_type::critter)
- return;
+ return std::static_pointer_cast<critter>(C);
_character_id = 0;
auto id = (object_id)-1;
+ std::shared_ptr<critter> ret;
+
for (const auto& [coord, c] : w.chunks())
{
for (const auto& e_ : c.objects())
@@ -58,7 +71,10 @@ void app::ensure_player_character(world& w)
{
const auto& C = static_cast<const critter&>(e);
if (C.playable)
+ {
id = std::min(id, C.id);
+ ret = std::static_pointer_cast<critter>(e_);
+ }
}
}
}
@@ -70,8 +86,11 @@ void app::ensure_player_character(world& w)
critter_proto cproto;
cproto.name = "Player"_s;
cproto.playable = true;
- _character_id = w.make_object<critter>(w.make_id(), global_coords{}, cproto)->id;
+ ret = w.make_object<critter>(w.make_id(), global_coords{}, cproto);
+ _character_id = ret->id;
}
+ fm_debug_assert(ret);
+ return ret;
}
void app::reset_world(struct world&& w_)
diff --git a/editor/app.hpp b/editor/app.hpp
index d035d1ec..15e9d7a7 100644
--- a/editor/app.hpp
+++ b/editor/app.hpp
@@ -26,12 +26,15 @@ struct tile_editor;
struct fm_settings;
struct anim_atlas;
struct critter;
+struct point;
struct cursor_state final {
Optional<Vector2i> pixel;
Optional<global_coords> tile;
Optional<Vector2b> subpixel;
bool in_imgui = false;
+
+ struct Optional<point> point() const;
};
struct clickable;
@@ -60,7 +63,11 @@ struct app final : floormat_app
#ifdef _WIN32
static void set_dpi_aware();
#endif
- object_id object_at_cursor();
+ object_id get_object_colliding_with_cursor();
+ floormat_main& main();
+ const struct cursor_state& cursor_state();
+ clickable* find_clickable_scenery(const Optional<Vector2i>& pixel);
+ std::shared_ptr<critter> ensure_player_character(world& w);
private:
using key_set = enum_bitset<key, key_COUNT>;
@@ -82,7 +89,6 @@ private:
void update_character(float dt);
void reset_world();
void reset_world(struct world&& w);
- void ensure_player_character(world& w);
void draw() override;
@@ -106,7 +112,6 @@ private:
void do_camera(float dt, const key_set& cmds, int mods);
void reset_camera_offset();
- clickable* find_clickable_scenery(const Optional<Vector2i>& pixel);
void do_quicksave();
void do_quickload();
@@ -173,7 +178,7 @@ private:
std::array<int, key_set::COUNT> key_modifiers = {};
std::vector<popup_target> inspectors;
object_id _character_id = 0;
- cursor_state cursor;
+ struct cursor_state cursor;
popup_target _popup_target;
Optional<chunk_coords_> tested_light_chunk;
diff --git a/editor/camera.cpp b/editor/camera.cpp
index 42b81c82..674c5e23 100644
--- a/editor/camera.cpp
+++ b/editor/camera.cpp
@@ -60,11 +60,8 @@ void app::reset_camera_offset()
update_cursor_tile(cursor.pixel);
}
-object_id app::object_at_cursor()
+object_id app::get_object_colliding_with_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();
diff --git a/editor/events.cpp b/editor/events.cpp
index 64f544e4..83039bcb 100644
--- a/editor/events.cpp
+++ b/editor/events.cpp
@@ -190,7 +190,7 @@ void app::on_key_up_down(const key_event& event, bool is_down) noexcept
static_assert(key_GLOBAL >= key_NO_REPEAT);
if (x == key_COUNT && (is_down ? _imgui.handleKeyPressEvent(e) : _imgui.handleKeyReleaseEvent(e)) ||
- x == key_COUNT && _editor.mode() == editor_mode::tests && tests_handle_key(event))
+ (x == key_COUNT || x == key_escape) && _editor.mode() == editor_mode::tests && tests_handle_key(event))
clear_non_global_keys();
else if (x >= key_NO_REPEAT)
is_down && !event.is_repeated ? do_key(x, mods) : void();
diff --git a/editor/scenery-editor.cpp b/editor/scenery-editor.cpp
index 511e5b6a..d338cdcb 100644
--- a/editor/scenery-editor.cpp
+++ b/editor/scenery-editor.cpp
@@ -86,7 +86,7 @@ void scenery_editor::place_tile(world& w, global_coords pos, const scenery_& s,
{
auto [c, t] = w[pos];
const auto& es = c.objects();
-start: while (auto id = a.object_at_cursor())
+start: while (auto id = a.get_object_colliding_with_cursor())
{
for (auto i = es.size()-1; i != (size_t)-1; i--)
{
diff --git a/editor/tests-private.hpp b/editor/tests-private.hpp
index 01a15a33..5c229696 100644
--- a/editor/tests-private.hpp
+++ b/editor/tests-private.hpp
@@ -1,17 +1,46 @@
#pragma once
-#include "compat/defs.hpp"
#include "tests.hpp"
+#include "compat/defs.hpp"
#include "src/point.hpp"
+#include "floormat/events.hpp"
+#include <Corrade/Containers/StringView.h>
#include <vector>
#include <variant>
+namespace floormat { struct app; }
+
namespace floormat::tests {
template<typename... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;
-struct path_test
+struct base_test
{
+ fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(base_test);
+ fm_DECLARE_DELETED_COPY_ASSIGNMENT(base_test);
+
+ virtual bool handle_key(app& a, const key_event& e) = 0;
+ virtual bool handle_mouse_click(app& a, const mouse_button_event& e) = 0;
+ virtual bool handle_mouse_move(app& a, const mouse_move_event& e) = 0;
+ virtual void draw_overlay(app& a) = 0;
+ virtual void update_pre(app& a) = 0;
+ virtual void update_post(app& a) = 0;
+
+ virtual ~base_test() noexcept;
+
+protected:
+ base_test();
+};
+
+struct path_test : base_test
+{
+ bool handle_key(app& a, const key_event& e) override;
+ bool handle_mouse_click(app& a, const mouse_button_event& e) override;
+ bool handle_mouse_move(app& a, const mouse_move_event& e) override;
+ void draw_overlay(app& a) override;
+ void update_pre(app& a) override;
+ void update_post(app& a) override;
+
point from;
std::vector<point> path;
bool active = false;
@@ -29,8 +58,14 @@ struct tests_data final : tests_data_, tests::variant
tests_data();
~tests_data() noexcept override;
using tests::variant::operator=;
- //tests::variant& operator*();
- //tests::variant* operator->();
+
+ struct pair { StringView str; size_t index; };
+
+ static constexpr inline pair fields[] = {
+ { "Path"_s, 1 },
+ };
+
+ void switch_to(size_t i);
};
} // namespace floormat
diff --git a/editor/tests.cpp b/editor/tests.cpp
index 04489ddc..706c15eb 100644
--- a/editor/tests.cpp
+++ b/editor/tests.cpp
@@ -2,11 +2,11 @@
#include "app.hpp"
#include "floormat/events.hpp"
#include "imgui-raii.hpp"
+#include <SDL_keycode.h>
namespace floormat {
using namespace floormat::tests;
-using namespace floormat::imgui;
tests_data_::~tests_data_() noexcept = default;
tests_data_::tests_data_() = default;
@@ -14,6 +14,22 @@ tests_data_::tests_data_() = default;
tests_data::~tests_data() noexcept = default;
tests_data::tests_data() = default;
+base_test::~base_test() noexcept = default;
+base_test::base_test() = default;
+
+using namespace floormat::imgui;
+
+void tests_data::switch_to(size_t i)
+{
+ constexpr auto size = std::variant_size_v<tests::variant>;
+ fm_assert(i < size);
+ switch (i)
+ {
+ case 0: *this = std::monostate{}; break;
+ case 1: *this = path_test{}; break;
+ }
+}
+
Pointer<tests_data_> tests_data_::make()
{
return Pointer<tests_data>{InPlaceInit};
@@ -21,51 +37,51 @@ Pointer<tests_data_> tests_data_::make()
void app::tests_pre_update()
{
+ std::visit(overloaded {
+ [](std::monostate) {},
+ [&](base_test& x) { return x.update_pre(*this); }
+ }, tests());
}
void app::tests_post_update()
{
+ std::visit(overloaded {
+ [](std::monostate) {},
+ [&](base_test& x) { return x.update_post(*this); }
+ }, tests());
}
bool app::tests_handle_mouse_click(const mouse_button_event& e)
{
update_cursor_tile(cursor.pixel);
- auto& var = tests();
- if (e.button == mouse_button_left)
- {
- std::visit(overloaded {
- [](std::monostate) {},
- [&](path_test& t) {
- // todo
- }
- }, var);
-
- return true;
- }
- else if (e.button == mouse_button_right)
- {
- bool ret = false;
- std::visit(overloaded {
- [](std::monostate) {},
- [&](path_test& t) {
- ret = t.active;
- t = {};
- },
- }, var);
- return ret;
- }
- return false;
+ return std::visit(overloaded {
+ [](std::monostate) { return false; },
+ [&](base_test& x) { return x.handle_mouse_click(*this, e); }
+ }, tests());
}
bool app::tests_handle_key(const key_event& e)
{
- return false;
+ switch (e.key)
+ {
+ case SDLK_ESCAPE:
+ tests().switch_to(0);
+ return true;
+ default:
+ return std::visit(overloaded {
+ [](std::monostate) { return false; },
+ [&](base_test& x) { return x.handle_key(*this, e); }
+ }, tests());
+ }
}
bool app::tests_handle_mouse_move(const mouse_move_event& e)
{
- return false;
+ return std::visit(overloaded {
+ [](std::monostate) { return false; },
+ [&](base_test& x) { return x.handle_mouse_move(*this, e); }
+ }, tests());
}
tests_data& app::tests()
@@ -81,10 +97,18 @@ void app::tests_reset_mode()
void app::draw_tests_pane()
{
+ constexpr int selectable_flags = ImGuiSelectableFlags_SpanAvailWidth;
+ for (auto [str, i] : tests_data::fields)
+ if (ImGui::Selectable(str.data(), i == tests().index(), selectable_flags))
+ tests().switch_to(i);
}
void app::draw_tests_overlay()
{
+ std::visit(overloaded {
+ [](std::monostate) {},
+ [&](base_test& x) { return x.draw_overlay(*this); }
+ }, tests());
}
} // namespace floormat
diff --git a/editor/tests/path.cpp b/editor/tests/path.cpp
new file mode 100644
index 00000000..3b015e27
--- /dev/null
+++ b/editor/tests/path.cpp
@@ -0,0 +1,77 @@
+#include "../tests-private.hpp"
+#include "../app.hpp"
+#include "floormat/main.hpp"
+#include "src/path-search.hpp"
+#include "src/critter.hpp"
+
+namespace floormat::tests {
+
+bool path_test::handle_key(app& a, const key_event& e)
+{
+ return false;
+}
+
+bool path_test::handle_mouse_click(app& a, const mouse_button_event& e)
+{
+ switch (e.button)
+ {
+ case mouse_button_left: {
+ auto& M = a.main();
+ auto& w = M.world();
+ auto& astar = M.astar();
+ auto C = a.ensure_player_character(w);
+ if (auto pt = a.cursor_state().point())
+ {
+ constexpr auto chunk_size = iTILE_SIZE2 * TILE_MAX_DIM;
+ auto pt0 = C->position();
+ auto vec = (pt->coord() - pt0.coord()) * iTILE_SIZE2 * 2 + chunk_size * 3;
+ auto dist = (uint32_t)vec.length();
+ auto res = astar.Dijkstra(w, *pt, pt0, C->id, dist, C->bbox_size, 1);
+ if (res)
+ {
+ active = true;
+ from = pt0;
+ path = res.path();
+ }
+ else
+ {
+ active = false;
+ from = {};
+ path = {};
+ }
+ }
+ return true;
+ }
+ case mouse_button_right:
+ if (active)
+ {
+ *this = {};
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool path_test::handle_mouse_move(app& a, const mouse_move_event& e)
+{
+ return false;
+}
+
+void path_test::draw_overlay(app& a)
+{
+
+}
+
+void path_test::update_pre(app& a)
+{
+
+}
+
+void path_test::update_post(app& a)
+{
+
+}
+
+} // namespace floormat::tests
diff --git a/editor/vobj-editor.cpp b/editor/vobj-editor.cpp
index 4d3f3f03..e5046e61 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, struct
{
auto [c, t] = w[pos];
const auto& es = c.objects();
-start: while (auto id = a.object_at_cursor())
+start: while (auto id = a.get_object_colliding_with_cursor())
{
for (auto i = es.size()-1; i != (size_t)-1; i--)
{
diff --git a/floormat/main.hpp b/floormat/main.hpp
index cf88510a..11a42bd7 100644
--- a/floormat/main.hpp
+++ b/floormat/main.hpp
@@ -22,6 +22,7 @@ struct wall_mesh;
struct anim_mesh;
struct texture_unit_cache;
class path_search;
+struct astar;
struct floormat_main
{
@@ -80,6 +81,7 @@ struct floormat_main
virtual struct texture_unit_cache& texture_unit_cache() = 0;
virtual path_search& search() = 0;
+ virtual struct astar& astar() = 0;
[[nodiscard]] static floormat_main* create(floormat_app& app, fm_settings&& options);
[[maybe_unused]] static void debug_break();
diff --git a/main/main-impl.cpp b/main/main-impl.cpp
index 69cda22c..4fe5d702 100644
--- a/main/main-impl.cpp
+++ b/main/main-impl.cpp
@@ -67,5 +67,6 @@ uint32_t main_impl::cursor() const noexcept
struct texture_unit_cache& main_impl::texture_unit_cache() { return _tuc; }
path_search& main_impl::search() { return _search; }
+astar& main_impl::astar() { return _astar; }
} // namespace floormat
diff --git a/main/main-impl.hpp b/main/main-impl.hpp
index a1550f01..5619dda6 100644
--- a/main/main-impl.hpp
+++ b/main/main-impl.hpp
@@ -98,6 +98,7 @@ struct main_impl final : Platform::Sdl2Application, floormat_main
struct texture_unit_cache& texture_unit_cache() override;
path_search& search() override;
+ struct astar& astar() override;
private:
struct texture_unit_cache _tuc;
@@ -117,6 +118,7 @@ private:
Framebuffer framebuffer;
#endif
path_search _search;
+ struct astar _astar;
struct {
float value = 0;
diff --git a/src/object.cpp b/src/object.cpp
index 001b9dc6..6284e3e9 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -103,6 +103,11 @@ bool object::is_virtual() const
return false;
}
+point object::position() const
+{
+ return {coord, offset};
+}
+
bool object::can_rotate(global_coords coord, rotation new_r, rotation old_r,
Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size)
{
diff --git a/src/object.hpp b/src/object.hpp
index bd5066b9..c02e4d07 100644
--- a/src/object.hpp
+++ b/src/object.hpp
@@ -63,6 +63,7 @@ struct object
struct chunk& chunk() const;
size_t index() const;
virtual bool is_virtual() const;
+ point position() const;
explicit operator object_proto() const;
diff --git a/src/path-search-dijkstra.cpp b/src/path-search-dijkstra.cpp
index b5f5355a..5012cb54 100644
--- a/src/path-search-dijkstra.cpp
+++ b/src/path-search-dijkstra.cpp
@@ -204,18 +204,18 @@ path_search_result astar::Dijkstra(world& w, const point from_, const point to_,
auto vec = Vector2(cur_pt.coord() - to_.coord()) * TILE_SIZE2 + Vector2(cur_pt.offset() - to_.offset());
auto bb1 = bbox<float>{goal_bb.min + vec, goal_bb.max + vec};
auto bb = bbox_union(goal_bb, bb1);
- bool fresh = true;
if (goal_idx != (uint32_t)-1)
- {
if (dist >= nodes[goal_idx].dist)
continue;
- fresh = false;
- }
if (path_search::is_passable(w, to_.chunk3(), bb, own_id, p))
{
- if (fresh)
+ if (goal_idx == (uint32_t)-1)
+ {
+ goal_idx = cache.lookup_index(goal_chunk_idx, goal_tile_idx);
+ }
+ if (goal_idx == (uint32_t)-1)
{
goal_idx = (uint32_t)nodes.size();
cache.add_index(goal_chunk_idx, goal_tile_idx, goal_idx);