mirror of
https://github.com/Ed94/Cog.git
synced 2026-08-06 15:48:48 +00:00
CogEngine: Plot window improvements.
This commit is contained in:
@@ -7,14 +7,33 @@
|
|||||||
#include "implot_internal.h"
|
#include "implot_internal.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::Initialize()
|
||||||
|
{
|
||||||
|
Super::Initialize();
|
||||||
|
|
||||||
|
bHasMenu = true;
|
||||||
|
|
||||||
|
Config = GetConfig<UCogEngineConfig_Plots>();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
void FCogEngineWindow_Plots::RenderHelp()
|
void FCogEngineWindow_Plots::RenderHelp()
|
||||||
{
|
{
|
||||||
ImGui::Text(
|
ImGui::Text(
|
||||||
"This window plots values overtime. When applicable, only the values of the selected actor are displayed."
|
"This window plots values and events overtime. When applicable, only the values of the selected actor are displayed."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::ResetConfig()
|
||||||
|
{
|
||||||
|
Super::ResetConfig();
|
||||||
|
|
||||||
|
Config->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
void FCogEngineWindow_Plots::RenderTick(float DeltaTime)
|
void FCogEngineWindow_Plots::RenderTick(float DeltaTime)
|
||||||
{
|
{
|
||||||
@@ -27,454 +46,511 @@ void FCogEngineWindow_Plots::RenderContent()
|
|||||||
{
|
{
|
||||||
Super::RenderContent();
|
Super::RenderContent();
|
||||||
|
|
||||||
static int Rows = 1;
|
RenderMenu();
|
||||||
static int Cols = 1;
|
|
||||||
|
|
||||||
if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable))
|
if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable))
|
||||||
{
|
{
|
||||||
ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f);
|
ImGui::TableSetupColumn("PlotsList", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::GetFontWidth() * 20.0f);
|
||||||
ImGui::TableSetupColumn("Graph", ImGuiTableColumnFlags_WidthStretch, 0.0f);
|
ImGui::TableSetupColumn("Plots", ImGuiTableColumnFlags_WidthStretch, 0.0f);
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------
|
TArray<FCogDebugPlotEntry*> VisiblePlots;
|
||||||
// Settings and Entries
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
if (ImGui::Button("Settings"))
|
RenderPlotsList(VisiblePlots);
|
||||||
{
|
|
||||||
ImGui::OpenPopup("SettingsPopup");
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
FCogWindowWidgets::ToggleButton(&FCogDebugPlot::Pause, "Pause", "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
||||||
|
|
||||||
if (ImGui::BeginPopup("SettingsPopup"))
|
ImGui::TableNextColumn();
|
||||||
{
|
RenderPlots(VisiblePlots);
|
||||||
ImGui::SliderInt("Rows", &Rows, 1, 5);
|
|
||||||
|
|
||||||
if (ImGui::Button("Clear Data", ImVec2(-1, 0)))
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bApplyTimeScale = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderMenu()
|
||||||
|
{
|
||||||
|
if (ImGui::BeginMenuBar())
|
||||||
|
{
|
||||||
|
if (ImGui::BeginMenu("Options"))
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Clear Data"))
|
||||||
{
|
{
|
||||||
FCogDebugPlot::Clear();
|
FCogDebugPlot::Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Reset Layout", ImVec2(-1, 0)))
|
if (ImGui::MenuItem("Reset"))
|
||||||
{
|
{
|
||||||
FCogDebugPlot::Pause = false;
|
FCogDebugPlot::Pause = false;
|
||||||
Rows = 1;
|
|
||||||
|
|
||||||
FCogDebugPlot::Reset();
|
FCogDebugPlot::Reset();
|
||||||
|
ResetConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginChild("Separator", ImVec2(0, 2)))
|
|
||||||
{
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
TArray<FCogDebugPlotEntry*> VisiblePlots;
|
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||||
if (ImGui::BeginChild("Plots", ImVec2(0, -1)))
|
if (ImGui::SliderInt("Rows", &Config->Rows, 1, 5))
|
||||||
{
|
|
||||||
int Index = 0;
|
|
||||||
|
|
||||||
for (FCogDebugPlotEntry& Plot : FCogDebugPlot::Plots)
|
|
||||||
{
|
{
|
||||||
const auto Label = StringCast<ANSICHAR>(*Plot.Name.ToString());
|
bApplyTimeScale = true;
|
||||||
|
|
||||||
if (Plot.CurrentYAxis != ImAxis_COUNT && Plot.CurrentRow != INDEX_NONE)
|
|
||||||
{
|
|
||||||
VisiblePlots.Add(&Plot);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PushID(Index);
|
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, Plot.IsEventPlot ? IM_COL32(128, 128, 255, 255) : IM_COL32(255, 255, 255, 255));
|
|
||||||
ImGui::Selectable(Label.Get(), false, 0);
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
|
|
||||||
{
|
|
||||||
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
|
|
||||||
ImGui::TextUnformatted(Label.Get());
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopID();
|
|
||||||
Index++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||||
|
if (ImGui::SliderFloat("Time Range", &Config->TimeRange, 1.0f, 30.0f, "%0.1f"))
|
||||||
if (ImGui::BeginDragDropTarget())
|
|
||||||
{
|
|
||||||
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
|
||||||
{
|
{
|
||||||
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
bApplyTimeScale = true;
|
||||||
{
|
|
||||||
Plot->ResetAxis();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ImGui::EndDragDropTarget();
|
|
||||||
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------
|
FCogWindowWidgets::ToggleMenuButton(&FCogDebugPlot::Pause, "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||||
// Graph
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
if (ImGui::BeginChild("Graph", ImVec2(0, -1)))
|
|
||||||
{
|
|
||||||
static float RowRatios[] = { 1, 1, 1, 1, 1, 1 };
|
|
||||||
static float ColRatios[] = { 1 };
|
|
||||||
static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols;
|
|
||||||
if (ImPlot::BeginSubplots("", Rows, Cols, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios))
|
|
||||||
{
|
|
||||||
for (int PlotIndex = 0; PlotIndex < Rows; ++PlotIndex)
|
|
||||||
{
|
|
||||||
if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250)))
|
|
||||||
{
|
|
||||||
ImPlotAxisFlags HasPlotOnAxisY1 = false;
|
|
||||||
ImPlotAxisFlags HasPlotOnAxisY2 = false;
|
|
||||||
ImPlotAxisFlags HasPlotOnAxisY3 = false;
|
|
||||||
|
|
||||||
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
|
ImGui::EndMenuBar();
|
||||||
{
|
|
||||||
HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex;
|
|
||||||
HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex;
|
|
||||||
HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines);
|
|
||||||
ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit);
|
|
||||||
ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
|
|
||||||
ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Set the initial X axis range. After it is automatically updated to move with the current time.
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
ImPlot::SetupAxisLimits(ImAxis_X1, 0, 10.0f, ImGuiCond_Appearing);
|
|
||||||
|
|
||||||
const ImPlotRange& Range = ImPlot::GetCurrentPlot()->Axes[ImAxis_X1].Range;
|
|
||||||
const float AxisXRange = Range.Max - Range.Min;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// Draw a vertical lines representing the current time and the mouse time
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
|
|
||||||
const ImVec2 PlotMin = ImPlot::GetPlotPos();
|
|
||||||
const ImVec2 PlotSize = ImPlot::GetPlotSize();
|
|
||||||
const ImVec2 PlotMax = ImVec2(PlotMin.x + PlotSize.x, PlotMin.y + PlotSize.y);
|
|
||||||
const float PlotTop = PlotMin.y;
|
|
||||||
const float TimeBarBottom = PlotTop + PlotSize.y;
|
|
||||||
|
|
||||||
ImPlot::PushPlotClipRect();
|
|
||||||
PlotDrawList->AddLine(ImVec2(ImGui::GetMousePos().x, PlotTop), ImVec2(ImGui::GetMousePos().x, TimeBarBottom), IM_COL32(128, 128, 128, 64));
|
|
||||||
if (FCogDebugPlot::Pause)
|
|
||||||
{
|
|
||||||
const float Time = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0;
|
|
||||||
const float TimeBarX = ImPlot::PlotToPixels(Time, 0.0f).x;
|
|
||||||
PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64));
|
|
||||||
}
|
|
||||||
ImPlot::PopPlotClipRect();
|
|
||||||
|
|
||||||
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
|
|
||||||
{
|
|
||||||
if (PlotPtr == nullptr)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FCogDebugPlotEntry& Entry = *PlotPtr;
|
|
||||||
|
|
||||||
if (Entry.CurrentRow == PlotIndex)
|
|
||||||
{
|
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
// Make the time axis move forward automatically, unless the user pauses or zoom.
|
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0)
|
|
||||||
{
|
|
||||||
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - AxisXRange, Entry.Time, ImGuiCond_Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImPlot::SetAxis(Entry.CurrentYAxis);
|
|
||||||
|
|
||||||
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL);
|
|
||||||
const auto Label = StringCast<ANSICHAR>(*Entry.Name.ToString());
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// Pause the scrolling if the user drag inside
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
ImVec2 Mouse = ImGui::GetMousePos();
|
|
||||||
if (Mouse.x > PlotMin.x
|
|
||||||
&& Mouse.y > PlotMin.y
|
|
||||||
&& Mouse.x < PlotMax.x
|
|
||||||
&& Mouse.y < PlotMax.y
|
|
||||||
&& ImGui::GetDragDropPayload() == nullptr)
|
|
||||||
{
|
|
||||||
ImVec2 Drag = ImGui::GetMouseDragDelta(0);
|
|
||||||
if (FMath::Abs(Drag.x) > 10)
|
|
||||||
{
|
|
||||||
FCogDebugPlot::Pause = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Plot Events
|
|
||||||
//-------------------------------------------------------
|
|
||||||
const bool IsEventPlot = Entry.Events.Num() > 0;
|
|
||||||
if (IsEventPlot)
|
|
||||||
{
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Update plot time for events as events are not pushed every frames
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
Entry.UpdateTime(GetWorld());
|
|
||||||
|
|
||||||
ImPlot::SetupAxisLimits(Entry.CurrentYAxis, 0, Entry.MaxRow + 2, ImGuiCond_Always);
|
|
||||||
|
|
||||||
ImPlot::PushPlotClipRect();
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// Plot line only to make the plotter move in time and auto scale
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
ImVector<ImVec2> DummyData;
|
|
||||||
DummyData.push_back(ImVec2(0, 0));
|
|
||||||
DummyData.push_back(ImVec2(0, 8));
|
|
||||||
ImPlot::PlotLine(Label.Get(), &DummyData[0].x, &DummyData[0].y, DummyData.size(), Entry.ValueOffset, 2 * sizeof(float));
|
|
||||||
|
|
||||||
const FCogDebugPlotEvent* HoveredEvent = nullptr;
|
|
||||||
|
|
||||||
for (const FCogDebugPlotEvent& Event : Entry.Events)
|
|
||||||
{
|
|
||||||
const ImVec2 PosBot = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.8f));
|
|
||||||
const ImVec2 PosTop = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.2f));
|
|
||||||
const ImVec2 PosMid(PosBot.x, PosBot.y + (PosTop.y - PosBot.y) * 0.5f);
|
|
||||||
|
|
||||||
const bool IsInstant = Event.StartTime == Event.EndTime;
|
|
||||||
if (IsInstant)
|
|
||||||
{
|
|
||||||
const float Radius = 10.0f;
|
|
||||||
PlotDrawList->AddNgon(PosMid, 10, Event.BorderColor, 4);
|
|
||||||
PlotDrawList->AddNgonFilled(PosMid, 10, Event.FillColor, 4);
|
|
||||||
PlotDrawList->AddText(ImVec2(PosMid.x + 15, PosMid.y - 6), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
|
|
||||||
|
|
||||||
if ((Mouse.x > PosMid.x - Radius) && (Mouse.x < PosMid.x + Radius) && (Mouse.y > PosMid.y - Radius) && (Mouse.y < PosMid.y + Radius))
|
|
||||||
{
|
|
||||||
HoveredEvent = &Event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const float ActualEndTime = Event.GetActualEndTime(Entry);
|
|
||||||
const ImVec2 PosEnd = ImPlot::PlotToPixels(ImPlotPoint(ActualEndTime, 0));
|
|
||||||
const ImVec2 Min = ImVec2(PosBot.x, PosBot.y);
|
|
||||||
const ImVec2 Max = ImVec2(PosEnd.x, PosTop.y);
|
|
||||||
|
|
||||||
ImDrawFlags Flags = Event.EndTime == 0.0f ? ImDrawFlags_RoundCornersLeft : ImDrawFlags_RoundCornersAll;
|
|
||||||
PlotDrawList->AddRect(Min, Max, Event.BorderColor, 6.0f, Flags);
|
|
||||||
PlotDrawList->AddRectFilled(Min, Max, Event.FillColor, 6.0f, Flags);
|
|
||||||
PlotDrawList->PushClipRect(ImMax(Min, PlotMin), ImMin(Max, PlotMax));
|
|
||||||
PlotDrawList->AddText(ImVec2(PosMid.x + 5, PosMid.y - 7), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
|
|
||||||
PlotDrawList->PopClipRect();
|
|
||||||
|
|
||||||
if (Mouse.x > Min.x && Mouse.x < Max.x && Mouse.y > Min.y && Mouse.y < Max.y)
|
|
||||||
{
|
|
||||||
HoveredEvent = &Event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Write info on the graph to help debugging
|
|
||||||
//-------------------------------------------------------
|
|
||||||
//char Buffer[64];
|
|
||||||
//ImFormatString(Buffer, 64, "%0.1f %0.1f", Mouse.x, Mouse.y);
|
|
||||||
//PlotDrawList->AddText(ImVec2(PlotMin.x + 50, PlotMin.y + 100), IM_COL32(255, 255, 255, 255), Buffer);
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Hovered event tooltip
|
|
||||||
//-------------------------------------------------------
|
|
||||||
if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr)
|
|
||||||
{
|
|
||||||
FCogWindowWidgets::BeginTableTooltip();
|
|
||||||
if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders))
|
|
||||||
{
|
|
||||||
//------------------------
|
|
||||||
// Event Name
|
|
||||||
//------------------------
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Name");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->DisplayName));
|
|
||||||
|
|
||||||
//------------------------
|
|
||||||
// Owner Name
|
|
||||||
//------------------------
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Owner");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->OwnerName));
|
|
||||||
|
|
||||||
//------------------------
|
|
||||||
// Times
|
|
||||||
//------------------------
|
|
||||||
if (HoveredEvent->EndTime != HoveredEvent->StartTime)
|
|
||||||
{
|
|
||||||
const float ActualEndTime = HoveredEvent->GetActualEndTime(Entry);
|
|
||||||
const uint64 ActualEndFrame = HoveredEvent->GetActualEndFrame(Entry);
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Duration");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%0.2fs", ActualEndTime - HoveredEvent->StartTime);
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Frames");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%d [%d-%d]",
|
|
||||||
(int32)(ActualEndFrame - HoveredEvent->StartFrame),
|
|
||||||
(int32)(HoveredEvent->StartFrame % 1000),
|
|
||||||
(int32)(ActualEndFrame % 1000));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Frame");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%d", (int32)(HoveredEvent->StartFrame % 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------
|
|
||||||
// Params
|
|
||||||
//------------------------
|
|
||||||
for (FCogDebugPlotEventParams Param : HoveredEvent->Params)
|
|
||||||
{
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Name.ToString()));
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Value));
|
|
||||||
}
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
FCogWindowWidgets::EndTableTooltip();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImPlot::PopPlotClipRect();
|
|
||||||
}
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Plot Values
|
|
||||||
//-------------------------------------------------------
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// Custom tooltip
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
if (ImPlot::IsPlotHovered())
|
|
||||||
{
|
|
||||||
float Value;
|
|
||||||
if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value))
|
|
||||||
{
|
|
||||||
ImGui::BeginTooltip();
|
|
||||||
ImGui::Text("%s: %0.2f", Label.Get(), Value);
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Entry.ShowValuesMarkers)
|
|
||||||
{
|
|
||||||
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImPlot::PlotLine(Label.Get(), &Entry.Values[0].x, &Entry.Values[0].y, Entry.Values.size(), ImPlotLineFlags_None, Entry.ValueOffset, 2 * sizeof(float));
|
|
||||||
|
|
||||||
if (ImPlot::BeginLegendPopup(Label.Get()))
|
|
||||||
{
|
|
||||||
if (ImGui::Button("Clear"))
|
|
||||||
{
|
|
||||||
Entry.Clear();
|
|
||||||
}
|
|
||||||
ImGui::Checkbox("Show Markers", &Entry.ShowValuesMarkers);
|
|
||||||
ImPlot::EndLegendPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Allow legend item labels to be drag and drop sources
|
|
||||||
//-------------------------------------------------------
|
|
||||||
if (ImPlot::BeginDragDropSourceItem(Label.Get()))
|
|
||||||
{
|
|
||||||
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
|
|
||||||
ImGui::TextUnformatted(Label.Get());
|
|
||||||
ImPlot::EndDragDropSource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Allow the main plot area to be a drag and drop target
|
|
||||||
//-------------------------------------------------------
|
|
||||||
if (ImPlot::BeginDragDropTargetPlot())
|
|
||||||
{
|
|
||||||
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
|
||||||
{
|
|
||||||
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
|
||||||
{
|
|
||||||
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImPlot::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Allow each y-axis to be a drag and drop target
|
|
||||||
//-------------------------------------------------------
|
|
||||||
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y)
|
|
||||||
{
|
|
||||||
if (ImPlot::BeginDragDropTargetAxis(y))
|
|
||||||
{
|
|
||||||
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
|
||||||
{
|
|
||||||
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
|
||||||
{
|
|
||||||
Plot->AssignAxis(PlotIndex, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImPlot::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// Allow the legend to be a drag and drop target
|
|
||||||
//-------------------------------------------------------
|
|
||||||
if (ImPlot::BeginDragDropTargetLegend())
|
|
||||||
{
|
|
||||||
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
|
||||||
{
|
|
||||||
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
|
||||||
{
|
|
||||||
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImPlot::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImPlot::EndPlot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImPlot::EndSubplots();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderPlots(const TArray<FCogDebugPlotEntry*>& VisiblePlots)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginChild("Graph", ImVec2(0, -1)))
|
||||||
|
{
|
||||||
|
static float RowRatios[] = { 1, 1, 1, 1, 1, 1 };
|
||||||
|
static float ColRatios[] = { 1 };
|
||||||
|
static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols;
|
||||||
|
if (ImPlot::BeginSubplots("", Config->Rows, 1, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios))
|
||||||
|
{
|
||||||
|
for (int PlotIndex = 0; PlotIndex < Config->Rows; ++PlotIndex)
|
||||||
|
{
|
||||||
|
if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250)))
|
||||||
|
{
|
||||||
|
ImPlotAxisFlags HasPlotOnAxisY1 = false;
|
||||||
|
ImPlotAxisFlags HasPlotOnAxisY2 = false;
|
||||||
|
ImPlotAxisFlags HasPlotOnAxisY3 = false;
|
||||||
|
|
||||||
|
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
|
||||||
|
{
|
||||||
|
HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex;
|
||||||
|
HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex;
|
||||||
|
HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines);
|
||||||
|
ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit);
|
||||||
|
ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
|
||||||
|
ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Set the initial X axis range. After, it is automatically updated to move with the current time.
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
ImPlot::SetupAxisLimits(ImAxis_X1, 0, Config->TimeRange, ImGuiCond_Appearing);
|
||||||
|
|
||||||
|
const ImPlotRange& PlotRange = ImPlot::GetCurrentPlot()->Axes[ImAxis_X1].Range;
|
||||||
|
const float TimeRange = PlotRange.Max - PlotRange.Min;
|
||||||
|
|
||||||
|
if (bApplyTimeScale == false)
|
||||||
|
{
|
||||||
|
Config->TimeRange = TimeRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImVec2 PlotMin = ImPlot::GetPlotPos();
|
||||||
|
const ImVec2 PlotSize = ImPlot::GetPlotSize();
|
||||||
|
const ImVec2 PlotMax = PlotMin + PlotSize;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Draw a vertical lines representing the current time and the mouse time
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
RenderTimeMarker();
|
||||||
|
|
||||||
|
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
|
||||||
|
{
|
||||||
|
if (PlotPtr == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FCogDebugPlotEntry& Entry = *PlotPtr;
|
||||||
|
|
||||||
|
if (Entry.CurrentRow == PlotIndex)
|
||||||
|
{
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Make the time axis move forward automatically, unless the user pauses or zoom.
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0)
|
||||||
|
{
|
||||||
|
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - TimeRange, Entry.Time, ImGuiCond_Always);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bApplyTimeScale)
|
||||||
|
{
|
||||||
|
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - Config->TimeRange, Entry.Time, ImGuiCond_Always);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot::SetAxis(Entry.CurrentYAxis);
|
||||||
|
|
||||||
|
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL);
|
||||||
|
const char* Label = TCHAR_TO_ANSI(*Entry.Name.ToString());
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Pause the scrolling if the user drag inside
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
const ImVec2 Mouse = ImGui::GetMousePos();
|
||||||
|
if (Mouse.x > PlotMin.x
|
||||||
|
&& Mouse.y > PlotMin.y
|
||||||
|
&& Mouse.x < PlotMax.x
|
||||||
|
&& Mouse.y < PlotMax.y
|
||||||
|
&& ImGui::GetDragDropPayload() == nullptr)
|
||||||
|
{
|
||||||
|
ImVec2 Drag = ImGui::GetMouseDragDelta(0);
|
||||||
|
if (FMath::Abs(Drag.x) > 10)
|
||||||
|
{
|
||||||
|
FCogDebugPlot::Pause = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Plot Events
|
||||||
|
//-------------------------------------------------------
|
||||||
|
const bool IsEventPlot = Entry.Events.Num() > 0;
|
||||||
|
if (IsEventPlot)
|
||||||
|
{
|
||||||
|
RenderEvents(Entry, Label, PlotMin, PlotMax);
|
||||||
|
}
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Plot Values
|
||||||
|
//-------------------------------------------------------
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderValues(Entry, Label);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Allow legend item labels to be drag and drop sources
|
||||||
|
//-------------------------------------------------------
|
||||||
|
if (ImPlot::BeginDragDropSourceItem(Label))
|
||||||
|
{
|
||||||
|
const auto EntryName = StringCast<ANSICHAR>(*Entry.Name.ToString());
|
||||||
|
ImGui::SetDragDropPayload("DragAndDrop", EntryName.Get(), EntryName.Length() + 1);
|
||||||
|
ImGui::TextUnformatted(EntryName.Get());
|
||||||
|
ImPlot::EndDragDropSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Allow the main plot area to be a drag and drop target
|
||||||
|
//-------------------------------------------------------
|
||||||
|
if (ImPlot::BeginDragDropTargetPlot())
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
||||||
|
{
|
||||||
|
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
||||||
|
{
|
||||||
|
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImPlot::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Allow each y-axis to be a drag and drop target
|
||||||
|
//-------------------------------------------------------
|
||||||
|
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y)
|
||||||
|
{
|
||||||
|
if (ImPlot::BeginDragDropTargetAxis(y))
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
||||||
|
{
|
||||||
|
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
||||||
|
{
|
||||||
|
Plot->AssignAxis(PlotIndex, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImPlot::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Allow the legend to be a drag and drop target
|
||||||
|
//-------------------------------------------------------
|
||||||
|
if (ImPlot::BeginDragDropTargetLegend())
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
||||||
|
{
|
||||||
|
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
||||||
|
{
|
||||||
|
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImPlot::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot::EndPlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImPlot::EndSubplots();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderPlotsList(TArray<FCogDebugPlotEntry*>& VisiblePlots)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginChild("Plots", ImVec2(0, -1)))
|
||||||
|
{
|
||||||
|
int Index = 0;
|
||||||
|
|
||||||
|
for (FCogDebugPlotEntry& Plot : FCogDebugPlot::Plots)
|
||||||
|
{
|
||||||
|
const auto Label = StringCast<ANSICHAR>(*Plot.Name.ToString());
|
||||||
|
|
||||||
|
if (Plot.CurrentYAxis != ImAxis_COUNT && Plot.CurrentRow != INDEX_NONE)
|
||||||
|
{
|
||||||
|
VisiblePlots.Add(&Plot);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushID(Index);
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, Plot.IsEventPlot ? IM_COL32(128, 128, 255, 255) : IM_COL32(255, 255, 255, 255));
|
||||||
|
ImGui::Selectable(Label.Get(), false, 0);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
|
||||||
|
{
|
||||||
|
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
|
||||||
|
ImGui::TextUnformatted(Label.Get());
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (ImGui::BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
|
||||||
|
{
|
||||||
|
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
|
||||||
|
{
|
||||||
|
Plot->ResetAxis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDragDropTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderTimeMarker()
|
||||||
|
{
|
||||||
|
const ImVec2 PlotMin = ImPlot::GetPlotPos();
|
||||||
|
const ImVec2 PlotSize = ImPlot::GetPlotSize();
|
||||||
|
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
|
||||||
|
|
||||||
|
const float PlotTop = PlotMin.y;
|
||||||
|
const float TimeBarBottom = PlotTop + PlotSize.y;
|
||||||
|
|
||||||
|
ImPlot::PushPlotClipRect();
|
||||||
|
PlotDrawList->AddLine(ImVec2(ImGui::GetMousePos().x, PlotTop), ImVec2(ImGui::GetMousePos().x, TimeBarBottom), IM_COL32(128, 128, 128, 64));
|
||||||
|
if (FCogDebugPlot::Pause)
|
||||||
|
{
|
||||||
|
const float Time = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0;
|
||||||
|
const float TimeBarX = ImPlot::PlotToPixels(Time, 0.0f).x;
|
||||||
|
PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64));
|
||||||
|
}
|
||||||
|
ImPlot::PopPlotClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderValues(FCogDebugPlotEntry& Entry, const char* Label)
|
||||||
|
{
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Custom tooltip
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
if (ImPlot::IsPlotHovered())
|
||||||
|
{
|
||||||
|
float Value;
|
||||||
|
if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value))
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("%s: %0.2f", Label, Value);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Entry.ShowValuesMarkers)
|
||||||
|
{
|
||||||
|
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot::PlotLine(Label, &Entry.Values[0].x, &Entry.Values[0].y, Entry.Values.size(), ImPlotLineFlags_None, Entry.ValueOffset, 2 * sizeof(float));
|
||||||
|
|
||||||
|
if (ImPlot::BeginLegendPopup(Label))
|
||||||
|
{
|
||||||
|
if (ImGui::Button("Clear"))
|
||||||
|
{
|
||||||
|
Entry.Clear();
|
||||||
|
}
|
||||||
|
ImGui::Checkbox("Show Markers", &Entry.ShowValuesMarkers);
|
||||||
|
ImPlot::EndLegendPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax)
|
||||||
|
{
|
||||||
|
const ImVec2 Mouse = ImGui::GetMousePos();
|
||||||
|
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// Update plot time for events as events are not pushed every frames
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
Entry.UpdateTime(GetWorld());
|
||||||
|
|
||||||
|
ImPlot::SetupAxisLimits(Entry.CurrentYAxis, 0, Entry.MaxRow + 2, ImGuiCond_Always);
|
||||||
|
|
||||||
|
ImPlot::PushPlotClipRect();
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Plot line only to make the plotter move in time and auto scale
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
ImVector<ImVec2> DummyData;
|
||||||
|
DummyData.push_back(ImVec2(0, 0));
|
||||||
|
DummyData.push_back(ImVec2(0, 8));
|
||||||
|
ImPlot::PlotLine(Label, &DummyData[0].x, &DummyData[0].y, DummyData.size(), Entry.ValueOffset, 2 * sizeof(float));
|
||||||
|
|
||||||
|
const FCogDebugPlotEvent* HoveredEvent = nullptr;
|
||||||
|
|
||||||
|
for (const FCogDebugPlotEvent& Event : Entry.Events)
|
||||||
|
{
|
||||||
|
const ImVec2 PosBot = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.8f));
|
||||||
|
const ImVec2 PosTop = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.2f));
|
||||||
|
const ImVec2 PosMid(PosBot.x, PosBot.y + (PosTop.y - PosBot.y) * 0.5f);
|
||||||
|
|
||||||
|
const bool IsInstant = Event.StartTime == Event.EndTime;
|
||||||
|
if (IsInstant)
|
||||||
|
{
|
||||||
|
const float Radius = 10.0f;
|
||||||
|
PlotDrawList->AddNgon(PosMid, 10, Event.BorderColor, 4);
|
||||||
|
PlotDrawList->AddNgonFilled(PosMid, 10, Event.FillColor, 4);
|
||||||
|
PlotDrawList->AddText(ImVec2(PosMid.x + 15, PosMid.y - 6), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
|
||||||
|
|
||||||
|
if ((Mouse.x > PosMid.x - Radius) && (Mouse.x < PosMid.x + Radius) && (Mouse.y > PosMid.y - Radius) && (Mouse.y < PosMid.y + Radius))
|
||||||
|
{
|
||||||
|
HoveredEvent = &Event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const float ActualEndTime = Event.GetActualEndTime(Entry);
|
||||||
|
const ImVec2 PosEnd = ImPlot::PlotToPixels(ImPlotPoint(ActualEndTime, 0));
|
||||||
|
const ImVec2 Min = ImVec2(PosBot.x, PosBot.y);
|
||||||
|
const ImVec2 Max = ImVec2(PosEnd.x, PosTop.y);
|
||||||
|
|
||||||
|
ImDrawFlags Flags = Event.EndTime == 0.0f ? ImDrawFlags_RoundCornersLeft : ImDrawFlags_RoundCornersAll;
|
||||||
|
PlotDrawList->AddRect(Min, Max, Event.BorderColor, 6.0f, Flags);
|
||||||
|
PlotDrawList->AddRectFilled(Min, Max, Event.FillColor, 6.0f, Flags);
|
||||||
|
PlotDrawList->PushClipRect(ImMax(Min, PlotMin), ImMin(Max, PlotMax));
|
||||||
|
PlotDrawList->AddText(ImVec2(PosMid.x + 5, PosMid.y - 7), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
|
||||||
|
PlotDrawList->PopClipRect();
|
||||||
|
|
||||||
|
if (Mouse.x > Min.x && Mouse.x < Max.x && Mouse.y > Min.y && Mouse.y < Max.y)
|
||||||
|
{
|
||||||
|
HoveredEvent = &Event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Write info on the graph to help debugging
|
||||||
|
//-------------------------------------------------------
|
||||||
|
//char Buffer[64];
|
||||||
|
//ImFormatString(Buffer, 64, "%0.1f %0.1f", Mouse.x, Mouse.y);
|
||||||
|
//PlotDrawList->AddText(ImVec2(PlotMin.x + 50, PlotMin.y + 100), IM_COL32(255, 255, 255, 255), Buffer);
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Hovered event tooltip
|
||||||
|
//-------------------------------------------------------
|
||||||
|
RenderEventTooltip(HoveredEvent, Entry);
|
||||||
|
|
||||||
|
ImPlot::PopPlotClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogEngineWindow_Plots::RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry)
|
||||||
|
{
|
||||||
|
if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr)
|
||||||
|
{
|
||||||
|
FCogWindowWidgets::BeginTableTooltip();
|
||||||
|
if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders))
|
||||||
|
{
|
||||||
|
//------------------------
|
||||||
|
// Event Name
|
||||||
|
//------------------------
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Name");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->DisplayName));
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// Owner Name
|
||||||
|
//------------------------
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Owner");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->OwnerName));
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// Times
|
||||||
|
//------------------------
|
||||||
|
if (HoveredEvent->EndTime != HoveredEvent->StartTime)
|
||||||
|
{
|
||||||
|
const float ActualEndTime = HoveredEvent->GetActualEndTime(Entry);
|
||||||
|
const uint64 ActualEndFrame = HoveredEvent->GetActualEndFrame(Entry);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Duration");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%0.2fs", ActualEndTime - HoveredEvent->StartTime);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Frames");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%d [%d-%d]",
|
||||||
|
(int32)(ActualEndFrame - HoveredEvent->StartFrame),
|
||||||
|
(int32)(HoveredEvent->StartFrame % 1000),
|
||||||
|
(int32)(ActualEndFrame % 1000));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Frame");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%d", (int32)(HoveredEvent->StartFrame % 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------
|
||||||
|
// Params
|
||||||
|
//------------------------
|
||||||
|
for (FCogDebugPlotEventParams Param : HoveredEvent->Params)
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Name.ToString()));
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Value));
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
FCogWindowWidgets::EndTableTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "CogWindow.h"
|
#include "CogWindow.h"
|
||||||
|
#include "CogWindowConfig.h"
|
||||||
|
#include "CogEngineWindow_Plots.generated.h"
|
||||||
|
|
||||||
|
struct ImVec2;
|
||||||
|
struct FCogDebugPlotEvent;
|
||||||
|
struct FCogDebugPlotEntry;
|
||||||
|
class UCogEngineConfig_Plots;
|
||||||
|
|
||||||
class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow
|
class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow
|
||||||
{
|
{
|
||||||
@@ -9,12 +16,55 @@ class COGENGINE_API FCogEngineWindow_Plots : public FCogWindow
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual void Initialize() override;
|
||||||
|
|
||||||
virtual void RenderHelp() override;
|
virtual void RenderHelp() override;
|
||||||
|
|
||||||
|
virtual void ResetConfig() override;
|
||||||
|
|
||||||
virtual void RenderTick(float DeltaTime) override;
|
virtual void RenderTick(float DeltaTime) override;
|
||||||
|
|
||||||
virtual void RenderContent() override;
|
virtual void RenderContent() override;
|
||||||
|
|
||||||
|
void RenderPlotsList(TArray<FCogDebugPlotEntry*>& VisiblePlots);
|
||||||
|
|
||||||
|
void RenderPlots(const TArray<FCogDebugPlotEntry*>& VisiblePlots);
|
||||||
|
|
||||||
|
void RenderMenu();
|
||||||
|
|
||||||
|
void RenderTimeMarker();
|
||||||
|
|
||||||
|
void RenderValues(FCogDebugPlotEntry& Entry, const char* Label);
|
||||||
|
|
||||||
|
void RenderEvents(FCogDebugPlotEntry& Entry, const char* Label, const ImVec2& PlotMin, const ImVec2& PlotMax);
|
||||||
|
|
||||||
|
void RenderEventTooltip(const FCogDebugPlotEvent* HoveredEvent, FCogDebugPlotEntry& Entry);
|
||||||
|
|
||||||
|
TObjectPtr<UCogEngineConfig_Plots> Config = nullptr;
|
||||||
|
|
||||||
|
bool bApplyTimeScale = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
UCLASS(Config = Cog)
|
||||||
|
class UCogEngineConfig_Plots : public UCogWindowConfig
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UPROPERTY(Config)
|
||||||
|
int Rows = 1;
|
||||||
|
|
||||||
|
UPROPERTY(Config)
|
||||||
|
float TimeRange = 10.0f;
|
||||||
|
|
||||||
|
virtual void Reset() override
|
||||||
|
{
|
||||||
|
Rows = 1;
|
||||||
|
TimeRange = 10.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -72,6 +72,43 @@ void FCogWindowWidgets::ProgressBarCentered(float Fraction, const ImVec2& Size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogWindowWidgets::ToggleMenuButton(bool* Value, const char* Text, const ImVec4& TrueColor)
|
||||||
|
{
|
||||||
|
bool IsTrue = *Value;
|
||||||
|
if (IsTrue)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 0.6f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 0.8f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(TrueColor.x, TrueColor.y, TrueColor.z, TrueColor.w * 1.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button(Text))
|
||||||
|
{
|
||||||
|
*Value = !*Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsTrue)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void FCogWindowWidgets::ToggleButton(bool* Value, const char* Text, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size)
|
||||||
|
{
|
||||||
|
ToggleButton(Value, Text, Text, TrueColor, FalseColor, Size);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
void FCogWindowWidgets::ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size)
|
void FCogWindowWidgets::ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ public:
|
|||||||
|
|
||||||
static void ProgressBarCentered(float Fraction, const ImVec2& Size, const char* Overlay);
|
static void ProgressBarCentered(float Fraction, const ImVec2& Size, const char* Overlay);
|
||||||
|
|
||||||
|
static void ToggleMenuButton(bool* Value, const char* Text, const ImVec4& TrueColor);
|
||||||
|
|
||||||
|
static void ToggleButton(bool* Value, const char* Text, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
|
||||||
|
|
||||||
static void ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
|
static void ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
|
||||||
|
|
||||||
static bool MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size = ImVec2(0, 0));
|
static bool MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size = ImVec2(0, 0));
|
||||||
|
|||||||
Reference in New Issue
Block a user