diff options
Diffstat (limited to 'loader')
-rw-r--r-- | loader/anim-info.hpp | 15 | ||||
-rw-r--r-- | loader/anim.cpp | 126 | ||||
-rw-r--r-- | loader/impl.cpp | 1 | ||||
-rw-r--r-- | loader/impl.hpp | 17 | ||||
-rw-r--r-- | loader/json.cpp | 13 | ||||
-rw-r--r-- | loader/loader.cpp | 7 | ||||
-rw-r--r-- | loader/loader.hpp | 24 |
7 files changed, 180 insertions, 23 deletions
diff --git a/loader/anim-info.hpp b/loader/anim-info.hpp new file mode 100644 index 00000000..97ba5954 --- /dev/null +++ b/loader/anim-info.hpp @@ -0,0 +1,15 @@ +#pragma once +#include <memory> +#include <Corrade/Containers/String.h> + +namespace floormat { + +class anim_atlas; + +struct anim_info +{ + String name; + std::shared_ptr<anim_atlas> atlas; +}; + +} // namespace floormat diff --git a/loader/anim.cpp b/loader/anim.cpp new file mode 100644 index 00000000..25b5e292 --- /dev/null +++ b/loader/anim.cpp @@ -0,0 +1,126 @@ +#include "impl.hpp" +#include "loader/anim-info.hpp" +#include "compat/exception.hpp" +#include "src/anim-atlas.hpp" +#include <Corrade/Containers/Array.h> +#include <Corrade/Containers/StridedArrayView.h> +#include <Corrade/Utility/Path.h> +#include <Magnum/Trade/ImageData.h> + +namespace floormat { + +std::shared_ptr<class anim_atlas> +loader_::get_anim_atlas(StringView path) noexcept(false) +{ + auto anim_info = deserialize_anim_def(path + ".json"); + + for (anim_group& group : anim_info.groups) + { + if (!group.mirror_from.isEmpty()) + { + auto it = std::find_if(anim_info.groups.cbegin(), anim_info.groups.cend(), + [&](const anim_group& x) { return x.name == group.mirror_from; }); + if (it == anim_info.groups.cend()) + fm_throw("can't find group '{}' to mirror from '{}'"_cf, group.mirror_from, group.name); + group.frames = array(arrayView(it->frames)); + for (anim_frame& f : group.frames) + f.ground = Vector2i((Int)f.size[0] - f.ground[0], f.ground[1]); + } + } + + auto tex = texture(""_s, path); + + fm_soft_assert(!anim_info.object_name.isEmpty()); + fm_soft_assert(anim_info.pixel_size.product() > 0); + fm_soft_assert(!anim_info.groups.isEmpty()); + fm_soft_assert(anim_info.nframes > 0); + fm_soft_assert(anim_info.nframes == 1 || anim_info.fps > 0); + const auto size = tex.pixels().size(); + const auto width = size[1], height = size[0]; + fm_soft_assert(anim_info.pixel_size[0] == width && anim_info.pixel_size[1] == height); + + auto atlas = std::make_shared<class anim_atlas>(path, tex, std::move(anim_info)); + return atlas; +} + +} // namespace floormat + +namespace floormat::loader_detail { + +ArrayView<const String> loader_impl::anim_atlas_list() +{ + if (anim_atlases.empty()) + get_anim_atlas_list(); + fm_assert(!anim_atlases.empty()); + return { anim_atlases.data(), anim_atlases.size() }; +} + +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]; + auto path = make_atlas_path(buf, dir, name); + + if (auto it = anim_atlas_map.find(path); it != anim_atlas_map.end()) + return it->second; + else + { + auto atlas = get_anim_atlas(path); + return anim_atlas_map[atlas->name()] = atlas; + } +} + +void loader_impl::get_anim_atlas_list() +{ + anim_atlases.clear(); + using f = Path::ListFlag; + constexpr auto flags = f::SkipDirectories | f::SkipDotAndDotDot | f::SkipSpecial | f::SortAscending; + if (const auto list = Path::list(ANIM_PATH, flags); list) + { + anim_atlases.reserve(list->size()); + constexpr auto suffix = ".json"_s; + for (StringView str : *list) + if (str.hasSuffix(suffix)) + anim_atlases.emplace_back(str.exceptSuffix(suffix.size())); + } + anim_atlases.shrink_to_fit(); + fm_assert(!anim_atlases.empty()); +} + +const anim_info& loader_impl::make_invalid_anim_atlas() +{ + if (invalid_anim_atlas) [[likely]] + return *invalid_anim_atlas; + + constexpr auto size = Vector2ui{16}; + + auto frame = anim_frame { + .ground = Vector2i(size/2), + .offset = {}, + .size = size, + }; + auto groups = Array<anim_group>{ValueInit, 1}; + groups[0] = anim_group { + .name = "n"_s, + .frames = array({ frame }), + }; + auto def = anim_def { + .object_name = INVALID, + .anim_name = INVALID, + .groups = Utility::move(groups), + .pixel_size = size, + .scale = anim_scale::fixed{size.x(), true}, + .nframes = 1, + }; + auto atlas = std::make_shared<class anim_atlas>(INVALID, make_error_texture(size), std::move(def)); + auto info = anim_info { + .name = INVALID, + .atlas = atlas, + }; + invalid_anim_atlas = Pointer<anim_info>{ InPlace, std::move(info) }; + return *invalid_anim_atlas; +} + +} // namespace floormat::loader_detail diff --git a/loader/impl.cpp b/loader/impl.cpp index f2f3c669..7da85f3f 100644 --- a/loader/impl.cpp +++ b/loader/impl.cpp @@ -2,6 +2,7 @@ #include "compat/assert.hpp" #include "loader/scenery.hpp" #include "loader/wall-info.hpp" +#include "loader/anim-info.hpp" #include "src/ground-atlas.hpp" #include <Corrade/Containers/Pair.h> #include <Magnum/Trade/ImageData.h> diff --git a/loader/impl.hpp b/loader/impl.hpp index b376503b..5c8a542a 100644 --- a/loader/impl.hpp +++ b/loader/impl.hpp @@ -10,12 +10,6 @@ #include <Corrade/PluginManager/PluginManager.h> #include <Magnum/Trade/AbstractImporter.h> -namespace floormat { -struct anim_def; -struct wall_info; -struct ground_info; -} - namespace floormat::loader_detail { struct loader_impl final : loader_ @@ -53,9 +47,9 @@ struct loader_impl final : loader_ std::shared_ptr<class wall_atlas> wall_atlas(StringView name, loader_policy policy) override; ArrayView<const wall_info> wall_atlas_list() override; void get_wall_atlas_list(); - const wall_info& make_invalid_wall_atlas(); + const wall_info& make_invalid_wall_atlas() override; - // >-----> tile >-----> + // >-----> ground >-----> tsl::robin_map<StringView, ground_info*> ground_atlas_map; std::vector<ground_info> ground_atlas_array; std::vector<String> missing_ground_atlases; @@ -63,15 +57,16 @@ struct loader_impl final : loader_ 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(); + const ground_info& 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; ArrayView<const String> anim_atlas_list() override; - std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir) noexcept(false) override; - static anim_def deserialize_anim(StringView filename); + 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; // >-----> scenery >-----> std::vector<serialized_scenery> sceneries_array; diff --git a/loader/json.cpp b/loader/json.cpp index 756f8151..5c7eecb5 100644 --- a/loader/json.cpp +++ b/loader/json.cpp @@ -6,6 +6,7 @@ #include "serialize/anim.hpp" #include "serialize/scenery.hpp" #include "loader/scenery.hpp" +#include "loader/anim-info.hpp" #include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Utility/Path.h> @@ -24,14 +25,26 @@ 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) + { + auto proto = scenery_proto{}; + proto.atlas = make_invalid_anim_atlas().atlas; + proto.bbox_size = Vector2ub{20}; + proto.subtype = generic_scenery_proto{false, true}; + sceneries_array.push_back({ .name = INVALID, .proto = proto }); + } + sceneries_map.clear(); sceneries_map.reserve(sceneries_array.size() * 2); + for (const serialized_scenery& s : sceneries_array) { if (sceneries_map.contains(s.name)) fm_abort("duplicate scenery name '%s'", s.name.data()); sceneries_map[s.name] = &s; } + fm_assert(!sceneries_map.empty()); } diff --git a/loader/loader.cpp b/loader/loader.cpp index af7b053f..531d731a 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -1,6 +1,7 @@ #include "impl.hpp" #include "ground-info.hpp" #include "wall-info.hpp" +#include "anim-info.hpp" #include "scenery.hpp" namespace floormat::loader_detail { @@ -19,8 +20,10 @@ void loader_impl::destroy() anim_atlas_map.clear(); anim_atlases.clear(); + invalid_anim_atlas = nullptr; sceneries_map.clear(); sceneries_array.clear(); + vobj_atlas_map.clear(); vobjs.clear(); } @@ -45,8 +48,6 @@ loader_::~loader_() noexcept = default; StringView loader_::strip_prefix(StringView name) { - if (name.hasPrefix(IMAGE_PATH_)) - return name.exceptPrefix(IMAGE_PATH_.size()); if (name.hasPrefix(ANIM_PATH)) return name.exceptPrefix(ANIM_PATH.size()); if (name.hasPrefix(SCENERY_PATH)) @@ -60,8 +61,6 @@ StringView loader_::strip_prefix(StringView name) return name; } -const StringView loader_::INVALID = "<invalid>"_s; // todo use it -const StringView loader_::IMAGE_PATH_ = "images/"_s; const StringView loader_::ANIM_PATH = "anim/"_s; const StringView loader_::SCENERY_PATH = "scenery/"_s; const StringView loader_::TEMP_PATH = "../../../"_s; diff --git a/loader/loader.hpp b/loader/loader.hpp index a9b1d262..96ab57ed 100644 --- a/loader/loader.hpp +++ b/loader/loader.hpp @@ -2,7 +2,7 @@ #include "compat/defs.hpp" #include "src/pass-mode.hpp" #include "loader/policy.hpp" -#include <stdio.h> +#include <stdio.h> // NOLINT(*-deprecated-headers) #include <memory> #include <Corrade/Containers/String.h> @@ -17,12 +17,14 @@ namespace floormat { struct anim_def; class anim_atlas; +struct anim_info; struct scenery_proto; struct vobj_info; class ground_atlas; struct ground_info; struct wall_info; class wall_atlas; +struct scenery_proto; struct vobj_info final { @@ -36,12 +38,12 @@ struct loader_ 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 ArrayView<const String> anim_atlas_list() = 0; - virtual std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH) noexcept(false) = 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 void destroy() = 0; static loader_& default_loader() noexcept; - virtual ArrayView<const ground_info> ground_atlas_list() noexcept(false) = 0; + virtual ArrayView<const ground_info> 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; @@ -51,16 +53,22 @@ struct loader_ static StringView make_atlas_path(char(&buf)[FILENAME_MAX], StringView dir, StringView name); [[nodiscard]] static bool check_atlas_name(StringView name) noexcept; - /** \deprecated{internal use only}*/ [[nodiscard]] std::shared_ptr<class ground_atlas> get_ground_atlas(StringView name, Vector2ub size, pass_mode pass) noexcept(false); - /** \deprecated{internal use only}*/ [[nodiscard]] std::shared_ptr<class wall_atlas> get_wall_atlas(StringView name) noexcept(false); - /** \deprecated{internal use only}*/ [[nodiscard]] std::shared_ptr<class anim_atlas> get_anim_atlas(StringView path) noexcept(false); + 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; + + /** \deprecated{internal use only}*/ [[nodiscard]] + std::shared_ptr<class ground_atlas> get_ground_atlas(StringView name, Vector2ub size, pass_mode pass) noexcept(false); + /** \deprecated{internal use only}*/ [[nodiscard]] + std::shared_ptr<class wall_atlas> get_wall_atlas(StringView name) noexcept(false); + /** \deprecated{internal use only}*/ [[nodiscard]] + std::shared_ptr<class anim_atlas> get_anim_atlas(StringView path) noexcept(false); virtual ~loader_() noexcept; fm_DECLARE_DELETED_COPY_ASSIGNMENT(loader_); fm_DECLARE_DELETED_MOVE_ASSIGNMENT(loader_); - static const StringView INVALID; - static const StringView IMAGE_PATH_; + static constexpr StringView INVALID = "<invalid>"_s; static const StringView ANIM_PATH; static const StringView SCENERY_PATH; static const StringView TEMP_PATH; |