tess 1.0.0
Performance-first tile and path simulation substrate
Loading...
Searching...
No Matches
tools.h
1#pragma once
2
3// Reference Dear ImGui world inspection and edit-intent helpers.
4//
5// This header is opt-in and dependency-free for tess core: its body is
6// compiled only when the CONSUMER defines TESS_ENABLE_IMGUI on its own target.
7// The consumer must include <imgui.h> BEFORE this header. tess.h does not
8// include it, and tess never fetches or links Dear ImGui.
9//
10// The helpers accept const worlds. A widget edit returns an explicit intent;
11// it never changes fields, residency, versions, or dirty state. The caller is
12// responsible for validating and applying an intent at an appropriate phase.
13
14#if defined(TESS_ENABLE_IMGUI)
15
16#ifndef IMGUI_VERSION
17#error "tess/debug/imgui/tools.h requires <imgui.h> to be included first"
18#endif
19
20#include <tess/storage/sparse_world.h>
21
22#include <cstdint>
23#include <optional>
24#include <type_traits>
25
26namespace tess::debug::imgui {
27
29enum class ToolStatus : std::uint8_t {
30 Shown,
31 OutOfBounds,
32 Missing,
33};
34
37 Coord3 tile{};
38 bool value = false;
39};
40
43 ToolStatus status = ToolStatus::Shown;
44 std::optional<BoolFieldEditIntent> intent;
45};
46
47namespace detail {
48
49[[nodiscard]] inline auto tool_to_ull(std::uint64_t value) noexcept
50 -> unsigned long long {
51 return static_cast<unsigned long long>(value);
52}
53
54[[nodiscard]] inline auto tool_to_ll(std::int64_t value) noexcept -> long long {
55 return static_cast<long long>(value);
56}
57
58[[nodiscard]] inline auto tool_chunk_activity_name(
59 ChunkActivity activity) noexcept -> const char* {
60 switch (activity) {
61 case ChunkActivity::Sleeping:
62 return "sleeping";
63 case ChunkActivity::Active:
64 return "active";
65 }
66 return "?";
67}
68
69} // namespace detail
70
72template <typename World>
73void draw_world_overview(const World& world) {
74 using Shape = typename World::shape_type;
75 using Traits = ShapeTraits<Shape>;
76
77 ImGui::TextUnformatted("World overview");
78 ImGui::Separator();
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));
88
89 if constexpr (std::is_same_v<typename World::residency_type,
90 AlwaysResident>) {
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));
95 } else {
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()));
100 }
101}
102
104template <typename World>
105[[nodiscard]] auto draw_chunk_inspector(const World& world, Coord3 selected)
106 -> ToolStatus {
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;
112 }
113
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;
119 }
120
121 // meta() is the precondition-based accessor. The same key's successful
122 // try_chunk() above establishes residency, so this avoids another nullable
123 // lookup without relying on an unchecked pointer dereference.
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");
128 ImGui::Separator();
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),
146 meta.entity_count);
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;
151}
152
160template <typename Tag, typename World>
161[[nodiscard]] auto draw_bool_field_editor(const World& world, Coord3 selected,
162 const char* label)
164 static_assert(
165 std::is_same_v<typename World::schema_type::template value_type<Tag>,
166 bool>,
167 "draw_bool_field_editor requires a bool field");
168
169 if (!world.try_resolve(selected).has_value()) {
170 ImGui::TextUnformatted("Selection is outside the world");
171 return {ToolStatus::OutOfBounds, std::nullopt};
172 }
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};
177 }
178
179 auto edited = *stored;
180 if (!ImGui::Checkbox(label, &edited)) {
181 return {ToolStatus::Shown, std::nullopt};
182 }
183 return {ToolStatus::Shown, BoolFieldEditIntent{selected, edited}};
184}
185
186} // namespace tess::debug::imgui
187
188#endif // defined(TESS_ENABLE_IMGUI)
Definition shape.h:46