diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-28 22:10:27 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-28 22:10:27 +0200 |
commit | 280b4c235fe11dd629f882f0fb5054384fcee1d7 (patch) | |
tree | e89735003b52b04e3c17a3ad5532b36e055cdda7 | |
parent | 1b84fc144f77c4ebef6fdc0a476410420e0a95b3 (diff) |
more work
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | compat/integer-types.hpp | 8 | ||||
-rw-r--r-- | loader/loader-impl.cpp | 1 | ||||
-rw-r--r-- | serialize/binary-reader.hpp | 6 | ||||
-rw-r--r-- | serialize/binary-reader.inl | 15 | ||||
-rw-r--r-- | serialize/binary-writer.hpp | 1 | ||||
-rw-r--r-- | serialize/world-impl.hpp | 5 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 89 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 21 | ||||
-rw-r--r-- | serialize/world.cpp | 12 | ||||
-rw-r--r-- | src/tile-image.hpp | 2 | ||||
-rw-r--r-- | src/tile.hpp | 2 | ||||
-rw-r--r-- | src/world.cpp | 2 | ||||
-rw-r--r-- | src/world.hpp | 12 |
14 files changed, 135 insertions, 43 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 17535755..c8c084d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD_DEFAULT 23) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_EXTENSIONS FALSE) -set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_DEFAULT 11) set(CMAKE_C_STANDARD_REQUIRED TRUE) set(CMAKE_C_EXTENSIONS FALSE) diff --git a/compat/integer-types.hpp b/compat/integer-types.hpp index d270abda..6411599f 100644 --- a/compat/integer-types.hpp +++ b/compat/integer-types.hpp @@ -20,7 +20,7 @@ typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; -#else +#elif __GNUG__ typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __INTPTR_TYPE__ intptr_t; @@ -34,8 +34,13 @@ typedef __UINT8_TYPE__ uint8_t; typedef __UINT16_TYPE__ uint16_t; typedef __UINT32_TYPE__ uint32_t; typedef __UINT64_TYPE__ uint64_t; +#else +#define FM_NO_INTTYPES_FORWARD_DECLARATION +#include <cstddef> +#include <cstdint> #endif +#ifndef FM_NO_INTTYPES_FORWARD_DECLARATION namespace std { using ::size_t; using ::ptrdiff_t; @@ -51,3 +56,4 @@ using ::uint16_t; using ::uint32_t; using ::uint64_t; } // namespace std +#endif diff --git a/loader/loader-impl.cpp b/loader/loader-impl.cpp index a6d05e32..8c478161 100644 --- a/loader/loader-impl.cpp +++ b/loader/loader-impl.cpp @@ -100,6 +100,7 @@ Trade::ImageData2D loader_impl::tile_texture(StringView filename_) } } const auto path = Utility::Path::currentDirectory(); + filename[len] = '\0'; fm_abort("can't open tile image '%s' (cwd '%s')", filename, path ? path->data() : "(null)"); } diff --git a/serialize/binary-reader.hpp b/serialize/binary-reader.hpp index 3b6eae9a..7eed2145 100644 --- a/serialize/binary-reader.hpp +++ b/serialize/binary-reader.hpp @@ -1,11 +1,12 @@ #pragma once
#include "binary-serializer.hpp"
#include <iterator>
+#include <Corrade/Containers/StringView.h>
namespace floormat::Serialize {
-union value_u {
- alignas(alignof(double)) char bytes[8];
+union alignas(alignof(double)) value_u {
+ char bytes[8];
unsigned char uc;
std::uint8_t u8;
std::uint16_t u16;
@@ -44,6 +45,7 @@ struct binary_reader final { template<typename T> T read() noexcept;
template<std::size_t N> constexpr std::array<char, N> read() noexcept;
constexpr std::size_t bytes_read() const noexcept { return num_bytes_read; }
+ constexpr StringView read_asciiz_string() noexcept;
private:
std::size_t num_bytes_read = 0;
diff --git a/serialize/binary-reader.inl b/serialize/binary-reader.inl index cf935a76..ad2d59bc 100644 --- a/serialize/binary-reader.inl +++ b/serialize/binary-reader.inl @@ -33,7 +33,7 @@ template<typename T> T binary_reader<It>::read() noexcept
{
value_u buf = read_u<T>();
- return *reinterpret_cast<T>(buf.bytes);
+ return *reinterpret_cast<T*>(buf.bytes);
}
template<string_input_iterator It>
@@ -79,9 +79,18 @@ constexpr value_u binary_reader<It>::read_u() noexcept template<string_input_iterator It, serializable T>
binary_reader<It>& operator>>(binary_reader<It>& reader, T& x) noexcept
{
- value_u u = reader.template read<T>();
- x = *reinterpret_cast<T*>(&u.bytes[0]);
+ x = reader.template read<T>();
return reader;
}
+template<string_input_iterator It>
+constexpr StringView binary_reader<It>::read_asciiz_string() noexcept
+{
+ const It pos = it;
+ while (it != end)
+ if (char c = *it++; c == '\0')
+ return StringView{pos, (std::size_t)std::distance(pos, end), StringViewFlag::NullTerminated};
+ fm_abort("unexpected EOF while reading a string");
+}
+
} // namespace floormat::Serialize
diff --git a/serialize/binary-writer.hpp b/serialize/binary-writer.hpp index ead0824d..02fe427d 100644 --- a/serialize/binary-writer.hpp +++ b/serialize/binary-writer.hpp @@ -11,7 +11,6 @@ struct binary_writer final { template<integer T> constexpr void write(T x) noexcept;
template<std::floating_point T> void write(T x) noexcept;
constexpr void write_asciiz_string(StringView str) noexcept;
-
constexpr std::size_t bytes_written() const noexcept { return _bytes_written; }
private:
diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index b2d74db3..26073edd 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -12,8 +12,9 @@ namespace floormat::Serialize { namespace {
using tilemeta = std::uint8_t;
-using imgvar = std::uint8_t;
+using imgvar = decltype(tile_image::variant);
using atlasid = std::uint16_t;
+using chunksiz = std::uint16_t;
using enum tile::pass_mode;
template<typename T> constexpr inline T int_max = std::numeric_limits<T>::max();
@@ -45,7 +46,7 @@ namespace { struct FILE_raii final {
FILE_raii(FILE* s) noexcept : s{s} {}
- ~FILE_raii() noexcept { if (s) ::fclose(s); }
+ ~FILE_raii() noexcept { close(); }
operator FILE*() noexcept { return s; }
void close() noexcept { if (s) ::fclose(s); s = nullptr; }
private:
diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index 86b07834..299386de 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -2,6 +2,8 @@ #include "world-impl.hpp"
#include "binary-reader.inl"
#include "src/world.hpp"
+#include "src/loader.hpp"
+#include "src/tile-atlas.hpp"
namespace floormat::Serialize {
@@ -12,9 +14,11 @@ struct reader_state final { void deserialize_world(ArrayView<const char> buf);
private:
+ using reader_t = binary_reader<decltype(ArrayView<const char>{}.cbegin())>;
+
std::shared_ptr<tile_atlas> lookup_atlas(atlasid id);
- void read_atlases();
- void read_chunks();
+ void read_atlases(reader_t& reader);
+ void read_chunks(reader_t& reader);
std::unordered_map<atlasid, std::shared_ptr<tile_atlas>> atlases;
struct world* world;
@@ -22,11 +26,84 @@ private: reader_state::reader_state(struct world& world) noexcept : world{&world} {}
+void reader_state::read_atlases(reader_t& s)
+{
+ const auto N = s.read<atlasid>();
+ atlases.reserve(N * 2);
+ for (atlasid i = 0; i < N; i++)
+ {
+ Vector2ub size;
+ s >> size[0];
+ s >> size[1];
+ atlases[i] = loader.tile_atlas(s.read_asciiz_string(), size);
+ }
+}
+
+std::shared_ptr<tile_atlas> reader_state::lookup_atlas(atlasid id)
+{
+ if (auto it = atlases.find(id); it != atlases.end())
+ return it->second;
+ else
+ fm_abort("not such atlas: '%zu'", (std::size_t)id);
+}
+
+void reader_state::read_chunks(reader_t& s)
+{
+ const auto N = s.read<chunksiz>();
+
+ for (std::size_t i = 0; i < N; i++)
+ {
+ std::decay_t<decltype(chunk_magic)> magic;
+ s >> magic;
+ if (magic != chunk_magic)
+ fm_abort("bad chunk magic");
+ chunk_coords coord;
+ s >> coord.x;
+ s >> coord.y;
+ auto& chunk = (*world)[coord];
+ for (std::size_t i = 0; i < TILE_COUNT; i++)
+ {
+ const tilemeta flags = s.read<tilemeta>();
+ const auto make_atlas = [&] -> tile_image {
+ auto atlas = lookup_atlas(s.read<atlasid>());
+ auto id = s.read<imgvar>();
+ return { atlas, id };
+ };
+ tile t;
+ if (flags & meta_ground)
+ t.ground_image = make_atlas();
+ if (flags & meta_wall_n)
+ t.wall_north = make_atlas();
+ if (flags & meta_wall_w)
+ t.wall_west = make_atlas();
+ switch (auto x = flags & pass_mask)
+ {
+ case tile::pass_shoot_through:
+ case tile::pass_blocked:
+ case tile::pass_ok:
+ t.passability = (tile::pass_mode)x;
+ break;
+ default:
+ fm_abort("bad pass mode '%zu' for tile %zu", i, (std::size_t)x);
+ }
+ chunk[i] = std::move(t);
+ }
+ }
+}
+
void reader_state::deserialize_world(ArrayView<const char> buf)
{
auto s = binary_reader{buf};
if (!!::memcmp(s.read<std::size(file_magic)-1>().data(), file_magic, std::size(file_magic)-1))
fm_abort("bad magic");
+ std::decay_t<decltype(proto_version)> proto;
+ s >> proto;
+ if (proto != proto_version)
+ fm_abort("bad proto version '%zu' (should be '%zu')",
+ (std::size_t)proto, (std::size_t)proto_version);
+ read_atlases(s);
+ read_chunks(s);
+ s.assert_end();
}
} // namespace
@@ -47,17 +124,17 @@ world world::deserialize(StringView filename) if (!f)
fm_abort("fopen(\"%s\", \"r\"): %s", filename.data(), strerror(errbuf));
if (int ret = ::fseek(f, 0, SEEK_END); ret != 0)
- fm_abort("fseek(\"%s\", 0, SEEK_END): %s", filename.data(), strerror(errbuf));
+ fm_abort("fseek(SEEK_END): %s", strerror(errbuf));
std::size_t len;
if (auto len_ = ::ftell(f); len_ >= 0)
len = (std::size_t)len_;
else
- fm_abort("ftell(\"%s\"): %s", filename.data(), strerror(errbuf));
+ fm_abort("ftell: %s", strerror(errbuf));
if (int ret = ::fseek(f, 0, SEEK_SET); ret != 0)
- fm_abort("fseek(\"%s\", 0, SEEK_SET): %s", filename.data(), strerror(errbuf));
+ fm_abort("fseek(SEEK_SET): %s", strerror(errbuf));
auto buf_ = std::make_unique<char[]>(len);
if (auto ret = ::fread(&buf_[0], len, 1, f); ret != 1)
- fm_abort("fread(\"%s\", %zu): %s", filename.data(), len, strerror(errbuf));
+ fm_abort("fread %zu: %s", len, strerror(errbuf));
world w;
Serialize::reader_state s{w};
diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 80c8de4a..c0f59e9b 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -106,8 +106,6 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) s << flags;
- static_assert(std::is_same_v<imgvar, imgvar>);
-
if (img_g != null_atlas)
s << img_g << x.ground_image.variant;
if (img_n != null_atlas)
@@ -126,8 +124,8 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) void writer_state::serialize_atlases()
{
- const std::size_t sz = tile_images.size();
- fm_assert(sz < int_max<atlasid>);
+ fm_assert(tile_images.size() < int_max<atlasid>);
+ const auto sz = (atlasid)tile_images.size();
const auto atlasbuf_size = sizeof(sz) + atlas_name_max*sz;
atlas_buf.resize(atlasbuf_size);
auto s = binary_writer{atlas_buf.begin()};
@@ -143,6 +141,8 @@ void writer_state::serialize_atlases() fm_debug_assert(s.bytes_written() + namesiz + 1 <= atlasbuf_size);
fm_assert(namesiz <= atlas_name_max - 1); // null terminated
fm_debug_assert(name.find('\0') == name.cend());
+ const auto sz2 = atlas->num_tiles2();
+ s << sz2[0]; s << sz2[1];
s.write_asciiz_string(name);
}
fm_assert(s.bytes_written() <= atlasbuf_size);
@@ -165,9 +165,15 @@ ArrayView<const char> writer_state::serialize_world() }
serialize_atlases();
+ using proto_t = std::decay_t<decltype(proto_version)>;
+ union { chunksiz x; char bytes[sizeof x]; } c = {.x = maybe_byteswap((chunksiz)world->size())};
+ union { proto_t x; char bytes[sizeof x]; } p = {.x = maybe_byteswap(proto_version)};
+ fm_assert(world->size() <= int_max<chunksiz>);
+
std::size_t len = 0;
len += std::size(file_magic)-1;
- len += sizeof(proto_version);
+ len += sizeof(p.x);
+ len += sizeof(c.x);
for (const auto& buf : chunk_bufs)
len += buf.size();
len += atlas_buf.size();
@@ -176,14 +182,15 @@ ArrayView<const char> writer_state::serialize_world() const auto copy = [&](const auto& in) {
#ifndef FM_NO_DEBUG
auto len1 = std::distance(std::cbegin(in), std::cend(in)),
- len2 = std::distance(it, file_buf.end());
+ len2 = std::distance(it, file_buf.end());
fm_assert(len1 <= len2);
#endif
it = std::copy(std::cbegin(in), std::cend(in), it);
};
copy(Containers::StringView{file_magic, std::size(file_magic)-1});
- copy(std::initializer_list<char>{ char(proto_version & 0xff), char((proto_version >> 8) & 0xff) });
+ copy(p.bytes);
copy(atlas_buf);
+ copy(c.bytes);
for (const auto& buf : chunk_bufs)
copy(buf);
return {file_buf.data(), file_buf.size()};
diff --git a/serialize/world.cpp b/serialize/world.cpp deleted file mode 100644 index 70d4d0c9..00000000 --- a/serialize/world.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#define FM_SERIALIZE_WORLD_IMPL -#include "world-impl.hpp" -#include "binary-reader.inl" -#include <Corrade/Utility/Path.h> - -namespace floormat { - -namespace Path = Corrade::Utility::Path; - - - -} // namespace floormat diff --git a/src/tile-image.hpp b/src/tile-image.hpp index deb04e9a..30ae7b0b 100644 --- a/src/tile-image.hpp +++ b/src/tile-image.hpp @@ -10,7 +10,7 @@ struct tile_atlas; struct tile_image final
{
std::shared_ptr<tile_atlas> atlas;
- std::uint8_t variant = (std::uint8_t)-1;
+ std::uint16_t variant = (std::uint8_t)-1;
explicit operator bool() const noexcept { return !!atlas; }
diff --git a/src/tile.hpp b/src/tile.hpp index 5103479d..ef0b1ade 100644 --- a/src/tile.hpp +++ b/src/tile.hpp @@ -12,9 +12,9 @@ struct tile final pass_mode passability = pass_shoot_through; constexpr tile() = default; - tile(tile&&) = default; fm_DECLARE_DEPRECATED_COPY_ASSIGNMENT(tile); + fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(tile); }; } //namespace floormat diff --git a/src/world.cpp b/src/world.cpp index cefb2485..39b47db1 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -29,7 +29,7 @@ chunk& world::operator[](chunk_coords coord) noexcept return ret; } -std::tuple<chunk&, tile&> world::operator[](global_coords pt) noexcept +auto world::operator[](global_coords pt) noexcept -> pair { auto& c = operator[](pt.chunk()); return { c, c[pt.local()] }; diff --git a/src/world.hpp b/src/world.hpp index fcbb97a2..a18f41f8 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -1,11 +1,10 @@ #pragma once #include "compat/int-hash.hpp" -#include "global-coords.hpp" -#include "tile.hpp" +#include "compat/integer-types.hpp" #include "chunk.hpp" +#include "global-coords.hpp" #include <unordered_map> #include <memory> -#include <optional> namespace std::filesystem { class path; } @@ -23,21 +22,24 @@ private: }; std::unordered_map<chunk_coords, chunk, decltype(hasher)> _chunks; - mutable std::tuple<chunk*, chunk_coords>_last_chunk; + mutable std::tuple<chunk*, chunk_coords> _last_chunk; std::size_t _last_collection = 0; explicit world(std::size_t capacity); public: explicit world(); + struct pair final { chunk& c; tile& t; }; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + template<typename Hash, typename Alloc, typename Pred> explicit world(std::unordered_map<chunk_coords, chunk, Hash, Alloc, Pred>&& chunks); chunk& operator[](chunk_coords c) noexcept; - std::tuple<chunk&, tile&> operator[](global_coords pt) noexcept; + pair operator[](global_coords pt) noexcept; bool contains(chunk_coords c) const noexcept; void clear(); void collect(bool force = false); + constexpr std::size_t size() const noexcept { return _chunks.size(); } [[deprecated]] const auto& chunks() const noexcept { return _chunks; } // only for serialization |