UI System¶
The UI layer provides the user interface using Dear ImGui.
Overview¶
Located in src/ui/, this layer provides:
- ImGui Vulkan integration
- Window and panel management
- Input handling
- Debug visualization
ImGui Backend¶
imgui_backend.hpp/cpp - Vulkan integration for ImGui.
Initialization¶
class ImGuiBackend {
public:
ImGuiBackend(VulkanContext& context, GLFWwindow* window);
~ImGuiBackend();
void newFrame();
void render(vk::CommandBuffer cmd);
};
Rendering Pipeline¶
sequenceDiagram
participant Loop
participant Backend
participant ImGui
participant Vulkan
Loop->>Backend: newFrame()
Backend->>ImGui: ImGui_ImplVulkan_NewFrame()
Backend->>ImGui: ImGui_ImplGlfw_NewFrame()
Backend->>ImGui: ImGui::NewFrame()
Note over Loop: UI code runs here
Loop->>Backend: render(cmd)
Backend->>ImGui: ImGui::Render()
Backend->>Vulkan: Draw commands
Font Loading¶
void ImGuiBackend::loadFonts() {
auto& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 16.0f);
// Upload to GPU
ImGui_ImplVulkan_CreateFontsTexture();
}
UI Manager¶
ui_manager.hpp/cpp - Component management.
Structure¶
graph TB
UM[UIManager]
UM --> Windows
UM --> Panels
Windows --> VP[Viewport]
Windows --> FB[FileBrowser]
Windows --> CON[Console]
Panels --> ANI[Animation]
Panels --> CAM[Camera]
Panels --> LOD[LOD]
Panels --> MOD[ModelInfo]
Panels --> DIS[Display]
Lifecycle¶
class UIManager {
public:
UIManager(UIContext& context);
void update(); // Process input, update state
void render(); // Draw all UI
// Window access
template<typename T>
T* getWindow();
};
Frame Update¶
void UIManager::update() {
// Update all windows
for (auto& window : windows) {
if (window->isVisible()) {
window->update();
}
}
// Update all panels
for (auto& panel : panels) {
if (panel->isVisible()) {
panel->update();
}
}
}
UI Context¶
ui_context.hpp - Shared state for UI components.
struct UIContext {
// Application state
HLodModel* currentModel;
Camera* camera;
AnimationPlayer* animPlayer;
// UI state
bool showSkeleton;
bool showBoundingBox;
bool showWireframe;
int forcedLOD;
// Selection
std::string hoveredMesh;
// Console
std::vector<std::string> consoleLines;
void log(const std::string& message);
};
Base Classes¶
UIWindow¶
ui_window.hpp - Base for floating windows.
class UIWindow {
public:
virtual ~UIWindow() = default;
virtual void update() = 0;
virtual void render() = 0;
bool isVisible() const { return visible; }
void setVisible(bool v) { visible = v; }
protected:
std::string title;
bool visible = true;
ImGuiWindowFlags flags = 0;
};
UIPanel¶
ui_panel.hpp - Base for dockable panels.
class UIPanel {
public:
virtual ~UIPanel() = default;
virtual void update() = 0;
virtual void render() = 0;
const std::string& name() const { return panelName; }
protected:
std::string panelName;
UIContext& context;
};
Windows¶
Viewport Window¶
viewport_window.hpp/cpp - 3D rendering viewport.
Handles:
- Viewport rendering area
- Mouse input for camera
- Hover detection display
void ViewportWindow::render() {
ImGui::Begin("Viewport", nullptr, flags);
// Get available size
ImVec2 size = ImGui::GetContentRegionAvail();
// Render 3D content to texture
renderToTexture(size);
// Display as ImGui image
ImGui::Image(viewportTexture, size);
// Handle input if window focused
if (ImGui::IsWindowFocused()) {
handleInput();
}
ImGui::End();
}
File Browser¶
file_browser.hpp/cpp - File selection dialog.
void FileBrowser::render() {
ImGui::Begin("File Browser");
// Path bar
renderPathBar();
// File list
for (const auto& entry : currentDirectory) {
if (entry.isDirectory()) {
if (ImGui::Selectable(entry.name().c_str(), false,
ImGuiSelectableFlags_AllowDoubleClick)) {
if (ImGui::IsMouseDoubleClicked(0)) {
navigateTo(entry);
}
}
} else if (entry.extension() == ".w3d") {
if (ImGui::Selectable(entry.name().c_str())) {
onFileSelected(entry.path());
}
}
}
ImGui::End();
}
Console Window¶
console_window.hpp/cpp - Debug output.
void ConsoleWindow::render() {
ImGui::Begin("Console");
// Scrolling region
ImGui::BeginChild("ScrollRegion", ImVec2(0, 0), false,
ImGuiWindowFlags_HorizontalScrollbar);
for (const auto& line : context.consoleLines) {
ImGui::TextUnformatted(line.c_str());
}
// Auto-scroll
if (autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
ImGui::SetScrollHereY(1.0f);
}
ImGui::EndChild();
ImGui::End();
}
Panels¶
Animation Panel¶
panels/animation_panel.hpp/cpp
void AnimationPanel::render() {
if (ImGui::CollapsingHeader("Animation", ImGuiTreeNodeFlags_DefaultOpen)) {
// Animation selection
if (ImGui::BeginCombo("Animation", currentAnim.c_str())) {
for (const auto& anim : animations) {
if (ImGui::Selectable(anim.name.c_str())) {
context.animPlayer->setAnimation(&anim);
}
}
ImGui::EndCombo();
}
// Playback controls
if (ImGui::Button(playing ? "Pause" : "Play")) {
playing ? context.animPlayer->pause() : context.animPlayer->play();
}
// Speed control
ImGui::SliderFloat("Speed", &speed, 0.0f, 2.0f);
// Timeline
float frame = context.animPlayer->getCurrentFrame();
if (ImGui::SliderFloat("Frame", &frame, 0, maxFrames)) {
context.animPlayer->setFrame(frame);
}
}
}
Camera Panel¶
panels/camera_panel.hpp/cpp
- FOV slider
- Near/far plane controls
- Position display (read-only)
Display Panel¶
panels/display_panel.hpp/cpp
- Wireframe toggle
- Skeleton visualization toggle
- Bounding box toggle
- Grid toggle
LOD Panel¶
panels/lod_panel.hpp/cpp
- Current LOD display
- Auto/manual LOD selection
- Force LOD dropdown
Model Info Panel¶
panels/model_info_panel.hpp/cpp
- Model name
- Mesh count and names
- Vertex/triangle counts
- Bone count
- Texture list
Hover Tooltip¶
hover_tooltip.hpp/cpp - Mesh hover display.
void HoverTooltip::render() {
if (!context.hoveredMesh.empty()) {
ImGui::BeginTooltip();
ImGui::Text("Mesh: %s", context.hoveredMesh.c_str());
ImGui::EndTooltip();
}
}
Styling¶
ImGui uses a dark theme configured at startup: