using ImGuiNET; using MoonTools.ECS; using Nerfed.Runtime; using System; namespace Nerfed.Editor.Systems { internal class EditorProfilerWindow : MoonTools.ECS.System { const ImGuiTableFlags tableFlags = ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.ScrollY | ImGuiTableFlags.ScrollX; const ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags.SpanAllColumns; const ImGuiTreeNodeFlags treeNodeLeafFlags = ImGuiTreeNodeFlags.SpanAllColumns | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen; int frame = 0; public EditorProfilerWindow(World world) : base(world) { } public override void Update(TimeSpan delta) { if (Profiler.frames.Count <= 0) { return; } ImGui.Begin("Profiler"); ImGui.BeginChild("Toolbar", new System.Numerics.Vector2(0, 0), ImGuiChildFlags.AutoResizeY); if (ImGui.RadioButton("Recording", Profiler.recording)) { Profiler.recording = !Profiler.recording; } ImGui.SameLine(); if (Profiler.recording) { frame = Profiler.frames.Count - 1; } if (ImGui.SliderInt(string.Empty, ref frame, 0, Profiler.frames.Count - 1)) { Profiler.recording = false; } Profiler.FrameData frameData = Profiler.frames.ElementAt(frame); double ms = frameData.ElapsedMilliseconds(); double s = 1000; ImGui.Text($"Frame: {frameData.frame} ({ms:0.000} ms | {(s / ms):0} fps)"); ImGui.EndChild(); ImGui.BeginChild("Hierachy", new System.Numerics.Vector2(150, 0), ImGuiChildFlags.ResizeX); if (ImGui.BeginTable("ProfilerData", 2, tableFlags, new System.Numerics.Vector2(0, 0))) { ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.8f, 0); ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.2f, 1); ImGui.TableSetupScrollFreeze(0, 1); // Make row always visible ImGui.TableHeadersRow(); foreach (Profiler.ProfileRecord record in frameData.records) { ImGui.TableNextRow(); ImGui.TableNextColumn(); string indentation = new string(' ', record.depth); // Indentation based on depth ImGui.Text($"{indentation}{record.label}"); ImGui.TableNextColumn(); ImGui.Text($"{record.ElapsedMilliseconds():0.000}"); } ImGui.EndTable(); } ImGui.EndChild(); ImGui.SameLine(); ImGui.BeginChild("Combined", new System.Numerics.Vector2(0, 0)); // Gather combined data. Dictionary combinedRecordData = new Dictionary(128); foreach (Profiler.ProfileRecord record in frameData.records) { if (combinedRecordData.TryGetValue(record.label, out double totalMs)) { combinedRecordData[record.label] = totalMs + record.ElapsedMilliseconds(); } else { combinedRecordData.Add(record.label, record.ElapsedMilliseconds()); } } IOrderedEnumerable> orderedCombinedData = combinedRecordData.OrderByDescending(x => x.Value); if (ImGui.BeginTable("ProfilerCombinedData", 2, tableFlags, new System.Numerics.Vector2(0, 0))) { ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.8f, 0); ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.2f, 1); ImGui.TableSetupScrollFreeze(0, 1); // Make row always visible ImGui.TableHeadersRow(); foreach (KeyValuePair combinedData in orderedCombinedData) { ImGui.TableNextRow(); ImGui.TableNextColumn(); ImGui.Text($"{combinedData.Key}"); ImGui.TableNextColumn(); ImGui.Text($"{combinedData.Value:0.000}"); } ImGui.EndTable(); } ImGui.EndChild(); ImGui.End(); } private void Draw() { } } }