diff options
45 files changed, 542 insertions, 312 deletions
diff --git a/bench/loader.cpp b/bench/loader.cpp index c96ef31c..bb878758 100644 --- a/bench/loader.cpp +++ b/bench/loader.cpp @@ -1,6 +1,6 @@ #include "loader/loader.hpp" -#include "loader/ground-info.hpp" -#include "loader/wall-info.hpp" +#include "loader/ground-cell.hpp" +#include "loader/wall-cell.hpp" #include "serialize/json-helper.hpp" #include "serialize/anim.hpp" #include <Corrade/Containers/ArrayView.h> diff --git a/compat/defs.hpp b/compat/defs.hpp index edefbb5e..6f3c9ab2 100644 --- a/compat/defs.hpp +++ b/compat/defs.hpp @@ -89,3 +89,5 @@ #ifndef fm_ASAN #define fm_ASAN 0 #endif + +#define fm_FILENAME_MAX 260 diff --git a/compat/int-hash.cpp b/compat/int-hash.cpp index 3c85a436..35422486 100644 --- a/compat/int-hash.cpp +++ b/compat/int-hash.cpp @@ -1,5 +1,6 @@ #include "compat/defs.hpp" #include "int-hash.hpp" +#include <Corrade/Containers/StringView.h> #include <bit> namespace floormat { @@ -78,15 +79,9 @@ fm_UNROLL_8 return hash; } -size_t hash_int(uint32_t x) noexcept -{ - return fnvhash_uint_32(x); -} - -size_t hash_int(uint64_t x) noexcept -{ - return fnvhash_uint_64(x); -} +size_t hash_int(uint32_t x) noexcept { return fnvhash_uint_32(x); } +size_t hash_int(uint64_t x) noexcept { return fnvhash_uint_64(x); } +size_t hash_string_view::operator()(StringView s) const noexcept { return Hash::fnvhash_buf(s.data(), s.size()); } } // namespace floormat diff --git a/compat/int-hash.hpp b/compat/int-hash.hpp index a5d6b147..27f2651f 100644 --- a/compat/int-hash.hpp +++ b/compat/int-hash.hpp @@ -1,5 +1,7 @@ #pragma once +// todo rename to hash-fnv.hpp + namespace floormat::Hash { template<size_t N = sizeof nullptr * 8> struct fnvhash_params; @@ -20,4 +22,6 @@ uint32_t hash_32(const void* buf, size_t size) noexcept; size_t hash_int(uint32_t x) noexcept; size_t hash_int(uint64_t x) noexcept; +struct hash_string_view { size_t operator()(StringView str) const noexcept; }; + } // namespace floormat diff --git a/compat/is-complete.hpp b/compat/is-complete.hpp new file mode 100644 index 00000000..d6bba88b --- /dev/null +++ b/compat/is-complete.hpp @@ -0,0 +1,21 @@ +#pragma once + +namespace floormat::detail_type_traits { + +namespace { template<class T> class IsComplete_ { + // from <Corrade/Containers/Pointer.h> + template<class U> static char get(U*, decltype(sizeof(U))* = nullptr); + static short get(...); + public: + enum: bool { value = sizeof(get(static_cast<T*>(nullptr))) == sizeof(char) }; +}; } // namespace + +} // namespace floormat::detail_type_traits + +namespace floormat { + +template<typename T> +constexpr inline bool is_complete = + bool(::floormat::detail_type_traits::IsComplete_<T>::value); + +} // namespace floormat diff --git a/compat/map.hpp b/compat/map.hpp index 3c1610d4..860b4d77 100644 --- a/compat/map.hpp +++ b/compat/map.hpp @@ -32,7 +32,7 @@ constexpr auto map(const F& fun, const std::array<T, N>& array) using return_type = std::decay_t<decltype( fun(array[0]) )>; static_assert(!std::is_same_v<return_type, void>); static_assert(std::is_same_v<T, std::decay_t<T>>); - static_assert(sizeof(return_type) > 0); + static_assert(sizeof(return_type)); using ::floormat::detail::map::map0; return map0(fun, array, std::make_index_sequence<N>{}); } diff --git a/compat/safe-ptr.hpp b/compat/safe-ptr.hpp index 0882f3be..95cd3bae 100644 --- a/compat/safe-ptr.hpp +++ b/compat/safe-ptr.hpp @@ -13,41 +13,26 @@ class safe_ptr final T* ptr; public: - template<typename... Ts> - requires requires (Ts&&... xs) { - new T{Utility::forward<Ts>(xs)...}; - } - safe_ptr(InPlaceInitT, Ts&&... args) noexcept: - ptr{new T{Utility::forward<Ts>(args)...}} - {} - - explicit safe_ptr(T*&& ptr) noexcept: ptr{ptr} - { - fm_assert(ptr != nullptr); - ptr = nullptr; - } - ~safe_ptr() noexcept { - if (ptr) [[likely]] - delete ptr; + delete ptr; ptr = (T*)0xbadcafedeadbabe; } - explicit safe_ptr(safe_ptr&& other) noexcept: ptr{other.ptr} - { - other.ptr = nullptr; - } + safe_ptr(std::nullptr_t) = delete; + safe_ptr(T* ptr) noexcept: ptr{ptr} { fm_assert(ptr != nullptr); } + safe_ptr(safe_ptr&& other) noexcept: ptr{other.ptr} { other.ptr = nullptr; } + + safe_ptr() noexcept: safe_ptr{InPlaceInit} {} - explicit safe_ptr() noexcept: - ptr{new T{}} + template<typename... Ts> safe_ptr(InPlaceInitT, Ts&&... args) noexcept: + ptr(new T{ Utility::forward<Ts>(args)... }) {} safe_ptr& operator=(safe_ptr&& other) noexcept { fm_assert(this != &other); - if (ptr) [[likely]] - delete ptr; + delete ptr; ptr = other.ptr; other.ptr = nullptr; return *this; @@ -57,6 +42,8 @@ public: //explicit operator bool() const noexcept { return ptr != nullptr; } + T* get() noexcept { return ptr; } + const T* get() const noexcept { return ptr; } const T& operator*() const noexcept { return *ptr; } T& operator*() noexcept { return *ptr; } const T* operator->() const noexcept { return ptr; } diff --git a/editor/ground-editor.cpp b/editor/ground-editor.cpp index 82a76405..653ad122 100644 --- a/editor/ground-editor.cpp +++ b/editor/ground-editor.cpp @@ -30,7 +30,10 @@ void ground_editor::load_atlases() fm_assert(_atlases.empty()); for (const auto& g : loader.ground_atlas_list()) { - (void)loader.ground_atlas(g.name); + if (g.name != loader.INVALID) [[likely]] + (void)loader.ground_atlas(g.name); + else + loader.make_invalid_ground_atlas(); fm_assert(g.atlas); _atlases[g.name] = &g; } diff --git a/editor/ground-editor.hpp b/editor/ground-editor.hpp index a0d99813..a7de3333 100644 --- a/editor/ground-editor.hpp +++ b/editor/ground-editor.hpp @@ -10,14 +10,14 @@ namespace floormat { class world; -struct ground_info; +struct ground_cell; class ground_editor final { enum selection_mode : unsigned char { sel_none, sel_tile, sel_perm, }; struct tuple; - std::map<StringView, const ground_info*> _atlases; + std::map<StringView, const ground_cell*> _atlases; tile_image_proto _selected_tile; safe_ptr<tuple> _permutation; selection_mode _selection_mode = sel_none; diff --git a/editor/imgui-editors.cpp b/editor/imgui-editors.cpp index 570094bc..efb37426 100644 --- a/editor/imgui-editors.cpp +++ b/editor/imgui-editors.cpp @@ -39,23 +39,23 @@ StringView scenery_type_to_string(const scenery_& sc) } } -StringView scenery_path(const wall_info* wa) { return wa->atlas->name(); } +StringView scenery_path(const wall_cell* wa) { return wa->atlas->name(); } StringView scenery_name(StringView, const scenery_& sc) { return sc.name; } StringView scenery_name(StringView, const vobj_& vobj) { return vobj.descr; } -StringView scenery_name(StringView, const wall_info* w) { return w->name; } +StringView scenery_name(StringView, const wall_cell* w) { return w->name; } std::shared_ptr<anim_atlas> get_atlas(const scenery_& sc) { return sc.proto.atlas; } std::shared_ptr<anim_atlas> get_atlas(const vobj_& vobj) { return vobj.factory->atlas(); } -std::shared_ptr<wall_atlas> get_atlas(const wall_info* w) { return loader.wall_atlas(w->name); } +std::shared_ptr<wall_atlas> get_atlas(const wall_cell* w) { return loader.wall_atlas(w->name); } Vector2ui get_size(const auto&, anim_atlas& atlas) { return atlas.frame(atlas.first_rotation(), 0).size; } Vector2ui get_size(const auto&, wall_atlas& atlas) { auto sz = atlas.image_size(); return { std::max(1u, std::min(sz.y()*3/2, sz.x())), sz.y() }; } bool is_selected(const scenery_editor& ed, const scenery_& sc) { return ed.is_item_selected(sc); } bool is_selected(const vobj_editor& vo, const vobj_& sc) { return vo.is_item_selected(sc); } -bool is_selected(const wall_editor& wa, const wall_info* sc) { return wa.is_atlas_selected(sc->atlas); } +bool is_selected(const wall_editor& wa, const wall_cell* sc) { return wa.is_atlas_selected(sc->atlas); } void select_tile(scenery_editor& ed, const scenery_& sc) { ed.select_tile(sc); } void select_tile(vobj_editor& vo, const vobj_& sc) { vo.select_tile(sc); } -void select_tile(wall_editor& wa, const wall_info* sc) { wa.select_atlas(sc->atlas); } +void select_tile(wall_editor& wa, const wall_cell* sc) { wa.select_atlas(sc->atlas); } auto get_texcoords(const auto&, anim_atlas& atlas) { return atlas.texcoords_for_frame(atlas.first_rotation(), 0, !atlas.group(atlas.first_rotation()).mirror_from.isEmpty()); } -auto get_texcoords(const wall_info* w, wall_atlas& atlas) { auto sz = get_size(w, atlas); return Quads::texcoords_at({}, sz, atlas.image_size()); } +auto get_texcoords(const wall_cell* w, wall_atlas& atlas) { auto sz = get_size(w, atlas); return Quads::texcoords_at({}, sz, atlas.image_size()); } void draw_editor_tile_pane_atlas(ground_editor& ed, StringView name, const std::shared_ptr<ground_atlas>& atlas, Vector2 dpi) { diff --git a/editor/wall-editor.cpp b/editor/wall-editor.cpp index f3e0b13f..681397a5 100644 --- a/editor/wall-editor.cpp +++ b/editor/wall-editor.cpp @@ -3,7 +3,7 @@ #include "src/wall-atlas.hpp" #include "src/world.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include <Corrade/Containers/ArrayView.h> namespace floormat { diff --git a/editor/wall-editor.hpp b/editor/wall-editor.hpp index 159135a0..b58dd72a 100644 --- a/editor/wall-editor.hpp +++ b/editor/wall-editor.hpp @@ -2,7 +2,7 @@ #include "editor-enums.hpp" #include "src/rotation.hpp" #include "src/global-coords.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include <memory> #include <map> @@ -13,7 +13,7 @@ class wall_atlas; class wall_editor { - std::map<StringView, const wall_info*> _atlases; + std::map<StringView, const wall_cell*> _atlases; std::shared_ptr<wall_atlas> _selected_atlas; enum rotation _r = rotation::N; diff --git a/loader/anim-info.hpp b/loader/anim-cell.hpp index 97ba5954..a9c92a23 100644 --- a/loader/anim-info.hpp +++ b/loader/anim-cell.hpp @@ -6,7 +6,7 @@ namespace floormat { class anim_atlas; -struct anim_info +struct anim_cell { String name; std::shared_ptr<anim_atlas> atlas; diff --git a/loader/anim.cpp b/loader/anim.cpp index 25b5e292..6fca5a49 100644 --- a/loader/anim.cpp +++ b/loader/anim.cpp @@ -1,5 +1,5 @@ #include "impl.hpp" -#include "loader/anim-info.hpp" +#include "loader/anim-cell.hpp" #include "compat/exception.hpp" #include "src/anim-atlas.hpp" #include <Corrade/Containers/Array.h> @@ -58,9 +58,10 @@ ArrayView<const String> loader_impl::anim_atlas_list() std::shared_ptr<anim_atlas> loader_impl::anim_atlas(StringView name, StringView dir, loader_policy policy) noexcept(false) { if (name == INVALID) return make_invalid_anim_atlas().atlas; // todo! hack + fm_soft_assert(check_atlas_name(name)); fm_soft_assert(!dir || dir[dir.size()-1] == '/'); - char buf[FILENAME_MAX]; + char buf[fm_FILENAME_MAX]; auto path = make_atlas_path(buf, dir, name); if (auto it = anim_atlas_map.find(path); it != anim_atlas_map.end()) @@ -89,7 +90,7 @@ void loader_impl::get_anim_atlas_list() fm_assert(!anim_atlases.empty()); } -const anim_info& loader_impl::make_invalid_anim_atlas() +const anim_cell& loader_impl::make_invalid_anim_atlas() { if (invalid_anim_atlas) [[likely]] return *invalid_anim_atlas; @@ -115,11 +116,11 @@ const anim_info& loader_impl::make_invalid_anim_atlas() .nframes = 1, }; auto atlas = std::make_shared<class anim_atlas>(INVALID, make_error_texture(size), std::move(def)); - auto info = anim_info { + auto info = anim_cell{ .name = INVALID, .atlas = atlas, }; - invalid_anim_atlas = Pointer<anim_info>{ InPlace, std::move(info) }; + invalid_anim_atlas = Pointer<anim_cell>{ InPlace, std::move(info) }; return *invalid_anim_atlas; } diff --git a/loader/atlas-loader-fwd.hpp b/loader/atlas-loader-fwd.hpp new file mode 100644 index 00000000..2fe1cd84 --- /dev/null +++ b/loader/atlas-loader-fwd.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace floormat::loader_detail { + +template<typename ATLAS> struct atlas_loader_traits; +template<typename ATLAS, typename TRAITS = atlas_loader_traits<ATLAS>> class atlas_loader; +template<typename ATLAS, typename TRAITS = atlas_loader_traits<ATLAS>> struct atlas_storage; + +} // namespace floormat::loader_detail diff --git a/loader/atlas-loader-storage.hpp b/loader/atlas-loader-storage.hpp new file mode 100644 index 00000000..f428be0a --- /dev/null +++ b/loader/atlas-loader-storage.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "compat/int-hash.hpp" +#include "atlas-loader-fwd.hpp" +#include <vector> +#include <tsl/robin_map.h> + +namespace floormat::loader_detail { + +template<typename ATLAS, typename TRAITS> +struct atlas_storage +{ + using Traits = TRAITS; + using Cell = typename TRAITS::Cell; + + tsl::robin_map<StringView, Cell*, hash_string_view> name_map; + std::vector<Cell> cell_array; + std::vector<String> missing_atlas_names; + Pointer<Cell> invalid_atlas; + + bool is_empty() const { return cell_array.empty(); } +}; + +} // namespace floormat::loader_detail diff --git a/loader/atlas-loader.hpp b/loader/atlas-loader.hpp new file mode 100644 index 00000000..9fa82e49 --- /dev/null +++ b/loader/atlas-loader.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "compat/defs.hpp" +#include "atlas-loader-fwd.hpp" +#include "policy.hpp" +#include <memory> + +namespace floormat::loader_detail { + +template<typename ATLAS, typename TRAITS> +class atlas_loader final +{ + [[fm_no_unique_address]] TRAITS t; + atlas_storage<ATLAS, TRAITS> s; + +public: + using Traits = TRAITS; + using Atlas = ATLAS; + using Cell = typename TRAITS::Cell; + + ~atlas_loader() noexcept = default; + fm_DECLARE_DELETED_COPY_ASSIGNMENT(atlas_loader); + fm_DECLARE_DELETED_MOVE_ASSIGNMENT(atlas_loader); + + atlas_loader(TRAITS&& traits); + atlas_loader() requires std::is_default_constructible_v<TRAITS>; + + ArrayView<const Cell> ensure_atlas_list(); + const std::shared_ptr<Atlas>& get_atlas(StringView name, loader_policy p); + const Cell& get_invalid_atlas(); +}; + +} // namespace floormat::loader_detail diff --git a/loader/atlas-loader.inl b/loader/atlas-loader.inl new file mode 100644 index 00000000..a2e3e2a7 --- /dev/null +++ b/loader/atlas-loader.inl @@ -0,0 +1,120 @@ +#pragma once +#include "compat/assert.hpp" +#include "compat/exception.hpp" +#include "atlas-loader.hpp" +#include "atlas-loader-storage.hpp" +#include "loader/loader.hpp" + +namespace floormat::loader_detail { + +template<typename ATLAS, typename TRAITS> +atlas_loader<ATLAS, TRAITS>::atlas_loader(TRAITS&& traits): // NOLINT(*-rvalue-reference-param-not-moved) + t{Utility::move(traits)} +{} + +template<typename ATLAS, typename TRAITS> +atlas_loader<ATLAS, TRAITS>::atlas_loader() requires std::is_default_constructible_v<TRAITS>: atlas_loader{TRAITS{}} {} + +template<typename TRAITS> +atlas_loader(TRAITS&& traits) noexcept -> atlas_loader<TRAITS, typename TRAITS::Atlas>; + +template<typename ATLAS, typename TRAITS> +auto atlas_loader<ATLAS, TRAITS>::ensure_atlas_list() -> ArrayView<const Cell> +{ + if (!s.cell_array.empty()) [[likely]] + return { s.cell_array.data(), s.cell_array.size() }; + t.ensure_atlases_loaded(s); + fm_assert(!s.cell_array.empty()); + return { s.cell_array.data(), s.cell_array.size() }; +} + +template<typename ATLAS, typename TRAITS> +const std::shared_ptr<ATLAS>& atlas_loader<ATLAS, TRAITS>::get_atlas(StringView name, loader_policy p) +{ + ensure_atlas_list(); + auto* const invalid_atlas = const_cast<Cell*>(&t.make_invalid_atlas(s)); + fm_debug_assert(invalid_atlas); + fm_debug_assert(t.atlas_of(*invalid_atlas)); + + switch (p) + { + using enum loader_policy; + case error: + case ignore: + case warn: + break; + default: + fm_abort("invalid loader_policy (%d)", (int)p); + } + + if (name == loader.INVALID) [[unlikely]] + switch (p) + { + using enum loader_policy; + case error: + goto error; + case ignore: + case warn: + return invalid_atlas->atlas; + } + + fm_soft_assert(loader.check_atlas_name(name)); + + if (auto it = s.name_map.find(name); it != s.name_map.end()) [[likely]] + { + if (it->second == invalid_atlas) + { + switch (p) + { + using enum loader_policy; + case error: + goto error; + case warn: + case ignore: + return invalid_atlas->atlas; + } + } + else if (!it->second->atlas) + return it->second->atlas = t.make_atlas(name, *it->second); + else + return it->second->atlas; + } + else + switch (p) + { + using enum loader_policy; + case error: + goto error; + case warn: + goto missing_warn; + case ignore: + return invalid_atlas->atlas; + } + + std::unreachable(); + fm_assert(false); + +error: + fm_throw("no such atlas '{}'"_cf, name); + +missing_warn: + s.missing_atlas_names.push_back(String { AllocatedInit, name }); + s.name_map[ s.missing_atlas_names.back() ] = invalid_atlas; + + if (name != loader.INVALID) + { + DBG_nospace << t.loader_name() << " '" << name << "' doesn't exist"; + } + + return invalid_atlas->atlas; +} + +template<typename ATLAS, typename TRAITS> +auto atlas_loader<ATLAS, TRAITS>::get_invalid_atlas() -> const Cell& +{ + const auto& cell = t.make_invalid_atlas(s); + fm_assert(t.atlas_of(cell)); + return cell; +} + +} // namespace floormat::loader_detail diff --git a/loader/atlas.cpp b/loader/atlas.cpp index a4c38264..e856f639 100644 --- a/loader/atlas.cpp +++ b/loader/atlas.cpp @@ -1,6 +1,7 @@ #include "impl.hpp" //#include "compat/assert.hpp" #include "compat/exception.hpp" +#include "loader/loader.hpp" //#include "src/emplacer.hpp" //#include "src/anim-atlas.hpp" #include <cstring> @@ -13,11 +14,11 @@ namespace floormat { -StringView loader_::make_atlas_path(char(&buf)[FILENAME_MAX], StringView dir, StringView name) +StringView loader_::make_atlas_path(char(&buf)[fm_FILENAME_MAX], StringView dir, StringView name) { fm_soft_assert(!dir || dir[dir.size()-1] == '/'); const auto dirsiz = dir.size(), namesiz = name.size(); - fm_soft_assert(dirsiz + namesiz + 1 < FILENAME_MAX); + fm_soft_assert(dirsiz + namesiz + 1 < fm_FILENAME_MAX); std::memcpy(buf, dir.data(), dirsiz); std::memcpy(&buf[dirsiz], name.data(), namesiz); auto len = dirsiz + namesiz; diff --git a/loader/error-tex.cpp b/loader/error-tex.cpp index c3a0a58b..16df2b43 100644 --- a/loader/error-tex.cpp +++ b/loader/error-tex.cpp @@ -11,7 +11,7 @@ Trade::ImageData2D loader_impl::make_error_texture(Vector2ui size) { fm_assert(size.product() != 0); constexpr auto magenta = Vector4ub{255, 0, 255, 255}; - auto array = Array<char>{NoInit, 4 * size.product()}; + auto array = Array<char>{NoInit, 4uz * size.product()}; auto data = array.data(), end = data + array.size(); while (data != end) { diff --git a/loader/ground-atlas.cpp b/loader/ground-atlas.cpp index ba4eaeb0..02186cec 100644 --- a/loader/ground-atlas.cpp +++ b/loader/ground-atlas.cpp @@ -1,30 +1,36 @@ #include "impl.hpp" +#include "atlas-loader-storage.hpp" +#include "atlas-loader.inl" +#include "ground-traits.hpp" +#include "ground-cell.hpp" #include "src/tile-constants.hpp" #include "src/ground-atlas.hpp" #include "compat/exception.hpp" #include "serialize/json-helper.hpp" -#include "serialize/corrade-string.hpp" #include "serialize/ground-atlas.hpp" -#include "src/tile-defs.hpp" #include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Utility/Path.h> #include <Magnum/Trade/ImageData.h> #include <Magnum/ImageView.h> +namespace floormat::loader_detail { + +template class atlas_loader<ground_atlas>; + +} // namespace floormat::loader_detail + namespace floormat { -using loader_detail::loader_impl; + +using loader_detail::atlas_loader_traits; +using ALT = atlas_loader_traits<ground_atlas>; std::shared_ptr<ground_atlas> loader_::get_ground_atlas(StringView name, Vector2ub size, pass_mode pass) noexcept(false) { fm_assert(name != loader.INVALID); - - char buf[FILENAME_MAX]; - auto filename = make_atlas_path(buf, loader.GROUND_TILESET_PATH, name); - auto tex = texture(""_s, filename); - + auto tex = texture(loader.GROUND_TILESET_PATH, name); auto info = ground_def{name, size, pass}; - auto atlas = std::make_shared<class ground_atlas>(info, filename, tex); + auto atlas = std::make_shared<class ground_atlas>(info, tex); return atlas; } @@ -32,128 +38,22 @@ loader_::get_ground_atlas(StringView name, Vector2ub size, pass_mode pass) noexc namespace floormat::loader_detail { -// todo copypasta from wall-atlas.cpp -std::shared_ptr<class ground_atlas> loader_impl::ground_atlas(StringView name, loader_policy policy) noexcept(false) +atlas_loader<class ground_atlas>* loader_impl::make_ground_atlas_loader() { - (void)ground_atlas_list(); - - switch (policy) - { - case loader_policy::error: - fm_assert(name != INVALID); - break; - case loader_policy::ignore: - case loader_policy::warn: - break; - default: - fm_abort("invalid loader_policy"); - } - - fm_soft_assert(check_atlas_name(name)); - auto it = ground_atlas_map.find(name); - - if (it != ground_atlas_map.end()) [[likely]] - { - if (it->second == (ground_info*)-1) [[unlikely]] - { - switch (policy) - { - case loader_policy::error: - goto error; - case loader_policy::warn: - case loader_policy::ignore: - goto missing_ok; - } - fm_assert(false); - std::unreachable(); - } - else if (!it->second->atlas) - return it->second->atlas = get_ground_atlas(name, it->second->size, it->second->pass); - else - return it->second->atlas; - } - else - { - switch (policy) - { - case loader_policy::error: - goto error; - case loader_policy::warn: - goto missing_warn; - case loader_policy::ignore: - goto missing_ok; - } - fm_assert(false); - std::unreachable(); - } - -missing_warn: - { - missing_ground_atlases.push_back(String { AllocatedInit, name }); - auto string_view = StringView{missing_ground_atlases.back()}; - ground_atlas_map[string_view] = (ground_info*)-1; - } - - if (name != loader.INVALID) - DBG_nospace << "ground_atlas '" << name << "' doesn't exist"; - -missing_ok: - return make_invalid_ground_atlas().atlas; - -error: - fm_throw("no such ground atlas '{}'"_cf, name); + return new atlas_loader<class ground_atlas>; } -ArrayView<const ground_info> loader_impl::ground_atlas_list() noexcept(false) -{ - if (ground_atlas_map.empty()) [[unlikely]] - { - get_ground_atlas_list(); - fm_assert(!ground_atlas_map.empty()); - } - return ground_atlas_array; -} +auto loader_impl::ground_atlas_list() noexcept(false) -> ArrayView<const ground_cell> { return _ground_loader->ensure_atlas_list(); } -void loader_impl::get_ground_atlas_list() +const ground_cell& loader_impl::make_invalid_ground_atlas() { - fm_assert(ground_atlas_map.empty()); - - auto defs = json_helper::from_json<std::vector<ground_def>>(Path::join(loader_::GROUND_TILESET_PATH, "ground.json"_s)); - std::vector<ground_info> infos; - infos.reserve(defs.size()); - - for (auto& x : defs) - infos.push_back(ground_info{std::move(x.name), {}, x.size, x.pass}); - - ground_atlas_array = infos; - ground_atlas_array.shrink_to_fit(); - ground_atlas_map.clear(); - ground_atlas_map.reserve(ground_atlas_array.size()*2); - - for (auto& x : ground_atlas_array) - { - fm_soft_assert(x.name != loader.INVALID); - fm_soft_assert(check_atlas_name(x.name)); - StringView name = x.name; - ground_atlas_map[name] = &x; - fm_debug_assert(name.data() == ground_atlas_map[name]->name.data()); - } - - fm_assert(!ground_atlas_map.empty()); + return _ground_loader->get_invalid_atlas(); } -const ground_info& loader_impl::make_invalid_ground_atlas() +const std::shared_ptr<class ground_atlas>& +loader_impl::ground_atlas(StringView filename, loader_policy policy) noexcept(false) { - if (invalid_ground_atlas) [[likely]] - return *invalid_ground_atlas; - - auto atlas = std::make_shared<class ground_atlas>( - ground_def{loader.INVALID, Vector2ub{1,1}, pass_mode::pass}, - ""_s, make_error_texture(Vector2ui(iTILE_SIZE2))); - invalid_ground_atlas = Pointer<ground_info>{ - InPlaceInit, atlas->name(), - atlas, atlas->num_tiles2(), atlas->pass_mode()}; - return *invalid_ground_atlas; + return _ground_loader->get_atlas(filename, policy); } } // namespace floormat::loader_detail diff --git a/loader/ground-atlas.hpp b/loader/ground-atlas.hpp new file mode 100644 index 00000000..b388f543 --- /dev/null +++ b/loader/ground-atlas.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace floormat::loader_detail { + + + +} // namespace floormat::loader_detail diff --git a/loader/ground-info.hpp b/loader/ground-cell.hpp index 1a21e960..260301c2 100644 --- a/loader/ground-info.hpp +++ b/loader/ground-cell.hpp @@ -1,17 +1,15 @@ #pragma once -#include "src/pass-mode.hpp" +#include "src/ground-def.hpp" #include <memory> -#include <Corrade/Containers/String.h> -#include <Magnum/Math/Vector2.h> namespace floormat { class ground_atlas; -struct ground_info +struct ground_cell { - String name; std::shared_ptr<ground_atlas> atlas; + String name; Vector2ub size; pass_mode pass = pass_mode::pass; }; diff --git a/loader/ground-traits.cpp b/loader/ground-traits.cpp new file mode 100644 index 00000000..cf0dee4e --- /dev/null +++ b/loader/ground-traits.cpp @@ -0,0 +1,87 @@ +#include "ground-traits.hpp" +#include "compat/assert.hpp" +#include "compat/exception.hpp" +#include "atlas-loader.hpp" +#include "atlas-loader-storage.hpp" +#include "ground-cell.hpp" +#include "loader.hpp" +#include "src/tile-defs.hpp" +#include "serialize/json-helper.hpp" +#include "serialize/ground-atlas.hpp" +#include <Corrade/Containers/StringView.h> +#include <Corrade/Containers/Pointer.h> +#include <Corrade/Utility/Path.h> +#include <Magnum/ImageView.h> +#include <Magnum/Trade/ImageData.h> + +namespace floormat::loader_detail { + +StringView atlas_loader_traits<ground_atlas>::loader_name() { return "ground_atlas"_s; } +StringView atlas_loader_traits<ground_atlas>::name_of(const Cell& x) { return x.name; } +auto atlas_loader_traits<ground_atlas>::atlas_of(const Cell& x) -> const std::shared_ptr<Atlas>& { return x.atlas; } +StringView atlas_loader_traits<ground_atlas>::name_of(const Atlas& x) { return x.name(); } + +void atlas_loader_traits<ground_atlas>::ensure_atlases_loaded(Storage& st) +{ + if (!st.is_empty()) [[likely]] + return; + + fm_assert(st.cell_array.empty()); + fm_assert(st.name_map.empty()); + + auto defs = json_helper::from_json<std::vector<ground_def>>(Path::join(loader_::GROUND_TILESET_PATH, "ground.json"_s)); + std::vector<ground_cell> infos; + infos.reserve(defs.size()); + + for (auto& x : defs) + infos.push_back(ground_cell{{}, std::move(x.name), x.size, x.pass}); + + st.cell_array = Utility::move(infos); + fm_assert(!st.cell_array.empty()); + fm_assert(st.name_map.empty()); + + constexpr bool add_invalid = true; + + if constexpr(add_invalid) + for (auto& x : st.cell_array) + fm_soft_assert(x.name != loader.INVALID); + + if constexpr(true) // NOLINT(*-simplify-boolean-expr) + st.cell_array.push_back(make_invalid_atlas(st)); // add invalid atlas + + st.name_map.reserve(st.cell_array.size()); + + for (auto& x : st.cell_array) + { + if constexpr(!add_invalid) + fm_soft_assert(x.name != loader.INVALID); + fm_soft_assert(loader.check_atlas_name(x.name)); + st.name_map[x.name] = &x; + } + + fm_assert(!st.cell_array.empty()); + fm_assert(!st.name_map.empty()); + fm_debug_assert(!st.is_empty()); +} + +auto atlas_loader_traits<ground_atlas>::make_invalid_atlas(Storage& s) -> const Cell& +{ + if (!s.invalid_atlas) [[unlikely]] + { + auto atlas = std::make_shared<Atlas>( + ground_def{loader.INVALID, Vector2ub{1,1}, pass_mode::pass}, + loader.make_error_texture(Vector2ui(tile_size_xy))); + s.invalid_atlas = Pointer<ground_cell>{ InPlaceInit, atlas, atlas->name(), atlas->num_tiles2(), atlas->pass_mode() }; + } + return *s.invalid_atlas; +} + +auto atlas_loader_traits<ground_atlas>::make_atlas(StringView name, const Cell& cell) -> std::shared_ptr<Atlas> +{ + auto def = ground_def{name, cell.size, cell.pass}; + auto tex = loader.texture(loader.GROUND_TILESET_PATH, name); + auto atlas = std::make_shared<Atlas>(def, tex); + return atlas; +} + +} // namespace floormat::loader_detail diff --git a/loader/ground-traits.hpp b/loader/ground-traits.hpp new file mode 100644 index 00000000..56923cd0 --- /dev/null +++ b/loader/ground-traits.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "atlas-loader-fwd.hpp" +#include <memory> + +namespace floormat { struct ground_cell; class ground_atlas; } + +namespace floormat::loader_detail { + +template<> struct atlas_loader_traits<ground_atlas> +{ + using Atlas = ground_atlas; + using Cell = ground_cell; // convertible to atlas and holding the atlas + using Self = atlas_loader_traits<ground_atlas>; + using Storage = atlas_storage<ground_atlas, Self>; + + static StringView loader_name(); + static const std::shared_ptr<Atlas>& atlas_of(const Cell& x); + static StringView name_of(const Cell& x); + static StringView name_of(const Atlas& x); + static void ensure_atlases_loaded(Storage& st); + static const Cell& make_invalid_atlas(Storage& st); + static std::shared_ptr<Atlas> make_atlas(StringView name, const Cell& c); +}; + +} // namespace floormat::loader_detail diff --git a/loader/impl.cpp b/loader/impl.cpp index 7da85f3f..543f0794 100644 --- a/loader/impl.cpp +++ b/loader/impl.cpp @@ -1,9 +1,13 @@ #include "impl.hpp" #include "compat/assert.hpp" -#include "loader/scenery.hpp" -#include "loader/wall-info.hpp" -#include "loader/anim-info.hpp" -#include "src/ground-atlas.hpp" +#include "scenery.hpp" +#include "wall-cell.hpp" +#include "anim-cell.hpp" +#include "ground-cell.hpp" +#include "ground-traits.hpp" +#include "atlas-loader.hpp" +#include "atlas-loader-storage.hpp" + #include <Corrade/Containers/Pair.h> #include <Magnum/Trade/ImageData.h> @@ -11,6 +15,10 @@ #pragma GCC diagnostic ignored "-Walloca" #endif +namespace floormat { + +} // namespace floormat + namespace floormat::loader_detail { StringView loader_impl::shader(StringView filename) noexcept @@ -23,9 +31,9 @@ StringView loader_impl::shader(StringView filename) noexcept return ret; } -loader_impl::loader_impl() +loader_impl::loader_impl() : + _ground_loader{ make_ground_atlas_loader() } { - missing_ground_atlases.reserve(32); missing_wall_atlases.reserve(32); system_init(); set_application_working_directory(); @@ -46,4 +54,22 @@ void loader_impl::ensure_plugins() fm_assert(tga_importer); } +void loader_impl::destroy() +{ + wall_atlas_map.clear(); + wall_atlas_array.clear(); + invalid_wall_atlas = nullptr; + missing_wall_atlases.clear(); + _ground_loader = {InPlace}; + anim_atlas_map.clear(); + anim_atlases.clear(); + invalid_anim_atlas = nullptr; + sceneries_map.clear(); + sceneries_array.clear(); + + vobj_atlas_map.clear(); + vobjs.clear(); +} + + } // namespace floormat::loader_detail diff --git a/loader/impl.hpp b/loader/impl.hpp index 5c8a542a..7bddda29 100644 --- a/loader/impl.hpp +++ b/loader/impl.hpp @@ -1,5 +1,7 @@ #pragma once +#include "compat/safe-ptr.hpp" #include "loader/loader.hpp" +#include "atlas-loader-fwd.hpp" #include <tsl/robin_map.h> #include <memory> #include <vector> @@ -12,6 +14,9 @@ namespace floormat::loader_detail { + + + struct loader_impl final : loader_ { explicit loader_impl(); @@ -36,37 +41,34 @@ struct loader_impl final : loader_ Optional<Utility::Resource> shader_res; StringView shader(StringView filename) noexcept override; - Trade::ImageData2D make_error_texture(Vector2ui size); + Trade::ImageData2D make_error_texture(Vector2ui size) override; Trade::ImageData2D texture(StringView prefix, StringView filename) noexcept(false) override; // >-----> walls >-----> - tsl::robin_map<StringView, wall_info*> wall_atlas_map; - std::vector<wall_info> wall_atlas_array; + tsl::robin_map<StringView, wall_cell*> wall_atlas_map; + std::vector<wall_cell> wall_atlas_array; std::vector<String> missing_wall_atlases; - Pointer<wall_info> invalid_wall_atlas; + Pointer<wall_cell> invalid_wall_atlas; std::shared_ptr<class wall_atlas> wall_atlas(StringView name, loader_policy policy) override; - ArrayView<const wall_info> wall_atlas_list() override; + ArrayView<const wall_cell> wall_atlas_list() override; void get_wall_atlas_list(); - const wall_info& make_invalid_wall_atlas() override; + const wall_cell& make_invalid_wall_atlas() override; // >-----> ground >-----> - tsl::robin_map<StringView, ground_info*> ground_atlas_map; - std::vector<ground_info> ground_atlas_array; - std::vector<String> missing_ground_atlases; - Pointer<ground_info> invalid_ground_atlas; - std::shared_ptr<class ground_atlas> ground_atlas(StringView filename, loader_policy policy) noexcept(false) override; - ArrayView<const ground_info> ground_atlas_list() noexcept(false) override; - void get_ground_atlas_list(); - const ground_info& make_invalid_ground_atlas() override; + static atlas_loader<class ground_atlas>* make_ground_atlas_loader(); + safe_ptr<atlas_loader<class ground_atlas>> _ground_loader{make_ground_atlas_loader()}; + const std::shared_ptr<class ground_atlas>& ground_atlas(StringView filename, loader_policy policy) noexcept(false) override; + ArrayView<const ground_cell> ground_atlas_list() noexcept(false) override; + const ground_cell& make_invalid_ground_atlas() override; // >-----> anim >-----> tsl::robin_map<StringView, std::shared_ptr<class anim_atlas>> anim_atlas_map; std::vector<String> anim_atlases; - Pointer<anim_info> invalid_anim_atlas; + Pointer<anim_cell> invalid_anim_atlas; ArrayView<const String> anim_atlas_list() override; std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir, loader_policy policy) noexcept(false) override; void get_anim_atlas_list(); - const anim_info& make_invalid_anim_atlas() override; + const anim_cell& make_invalid_anim_atlas() override; // >-----> scenery >-----> std::vector<serialized_scenery> sceneries_array; diff --git a/loader/json.cpp b/loader/json.cpp index 5c7eecb5..d374571c 100644 --- a/loader/json.cpp +++ b/loader/json.cpp @@ -6,7 +6,7 @@ #include "serialize/anim.hpp" #include "serialize/scenery.hpp" #include "loader/scenery.hpp" -#include "loader/anim-info.hpp" +#include "loader/anim-cell.hpp" #include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Utility/Path.h> @@ -26,7 +26,7 @@ void loader_impl::get_scenery_list() sceneries_array.clear(); sceneries_array = json_helper::from_json<std::vector<serialized_scenery>>(Path::join(SCENERY_PATH, "scenery.json")); - if constexpr(false) + if constexpr(true) // todo! { auto proto = scenery_proto{}; proto.atlas = make_invalid_anim_atlas().atlas; diff --git a/loader/loader.cpp b/loader/loader.cpp index 531d731a..8b711206 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -1,35 +1,9 @@ #include "impl.hpp" -#include "ground-info.hpp" -#include "wall-info.hpp" -#include "anim-info.hpp" +#include "ground-cell.hpp" +#include "loader/wall-cell.hpp" +#include "anim-cell.hpp" #include "scenery.hpp" -namespace floormat::loader_detail { - -void loader_impl::destroy() -{ - wall_atlas_map.clear(); - wall_atlas_array.clear(); - invalid_wall_atlas = nullptr; - missing_wall_atlases.clear(); - - ground_atlas_map.clear(); - ground_atlas_array.clear(); - invalid_ground_atlas = nullptr; - missing_ground_atlases.clear(); - - anim_atlas_map.clear(); - anim_atlases.clear(); - invalid_anim_atlas = nullptr; - sceneries_map.clear(); - sceneries_array.clear(); - - vobj_atlas_map.clear(); - vobjs.clear(); -} - -} // namespace floormat::loader_detail - namespace floormat { using loader_detail::loader_impl; diff --git a/loader/loader.hpp b/loader/loader.hpp index 96ab57ed..faa0269a 100644 --- a/loader/loader.hpp +++ b/loader/loader.hpp @@ -2,27 +2,26 @@ #include "compat/defs.hpp" #include "src/pass-mode.hpp" #include "loader/policy.hpp" -#include <stdio.h> // NOLINT(*-deprecated-headers) #include <memory> #include <Corrade/Containers/String.h> -namespace Magnum { using Vector2ub = Math::Vector2<unsigned char>; } -namespace floormat { struct serialized_scenery; } -namespace Magnum::Trade { -template<uint32_t> class ImageData; -using ImageData2D = ImageData<2>; -} // namespace Magnum::Trade +//namespace Magnum { using Vector2ub = Math::Vector2<unsigned char>; } +namespace Magnum::Trade { template<uint32_t> class ImageData; using ImageData2D = ImageData<2>; } namespace floormat { +struct serialized_scenery; +namespace loader_detail {} +namespace Serialize {} + struct anim_def; class anim_atlas; -struct anim_info; +struct anim_cell; struct scenery_proto; struct vobj_info; class ground_atlas; -struct ground_info; -struct wall_info; +struct ground_cell; +struct wall_cell; class wall_atlas; struct scenery_proto; @@ -35,27 +34,28 @@ struct vobj_info final struct loader_ { virtual StringView shader(StringView filename) noexcept = 0; + virtual Trade::ImageData2D make_error_texture(Vector2ui size) = 0; virtual Trade::ImageData2D texture(StringView prefix, StringView filename) noexcept(false) = 0; - virtual std::shared_ptr<class ground_atlas> ground_atlas(StringView filename, loader_policy policy = loader_policy::DEFAULT) noexcept(false) = 0; + virtual const std::shared_ptr<class ground_atlas>& ground_atlas(StringView filename, loader_policy policy = loader_policy::DEFAULT) noexcept(false) = 0; virtual ArrayView<const String> anim_atlas_list() = 0; virtual std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH, loader_policy policy = loader_policy::DEFAULT) noexcept(false) = 0; virtual std::shared_ptr<class wall_atlas> wall_atlas(StringView name, loader_policy policy = loader_policy::DEFAULT) noexcept(false) = 0; - virtual ArrayView<const wall_info> wall_atlas_list() = 0; + virtual ArrayView<const wall_cell> wall_atlas_list() = 0; virtual void destroy() = 0; static loader_& default_loader() noexcept; - virtual ArrayView<const ground_info> ground_atlas_list() noexcept(false) = 0; // todo maybe try returning + virtual ArrayView<const ground_cell> ground_atlas_list() noexcept(false) = 0; // todo maybe try returning virtual ArrayView<const serialized_scenery> sceneries() = 0; virtual const scenery_proto& scenery(StringView name) noexcept(false) = 0; virtual StringView startup_directory() noexcept = 0; static StringView strip_prefix(StringView name); virtual const vobj_info& vobj(StringView name) = 0; virtual ArrayView<const struct vobj_info> vobj_list() = 0; - static StringView make_atlas_path(char(&buf)[FILENAME_MAX], StringView dir, StringView name); + static StringView make_atlas_path(char(&buf)[fm_FILENAME_MAX], StringView dir, StringView name); [[nodiscard]] static bool check_atlas_name(StringView name) noexcept; - virtual const wall_info& make_invalid_wall_atlas() = 0; - virtual const ground_info& make_invalid_ground_atlas() = 0; - virtual const anim_info& make_invalid_anim_atlas() = 0; + virtual const wall_cell& make_invalid_wall_atlas() = 0; + virtual const ground_cell& make_invalid_ground_atlas() = 0; + virtual const anim_cell& make_invalid_anim_atlas() = 0; /** \deprecated{internal use only}*/ [[nodiscard]] std::shared_ptr<class ground_atlas> get_ground_atlas(StringView name, Vector2ub size, pass_mode pass) noexcept(false); diff --git a/loader/texture.cpp b/loader/texture.cpp index 8ac9e793..e93b21af 100644 --- a/loader/texture.cpp +++ b/loader/texture.cpp @@ -4,7 +4,7 @@ #include "compat/defs.hpp" #include "compat/strerror.hpp" #include <cstring> -#include <cstdio> +//#include <cstdio> #include <Corrade/Utility/Path.h> #include <Magnum/Trade/ImageData.h> @@ -19,11 +19,11 @@ Trade::ImageData2D loader_impl::texture(StringView prefix, StringView filename_) const auto N = prefix.size(); if (N > 0) [[likely]] fm_assert(prefix[N-1] == '/'); - fm_soft_assert(filename_.size() + prefix.size() + max_extension_length + 1 < FILENAME_MAX); + fm_soft_assert(filename_.size() + prefix.size() + max_extension_length + 1 < fm_FILENAME_MAX); fm_soft_assert(check_atlas_name(filename_)); fm_soft_assert(tga_importer); - char buf[FILENAME_MAX]; + char buf[fm_FILENAME_MAX]; const auto path_no_ext = make_atlas_path(buf, prefix, filename_); const auto len = path_no_ext.size(); diff --git a/loader/wall-atlas.cpp b/loader/wall-atlas.cpp index ee33e052..80eb6e0f 100644 --- a/loader/wall-atlas.cpp +++ b/loader/wall-atlas.cpp @@ -1,12 +1,11 @@ #include "loader/impl.hpp" #include "src/tile-constants.hpp" -#include "wall-info.hpp" +#include "loader/wall-cell.hpp" #include "compat/assert.hpp" #include "compat/exception.hpp" #include "src/wall-atlas.hpp" #include "serialize/json-helper.hpp" #include "serialize/corrade-string.hpp" -#include "src/tile-defs.hpp" #include <Corrade/Containers/Array.h> #include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Containers/StringIterable.h> @@ -19,14 +18,14 @@ namespace floormat { using nlohmann::json; using loader_detail::loader_impl; -[[maybe_unused]] static void from_json(const json& j, wall_info& val) +[[maybe_unused]] static void from_json(const json& j, wall_cell& val) { val = {}; val.name = j["name"]; fm_soft_assert(loader.check_atlas_name(val.name)); } -[[maybe_unused]] static void to_json(json& j, const wall_info& val) +[[maybe_unused]] static void to_json(json& j, const wall_cell& val) { j["name"] = val.name; } @@ -34,7 +33,7 @@ using loader_detail::loader_impl; std::shared_ptr<wall_atlas> loader_::get_wall_atlas(StringView name) noexcept(false) { fm_assert(name != "<invalid>"_s); - char buf[FILENAME_MAX]; + char buf[fm_FILENAME_MAX]; auto filename = make_atlas_path(buf, loader.WALL_TILESET_PATH, name); auto def = wall_atlas_def::deserialize(""_s.join({filename, ".json"_s})); auto tex = texture(""_s, filename); @@ -49,7 +48,7 @@ std::shared_ptr<wall_atlas> loader_::get_wall_atlas(StringView name) noexcept(fa namespace floormat::loader_detail { -const wall_info& loader_impl::make_invalid_wall_atlas() +const wall_cell& loader_impl::make_invalid_wall_atlas() { if (invalid_wall_atlas) [[likely]] return *invalid_wall_atlas; @@ -65,7 +64,7 @@ const wall_info& loader_impl::make_invalid_wall_atlas() {{ {.val = 0}, {}, }}, {1u}, }, name, make_error_texture(frame_size)); - invalid_wall_atlas = Pointer<wall_info>{InPlaceInit, wall_info{ .name = name, .atlas = std::move(a) } }; + invalid_wall_atlas = Pointer<wall_cell>{InPlaceInit, wall_cell{ .name = name, .atlas = std::move(a) } }; return *invalid_wall_atlas; } @@ -90,7 +89,7 @@ std::shared_ptr<class wall_atlas> loader_impl::wall_atlas(StringView name, loade if (it != wall_atlas_map.end()) [[likely]] { - if (it->second == (wall_info*)-1) [[unlikely]] + if (it->second == (wall_cell*)-1) [[unlikely]] { switch (policy) { @@ -125,7 +124,7 @@ missing_warn: { missing_wall_atlases.push_back(String { AllocatedInit, name }); auto string_view = StringView{missing_wall_atlases.back()}; - wall_atlas_map[string_view] = (wall_info*)-1; + wall_atlas_map[string_view] = (wall_cell*)-1; } if (name != "<invalid>") @@ -142,7 +141,7 @@ void loader_impl::get_wall_atlas_list() { fm_assert(wall_atlas_map.empty()); - wall_atlas_array = json_helper::from_json<std::vector<wall_info>>(Path::join(WALL_TILESET_PATH, "walls.json"_s)); + wall_atlas_array = json_helper::from_json<std::vector<wall_cell>>(Path::join(WALL_TILESET_PATH, "walls.json"_s)); wall_atlas_array.shrink_to_fit(); wall_atlas_map.clear(); wall_atlas_map.reserve(wall_atlas_array.size()*2); @@ -159,7 +158,7 @@ void loader_impl::get_wall_atlas_list() fm_assert(!wall_atlas_map.empty()); } -ArrayView<const wall_info> loader_impl::wall_atlas_list() +ArrayView<const wall_cell> loader_impl::wall_atlas_list() { if (wall_atlas_map.empty()) [[unlikely]] { diff --git a/loader/wall-info.hpp b/loader/wall-cell.hpp index 9b586a10..3dfa698b 100644 --- a/loader/wall-info.hpp +++ b/loader/wall-cell.hpp @@ -6,7 +6,7 @@ namespace floormat { class wall_atlas; -struct wall_info +struct wall_cell { String name; std::shared_ptr<wall_atlas> atlas; diff --git a/serialize/ground-atlas.cpp b/serialize/ground-atlas.cpp index 71c53510..d5c04332 100644 --- a/serialize/ground-atlas.cpp +++ b/serialize/ground-atlas.cpp @@ -38,10 +38,8 @@ void adl_serializer<std::shared_ptr<ground_atlas>>::to_json(json& j, const std:: void adl_serializer<std::shared_ptr<ground_atlas>>::from_json(const json& j, std::shared_ptr<ground_atlas>& val) { - char buf[FILENAME_MAX]; - ground_def info = j; - auto path = loader.make_atlas_path(buf, loader.GROUND_TILESET_PATH, info.name); - val = std::make_shared<ground_atlas>(std::move(info), path, loader.texture(""_s, path)); + ground_def def = j; + val = std::make_shared<ground_atlas>(std::move(def), loader.texture(loader.GROUND_TILESET_PATH, def.name)); } } // namespace nlohmann diff --git a/serialize/ground-atlas.hpp b/serialize/ground-atlas.hpp index fc8acec5..a423ebbe 100644 --- a/serialize/ground-atlas.hpp +++ b/serialize/ground-atlas.hpp @@ -4,7 +4,7 @@ namespace floormat { -struct ground_info; +struct ground_cell; } // namespace floormat diff --git a/src/ground-atlas.cpp b/src/ground-atlas.cpp index f918f940..ea513d44 100644 --- a/src/ground-atlas.cpp +++ b/src/ground-atlas.cpp @@ -3,6 +3,7 @@ #include "compat/assert.hpp" #include "tile-image.hpp" #include "compat/exception.hpp" +#include "loader/loader.hpp" #include <limits> #include <Magnum/Math/Color.h> #include <Magnum/ImageView.h> @@ -12,15 +13,16 @@ namespace floormat { using namespace floormat::Quads; -ground_atlas::ground_atlas(ground_def info, String path, const ImageView2D& image) : - texcoords_{make_texcoords_array(Vector2ui(image.size()), info.size)}, - path_{std::move(path)}, name_{std::move(info.name)}, size_{image.size()}, dims_{info.size}, passability{info.pass} +ground_atlas::ground_atlas(ground_def info, const ImageView2D& image) : + _def{std::move(info)}, _path{make_path(_def.name)}, + _texcoords{make_texcoords_array(Vector2ui(image.size()), _def.size)}, + _pixel_size{image.size()} { constexpr auto variant_max = std::numeric_limits<variant_t>::max(); fm_soft_assert(num_tiles() <= variant_max); - fm_soft_assert(dims_[0] > 0 && dims_[1] > 0); - fm_soft_assert(size_ % Vector2ui{info.size} == Vector2ui()); - tex_.setLabel(path_) + fm_soft_assert(_def.size.x() > 0 && _def.size.y() > 0); + fm_soft_assert(_pixel_size % Vector2ui{_def.size} == Vector2ui()); + _tex.setLabel(_path) .setWrapping(GL::SamplerWrapping::ClampToEdge) .setMagnificationFilter(GL::SamplerFilter::Nearest) .setMinificationFilter(GL::SamplerFilter::Linear) @@ -33,7 +35,7 @@ ground_atlas::ground_atlas(ground_def info, String path, const ImageView2D& imag std::array<Vector2, 4> ground_atlas::texcoords_for_id(size_t i) const { fm_assert(i < num_tiles()); - return texcoords_[i]; + return _texcoords[i]; } auto ground_atlas::make_texcoords(Vector2ui pixel_size, Vector2ub tile_count, size_t i) -> texcoords @@ -53,7 +55,14 @@ auto ground_atlas::make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_cou return ptr; } -size_t ground_atlas::num_tiles() const { return Vector2ui{dims_}.product(); } -enum pass_mode ground_atlas::pass_mode() const { return passability; } +size_t ground_atlas::num_tiles() const { return Vector2ui{_def.size}.product(); } +enum pass_mode ground_atlas::pass_mode() const { return _def.pass; } + +String ground_atlas::make_path(StringView name) +{ + char buf[fm_FILENAME_MAX]; + auto sv = loader.make_atlas_path(buf, loader.GROUND_TILESET_PATH, name); + return String{sv}; +} } // namespace floormat diff --git a/src/ground-atlas.hpp b/src/ground-atlas.hpp index 38832f9b..e13c0012 100644 --- a/src/ground-atlas.hpp +++ b/src/ground-atlas.hpp @@ -1,7 +1,7 @@ #pragma once #include "src/pass-mode.hpp" #include "src/quads.hpp" -#include "loader/ground-info.hpp" +#include "loader/ground-cell.hpp" #include <array> #include <memory> #include <Corrade/Containers/Optional.h> @@ -12,13 +12,6 @@ namespace floormat { -struct ground_def -{ - String name; - Vector2ub size; - pass_mode pass = pass_mode::pass; -}; - class ground_atlas; class ground_atlas final @@ -28,25 +21,23 @@ class ground_atlas final static std::unique_ptr<const texcoords[]> make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_count); static texcoords make_texcoords(Vector2ui pixel_size, Vector2ub tile_count, size_t i); + static String make_path(StringView name); - std::unique_ptr<const texcoords[]> texcoords_; - GL::Texture2D tex_; - String path_, name_; - Vector2ui size_; - Vector2ub dims_; - enum pass_mode passability; + ground_def _def; + String _path; + std::unique_ptr<const texcoords[]> _texcoords; + GL::Texture2D _tex; + Vector2ui _pixel_size; public: - ground_atlas(ground_def info, String path, const ImageView2D& img); + ground_atlas(ground_def info, const ImageView2D& img); texcoords texcoords_for_id(size_t id) const; - [[maybe_unused]] Vector2ui pixel_size() const { return size_; } + [[maybe_unused]] Vector2ui pixel_size() const { return _pixel_size; } size_t num_tiles() const; - Vector2ub num_tiles2() const { return dims_; } - GL::Texture2D& texture() { return tex_; } - StringView name() const { return name_; } + Vector2ub num_tiles2() const { return _def.size; } + GL::Texture2D& texture() { return _tex; } + StringView name() const { return _def.name; } enum pass_mode pass_mode() const; - - static constexpr enum pass_mode default_pass_mode = pass_mode::pass; }; } // namespace floormat diff --git a/src/ground-def.hpp b/src/ground-def.hpp new file mode 100644 index 00000000..9b3825ff --- /dev/null +++ b/src/ground-def.hpp @@ -0,0 +1,15 @@ +#pragma once +#include "pass-mode.hpp" +#include <Corrade/Containers/String.h> +#include <Magnum/Math/Vector2.h> + +namespace floormat { + +struct ground_def +{ + String name; + Vector2ub size; + pass_mode pass = pass_mode::pass; +}; + +} // namespace floormat diff --git a/src/world.cpp b/src/world.cpp index 59ea8d3d..759b9060 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -44,7 +44,7 @@ world& world::operator=(world&& w) noexcept _last_chunk = {}; _chunks = std::move(w._chunks); _objects = std::move(w._objects); - w._objects = safe_ptr<robin_map_wrapper>{}; + w._objects = {}; _unique_id = std::move(w._unique_id); fm_debug_assert(_unique_id); fm_debug_assert(w._unique_id == nullptr); diff --git a/test/dijkstra.cpp b/test/dijkstra.cpp index 8a702a52..6b2eafd4 100644 --- a/test/dijkstra.cpp +++ b/test/dijkstra.cpp @@ -1,7 +1,7 @@ #include "app.hpp" #include "src/path-search.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include <Magnum/Math/Functions.h> namespace floormat { diff --git a/test/json.cpp b/test/json.cpp index d94489ee..aac6fdee 100644 --- a/test/json.cpp +++ b/test/json.cpp @@ -11,7 +11,7 @@ #include "src/chunk.hpp" #include "src/world.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include <memory> #include <Corrade/Containers/StringView.h> #include <Corrade/Utility/Path.h> diff --git a/test/loader.cpp b/test/loader.cpp index 3b04459a..c517d00a 100644 --- a/test/loader.cpp +++ b/test/loader.cpp @@ -1,7 +1,7 @@ #include "app.hpp" #include "compat/assert.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include "src/ground-atlas.hpp" namespace floormat { @@ -53,6 +53,7 @@ void test_app::test_loader() (void)loader.get_wall_atlas(name); for (const auto& x : loader.ground_atlas_list()) + if (x.name != loader.INVALID) // todo! (void)loader.ground_atlas(x.name); fm_assert(loader.ground_atlas("texel")->pass_mode() == pass_mode::blocked); fm_assert(loader.ground_atlas("metal1")->pass_mode() == pass_mode::pass); diff --git a/test/path-search.cpp b/test/path-search.cpp index 5a1dc825..f602a8b9 100644 --- a/test/path-search.cpp +++ b/test/path-search.cpp @@ -2,7 +2,7 @@ #include "compat/assert.hpp" #include "compat/function2.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include "src/world.hpp" #include "src/scenery.hpp" #include "src/path-search.hpp" diff --git a/test/raycast.cpp b/test/raycast.cpp index cb76333f..6e3880cd 100644 --- a/test/raycast.cpp +++ b/test/raycast.cpp @@ -3,7 +3,7 @@ #include "src/raycast-diag.hpp" #include "src/world.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" #include <Magnum/Math/Functions.h> namespace floormat { diff --git a/test/wall-atlas2.cpp b/test/wall-atlas2.cpp index 4e86885b..8387d656 100644 --- a/test/wall-atlas2.cpp +++ b/test/wall-atlas2.cpp @@ -3,7 +3,7 @@ #include "src/tile-constants.hpp" #include "src/wall-atlas.hpp" #include "loader/loader.hpp" -#include "loader/wall-info.hpp" +#include "loader/wall-cell.hpp" namespace floormat { |