diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-12 17:48:01 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-12 18:24:55 +0100 |
commit | b84cfa301e2fb131275711c67a2e91e3cda65c4e (patch) | |
tree | d060791ca783f6b9c4da5959535ec0eb85dd73cf /loader | |
parent | eea6fad65d5c9fecfb47c4a1c516c253cee85fd2 (diff) |
loader: fix static initializer mess
Diffstat (limited to 'loader')
-rw-r--r-- | loader/atlas.cpp | 61 | ||||
-rw-r--r-- | loader/filesystem.cpp | 40 | ||||
-rw-r--r-- | loader/impl.cpp | 185 | ||||
-rw-r--r-- | loader/impl.hpp | 42 | ||||
-rw-r--r-- | loader/init.cpp | 6 | ||||
-rw-r--r-- | loader/json.cpp | 2 | ||||
-rw-r--r-- | loader/loader.cpp | 25 | ||||
-rw-r--r-- | loader/loader.hpp | 13 | ||||
-rw-r--r-- | loader/texture.cpp | 48 |
9 files changed, 235 insertions, 187 deletions
diff --git a/loader/atlas.cpp b/loader/atlas.cpp new file mode 100644 index 00000000..4a5c6cfa --- /dev/null +++ b/loader/atlas.cpp @@ -0,0 +1,61 @@ +#include "impl.hpp" +#include "compat/assert.hpp" +#include "src/emplacer.hpp" +#include "src/tile-atlas.hpp" +#include "src/anim-atlas.hpp" +#include <Corrade/Containers/ArrayViewStl.h> +#include <Corrade/Containers/Pair.h> +#include <Corrade/Containers/StringView.h> +#include <Corrade/Utility/Path.h> +#include <Magnum/Trade/ImageData.h> + +namespace floormat::loader_detail { + +std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub size) +{ + const emplacer e{[&] { return std::make_shared<struct tile_atlas>(name, texture(IMAGE_PATH, name), size); }}; + auto atlas = tile_atlas_map.try_emplace(name, e).first->second; + return atlas; +} + +ArrayView<String> loader_impl::anim_atlas_list() +{ + if (anim_atlases.empty()) + get_anim_atlas_list(); + return anim_atlases; +} + +std::shared_ptr<anim_atlas> loader_impl::anim_atlas(StringView name) +{ + if (auto it = anim_atlas_map.find(name); it != anim_atlas_map.end()) + return it->second; + else + { + const auto path = Path::join(ANIM_PATH, Path::splitExtension(name).first()); + auto anim_info = deserialize_anim(path + ".json"); + auto tex = texture("", path); + + fm_assert(!anim_info.anim_name.isEmpty() && !anim_info.object_name.isEmpty()); + fm_assert(anim_info.pixel_size.product() > 0); + fm_assert(!anim_info.groups.empty()); + fm_assert(anim_info.nframes > 0); + fm_assert(anim_info.nframes == 1 || anim_info.fps > 0); + + auto atlas = std::make_shared<struct anim_atlas>(path, tex, std::move(anim_info)); + return anim_atlas_map[atlas->name()] = atlas; + } +} + +void loader_impl::get_anim_atlas_list() +{ + anim_atlases.clear(); + anim_atlases.reserve(64); + 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) + for (StringView str : *list) + if (str.hasSuffix(".json")) + anim_atlases.emplace_back(str.exceptSuffix(std::size(".json")-1)); +} + +} // namespace floormat::loader_detail diff --git a/loader/filesystem.cpp b/loader/filesystem.cpp index 4fbeb98a..850ec84f 100644 --- a/loader/filesystem.cpp +++ b/loader/filesystem.cpp @@ -1,9 +1,11 @@ #include "impl.hpp" #include "compat/assert.hpp" #include <cerrno> -#include <Corrade/Containers/StringView.h> +#include <Corrade/Containers/Pair.h> +#include <Corrade/Containers/String.h> #include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Implementation/ErrorString.h> +#include <Corrade/Utility/Path.h> #ifdef _WIN32 #include <Corrade/Containers/Array.h> #include <Corrade/Utility/Unicode.h> @@ -18,21 +20,51 @@ namespace floormat::loader_detail { namespace Unicode = Corrade::Utility::Unicode; #endif -bool chdir(StringView pathname) +bool loader_impl::chdir(StringView pathname) { + fm_assert(pathname.flags() & StringViewFlag::NullTerminated); int ret; #ifdef _WIN32 - ret = _wchdir(Unicode::widen(pathname)); + ret = ::_wchdir(Unicode::widen(pathname)); #else ret = ::chdir(pathname.data()); #endif if (ret) { Error err; - err << "chdir: can't change directory to" << pathname << Error::nospace << ':'; + err << "chdir: can't change directory to" << pathname << Error::nospace << ": "; Corrade::Utility::Implementation::printErrnoErrorString(err, errno); } return !ret; } +void loader_impl::set_application_working_directory() +{ + static bool once = false; + if (once) + return; + once = true; + if (const auto loc = Path::executableLocation()) + { + String path; +#ifdef _WIN32 + path = "\\\\?\\"_s + *loc; +#else + path = *loc; +#endif + StringView p = path; + p = Path::split(p).first(); + p = Path::split(p).first(); + path = p; +#ifdef _WIN32 + for (char& c : path) + if (c == '/') + c = '\\'; +#endif + chdir(path); + } + else + fm_warn("can't find install prefix!"); +} + } // namespace floormat::loader_detail diff --git a/loader/impl.cpp b/loader/impl.cpp index 99be0be6..6b0ba333 100644 --- a/loader/impl.cpp +++ b/loader/impl.cpp @@ -1,60 +1,15 @@ #include "impl.hpp" -#include "loader/loader.hpp" -#include "src/tile-atlas.hpp" #include "compat/assert.hpp" -#include "compat/alloca.hpp" -#include "src/anim-atlas.hpp" -#include "src/emplacer.hpp" #include <cstring> -#include <unordered_map> -#include <utility> #include <memory> -#include <Corrade/Containers/ArrayViewStl.h> -#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Pair.h> -#include <Corrade/Containers/StringView.h> -#include <Corrade/Containers/StringStlHash.h> -#include <Corrade/PluginManager/PluginManager.h> -#include <Corrade/Utility/Resource.h> -#include <Corrade/Utility/Path.h> -#include <Magnum/ImageView.h> -#include <Magnum/Trade/AbstractImporter.h> #include <Magnum/Trade/ImageData.h> -#include <Magnum/Trade/AbstractImageConverter.h> #ifdef __GNUG__ #pragma GCC diagnostic ignored "-Walloca" #endif -namespace floormat { - -struct loader_impl final : loader_ -{ - Optional<Utility::Resource> shader_res; - PluginManager::Manager<Trade::AbstractImporter> importer_plugins; - Containers::Pointer<Trade::AbstractImporter> image_importer = - importer_plugins.loadAndInstantiate("StbImageImporter"); - - Containers::Pointer<Trade::AbstractImporter> tga_importer = - importer_plugins.loadAndInstantiate("TgaImporter"); - - std::unordered_map<String, std::shared_ptr<struct tile_atlas>> tile_atlas_map; - std::unordered_map<String, std::shared_ptr<struct anim_atlas>> anim_atlas_map; - std::vector<String> anim_atlases; - - StringView shader(StringView filename) override; - template<std::size_t N> Trade::ImageData2D texture(const char(&prefix)[N], StringView filename); - std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) override; - ArrayView<String> anim_atlas_list() override; - std::shared_ptr<struct anim_atlas> anim_atlas(StringView name) override; - - void get_anim_atlas_list(); - - static void set_application_working_directory(); - - explicit loader_impl(); - ~loader_impl() override; -}; +namespace floormat::loader_detail { StringView loader_impl::shader(StringView filename) { @@ -66,138 +21,28 @@ StringView loader_impl::shader(StringView filename) return ret; } -std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub size) -{ - const emplacer e{[&] { return std::make_shared<struct tile_atlas>(name, texture(FM_IMAGE_PATH, name), size); }}; - auto atlas = tile_atlas_map.try_emplace(name, e).first->second; - return atlas; -} - -template<std::size_t N> -fm_noinline -Trade::ImageData2D loader_impl::texture(const char(&prefix)[N], StringView filename_) +loader_impl::loader_impl() { - if constexpr(N > 1) - fm_assert(prefix[N-2] == '/'); - fm_assert(filename_.size() < 4096); - fm_assert(filename_.find('\\') == filename_.end()); - fm_assert(filename_.find('\0') == filename_.end()); - fm_assert(tga_importer); - constexpr std::size_t max_extension_length = 16; - - char* const filename = (char*)alloca(filename_.size() + N + max_extension_length); - const std::size_t len = fm_begin( - std::size_t off = N-1; - if constexpr(N > 1) - std::memcpy(filename, prefix, off); - std::memcpy(filename + off, filename_.cbegin(), filename_.size()); - return off + filename_.size(); - ); - - for (const auto& extension : std::initializer_list<StringView>{ ".tga", ".png", ".webp", }) - { - std::memcpy(filename + len, extension.data(), extension.size()); - filename[len + extension.size()] = '\0'; - auto& importer = extension == StringView(".tga") ? tga_importer : image_importer; - if (Path::exists(filename) && importer->openFile(filename)) - { - auto img = importer->image2D(0); - if (!img) - fm_abort("can't allocate image for '%s'", filename); - auto ret = std::move(*img); - return ret; - } - } - const auto path = Path::currentDirectory(); - filename[len] = '\0'; - fm_abort("can't open image '%s' (cwd '%s')", filename, path ? path->data() : "(null)"); + system_init(); + set_application_working_directory(); } -ArrayView<String> loader_impl::anim_atlas_list() -{ - if (anim_atlases.empty()) - get_anim_atlas_list(); - return anim_atlases; -} +loader_impl::~loader_impl() = default; -std::shared_ptr<anim_atlas> loader_impl::anim_atlas(StringView name) +void loader_impl::ensure_plugins() { - if (auto it = anim_atlas_map.find(name); it != anim_atlas_map.end()) - return it->second; - else + if (!importer_plugins) + importer_plugins.emplace(); + if (!image_importer) { - const auto path = Path::join(FM_ANIM_PATH, Path::splitExtension(name).first()); - auto anim_info = loader_detail::deserialize_anim(path + ".json"); - auto tex = texture("", path); - - fm_assert(!anim_info.anim_name.isEmpty() && !anim_info.object_name.isEmpty()); - fm_assert(anim_info.pixel_size.product() > 0); - fm_assert(!anim_info.groups.empty()); - fm_assert(anim_info.nframes > 0); - fm_assert(anim_info.nframes == 1 || anim_info.fps > 0); - - auto atlas = std::make_shared<struct anim_atlas>(path, tex, std::move(anim_info)); - return anim_atlas_map[atlas->name()] = atlas; + image_importer = importer_plugins->loadAndInstantiate("StbImageImporter"); + fm_assert(image_importer); } -} - -void loader_impl::get_anim_atlas_list() -{ - anim_atlases.clear(); - anim_atlases.reserve(64); - using f = Path::ListFlag; - constexpr auto flags = f::SkipDirectories | f::SkipDotAndDotDot | f::SkipSpecial | f::SortAscending; - if (const auto list = Path::list(FM_ANIM_PATH, flags); list) - for (StringView str : *list) - if (str.hasSuffix(".json")) - anim_atlases.emplace_back(str.exceptSuffix(std::size(".json")-1)); -} - -void loader_::destroy() -{ - loader.~loader_(); - new (&loader) loader_impl(); -} - -void loader_impl::set_application_working_directory() -{ - static bool once = false; - if (once) - return; - once = true; - if (const auto loc = Path::executableLocation()) + if (!tga_importer) { - StringView path = *loc; - path = Path::split(path).first(); - path = Path::split(path).first(); -#ifdef _WIN32 - String p = "\\\\?\\" + path; - for (char& c : p) - if (c == '/') - c = '\\'; - path = p; -#endif - loader_detail::chdir(path); + tga_importer = importer_plugins->loadAndInstantiate("TgaImporter"); + fm_assert(tga_importer); } - else - fm_warn("can't find install prefix!"); } -loader_impl::loader_impl() -{ - loader_detail::system_init(); - set_application_working_directory(); -} - -loader_impl::~loader_impl() = default; - -loader_& loader_::default_loader() noexcept -{ - static loader_impl loader_singleton{}; - return loader_singleton; -} - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -loader_& loader = loader_::default_loader(); - -} // namespace floormat +} // namespace floormat::loader_detail diff --git a/loader/impl.hpp b/loader/impl.hpp index 08467038..343d3ee1 100644 --- a/loader/impl.hpp +++ b/loader/impl.hpp @@ -1,12 +1,46 @@ #pragma once +#include "loader/loader.hpp" +#include <memory> +#include <vector> +#include <unordered_map> +#include <Corrade/Containers/Optional.h> +#include <Corrade/Containers/StringView.h> +#include <Corrade/Containers/StringStlHash.h> +#include <Corrade/Utility/Resource.h> +#include <Corrade/PluginManager/PluginManager.h> +#include <Magnum/Trade/AbstractImporter.h> namespace floormat { struct anim_def; } -namespace Corrade::Containers { template<typename T> class BasicStringView; using StringView = BasicStringView<const char>; } namespace floormat::loader_detail { -bool chdir(StringView pathname); -anim_def deserialize_anim(StringView filename); -void system_init(); +struct loader_impl final : loader_ +{ + Optional<Utility::Resource> shader_res; + Optional<PluginManager::Manager<Trade::AbstractImporter>> importer_plugins; + Containers::Pointer<Trade::AbstractImporter> image_importer; + Containers::Pointer<Trade::AbstractImporter> tga_importer; + + std::unordered_map<String, std::shared_ptr<struct tile_atlas>> tile_atlas_map; + std::unordered_map<String, std::shared_ptr<struct anim_atlas>> anim_atlas_map; + std::vector<String> anim_atlases; + + StringView shader(StringView filename) override; + Trade::ImageData2D texture(StringView prefix, StringView filename); + std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) override; + ArrayView<String> anim_atlas_list() override; + std::shared_ptr<struct anim_atlas> anim_atlas(StringView name) override; + + void get_anim_atlas_list(); + + static void set_application_working_directory(); + static anim_def deserialize_anim(StringView filename); + static void system_init(); + static bool chdir(StringView pathname); + void ensure_plugins(); + + explicit loader_impl(); + ~loader_impl() override; +}; } // namespace floormat::loader_detail diff --git a/loader/init.cpp b/loader/init.cpp index b4733ca7..89d9d6c9 100644 --- a/loader/init.cpp +++ b/loader/init.cpp @@ -10,6 +10,10 @@ extern "C" __declspec(dllimport) long WINAPI RtlGetVersion(PRTL_OSVERSIONINFOEXW #ifdef _MSC_VER #pragma comment(lib, "ntdll.lib") #endif +#if defined __GNUG__ && !defined __clang__ +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + #endif // _WIN32 namespace floormat::loader_detail { @@ -35,7 +39,7 @@ static void system_init_() #endif } -void system_init() +void loader_impl::system_init() { static bool once = false; if (once) diff --git a/loader/json.cpp b/loader/json.cpp index be621b61..1a30a66b 100644 --- a/loader/json.cpp +++ b/loader/json.cpp @@ -4,7 +4,7 @@ namespace floormat::loader_detail { -anim_def deserialize_anim(StringView filename) +anim_def loader_impl::deserialize_anim(StringView filename) { return json_helper::from_json<anim_def>(filename); } diff --git a/loader/loader.cpp b/loader/loader.cpp index 83c3eed2..a2fcd161 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -1,5 +1,28 @@ -#include "loader.hpp" +#include "impl.hpp" + namespace floormat { + +using loader_detail::loader_impl; + +void loader_::destroy() +{ + loader.~loader_(); + new (&loader) loader_impl(); +} + +loader_& loader_::default_loader() noexcept +{ + static loader_impl loader_singleton{}; + return loader_singleton; +} + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +loader_& loader = loader_::default_loader(); + loader_::loader_() = default; loader_::~loader_() = default; + +const StringView loader_::IMAGE_PATH = "share/floormat/images/"_s; +const StringView loader_::ANIM_PATH = "share/floormat/anim/"_s; + } // namespace floormat diff --git a/loader/loader.hpp b/loader/loader.hpp index 32158675..3320b839 100644 --- a/loader/loader.hpp +++ b/loader/loader.hpp @@ -1,12 +1,10 @@ #pragma once - #include <memory> -#include <Corrade/Containers/ArrayView.h> -#include <Corrade/Containers/StringView.h> -#include <Magnum/Trade/ImageData.h> -#define FM_IMAGE_PATH "share/floormat/images/" -#define FM_ANIM_PATH "share/floormat/anim/" +namespace Corrade::Containers { template<typename T> class ArrayView; class String; } +namespace Corrade::Containers { template<typename T> class BasicStringView; using StringView = BasicStringView<const char>; } +namespace Magnum::Math { template<class T> class Vector2; } +namespace Magnum { using Vector2ub = Math::Vector2<unsigned char>; } namespace floormat { @@ -27,6 +25,9 @@ struct loader_ virtual ~loader_(); + static const StringView IMAGE_PATH; + static const StringView ANIM_PATH; + protected: loader_(); }; diff --git a/loader/texture.cpp b/loader/texture.cpp new file mode 100644 index 00000000..c142cf69 --- /dev/null +++ b/loader/texture.cpp @@ -0,0 +1,48 @@ +#include "impl.hpp" +#include "compat/assert.hpp" +#include <cstring> +#include <Corrade/Utility/Path.h> +#include <Magnum/Trade/ImageData.h> + +namespace floormat::loader_detail { + +fm_noinline +Trade::ImageData2D loader_impl::texture(StringView prefix, StringView filename_) +{ + ensure_plugins(); + + const auto N = prefix.size(); + if (N > 0) + fm_assert(prefix[N-1] == '/'); + fm_assert(filename_.size() < 4096); + fm_assert(filename_.find('\\') == filename_.end()); + fm_assert(filename_.find('\0') == filename_.end()); + fm_assert(tga_importer); + constexpr std::size_t max_extension_length = 16; + + char* const filename = (char*)alloca(filename_.size() + N + 1 + max_extension_length); + if (N > 0) + std::memcpy(filename, prefix.data(), N); + std::memcpy(filename + N, filename_.cbegin(), filename_.size()); + std::size_t len = filename_.size() + N; + + for (const auto& extension : std::initializer_list<StringView>{ ".tga", ".png", ".webp", }) + { + std::memcpy(filename + len, extension.data(), extension.size()); + filename[len + extension.size()] = '\0'; + auto& importer = extension == StringView(".tga") ? tga_importer : image_importer; + if (Path::exists(filename) && importer->openFile(filename)) + { + auto img = importer->image2D(0); + if (!img) + fm_abort("can't allocate image for '%s'", filename); + auto ret = std::move(*img); + return ret; + } + } + const auto path = Path::currentDirectory(); + filename[len] = '\0'; + fm_abort("can't open image '%s' (cwd '%s')", filename, path ? path->data() : "(null)"); +} + +} // namespace floormat::loader_detail |