14#if defined(TESS_ENABLE_IMGUI)
17#error "tess/debug/imgui/tools.h requires <imgui.h> to be included first"
20#include <tess/storage/sparse_world.h>
26namespace tess::debug::imgui {
29enum class ToolStatus : std::uint8_t {
43 ToolStatus status = ToolStatus::Shown;
44 std::optional<BoolFieldEditIntent> intent;
49[[nodiscard]]
inline auto tool_to_ull(std::uint64_t value)
noexcept
50 ->
unsigned long long {
51 return static_cast<unsigned long long>(value);
54[[nodiscard]]
inline auto tool_to_ll(std::int64_t value)
noexcept ->
long long {
55 return static_cast<long long>(value);
58[[nodiscard]]
inline auto tool_chunk_activity_name(
59 ChunkActivity activity)
noexcept ->
const char* {
61 case ChunkActivity::Sleeping:
63 case ChunkActivity::Active:
72template <
typename World>
73void draw_world_overview(
const World& world) {
74 using Shape =
typename World::shape_type;
75 using Traits = ShapeTraits<Shape>;
77 ImGui::TextUnformatted(
"World overview");
79 ImGui::Text(
"tiles: %llu x %llu x %llu", detail::tool_to_ull(Traits::size.x),
80 detail::tool_to_ull(Traits::size.y),
81 detail::tool_to_ull(Traits::size.z));
82 ImGui::Text(
"chunks: %llu x %llu x %llu (%llu total)",
83 detail::tool_to_ull(Traits::chunk_count_x),
84 detail::tool_to_ull(Traits::chunk_count_y),
85 detail::tool_to_ull(Traits::chunk_count_z),
86 detail::tool_to_ull(World::chunk_count));
87 ImGui::Text(
"page bytes: %llu", detail::tool_to_ull(World::page_byte_size));
89 if constexpr (std::is_same_v<
typename World::residency_type,
91 ImGui::Text(
"resident: %llu / %llu (%llu bytes)",
92 detail::tool_to_ull(World::chunk_count),
93 detail::tool_to_ull(World::chunk_count),
94 detail::tool_to_ull(World::storage_byte_size));
96 ImGui::Text(
"resident: %llu / %llu (%llu bytes)",
97 detail::tool_to_ull(world.resident_count()),
98 detail::tool_to_ull(world.capacity()),
99 detail::tool_to_ull(world.resident_byte_size()));
104template <
typename World>
105[[nodiscard]]
auto draw_chunk_inspector(
const World& world, Coord3 selected)
107 using Shape =
typename World::shape_type;
108 const auto resolved = world.try_resolve(selected);
109 if (!resolved.has_value()) {
110 ImGui::TextUnformatted(
"Selection is outside the world");
111 return ToolStatus::OutOfBounds;
114 const auto* page = world.try_chunk(resolved->chunk_key);
115 if (page ==
nullptr) {
116 ImGui::Text(
"Chunk %llu is not resident",
117 detail::tool_to_ull(resolved->chunk_key.value));
118 return ToolStatus::Missing;
124 const auto& meta = world.meta(resolved->chunk_key);
125 const auto chunk = chunk_coord<Shape>(resolved->chunk_key);
126 const auto local = local_coord<Shape>(selected);
127 ImGui::TextUnformatted(
"Chunk inspector");
129 ImGui::Text(
"tile: %lld, %lld, %lld", detail::tool_to_ll(selected.x),
130 detail::tool_to_ll(selected.y), detail::tool_to_ll(selected.z));
131 ImGui::Text(
"chunk: %llu (%llu, %llu, %llu)",
132 detail::tool_to_ull(resolved->chunk_key.value),
133 detail::tool_to_ull(chunk.x), detail::tool_to_ull(chunk.y),
134 detail::tool_to_ull(chunk.z));
135 ImGui::Text(
"local: %llu (%llu, %llu, %llu)",
136 detail::tool_to_ull(resolved->local_tile_id.value),
137 detail::tool_to_ull(local.x), detail::tool_to_ull(local.y),
138 detail::tool_to_ull(local.z));
139 ImGui::Text(
"activity: %s; content version: %llu; topology: %llu",
140 detail::tool_chunk_activity_name(
141 world.chunk_activity(resolved->chunk_key)),
142 detail::tool_to_ull(meta.content_version.value),
143 detail::tool_to_ull(meta.topology_version.value));
144 ImGui::Text(
"active categories / entities: %u / %u",
145 world.active_category_count(resolved->chunk_key),
147 ImGui::Text(
"dirty / active masks: 0x%08x / 0x%08x",
148 world.dirty_mask(resolved->chunk_key).value,
149 world.active_mask(resolved->chunk_key).value);
150 return ToolStatus::Shown;
160template <
typename Tag,
typename World>
161[[nodiscard]]
auto draw_bool_field_editor(
const World& world, Coord3 selected,
165 std::is_same_v<typename World::schema_type::template value_type<Tag>,
167 "draw_bool_field_editor requires a bool field");
169 if (!world.try_resolve(selected).has_value()) {
170 ImGui::TextUnformatted(
"Selection is outside the world");
171 return {ToolStatus::OutOfBounds, std::nullopt};
173 const auto* stored = world.template try_field<Tag>(selected);
174 if (stored ==
nullptr) {
175 ImGui::TextUnformatted(
"Selected tile is not resident");
176 return {ToolStatus::Missing, std::nullopt};
179 auto edited = *stored;
180 if (!ImGui::Checkbox(label, &edited)) {
181 return {ToolStatus::Shown, std::nullopt};