hierarchy.cpp

cross platform rendering playground

src/editor/hierarchy.cpp

3.06 KB
#ifdef ENABLE_EDITOR
#define IMGUI_DEFINE_MATH_OPERATORS
#include "editor.h"

#include <imgui.h>

#include <cstdio>

#include "scene/scene.h"

namespace editor {

void draw_node_tree(const Scene &scene, const AssetManager &mgr, u32 node, int depth, int &selected_node) {
    const SceneGraph &sc = scene.scene_graph;
    if (!sc.is_node_alive(node)) {
        return;
    }
    ImGui::PushID((int)node);

    bool is_leaf = sc.first_child[node] == SCENE_INVALID;
    u32 flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth;
    if (is_leaf) {
        flags |= ImGuiTreeNodeFlags_Leaf;
    }
    if ((int)node == selected_node) {
        flags |= ImGuiTreeNodeFlags_Selected;
    }

    char type_prefix[16] = "";
    int tp_len = 0;
    for (u32 mn : scene.mesh_nodes) {
        if (mn == node) {
            tp_len += snprintf(type_prefix + tp_len, sizeof(type_prefix) - tp_len, "[M]");
            break;
        }
    }
    for (auto &cam : scene.cameras) {
        if (cam.node == node) {
            tp_len += snprintf(type_prefix + tp_len, sizeof(type_prefix) - tp_len, "[C]");
            break;
        }
    }
    for (auto &dl : scene.directional_lights) {
        if (dl.node == node) {
            tp_len += snprintf(type_prefix + tp_len, sizeof(type_prefix) - tp_len, "[D]");
            break;
        }
    }
    for (auto &pl : scene.point_lights) {
        if (pl.node == node) {
            tp_len += snprintf(type_prefix + tp_len, sizeof(type_prefix) - tp_len, "[L]");
            break;
        }
    }

    char label[128];
    const char *name = scene.node_name(mgr, node);
    if (name) {
        if (tp_len > 0) {
            (void)snprintf(label, sizeof(label), "%s %s", type_prefix, name);
        } else {
            (void)snprintf(label, sizeof(label), "%s", name);
        }
    } else if (tp_len > 0) {
        (void)snprintf(label, sizeof(label), "%s Node %u", type_prefix, node);
    } else {
        (void)snprintf(label, sizeof(label), "[N] Node %u", node);
    }

    bool open = ImGui::TreeNodeEx(label, flags);
    if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
        selected_node = (int)node;
    }
    if (open) {
        for (u32 child = sc.first_child[node]; child != SCENE_INVALID; child = sc.next_sibling[child]) {
            draw_node_tree(scene, mgr, child, depth + 1, selected_node);
        }
        ImGui::TreePop();
    }
    ImGui::PopID();
}

void draw_scene_graph_window(Scene &scene, const AssetManager &mgr, int &selected_node) {
    if (ImGui::Begin("Hierarchy", nullptr, PANEL_FLAGS)) {
        SceneGraph *sc = &scene.scene_graph;
        if (!sc || sc->node_count == 0) {
            ImGui::TextUnformatted("No scene graph loaded");
            ImGui::End();
            return;
        }
        ImGui::Text("Nodes: %u  Roots: %zu", sc->node_count, sc->roots.size());
        ImGui::BeginChild("TreePanel", ImVec2(0, 0), 0);
        for (u32 root : sc->roots) {
            draw_node_tree(scene, mgr, root, 0, selected_node);
        }
        ImGui::EndChild();
    }
    ImGui::End();
}

} // namespace editor

#endif // ENABLE_EDITOR