diff options
-rw-r--r-- | loader/atlas.cpp | 4 | ||||
-rw-r--r-- | loader/error-tex.cpp | 13 | ||||
-rw-r--r-- | loader/impl.hpp | 2 | ||||
-rw-r--r-- | loader/texture.cpp | 2 | ||||
-rw-r--r-- | loader/wall-atlas.cpp | 4 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 38 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 50 |
7 files changed, 58 insertions, 55 deletions
diff --git a/loader/atlas.cpp b/loader/atlas.cpp index c32ae345..39442b6a 100644 --- a/loader/atlas.cpp +++ b/loader/atlas.cpp @@ -30,9 +30,11 @@ bool loader_::check_atlas_name(StringView str) noexcept { constexpr auto first_char = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"_s; + if (str == "<invalid>"_s) + return true; if (!str || !first_char.find(str[0])) return false; - if (str.findAny("\\\"'\n\r\t\a\033\0|$!%{}#^*?<>&;:^"_s) || str.find("/."_s)) + if (str.findAny("\\\"'\n\r\t\a\033\0|$!%{}^*?<>&;:^"_s) || str.find("/."_s)) return false; return true; diff --git a/loader/error-tex.cpp b/loader/error-tex.cpp index 4cc64f91..7f91f032 100644 --- a/loader/error-tex.cpp +++ b/loader/error-tex.cpp @@ -1,15 +1,20 @@ #include "impl.hpp" +#include "compat/assert.hpp" +#include <Corrade/Containers/Array.h> #include <Magnum/Math/Vector4.h> #include <Magnum/PixelFormat.h> #include <Magnum/Trade/ImageData.h> namespace floormat::loader_detail { -Trade::ImageData2D loader_impl::make_error_texture() +Trade::ImageData2D loader_impl::make_error_texture(Vector2ui size) { - static const Vector4ub data[] = { {255, 0, 255, 255} }; // magenta - return Trade::ImageData2D{PixelFormat::RGBA8Unorm, {1, 1}, {}, - Containers::arrayView(data, 1), {}, {}}; + fm_assert(size.product() != 0); + constexpr auto magenta = Vector4ub{255, 0, 255, 255}; + auto array = Array<Vector4ub>{DirectInit, size.product(), magenta}; + auto img = Trade::ImageData2D{PixelFormat::RGBA8Unorm, Vector2i(size), {}, + std::move(array), {}, {}}; + return img; } } // namespace floormat::loader_detail diff --git a/loader/impl.hpp b/loader/impl.hpp index 84022f8d..4cb9236b 100644 --- a/loader/impl.hpp +++ b/loader/impl.hpp @@ -41,7 +41,7 @@ struct loader_impl final : loader_ Optional<Utility::Resource> shader_res; StringView shader(StringView filename) noexcept override; - Trade::ImageData2D make_error_texture(); + Trade::ImageData2D make_error_texture(Vector2ui size); Trade::ImageData2D texture(StringView prefix, StringView filename, bool fail_ok = true) noexcept(false) override; // >-----> walls >-----> diff --git a/loader/texture.cpp b/loader/texture.cpp index 1e4ac709..a12986b4 100644 --- a/loader/texture.cpp +++ b/loader/texture.cpp @@ -51,7 +51,7 @@ Trade::ImageData2D loader_impl::texture(StringView prefix, StringView filename_, if (!fail_ok) fm_throw("can't open image '{}' (cwd '{}'): {}"_cf, buf, path ? StringView{*path} : "(null)"_s, get_error_string(errbuf)); else - return make_error_texture(); + return make_error_texture({1,1}); } } // namespace floormat::loader_detail diff --git a/loader/wall-atlas.cpp b/loader/wall-atlas.cpp index 4f13e91a..502cfd0c 100644 --- a/loader/wall-atlas.cpp +++ b/loader/wall-atlas.cpp @@ -65,10 +65,10 @@ const wall_info& loader_impl::make_invalid_wall_atlas() wall_atlas_def { Wall::Info{.name = name, .depth = 8}, {{ {}, frame_size}, }, - {{ {.index = 0, .count = 1, .pixel_size = frame_size, } } }, + {{ {.index = 0, .count = 1, .pixel_size = frame_size, .is_defined = true, } } }, {{ {.val = 0}, {}, }}, {1u}, - }, name, make_error_texture()); + }, name, make_error_texture(frame_size)); invalid_wall_atlas = Pointer<wall_info>{InPlaceInit, wall_info{ .name = name, .atlas = std::move(a) } }; return *invalid_wall_atlas; } diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index d3954b09..f90acbd6 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -27,7 +27,7 @@ struct reader_state final { private: using reader_t = binary_reader<decltype(ArrayView<const char>{}.cbegin())>; - const std::shared_ptr<tile_atlas>& lookup_atlas(atlasid id); + StringView lookup_atlas(atlasid id); const scenery_proto& lookup_scenery(atlasid id); StringView lookup_string(uint32_t idx); void read_atlases(reader_t& reader); @@ -38,7 +38,7 @@ private: std::vector<String> strings; std::vector<scenery_proto> sceneries; - std::vector<std::shared_ptr<tile_atlas>> atlases; + std::vector<String> atlases; world* _world; uint16_t PROTO = proto_version; @@ -59,9 +59,7 @@ void reader_state::read_atlases(reader_t& s) size[0] << s; size[1] << s; const auto& [buf, len] = s.read_asciiz_string<atlas_name_max>(); - auto atlas = loader.tile_atlas({buf, len}); - fm_soft_assert(size <= atlas->num_tiles2()); - atlases.push_back(std::move(atlas)); + atlases.push_back({buf, len}); } } @@ -136,7 +134,7 @@ void reader_state::read_strings(reader_t& s) } } -const std::shared_ptr<tile_atlas>& reader_state::lookup_atlas(atlasid id) +StringView reader_state::lookup_atlas(atlasid id) { if (id < atlases.size()) return atlases[id]; @@ -202,7 +200,7 @@ void reader_state::read_chunks(reader_t& s) tile_ref t = c[i]; using uchar = uint8_t; - const auto make_atlas = [&]() -> tile_image_proto { + const auto make_atlas = [&]<typename T>() -> image_proto_<T> { atlasid id; if (PROTO < 8) [[unlikely]] id = flags & meta_short_atlasid_ ? atlasid{s.read<uchar>()} : s.read<atlasid>(); @@ -215,21 +213,29 @@ void reader_state::read_chunks(reader_t& s) v = flags & meta_short_variant_ ? s.read<uint8_t>() : uint8_t(s.read<uint16_t>()); - auto atlas = lookup_atlas(id); - fm_soft_assert(v < atlas->num_tiles()); - return { atlas, v }; + auto name = lookup_atlas(id); + if constexpr(std::is_same_v<tile_atlas, T>) + { + auto atlas = loader.tile_atlas(name); + fm_soft_assert(v < atlas->num_tiles()); + return { atlas, v }; + } + else if (std::is_same_v<wall_atlas, T>) + { + auto atlas = loader.wall_atlas(name, true); + return { atlas, v }; + } + else + std::unreachable(); }; SET_CHUNK_SIZE(); //t.passability() = pass_mode(flags & pass_mask); if (flags & meta_ground) - t.ground() = make_atlas(); - // todo! -#if 0 + t.ground() = make_atlas.operator()<tile_atlas>(); if (flags & meta_wall_n) - t.wall_north() = make_atlas(); + t.wall_north() = make_atlas.operator()<wall_atlas>(); if (flags & meta_wall_w) - t.wall_west() = make_atlas(); -#endif + t.wall_west() = make_atlas.operator()<wall_atlas>(); if (PROTO >= 3 && PROTO < 8) [[unlikely]] if (flags & meta_scenery_) read_old_scenery(s, ch, i); diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 90fcf3b4..a89f039a 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -1,7 +1,7 @@ #define FM_SERIALIZE_WORLD_IMPL #include "world-impl.hpp" - #include "src/tile-atlas.hpp" +#include "src/wall-atlas.hpp" #include "binary-writer.inl" #include "src/global-coords.hpp" #include "src/chunk.hpp" @@ -30,8 +30,9 @@ using namespace floormat::Serialize; namespace { struct interned_atlas final { - const tile_atlas* img; + StringView name; atlasid index; + Vector2ub num_tiles; }; struct interned_scenery { @@ -55,8 +56,7 @@ struct writer_state final { private: using writer_t = binary_writer<decltype(std::vector<char>{}.begin())>; - atlasid intern_atlas(const tile_image_proto& img); - atlasid maybe_intern_atlas(const tile_image_proto& img); + atlasid intern_atlas(const void* ptr, StringView name, Vector2ub num_tiles); scenery_pair intern_scenery(const scenery& sc, bool create); uint32_t intern_string(StringView name); @@ -97,17 +97,17 @@ uint32_t writer_state::intern_string(StringView name) return kv->second; } -atlasid writer_state::intern_atlas(const tile_image_proto& img) +atlasid writer_state::intern_atlas(const void* ptr, StringView name, Vector2ub num_tiles) { - const void* const ptr = img.atlas.get(); fm_debug_assert(ptr != nullptr); - emplacer e{[&]() -> interned_atlas { return { &*img.atlas, (atlasid)tile_images.size() }; }}; - return tile_images.try_emplace(ptr, e).first->second.index; -} - -atlasid writer_state::maybe_intern_atlas(const tile_image_proto& img) -{ - return img ? intern_atlas(img) : null_atlas; + if (auto it = tile_images.find(ptr); it != tile_images.end()) + return it->second.index; + else + { + auto aid = (atlasid)tile_images.size(); + tile_images[ptr] = { name, aid, num_tiles }; + return aid; + } } void writer_state::load_scenery_1(const serialized_scenery& s) @@ -227,14 +227,12 @@ void writer_state::serialize_atlases() return a.index < b.index; }); - for (const auto& [atlas, _] : atlases) + for (const auto& [name, aid, num_tiles] : atlases) { - const auto name = atlas->name(); const auto namesiz = name.size(); fm_debug_assert(s.bytes_written() + namesiz < atlasbuf_size); fm_assert(namesiz < atlas_name_max); - const auto sz2 = atlas->num_tiles2(); - s << sz2[0]; s << sz2[1]; + s << num_tiles[0]; s << num_tiles[1]; s.write_asciiz_string(name); } atlas_buf.resize(s.bytes_written()); @@ -464,11 +462,11 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords_ coord) fm_debug_assert(s.bytes_written() + tile_size <= chunkbuf_size); - auto img_g = maybe_intern_atlas(ground); - //auto img_n = maybe_intern_atlas(wall_north); - //auto img_w = maybe_intern_atlas(wall_west); - // todo! - auto img_n = null_atlas, img_w = null_atlas; + auto img_g = ground.atlas ? intern_atlas(&*ground.atlas, ground.atlas->name(), ground.atlas->num_tiles2()) : null_atlas; + auto img_n = wall_north ? intern_atlas(&*wall_north.atlas, wall_north.atlas->name(), {0xff, 0xff}) : null_atlas; + auto img_w = wall_west ? intern_atlas(&*wall_west.atlas, wall_west.atlas->name(), {0xff, 0xff}) : null_atlas; + + fm_assert(!ground.atlas || ground.variant < ground.atlas->num_tiles()); if (img_g == null_atlas && img_n == null_atlas && img_w == null_atlas) { @@ -494,14 +492,6 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords_ coord) flags |= meta_wall_w * (img_w != null_atlas); s << flags; - constexpr auto check_atlas = [](const tile_image_proto& x) { - fm_assert(!x.atlas || x.variant < x.atlas->num_tiles()); - }; - check_atlas(ground); - // todo! - //check_atlas(wall_north); - //check_atlas(wall_west); - if (img_g != null_atlas) { s << img_g; |