summaryrefslogtreecommitdiffhomepage
path: root/loader
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-11-12 17:48:01 +0100
committerStanislaw Halik <sthalik@misaki.pl>2022-11-12 18:24:55 +0100
commitb84cfa301e2fb131275711c67a2e91e3cda65c4e (patch)
treed060791ca783f6b9c4da5959535ec0eb85dd73cf /loader
parenteea6fad65d5c9fecfb47c4a1c516c253cee85fd2 (diff)
loader: fix static initializer mess
Diffstat (limited to 'loader')
-rw-r--r--loader/atlas.cpp61
-rw-r--r--loader/filesystem.cpp40
-rw-r--r--loader/impl.cpp185
-rw-r--r--loader/impl.hpp42
-rw-r--r--loader/init.cpp6
-rw-r--r--loader/json.cpp2
-rw-r--r--loader/loader.cpp25
-rw-r--r--loader/loader.hpp13
-rw-r--r--loader/texture.cpp48
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