refactor(ui): replace Text with Label/Widget component system

Replace the old `Text` class with a new component-based UI system consisting of `Widget` and `Label` classes. Key changes:

- Remove `Text` class and its GPU upload logic; introduce `Label` as a `Widget` subclass with dirty-flag vertex update.
- Add `UIVertexData` struct to manage per-label vertex buffer/array and memory.
- Refactor `DebugCollector` to store labels in a `Widget` tree, removing hash-based lookup.
- Simplify `Font::vertices()` signature by removing position/scale parameters; scaling is now applied in the renderer’s model matrix.
- Update `Renderer` with `render_label()` and move UI rendering to a `render_ui()` that renders the widget tree.
- Add new source files `label.cpp`, `widget.cpp`, `ui_vertex_data.cpp` and update CMakeLists.
This commit is contained in:
2026-07-11 11:44:31 +08:00
parent 03259f323c
commit 09653c318a
17 changed files with 378 additions and 231 deletions

View File

@@ -1,6 +1,5 @@
#include "Cubed/debug_collector.hpp"
#include "Cubed/tools/cubed_hash.hpp"
#include "Cubed/tools/system_info.hpp"
#include "version.hpp"
@@ -14,88 +13,105 @@ DebugCollector& DebugCollector::get() {
}
void DebugCollector::init_text() {
Text version_text("version");
Text fps_text("fps");
Text player_pos_text("player_pos");
Text rendered_chunk_text("rendered_chunk");
Text rss_text("rss");
Text cpu_text("cpu");
Text gpu_text("gpu");
Text opengl_version_text("opengl_version");
Text biome_text("biome");
Text speed_text("speed");
// version_text
auto& version_text = m_widget.add_child<Label>("version");
std::string version{"Version: " CUBED_VERSION};
#ifdef DEBUG_MODE
version.append("-debug");
#else
version.append("-release");
#endif
version_text.position(0.0f, 100.0f)
.scale(0.8f)
.color(Color::WHITE)
.text(version);
fps_text.position(0.0f, 50.0f).text("FPS: 0");
player_pos_text.position(0.0f, 150.0f)
.scale(0.8f)
.text("x: 0.00 y: 0.00 z: 0.00");
rendered_chunk_text.text("Rendered Chunk: 0")
.scale(0.8f)
.position(0.0, 200.0f);
rss_text.text("RSS: 0mb").scale(0.8f).position(0.0f, 300.0f);
std::string os;
version_text.set_position(0.0f, 100.0f)
.set_scale(0.8f)
.set_color(Color::WHITE)
.set_text(version);
m_component.try_emplace(version_text.id(), &version_text);
Text os_text("os");
os_text.scale(0.8f).position(0.0f, 250.0f);
// fps
auto& fps_text = m_widget.add_child<Label>("fps");
fps_text.set_position(0.0f, 50.0f).set_text("FPS: 0");
m_component.try_emplace(fps_text.id(), &fps_text);
// player_pos
auto& player_pos_text = m_widget.add_child<Label>("player_pos");
player_pos_text.set_position(0.0f, 150.0f)
.set_scale(0.8f)
.set_text("x: 0.00 y: 0.00 z: 0.00");
m_component.try_emplace(player_pos_text.id(), &player_pos_text);
// rendered_chunk
auto& rendered_chunk_text = m_widget.add_child<Label>("rendered_chunk");
rendered_chunk_text.set_text("Rendered Chunk: 0")
.set_scale(0.8f)
.set_position(0.0f, 200.0f);
m_component.try_emplace(rendered_chunk_text.id(), &rendered_chunk_text);
// rss
auto& rss_text = m_widget.add_child<Label>("rss");
rss_text.set_text("RSS: 0mb").set_scale(0.8f).set_position(0.0f, 300.0f);
m_component.try_emplace(rss_text.id(), &rss_text);
// os
std::string os;
auto& os_text = m_widget.add_child<Label>("os");
os_text.set_scale(0.8f).set_position(0.0f, 250.0f);
if (Tools::get_os_version(os)) {
os_text.text("OS: " + os);
os_text.set_text("OS: " + os);
Logger::info("System: {}", os);
} else {
os_text.text("OS: Unknown");
os_text.set_text("OS: Unknown");
}
cpu_text.text("CPU: " + Tools::get_cpu_info())
.scale(0.7f)
.position(0.0f, 350.0f);
m_component.try_emplace(os_text.id(), &os_text);
// cpu
auto& cpu_text = m_widget.add_child<Label>("cpu");
cpu_text.set_text("CPU: " + Tools::get_cpu_info())
.set_scale(0.7f)
.set_position(0.0f, 350.0f);
m_component.try_emplace(cpu_text.id(), &cpu_text);
// gpu
auto& gpu_text = m_widget.add_child<Label>("gpu");
gpu_text
.text(std::string{"GPU: "} +
reinterpret_cast<const char*>(glGetString(GL_RENDERER)))
.scale(0.7f)
.position(0.0f, 400.0f);
.set_text(std::string{"GPU: "} +
reinterpret_cast<const char*>(glGetString(GL_RENDERER)))
.set_scale(0.7f)
.set_position(0.0f, 400.0f);
m_component.try_emplace(gpu_text.id(), &gpu_text);
// opengl_version
auto& opengl_version_text = m_widget.add_child<Label>("opengl_version");
opengl_version_text
.text("OpenGL: " + std::to_string(GLVersion.major) + "." +
std::to_string(GLVersion.minor))
.scale(0.7f)
.position(0.0f, 450.0f);
biome_text.text("Biome: ").scale(0.8f).position(0.0f, 500.0f);
speed_text.text("Speed: 0 m/s").scale(0.8f).position(0.0f, 550.0f);
m_texts.insert({version_text.uuid(), std::move(version_text)});
m_texts.insert({fps_text.uuid(), std::move(fps_text)});
m_texts.insert({player_pos_text.uuid(), std::move(player_pos_text)});
m_texts.insert(
{rendered_chunk_text.uuid(), std::move(rendered_chunk_text)});
m_texts.insert({os_text.uuid(), std::move(os_text)});
m_texts.insert({rss_text.uuid(), std::move(rss_text)});
m_texts.insert({cpu_text.uuid(), std::move(cpu_text)});
m_texts.insert({gpu_text.uuid(), std::move(gpu_text)});
m_texts.insert(
{opengl_version_text.uuid(), std::move(opengl_version_text)});
m_texts.insert({biome_text.uuid(), std::move(biome_text)});
m_texts.insert({speed_text.uuid(), std::move(speed_text)});
.set_text("OpenGL: " + std::to_string(GLVersion.major) + "." +
std::to_string(GLVersion.minor))
.set_scale(0.7f)
.set_position(0.0f, 450.0f);
m_component.try_emplace(opengl_version_text.id(), &opengl_version_text);
// biome
auto& biome_text = m_widget.add_child<Label>("biome");
biome_text.set_text("Biome: ").set_scale(0.8f).set_position(0.0f, 500.0f);
m_component.try_emplace(biome_text.id(), &biome_text);
// speed
auto& speed_text = m_widget.add_child<Label>("speed");
speed_text.set_text("Speed: 0 m/s")
.set_scale(0.8f)
.set_position(0.0f, 550.0f);
m_component.try_emplace(speed_text.id(), &speed_text);
}
std::unordered_map<std::size_t, Text>& DebugCollector::all_texts() {
return m_texts;
}
Widget& DebugCollector::get_widget() { return m_widget; }
Text& DebugCollector::text(std::string_view name) {
std::size_t id = HASH::str(name);
auto it = m_texts.find(id);
ASSERT_MSG(it != m_texts.end(), "Can't Find Text");
return it->second;
}
void DebugCollector::report(std::string_view name, std::string_view content) {
auto& t = text(name);
t.text(content);
void DebugCollector::report(const std::string& name, std::string_view content) {
auto t = m_component.find(name);
if (t == m_component.end()) {
return;
}
if (!t->second) {
return;
}
t->second->set_text(content);
}
} // namespace Cubed