kanzi运行时节点状态展示

发布于:2024-04-03 ⋅ 阅读:(134) ⋅ 点赞:(0)

背景:有时候kanzi运行后节点不显示,可能是visible/opacity等属性设置不正确,排查困难。做一个实时节点树,方便查看节点信息。

1. 引入imgui

在vs工程里导入glad,glfw,imgui代码
vs属性-链接库,增加glfw3.lib
在这里插入图片描述

在这里插入图片描述

2. 实现框架

onProjectLoaded里创建子线程

CreateThread(NULL, 0, multiTask, 0, 0, NULL);

子线程负责创建glfw窗口,刷新,销毁窗口

DWORD WINAPI multiTask(LPVOID p) {
    FCreateWindow();
    while (!glfwWindowShouldClose(m_Window)) {
        Update();
    }
    Destory();
    return 0;
};

2.1 创建窗口

void FCreateWindow() {
    glfwInit();

    const char* glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    m_Window = glfwCreateWindow(m_WindowWidth, m_WindowHeight, "Xml", nullptr, nullptr);

    glfwMakeContextCurrent(m_Window);
    glfwSwapInterval(1); // Enable vsync
    int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);

    printf("status-%d\n", status);
    printf("Vendor-%s\n", glGetString(GL_VENDOR));
    printf("Renderer-%s\n", glGetString(GL_RENDERER));
    printf("Version-%s\n", glGetString(GL_VERSION));

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
    // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;	// Enable Docking
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
    // io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
    // io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;

    float fontSize = 18.0f; // *2.0f;
    io.Fonts->AddFontFromFileTTF(("./font/Alimama_DongFangDaKai_Regular.ttf"), fontSize, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
    io.FontDefault = io.Fonts->AddFontFromFileTTF(("./font/Alimama_DongFangDaKai_Regular.ttf"), fontSize, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsClassic();

    // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
    ImGuiStyle &style = ImGui::GetStyle();
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        style.WindowRounding = 0.0f;
        style.Colors[ImGuiCol_WindowBg].w = 1.0f;
    }

    // Setup Platform/Renderer bindings
    ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);
};

2.2 刷新

void Update() {
    glfwPollEvents();

    //start
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    {
      //  bool show_demo_window = true;
       // ImGui::ShowDemoWindow(&show_demo_window);

        ImGui::Begin("Project");

        if (g_pApplication) {
            ShowProjectTreeTop();
        }
        ImGui::End();

        bool show_demo_window = true;
        ImGui::ShowDemoWindow(&show_demo_window);
    }

    //end
    ImGuiIO &io = ImGui::GetIO();

    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
    // Rendering
    ImGui::Render();
    int display_w, display_h;
    glfwGetFramebufferSize(m_Window, &display_w, &display_h);
    glViewport(0, 0, display_w, display_h);
    glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
    glClear(GL_COLOR_BUFFER_BIT);
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

    io.DisplaySize = ImVec2(display_w, display_h);
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        GLFWwindow *backup_current_context = glfwGetCurrentContext();
        ImGui::UpdatePlatformWindows();
        ImGui::RenderPlatformWindowsDefault();
        glfwMakeContextCurrent(backup_current_context);
    }

    glfwSwapBuffers(m_Window);

};

2.3 销毁窗口

void Destory() {
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(m_Window);
    glfwTerminate();
};

3. 实现功能逻辑

遍历kanzi运行时节点,用tree展示

void ShowProjectTreeTop()
{
    static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen;
    static bool align_label_with_current_x_position = false;
    static bool test_drag_and_drop = true;

    if (align_label_with_current_x_position)
        ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());

    static int selection_mask = 0;
    int node_clicked = -1;

    ImGuiTreeNodeFlags node_flags = base_flags;
    const bool is_selected = (selection_mask & (1 << 0)) != 0;

    shared_ptr<Node> node = dynamic_pointer_cast<Node>(g_pApplication->getRoot());

    if (is_selected && node.get() == g_CurrentNode)
        node_flags |= ImGuiTreeNodeFlags_Selected;


    bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)0, node_flags, node->getName().c_str(), 0);

    if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
        node_clicked = 0;
        g_CurrentNode = node.get();
    }

    if (node_open)
    {
        ShowProjectTree(node);
        ImGui::TreePop();
    }

    if (node_clicked != -1)
    {
        // Update selection state
        // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
        if (ImGui::GetIO().KeyCtrl)
            selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
        else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
            selection_mask = (1 << node_clicked);           // Click to single-select
    }
    if (align_label_with_current_x_position)
        ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());

}

void ShowProjectTree(shared_ptr<Node>& node)
{

    static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen;
    static bool align_label_with_current_x_position = false;
    static bool test_drag_and_drop = false;

    if (align_label_with_current_x_position)
        ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());

    static int selection_mask = 0;
    int node_clicked = -1;

    size_t size = node->getAbstractChildCountOverride();
    for (unsigned int i = 0; i < size; ++i)
    {
        shared_ptr<Node> object = dynamic_pointer_cast<Node>(node->getAbstractChildOverride(i));

        // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
        // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
        ImGuiTreeNodeFlags node_flags = base_flags;
        const bool is_selected = (selection_mask & (1 << i)) != 0;
        if (is_selected && object.get() == g_CurrentNode)
            node_flags |= ImGuiTreeNodeFlags_Selected;

        std::string name = object->getName();
        if (object->getProperty(Node::VisibleProperty)) {
        }
        else {
            name += " NoVisible";
            node_flags |= ImGuiTreeNodeFlags_TextDisabled;
        }

        if (object->getProperty(Node::OpacityProperty)) {
        }
        else {
            //ImGui::TextDisabled("NoVisible");
            name += " NoOpacity";
            node_flags |= ImGuiTreeNodeFlags_TextDisabled;
        }

        bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, (char *)name.c_str(), i);
        if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
            node_clicked = i;
            g_CurrentNode = object.get();
        }

        if (node_open)
        {
            if (object->getAbstractChildCountOverride() > 0)
            {
                ShowProjectTree(object);
            }
            else {
                Viewport2DSharedPtr v2d = dynamic_pointer_cast<Viewport2D>(object);
                if (v2d) {//Viewport2D                
                    SceneSharedPtr sc = v2d->getScene();
                    if (sc->getChildCount() > 0)
                    {
                        shared_ptr<Node3D> node = dynamic_pointer_cast<Node3D>(sc);
                        ShowProjectTree3D(node);
                    }
                }
            }

            ImGui::TreePop();
        }
        
    }
    if (node_clicked != -1)
    {
        // Update selection state
        // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
        if (ImGui::GetIO().KeyCtrl)
            selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
        else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
            selection_mask = (1 << node_clicked);           // Click to single-select
    }
    if (align_label_with_current_x_position)
        ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
}

void ShowProjectTree3D(shared_ptr<Node3D>& node)
{
    static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_DefaultOpen;
    static bool align_label_with_current_x_position = false;
    static bool test_drag_and_drop = false;

    if (align_label_with_current_x_position)
        ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());

    static int selection_mask = 0;
    int node_clicked = -1;

    size_t size = node->getChildCount();
    for (unsigned int i = 0; i < size; ++i)
    {
        Node3DSharedPtr object = node->getChild(i);

        // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
        // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
        ImGuiTreeNodeFlags node_flags = base_flags;
        const bool is_selected = (selection_mask & (1 << i)) != 0;
        if (is_selected && object.get() == g_CurrentNode)
            node_flags |= ImGuiTreeNodeFlags_Selected;

        std::string name = object->getName();
        if (object->getProperty(Node::VisibleProperty)) {
        }
        else {
            name += " NoVisible";
            node_flags |= ImGuiTreeNodeFlags_TextDisabled;
        }

        if (object->getProperty(Node::OpacityProperty)) {
        }
        else {
            //ImGui::TextDisabled("NoVisible");
            name += " NoOpacity";
            node_flags |= ImGuiTreeNodeFlags_TextDisabled;
        }

        bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, (char *)name.c_str(), i);
        if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
            node_clicked = i;
            g_CurrentNode = object.get();
        }

        if (node_open)
        {
            if (object->getChildCount() > 0)
            {
                ShowProjectTree3D(object);
            }

            ImGui::TreePop();
        }
        
        
    }

    if (node_clicked != -1)
    {
        // Update selection state
        // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
        if (ImGui::GetIO().KeyCtrl)
            selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
        else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
            selection_mask = (1 << node_clicked);           // Click to single-select
    }
    if (align_label_with_current_x_position)
        ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
}

4. 效果

运行kanzi程序后,会额外出来一个窗口,实时显示所有节点信息

在这里插入图片描述
节点无效置灰请参考 imgui tree节点无效置灰实现方案

5. 拓展

将来可以根据点击某一个节点,展示属性窗口。


网站公告

今日签到

点亮在社区的每一天
去签到