summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-05-30 11:24:46 +0200
committerStanislaw Halik <sthalik@misaki.pl>2023-05-30 11:24:46 +0200
commit49e8918e20d9cce86a7a136a231e400c2680e88f (patch)
treebe8efc9f7d13b667a4e225b8dfa5f2c348b7ec10
parent2970f407be7dd7aec13cf4733bf93b700abd2b0f (diff)
wip light inspect & serialize stuff
-rw-r--r--editor/imgui.cpp16
-rw-r--r--editor/inspect-types.cpp21
-rw-r--r--serialize/world-impl.hpp6
-rw-r--r--serialize/world-reader.cpp41
-rw-r--r--serialize/world-writer.cpp69
-rw-r--r--src/light-falloff.hpp4
-rw-r--r--src/light.cpp17
-rw-r--r--src/light.hpp15
-rw-r--r--src/pass-mode.hpp2
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