diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-05-30 16:20:01 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-05-30 16:20:01 +0200 |
commit | 25acfd26024bf4d1ab806c1b3cbc885118b0eb7b (patch) | |
tree | a56047b16732eee9a689588970c5d61d296614b5 /serialize | |
parent | 64dcfaca1548a669c93fae686cacd634048cb2ea (diff) |
add light entity serialization
Diffstat (limited to 'serialize')
-rw-r--r-- | serialize/binary-writer.inl | 3 | ||||
-rw-r--r-- | serialize/world-impl.hpp | 7 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 27 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 34 |
4 files changed, 49 insertions, 22 deletions
diff --git a/serialize/binary-writer.inl b/serialize/binary-writer.inl index e2428c5e..0833a6f0 100644 --- a/serialize/binary-writer.inl +++ b/serialize/binary-writer.inl @@ -31,7 +31,8 @@ constexpr binary_writer<It>& operator<<(binary_writer<It>& writer, T x) noexcept template<std::output_iterator<char> It> constexpr void binary_writer<It>::write_asciiz_string(StringView str) noexcept { - fm_debug_assert(str.flags() & StringViewFlag::NullTerminated); + //fm_debug_assert(str.flags() & StringViewFlag::NullTerminated); + fm_debug_assert(!str.find('\0')); const auto sz = str.size(); _bytes_written += sz + 1; for (auto i = 0uz; i < sz; i++) diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index b03086da..4b215063 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -26,6 +26,7 @@ * 11) RLE empty tiles. * 12) Don't write entity name twice. * 13) Entity counter initialized to 1024. + * 14) Always store entity offset, rework how sc_exact works. */ namespace floormat { @@ -62,11 +63,13 @@ using pass_mode_i = std::underlying_type_t<pass_mode>; constexpr inline pass_mode_i pass_mask = (1 << pass_mode_BITS)-1; using entity_type_i = std::underlying_type_t<entity_type>; -template<typename T> constexpr inline auto highbit = T(1) << sizeof(T)*8-1; template<typename T, size_t N, size_t off> constexpr inline auto highbits = (T(1) << N)-1 << sizeof(T)*8-N-off; -constexpr inline atlasid meta_short_scenery_bit = highbit<atlasid>; +template<size_t N, typename T = uint8_t> +constexpr auto lowbits = (T(1) << N)-T(1); + +constexpr inline atlasid meta_short_scenery_bit = highbits<atlasid, 1, 0>; constexpr inline atlasid meta_rotation_bits = highbits<atlasid, rotation_BITS, 1>; constexpr inline atlasid scenery_id_flag_mask = meta_short_scenery_bit | meta_rotation_bits; constexpr inline atlasid scenery_id_max = int_max<atlasid> & ~scenery_id_flag_mask; diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index de0e5784..eadda90a 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -272,6 +272,7 @@ void reader_state::read_chunks(reader_t& s) Vector2s offset_frac; offset_frac[0] << s; offset_frac[1] << s; + const bool exact = id & meta_short_scenery_bit; SET_CHUNK_SIZE(); if (PROTO >= 9) [[likely]] @@ -287,7 +288,7 @@ void reader_state::read_chunks(reader_t& s) auto name = StringView{buf, len}; proto.name = name; } - if (!(id & meta_short_scenery_bit)) + if (!exact) { if (PROTO < 14) [[unlikely]] { @@ -334,9 +335,29 @@ void reader_state::read_chunks(reader_t& s) case entity_type::light: { light_proto proto; proto.offset = offset; + uint8_t flags; flags << s; - const bool sc_exact = flags & (1 << 7); - proto.r = rotation((flags >> 4) & rotation_MASK); + const bool exact = flags & 1; + proto.r = rotation((flags >> 1) & lowbits<rotation_BITS>); + proto.falloff = light_falloff((flags >> 4) & lowbits<light_falloff_BITS>); + const bool enabled = (flags >> 6) & 1; + + s >> proto.max_distance; + for (auto i = 0uz; i < 3; i++) + s >> proto.color[i]; + if (!exact) + { + uint16_t frame; frame << s; + auto pass = pass_mode((frame >> 14) & lowbits<2>); + frame &= lowbits<14, uint16_t>; + proto.pass = pass; + proto.frame = frame; + read_bbox(s, proto); + } + SET_CHUNK_SIZE(); + auto L = _world->make_entity<light, false>(oid, {ch, local}, proto); + L->enabled = enabled; + (void)L; break; } default: diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 8b8416fd..50ffe3fb 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -77,7 +77,7 @@ private: constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3; constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords_) + tile_size * TILE_COUNT + sizeof(uint32_t); -constexpr auto entity_size = std::max(sizeof(character), sizeof(scenery)); +constexpr auto entity_size = std::max({ sizeof(character), sizeof(scenery), sizeof(light), }); writer_state::writer_state(const world& world) : _world{&world} { @@ -230,7 +230,6 @@ void writer_state::serialize_atlases() const auto namesiz = name.size(); fm_debug_assert(s.bytes_written() + namesiz < atlasbuf_size); fm_assert(namesiz < atlas_name_max); - 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); @@ -284,6 +283,7 @@ void writer_state::serialize_scenery_names() num++; fm_assert(num < int_max<uint8_t>); s << (uint8_t)num; + fm_assert(sc->name.size() < atlas_name_max); s.write_asciiz_string(sc->name); } s << idx; @@ -310,7 +310,10 @@ void writer_state::serialize_strings() auto s = binary_writer{string_buf.begin()}; s << (uint32_t)string_map.size(); for (const auto& [k, v] : string_map) + { + fm_assert(k.size() < string_max); s.write_asciiz_string(k); + } fm_assert(s.bytes_written() == sizeof(uint32_t) + len); fm_assert(s.bytes_written() == string_buf.size()); } @@ -327,10 +330,10 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) const auto& e = *e_; fm_assert(s.bytes_written() + entity_size <= chunk_buf.size()); object_id oid = e.id; - fm_assert((oid & ((object_id)1 << 60)-1) == oid); + fm_assert((oid & lowbits<60, object_id>) == oid); static_assert(entity_type_BITS == 3); const auto type = e.type(); - fm_assert(((entity_type_i)type & (1 << entity_type_BITS)-1) == (entity_type_i)type); + fm_assert(((entity_type_i)type & lowbits<entity_type_BITS, entity_type_i>) == (entity_type_i)type); oid |= (object_id)type << 64 - entity_type_BITS; s << oid; const auto local = e.coord.local(); @@ -374,15 +377,15 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) const auto& sc = static_cast<const scenery&>(e); auto [ss, img_s, sc_exact] = intern_scenery(sc, true); sc_exact = sc_exact && - e.bbox_offset == ss->bbox_offset && e.bbox_size == ss->bbox_size && - e.pass == ss->pass && sc.sc_type == ss->sc_type && + sc.bbox_offset == ss->bbox_offset && sc.bbox_size == ss->bbox_size && + sc.pass == ss->pass && sc.sc_type == ss->sc_type && sc.active == ss->active && sc.closing == ss->closing && sc.interactive == ss->interactive && sc.delta == 0 && sc.frame == ss->frame; fm_assert(img_s != null_atlas); atlasid id = img_s; static_assert(rotation_BITS == 3); - fm_assert((id & (1 << 16-3-1)-1) == id); + fm_assert(id == (id & lowbits<16-3-1, atlasid>)); id |= meta_short_scenery_bit * sc_exact; id |= static_cast<decltype(id)>(sc.r) << sizeof(id)*8-1-rotation_BITS; s << id; @@ -402,18 +405,16 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) } case entity_type::light: { const auto& L = static_cast<const light&>(e); - const auto sc_exact = L.frame == 0 && L.pass == pass_mode::pass && - L.bbox_offset.isZero() && L.bbox_size.isZero(); + const auto exact = L.frame == 0 && L.pass == pass_mode::pass && + L.bbox_offset.isZero() && L.bbox_size.isZero(); { fm_assert(L.r < rotation_COUNT); fm_assert(L.falloff < light_falloff_COUNT); - fm_assert(L.pass < pass_mode_COUNT); - uint8_t flags = 0; - flags |= uint8_t(sc_exact) << 0; // 1 bit - flags |= uint8_t(L.r) << 1; // 3 bits - flags |= (uint8_t)L.falloff << 4; // 2 bits - flags |= (uint8_t)L.enabled << 5; // 1 bit + flags |= (uint8_t)exact; // 1 bit + flags |= ((uint8_t)L.r & lowbits<rotation_BITS>) << 1; // 3 bits + flags |= ((uint8_t)L.falloff & lowbits<light_falloff_BITS>) << 4; // 2 bits + flags |= (uint8_t)!!L.enabled << 6; // 1 bit s << flags; } { @@ -421,7 +422,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) for (auto i = 0uz; i < 3; i++) s << L.color[i]; } - if (!sc_exact) + if (!exact) { fm_assert(L.frame < (1 << 14)); fm_assert(L.pass < pass_mode_COUNT); @@ -542,6 +543,7 @@ ArrayView<const char> writer_state::serialize_world() intern_scenery(static_cast<const scenery&>(e), false); break; case entity_type::character: + case entity_type::light: break; default: fm_abort("invalid scenery type '%d'", (int)e.type()); |