diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-05-30 11:24:46 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-05-30 11:24:46 +0200 |
commit | 49e8918e20d9cce86a7a136a231e400c2680e88f (patch) | |
tree | be8efc9f7d13b667a4e225b8dfa5f2c348b7ec10 | |
parent | 2970f407be7dd7aec13cf4733bf93b700abd2b0f (diff) |
wip light inspect & serialize stuff
-rw-r--r-- | editor/imgui.cpp | 16 | ||||
-rw-r--r-- | editor/inspect-types.cpp | 21 | ||||
-rw-r--r-- | serialize/world-impl.hpp | 6 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 41 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 69 | ||||
-rw-r--r-- | src/light-falloff.hpp | 4 | ||||
-rw-r--r-- | src/light.cpp | 17 | ||||
-rw-r--r-- | src/light.hpp | 15 | ||||
-rw-r--r-- | src/pass-mode.hpp | 2 |
9 files changed, 118 insertions, 73 deletions
diff --git a/editor/imgui.cpp b/editor/imgui.cpp index c6a5bff9..df75501a 100644 --- a/editor/imgui.cpp +++ b/editor/imgui.cpp @@ -170,28 +170,22 @@ void app::draw_light_info() switch (e.falloff) { default: falloff = "?"_s; break; - case light_falloff::constant: falloff = "Constant"_s; break; - case light_falloff::linear: falloff = "Linear"_s; break; - case light_falloff::quadratic: falloff = "Quadratic"_s; break; + case light_falloff::constant: falloff = "constant"_s; break; + case light_falloff::linear: falloff = "linear"_s; break; + case light_falloff::quadratic: falloff = "quadratic"_s; break; } - char dist[32]; - if (!e.symmetric) - snformat(dist, "{{{}, {}}}"_cf, e.half_dist.x(), e.half_dist.y()); - else - snformat(dist, "{}"_cf, e.half_dist.x()); - // todo add rendering color as part of the lightbulb icon #if 0 char color[8]; snformat(color, "{:2X}{:2X}{:2X}"_cf, e.color.x(), e.color.y(), e.color.z()); #endif - char buf[128]; + if (e.falloff == light_falloff::constant) snformat(buf, "{}"_cf, falloff); else - snformat(buf, "{} D={}"_cf, falloff, dist); + snformat(buf, "{} range={}"_cf, falloff, e.max_distance); auto text_size = ImGui::CalcTextSize(buf); float offy = dest.max().y() + 5 * dpi.y(); diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp index 75d79901..c7d4b494 100644 --- a/editor/inspect-types.cpp +++ b/editor/inspect-types.cpp @@ -203,7 +203,8 @@ template<typename U> struct enum_values<light_falloff, U> }; template<> -struct entity_accessors<light> { +struct entity_accessors<light> +{ static constexpr auto accessors() { using E = Entity<light>; @@ -218,19 +219,13 @@ struct entity_accessors<light> { [](const light& x) { return x.falloff; }, [](light& x, light_falloff value) { x.falloff = value; }, }, - E::type<Vector2>::field{"half-dist"_s, - [](const light& x) { return x.half_dist; }, - [](light& x, Vector2 value) { x.half_dist = value; }, - [](const light& x) { return !x.symmetric ? st::enabled : st::hidden; }, - }, - E::type<float>::field{"half-dist"_s, - [](const light& x) { return x.half_dist.x(); }, - [](light& x, float value) { x.half_dist = Vector2(value); }, - [](const light& x) { return x.symmetric ? st::enabled : st::hidden; } + E::type<float>::field{"range"_s, + [](const light& x) { return x.max_distance; }, + [](light& x, float value) { x.max_distance = value; }, }, - E::type<bool>::field{"symmetric"_s, - [](const light& x) { return x.symmetric; }, - [](light& x, bool value) { x.symmetric = value; if (value) x.half_dist = Vector2(x.half_dist.x()); }, + E::type<bool>::field{"enabled"_s, + [](const light& x) { return !!x.enabled; }, + [](light& x, bool value) { x.enabled = value; }, }, }; return std::tuple_cat(tuple0, tuple); diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index 88844869..b03086da 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -46,20 +46,20 @@ template<typename T> constexpr inline T int_max = std::numeric_limits<T>::max(); #define file_magic ".floormat.save" +constexpr inline proto_t proto_version = 14; + constexpr inline size_t atlas_name_max = 128; constexpr inline auto null_atlas = (atlasid)-1LL; constexpr inline size_t character_name_max = 128; constexpr inline size_t string_max = 512; -constexpr inline proto_t proto_version = 13; constexpr inline proto_t min_proto_version = 1; constexpr inline auto chunk_magic = (uint16_t)~0xc0d3; constexpr inline auto scenery_magic = (uint16_t)~0xb00b; using pass_mode_i = std::underlying_type_t<pass_mode>; -constexpr inline pass_mode_i pass_mask = pass_mode_COUNT - 1; -constexpr inline auto pass_bits = std::bit_width(pass_mask); +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; diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index f72065ef..de0e5784 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -4,6 +4,7 @@ #include "src/world.hpp" #include "src/scenery.hpp" #include "src/character.hpp" +#include "src/light.hpp" #include "loader/loader.hpp" #include "loader/scenery.hpp" #include "src/tile-atlas.hpp" @@ -243,9 +244,14 @@ void reader_state::read_chunks(reader_t& s) static_assert(entity_type_BITS == 3); const auto type = entity_type(_id >> 61); const auto local = local_coords{s.read<uint8_t>()}; - constexpr auto read_offsets = [](auto& s, auto& e) { - s >> e.offset[0]; - s >> e.offset[1]; + + Vector2b offset; + if (PROTO >= 14) [[likely]] + { + offset[0] << s; + offset[1] << s; + } + constexpr auto read_bbox = [](auto& s, auto& e) { s >> e.bbox_offset[0]; s >> e.bbox_offset[1]; s >> e.bbox_size[0]; @@ -256,6 +262,7 @@ void reader_state::read_chunks(reader_t& s) { case entity_type::character: { character_proto proto; + proto.offset = offset; uint8_t id; id << s; proto.r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); if (read_entity_flags(s, proto)) @@ -280,11 +287,18 @@ void reader_state::read_chunks(reader_t& s) auto name = StringView{buf, len}; proto.name = name; } - if (!(id & meta_short_scenery_bit)) - read_offsets(s, proto); + { + if (PROTO < 14) [[unlikely]] + { + s >> proto.offset[0]; + s >> proto.offset[1]; + } + read_bbox(s, proto); + } SET_CHUNK_SIZE(); auto e = _world->make_entity<character, false>(oid, {ch, local}, proto); + e->offset_frac = offset_frac; (void)e; break; } @@ -294,6 +308,7 @@ void reader_state::read_chunks(reader_t& s) const auto r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); id &= ~scenery_id_flag_mask; auto sc = lookup_scenery(id); + sc.offset = offset; (void)sc.atlas->group(r); sc.r = r; if (!exact) @@ -302,7 +317,13 @@ void reader_state::read_chunks(reader_t& s) sc.frame = s.read<uint8_t>(); else sc.frame << s; - read_offsets(s, sc); + (void)sc.atlas->frame(sc.r, sc.frame); + if (PROTO < 14) [[unlikely]] + { + s >> sc.offset[0]; + s >> sc.offset[1]; + } + read_bbox(s, sc); if (sc.active) sc.delta << s; } @@ -310,6 +331,14 @@ void reader_state::read_chunks(reader_t& s) (void)e; break; } + 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); + break; + } default: fm_throw("invalid_entity_type '{}'"_cf, (int)type); } diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 4ec9a3a6..8b8416fd 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -12,6 +12,7 @@ #include "src/character.hpp" #include "loader/scenery.hpp" #include "src/anim-atlas.hpp" +#include "src/light.hpp" #include <concepts> #include <cstring> #include <vector> @@ -37,7 +38,7 @@ struct interned_scenery { }; struct scenery_pair { - const serialized_scenery* s; + const scenery_proto* s; atlasid index; bool exact_match; }; @@ -150,7 +151,7 @@ scenery_pair writer_state::intern_scenery(const scenery& sc, bool create) if (s == proto) { if (x.index != null_atlas) - return { x.s, x.index, true }; + return { &x.s->proto, x.index, true }; else ret = &x; } @@ -161,16 +162,16 @@ scenery_pair writer_state::intern_scenery(const scenery& sc, bool create) if (ret) { ret->index = scenery_map_size++; - return { ret->s, ret->index, true }; + return { &ret->s->proto, ret->index, true }; } else if (create) { if (ret2) - return { ret2->s, ret2->index, false }; + return { &ret2->s->proto, ret2->index, false }; else { fm_assert(vec[0].index == null_atlas); - return { vec[0].s, vec[0].index = scenery_map_size++, false }; + return { &vec[0].s->proto, vec[0].index = scenery_map_size++, false }; } } else @@ -316,7 +317,8 @@ void writer_state::serialize_strings() void writer_state::serialize_scenery(const chunk& c, writer_t& s) { - const auto def_char_bbox_size = character_proto{}.bbox_size; + constexpr auto def_char_bbox_size = Vector2ub(iTILE_SIZE2); // copied from character_proto + const auto entity_count = (uint32_t)c.entities().size(); s << entity_count; fm_assert(entity_count == c.entities().size()); @@ -333,9 +335,10 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) s << oid; const auto local = e.coord.local(); s << local.to_index(); - constexpr auto write_offsets = [](auto& s, const auto& e) { - s << e.offset[0]; - s << e.offset[1]; + s << e.offset[0]; + s << e.offset[1]; + + constexpr auto write_bbox = [](auto& s, const auto& e) { s << e.bbox_offset[0]; s << e.bbox_offset[1]; s << e.bbox_size[0]; @@ -349,7 +352,7 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) const auto& C = static_cast<const character&>(e); uint8_t id = 0; const auto sc_exact = - C.offset.isZero() && C.bbox_offset.isZero() && + C.bbox_offset.isZero() && C.bbox_size == def_char_bbox_size; id |= meta_short_scenery_bit * sc_exact; id |= static_cast<decltype(id)>(C.r) << sizeof(id)*8-1-rotation_BITS; @@ -364,15 +367,18 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) fm_assert(C.name.size() < character_name_max); s << intern_string(C.name); if (!sc_exact) - write_offsets(s, C); + write_bbox(s, C); break; } case entity_type::scenery: { const auto& sc = static_cast<const scenery&>(e); auto [ss, img_s, sc_exact] = intern_scenery(sc, true); sc_exact = sc_exact && - e.offset.isZero() && e.bbox_offset.isZero() && e.bbox_size.isZero() && - !sc.active && !sc.closing && !sc.interactive; + e.bbox_offset == ss->bbox_offset && e.bbox_size == ss->bbox_size && + e.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); @@ -383,17 +389,50 @@ void writer_state::serialize_scenery(const chunk& c, writer_t& s) if (!sc_exact) { write_entity_flags(s, sc); - fm_assert(sc.active || sc.delta == 0.f); + fm_assert(sc.active || sc.delta == 0); if (sc.frame <= 0xff) s << (uint8_t)sc.frame; else s << sc.frame; - write_offsets(s, sc); + write_bbox(s, sc); if (sc.active) s << sc.delta; } break; } + 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(); + { + 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 + s << flags; + } + { + s << L.max_distance; + for (auto i = 0uz; i < 3; i++) + s << L.color[i]; + } + if (!sc_exact) + { + fm_assert(L.frame < (1 << 14)); + fm_assert(L.pass < pass_mode_COUNT); + uint16_t frame = 0; + frame |= L.frame; + frame |= uint16_t(L.pass) << 14; + s << frame; + write_bbox(s, L); + } + break; + } } } } diff --git a/src/light-falloff.hpp b/src/light-falloff.hpp index b9b1c4bf..3d047731 100644 --- a/src/light-falloff.hpp +++ b/src/light-falloff.hpp @@ -6,4 +6,8 @@ enum class light_falloff : uint8_t { constant = 1, linear = 0, quadratic = 2, }; +constexpr inline light_falloff light_falloff_COUNT{3}; +constexpr inline uint8_t light_falloff_BITS = 2; +constexpr inline uint8_t light_falloff_MASK = (1 << 2)-1; + } // namespace floormat diff --git a/src/light.cpp b/src/light.cpp index ed9469f2..03fe4690 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -20,7 +20,7 @@ bool light_proto::operator==(const light_proto&) const = default; light::light(object_id id, struct chunk& c, const light_proto& proto) : entity{id, c, proto}, - half_dist{proto.half_dist}, + max_distance{proto.max_distance}, color{proto.color}, falloff{proto.falloff} { @@ -43,19 +43,4 @@ bool light::update(size_t, float) { return false; } bool light::is_dynamic() const { return true; } bool light::is_virtual() const { return true; } -Vector2 light::intensity(Vector2 half_dist, light_falloff falloff) -{ - switch (falloff) - { - case light_falloff::linear: return 2 * half_dist; - case light_falloff::quadratic: return Vector2{std::sqrt(2 * half_dist.x()), std::sqrt(2 * half_dist.y())}; - default: case light_falloff::constant: return Vector2{1, 1}; - } -} - -Vector2 light::intensity() const -{ - return intensity(half_dist, falloff); -} - } // namespace floormat diff --git a/src/light.hpp b/src/light.hpp index e228c8b5..2202651a 100644 --- a/src/light.hpp +++ b/src/light.hpp @@ -15,18 +15,17 @@ struct light_proto : entity_proto ~light_proto() noexcept override; bool operator==(const light_proto&) const; - Vector2 half_dist{3}; + float max_distance = 0; Color3ub color{255, 255, 255}; light_falloff falloff : 3 = light_falloff::linear; - uint8_t symmetric : 1 = true; }; struct light final : entity { - Vector2 half_dist; + float max_distance; Color3ub color; - light_falloff falloff : 3; - uint8_t symmetric : 1 = true; + light_falloff falloff : 2; + uint8_t enabled : 1 = true; light(object_id id, struct chunk& c, const light_proto& proto); @@ -37,10 +36,10 @@ struct light final : entity bool is_dynamic() const override; bool is_virtual() const override; - static Vector2 intensity(Vector2 half_dist, light_falloff falloff); - Vector2 intensity() const; - friend struct world; }; +template<> struct entity_type_<struct light> : std::integral_constant<entity_type, entity_type::light> {}; +template<> struct entity_type_<struct light_proto> : std::integral_constant<entity_type, entity_type::light> {}; + } // namespace floormat diff --git a/src/pass-mode.hpp b/src/pass-mode.hpp index 876466d7..0bf8d867 100644 --- a/src/pass-mode.hpp +++ b/src/pass-mode.hpp @@ -3,7 +3,7 @@ namespace floormat { enum class pass_mode : unsigned char { blocked, see_through, shoot_through, pass, }; -constexpr inline unsigned char pass_mode_COUNT = 4; +constexpr inline pass_mode pass_mode_COUNT{4}; constexpr inline unsigned char pass_mode_BITS = 2; } // namespace floormat |