// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2008-2020 NVIDIA Corporation. All rights reserved. #include "CommonUIController.h" #include "Renderer.h" #include "BlastController.h" #include "DamageToolController.h" #include "SceneController.h" #include "SampleController.h" #include "PhysXController.h" #include "SampleProfiler.h" #include "PxVisualizationParameter.h" #include "PxScene.h" #include #include "imgui_impl_dx11.h" #include "UIHelpers.h" #include #include inline float memorySizeOutput(const char*& prefix, float value) { for (prefix = "\0\0k\0M\0G\0T\0P\0E"; value >= 1024 && *prefix != 'E'; value /= 1024, prefix += 2); return value; } CommonUIController::CommonUIController() { } HRESULT CommonUIController::DeviceCreated(ID3D11Device* pDevice) { DeviceManager* manager = GetDeviceManager(); ID3D11DeviceContext* pd3dDeviceContext; pDevice->GetImmediateContext(&pd3dDeviceContext); ImGui_ImplDX11_Init(manager->GetHWND(), pDevice, pd3dDeviceContext); ImGuiStyle& style = ImGui::GetStyle(); style.WindowRounding = 8.0f; style.ScrollbarRounding = 8.0f; style.FrameRounding = 8.0f; //style.IndentSpacing = 20; int mainColor[3] = { 110, 110, 110 }; // previous green one { 50, 110, 30 } style.Colors[ImGuiCol_TitleBg] = ImColor(mainColor[0], mainColor[1], mainColor[2], 62); style.Colors[ImGuiCol_TitleBgCollapsed] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52); style.Colors[ImGuiCol_TitleBgActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 87); style.Colors[ImGuiCol_Header] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52); style.Colors[ImGuiCol_HeaderHovered] = ImColor(mainColor[0], mainColor[1], mainColor[2], 92); style.Colors[ImGuiCol_HeaderActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 72); style.Colors[ImGuiCol_ScrollbarBg] = ImColor(mainColor[0], mainColor[1], mainColor[2], 12); style.Colors[ImGuiCol_ScrollbarGrab] = ImColor(mainColor[0], mainColor[1], mainColor[2], 52); style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImColor(mainColor[0], mainColor[1], mainColor[2], 92); style.Colors[ImGuiCol_ScrollbarGrabActive] = ImColor(mainColor[0], mainColor[1], mainColor[2], 72); style.Colors[ImGuiCol_Button] = ImColor(40, 100, 80, 30); style.Colors[ImGuiCol_ButtonHovered] = ImColor(40, 100, 80, 100); style.Colors[ImGuiCol_ButtonActive] = ImColor(40, 100, 80, 70); style.Colors[ImGuiCol_PopupBg] = ImColor(10, 23, 18, 230); style.Colors[ImGuiCol_TextSelectedBg] = ImColor(10, 23, 18, 180); style.Colors[ImGuiCol_FrameBg] = ImColor(70, 70, 70, 30); style.Colors[ImGuiCol_FrameBgHovered] = ImColor(70, 70, 70, 70); style.Colors[ImGuiCol_FrameBgActive] = ImColor(70, 70, 70, 50); style.Colors[ImGuiCol_ComboBg] = ImColor(20, 20, 20, 252); return S_OK; } void CommonUIController::DeviceDestroyed() { ImGui_ImplDX11_Shutdown(); } extern LRESULT ImGui_ImplDX11_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT CommonUIController::MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PX_UNUSED(hWnd); PX_UNUSED(wParam); PX_UNUSED(lParam); ImGui_ImplDX11_WndProcHandler(hWnd, uMsg, wParam, lParam); if (uMsg == WM_KEYDOWN && !ImGui::GetIO().WantCaptureKeyboard) { int iKeyPressed = static_cast(wParam); switch (iKeyPressed) { case 'P': { getPhysXController().setPaused(!getPhysXController().isPaused()); break; } case 'O': { getRenderer().setWireframeMode(!getRenderer().getWireframeMode()); break; } case 'I': { getBlastController().debugRenderMode = (BlastFamily::DebugRenderMode)(((int)getBlastController().debugRenderMode + 1) % BlastFamily::DebugRenderMode::DEBUG_RENDER_MODES_COUNT); break; } case VK_F5: { getRenderer().reloadShaders(); break; } default: break; } } if (ImGui::GetIO().WantCaptureMouse) return 0; return 1; } void CommonUIController::Animate(double fElapsedTimeSeconds) { m_dt = (float)fElapsedTimeSeconds; } void CommonUIController::Render(ID3D11Device*, ID3D11DeviceContext*, ID3D11RenderTargetView*, ID3D11DepthStencilView*) { ImGui_ImplDX11_NewFrame(); drawUI(); ImGui::Render(); } void CommonUIController::addDelayedCall(const char* title, const char* message, std::function func, float delay) { DelayedCall call = { func, title, message, delay, delay }; m_delayedCalls.emplace(call); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // IMGUI UI /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CommonUIController::drawUI() { const float padding = 8.0f; ImGui::SetNextWindowPos(ImVec2(padding, padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/); ImGui::SetNextWindowSize(ImVec2(420, getRenderer().getScreenHeight() - 2 * padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/); ImGui::SetNextWindowCollapsed(false, ImGuiSetCond_Once); ImGui::Begin("New Shiny UI", 0, ImGuiWindowFlags_NoTitleBar); { ImGui::PushItemWidth(ImGui::GetWindowSize().x * 0.5f); /////////////////////////////////////////////////////////////////////////////////////////// // Scene /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Scene")) { getSceneController().drawUI(); } /////////////////////////////////////////////////////////////////////////////////////////// // Blast /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Blast")) { getBlastController().drawUI(); } /////////////////////////////////////////////////////////////////////////////////////////// // Damage Tool /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Damage Tool")) { getDamageToolController().drawUI(); } /////////////////////////////////////////////////////////////////////////////////////////// // Stats /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Stats")) { BlastController& blastController = getBlastController(); const char* prefix; float sizeVal; // FPS double averageTime = GetDeviceManager()->GetAverageFrameTime(); float fps = (averageTime > 0) ? 1.0 / averageTime : 0.0; float frameMs = 1000.0f / fps; ImGui::Text("Frame Time %.3f ms (%.1f FPS)", frameMs, fps); static PlotLinesInstance<> fpsPlot; fpsPlot.plot("FPS", frameMs, "ms/frame", 0.0f, 100.0f); // Render stats ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0xFF, 0x3B, 0xD8, 0xFF)); ImGui::Text("Draw Calls (Opaque/Transparent): %d/%d", getRenderer().getVisibleOpaqueRenderablesCount(), getRenderer().getVisibleTransparentRenderablesCount()); ImGui::PopStyleColor(); // Blast stats const BlastTimers& timers = blastController.getLastBlastTimers(); ImGui::Text("Simulation Time: %.2f ms ", getPhysXController().getLastSimulationTime() * 1000); ImGui::Text("Actor Count: %d", blastController.getActorCount()); ImGui::Text("Visible Chunk Count: %d", blastController.getTotalVisibleChunkCount()); getManager()->getSceneController().drawStatsUI(); sizeVal = memorySizeOutput(prefix, (float)blastController.getFamilySize()); ImGui::Text("Family Size: %.3g %sB", sizeVal, prefix); sizeVal = memorySizeOutput(prefix, (float)blastController.getBlastAssetsSize()); ImGui::Text("Blast asset Data size: %.3g %sB", sizeVal, prefix); //ImGui::Text(" Last Blast Extern Time: %8.3f ms", timers.mLastExternalTime * 1000); // ImGui::Text(" Last Damage Time: %8.3f ms", timers.blastDamage * 1000); #if NV_PROFILE ImGui::Text("Last Material Time: %8.3f ms", timers.blastDamageMaterial * 1000); ImGui::Text("Last Fracture Time: %8.3f ms", timers.blastDamageFracture * 1000); #endif // ImGui::Text("Last Physics Split Time: %.3f ms", timers.physicsSplit * 1000); #if NV_PROFILE ImGui::Text("Last Island Time: %8.3f ms", timers.blastSplitIsland * 1000); ImGui::Text("Last Partition Time: %8.3f ms", timers.blastSplitPartition * 1000); ImGui::Text("Last Visibility Time: %8.3f ms", timers.blastSplitVisibility * 1000); #endif #if NV_PROFILE // Sample Profiler static bool s_showProfilerWindow = false; if (ImGui::Button("Code Profiler")) { s_showProfilerWindow = !s_showProfilerWindow; } if (s_showProfilerWindow) { drawCodeProfiler(&s_showProfilerWindow); } #endif } /////////////////////////////////////////////////////////////////////////////////////////// // Application /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Application")) { // Paused bool isPaused = getPhysXController().isPaused(); if (ImGui::Checkbox("Pause (P)", &isPaused)) { getPhysXController().setPaused(isPaused); } // Reload Shaders if (ImGui::Button("Reload Shaders (F5)")) { getRenderer().reloadShaders(); } // ImGui Test Window (just in case) static bool s_showTestWindow = false; if (ImGui::Button("ImGui Test Window")) { s_showTestWindow = !s_showTestWindow; } if (s_showTestWindow) { ImGui::ShowTestWindow(); } } /////////////////////////////////////////////////////////////////////////////////////////// // Debug Render /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Debug Render")) { // WireFrame bool wireFrameEnabled = getRenderer().getWireframeMode(); if (ImGui::Checkbox("WireFrame (O)", &wireFrameEnabled)) { getRenderer().setWireframeMode(wireFrameEnabled); } // - - - - - - - - ImGui::Spacing(); // Blast Debug Render Mode const char* debugRenderItems[] = { "Disabled", // DEBUG_RENDER_DISABLED "Health Graph", // DEBUG_RENDER_HEALTH_GRAPH "Centroids", // DEBUG_RENDER_CENTROIDS "Health Graph + Centroids", // DEBUG_RENDER_HEALTH_GRAPH_CENTROIDS "Joints", // DEBUG_RENDER_JOINTS "Stress Graph", // DEBUG_RENDER_STRESS_GRAPH "Stress Graph + Nodes Impulses", // DEBUG_RENDER_STRESS_GRAPH_NODES_IMPULSES "Stress Graph + Bonds Impulses" // DEBUG_RENDER_STRESS_GRAPH_BONDS_IMPULSES }; ImGui::Combo("Blast Debug Render Mode (I)", (int*)&getBlastController().debugRenderMode, debugRenderItems, IM_ARRAYSIZE(debugRenderItems), -1); // Blast Debug Render Scale ImGui::DragFloat("Blast Debug Render Scale", &getBlastController().debugRenderScale, 0.01f, 0.0f, 10.0f, "%.3f", 4.0f); // - - - - - - - - ImGui::Spacing(); // PhysX Debug Render if (ImGui::TreeNode("PhysX Debug Render")) { auto addParam = [&](physx::PxVisualizationParameter::Enum param, const char* uiName) { bool enabled = getPhysXController().getPhysXScene().getVisualizationParameter(param) != 0; if (ImGui::Checkbox(uiName, &enabled)) { getPhysXController().getPhysXScene().setVisualizationParameter(param, enabled ? 1.0f : 0.0f); } }; addParam(PxVisualizationParameter::eSCALE, "Scale"); addParam(PxVisualizationParameter::eBODY_AXES, "Body Axes"); addParam(PxVisualizationParameter::eWORLD_AXES, "World Axes"); addParam(PxVisualizationParameter::eBODY_MASS_AXES, "Body Mass Axes"); addParam(PxVisualizationParameter::eBODY_LIN_VELOCITY, "Body Lin Velocity"); addParam(PxVisualizationParameter::eBODY_ANG_VELOCITY, "Body Ang Velocity"); //addParam(PxVisualizationParameter::eBODY_JOINT_GROUPS, "Body Joint"); addParam(PxVisualizationParameter::eCONTACT_POINT, "Contact Point"); addParam(PxVisualizationParameter::eCONTACT_NORMAL, "Contact Normal"); addParam(PxVisualizationParameter::eCONTACT_ERROR, "Contact Error"); addParam(PxVisualizationParameter::eCONTACT_FORCE, "Contact Force"); addParam(PxVisualizationParameter::eACTOR_AXES, "Actor Axes"); addParam(PxVisualizationParameter::eCOLLISION_AABBS, "Collision AABBs"); addParam(PxVisualizationParameter::eCOLLISION_SHAPES, "Collision Shapes"); addParam(PxVisualizationParameter::eCOLLISION_AXES, "Collision Axes"); addParam(PxVisualizationParameter::eCOLLISION_COMPOUNDS, "Collision Compounds"); addParam(PxVisualizationParameter::eCOLLISION_FNORMALS, "Collision FNormals"); addParam(PxVisualizationParameter::eCOLLISION_EDGES, "Collision Edges"); addParam(PxVisualizationParameter::eCOLLISION_STATIC, "Collision Static"); addParam(PxVisualizationParameter::eCOLLISION_DYNAMIC, "Collision Dynamic"); //addParam(PxVisualizationParameter::eDEPRECATED_COLLISION_PAIRS, "Collision Pairs"); addParam(PxVisualizationParameter::eJOINT_LOCAL_FRAMES, "Joint Local Frames"); addParam(PxVisualizationParameter::eJOINT_LIMITS, "Joint Limits"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_POSITION, "PS Position"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_VELOCITY, "PS Velocity"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_COLLISION_NORMAL, "PS Collision Normal"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_BOUNDS, "PS Bounds"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_GRID, "PS Grid"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_BROADPHASE_BOUNDS, "PS Broadphase Bounds"); //addParam(PxVisualizationParameter::ePARTICLE_SYSTEM_MAX_MOTION_DISTANCE, "PS Max Motion Distance"); addParam(PxVisualizationParameter::eCULL_BOX, "Cull Box"); //addParam(PxVisualizationParameter::eCLOTH_VERTICAL, "Cloth Vertical"); //addParam(PxVisualizationParameter::eCLOTH_HORIZONTAL, "Cloth Horizontal"); //addParam(PxVisualizationParameter::eCLOTH_BENDING, "Cloth Bending"); //addParam(PxVisualizationParameter::eCLOTH_SHEARING, "Cloth Shearing"); //addParam(PxVisualizationParameter::eCLOTH_VIRTUAL_PARTICLES, "Cloth Virtual Particles"); addParam(PxVisualizationParameter::eMBP_REGIONS, "MBP Regions"); ImGui::TreePop(); } } /////////////////////////////////////////////////////////////////////////////////////////// // PhysX /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("PhysX")) { // PhysX getPhysXController().drawUI(); // GPU getSampleController().drawPhysXGpuUI(); } /////////////////////////////////////////////////////////////////////////////////////////// // Renderer /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Renderer")) { getRenderer().drawUI(); } /////////////////////////////////////////////////////////////////////////////////////////// // Hints /////////////////////////////////////////////////////////////////////////////////////////// if (ImGui::CollapsingHeader("Hints / Help")) { ImGui::BulletText("Rotate camera - RMB"); ImGui::BulletText("Move camera - WASDQE(SHIFT)"); ImGui::BulletText("Play/Pause - P"); ImGui::BulletText("Reload shaders - F5"); ImGui::BulletText("Wireframe - O"); ImGui::BulletText("Blast Debug Render - I"); ImGui::BulletText("Apply damage - LMB"); ImGui::BulletText("Damage radius - +/-/wheel"); ImGui::BulletText("Damage profile - 1-9"); ImGui::BulletText("Explosive - X"); ImGui::BulletText("Throw cube - F"); ImGui::BulletText("Restart - R"); } ImGui::PopItemWidth(); } ImGui::End(); /////////////////////////////////////////////////////////////////////////////////////////// // Mode Text /////////////////////////////////////////////////////////////////////////////////////////// { ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4()); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); const char* text = getDamageToolController().isDamageMode() ? "DAMAGE MODE (PRESS SPACE)" : "DRAG MODE (PRESS SPACE)"; ImVec2 size = ImGui::CalcTextSize(text); ImGui::SetNextWindowPos(ImVec2((getRenderer().getScreenWidth() - size.x) / 2, 0)); ImGui::Begin("Mode Text", 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); ImGui::Text(text); ImGui::End(); ImGui::PopStyleVar(); ImGui::PopStyleColor(); } /////////////////////////////////////////////////////////////////////////////////////////// // FPS /////////////////////////////////////////////////////////////////////////////////////////// { ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4()); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); double averageTime = GetDeviceManager()->GetAverageFrameTime(); float fps = (averageTime > 0) ? 1.0 / averageTime : 0.0; static char buf[32]; std::sprintf(buf, "%.1f FPS", fps); ImVec2 size = ImGui::CalcTextSize(buf); size.x += 20.0; ImGui::SetNextWindowSize(size); ImGui::SetNextWindowPos(ImVec2(getRenderer().getScreenWidth() - size.x, 0)); ImGui::Begin("FPS", 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); ImGui::Text(buf); ImGui::End(); ImGui::PopStyleVar(); ImGui::PopStyleColor(); } /////////////////////////////////////////////////////////////////////////////////////////// // Loading overlay /////////////////////////////////////////////////////////////////////////////////////////// if (!m_delayedCalls.empty()) { DelayedCall& call = m_delayedCalls.front(); if (call.delay > 0) { const int height = 50; const char* message = call.message; const float alpha = PxClamp(lerp(0.0f, 1.0f, (call.delayTotal - call.delay) * 10.0f), 0.0f, 1.0f); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImColor(0, 0, 0, 200)); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); ImGui::SetNextWindowPosCenter(); ImVec2 size = ImGui::CalcTextSize(message); int width = std::max(200, size.x) + 50; ImGui::SetNextWindowSize(ImVec2(width, height)); ImGui::Begin(call.title, 0, ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); ImGui::SetCursorPos(ImVec2((width - size.x) * 0.5f, (height - size.y) * 0.5f)); ImGui::Text(message); ImGui::End(); ImGui::PopStyleVar(); ImGui::PopStyleColor(); call.delay -= PxClamp(m_dt, 0.0f, 0.1f); } else { call.func(); m_delayedCalls.pop(); } } } void CommonUIController::drawCodeProfiler(bool* open) { ImGuiWindowFlags window_flags = 0; const float padding = 8.0f; const float width = 550; const float height = 580; ImGui::SetNextWindowPos(ImVec2(getRenderer().getScreenWidth() - width - padding, padding), ImGuiSetCond_Once/*ImGuiSetCond_FirstUseEver*/); ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiSetCond_Once); if (!ImGui::Begin("Code Profiler", open, window_flags)) { // Early out if the window is collapsed, as an optimization. ImGui::End(); return; } /////////////////////////////////////////////////////////////////////////////////////////// // Control/Main Bar /////////////////////////////////////////////////////////////////////////////////////////// { if (ImGui::Button("Reset")) { PROFILER_INIT(); } ImGui::SameLine(); if (ImGui::Button("Dump To File (profile.txt)")) { SampleProfilerDumpToFile("profile.txt"); } ImGui::SameLine(); ImGui::Text("Profiler overhead: %2.3f ms", SampleProfilerGetOverhead().count() * 0.001f); } /////////////////////////////////////////////////////////////////////////////////////////// // Legend /////////////////////////////////////////////////////////////////////////////////////////// { ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); ImGui::Text("Legend: name | calls | time | max time"); ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); } /////////////////////////////////////////////////////////////////////////////////////////// // Stats Tree /////////////////////////////////////////////////////////////////////////////////////////// ImGui::SetNextTreeNodeOpen(true, ImGuiSetCond_Once); float plotMS = 0.0f; float plotMaxMS = 0.0f; const char* plotName = nullptr; if (ImGui::TreeNode("Root")) { auto treeIt = SampleProfilerCreateTreeIterator(); if (treeIt) { uint32_t depth = 1; uint32_t openeDepth = 1; while (!treeIt->isDone()) { const auto data = treeIt->data(); while (data->depth < depth) { ImGui::TreePop(); depth--; } const uint32_t maxLen = 30; auto hash = data->hash; static uint64_t selectedNodeHash = 0; if (selectedNodeHash == hash) { plotMS = data->time.count() * 0.001f; plotMaxMS = data->maxTime.count() * 0.001f; plotName = data->name; } if (ImGui::TreeNodeEx(data->name, data->hasChilds ? 0 : ImGuiTreeNodeFlags_Leaf, "%-*.*s | %d | %2.3f ms | %2.3f ms", maxLen, maxLen, data->name, data->calls, data->time.count() * 0.001f, data->maxTime.count() * 0.001f)) { depth++; treeIt->next(); } else { treeIt->next(); while (!treeIt->isDone() && treeIt->data()->depth > depth) treeIt->next(); } if (ImGui::IsItemClicked()) { selectedNodeHash = hash; } } while (depth > 0) { ImGui::TreePop(); depth--; } treeIt->release(); } else { ImGui::Text("Profiler Is Broken. Begin/End Mismatch."); } } /////////////////////////////////////////////////////////////////////////////////////////// // Selected Item Plot /////////////////////////////////////////////////////////////////////////////////////////// { ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); if (plotName) { static PlotLinesInstance<> selectedNodePlot; selectedNodePlot.plot("", plotMS, plotName, 0.0f, plotMaxMS); } else { ImGui::Text("Select item to plot."); } } ImGui::End(); }