Files
UnrealEngine/Engine/Source/Developer/TraceInsights/Private/Insights/ViewModels/DrawHelpers.cpp
2025-05-18 13:04:45 +08:00

345 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DrawHelpers.h"
#include "Fonts/FontMeasure.h"
#include "Fonts/SlateFontInfo.h"
// TraceInsightsCore
#include "InsightsCore/Common/PaintUtils.h"
#include "InsightsCore/Common/TimeUtils.h"
// TraceInsights
#include "Insights/ViewModels/TimingTrackViewport.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawBackground(
const UE::Insights::FDrawContext& DrawContext,
const FSlateBrush* BackgroundAreaBrush,
const FLinearColor& ValidAreaColor,
const FLinearColor& InvalidAreaColor,
const FLinearColor& EdgeColor,
const float X0,
const float X1,
const float X2,
const float X3,
const float Y,
const float H,
float& OutValidAreaX,
float& OutValidAreaW)
{
// <------- W ------->
// X0 X1 X2 X3
// ++++++|*****|++++++
// ++++++|*****|++++++
// ++++++|*****|++++++
if (X1 >= X3 || X2 <= X0)
{
OutValidAreaX = X0;
OutValidAreaW = X3 - X0;
// Draw invalid area (entire view).
DrawContext.DrawBox(X0, Y, X3 - X0, H, BackgroundAreaBrush, InvalidAreaColor);
}
else // X1 < X3 && X2 > X0
{
if (X1 > X0)
{
// Draw invalid area (left).
DrawContext.DrawBox(X0, Y, X1 - X0, H, BackgroundAreaBrush, InvalidAreaColor);
}
if (X2 < X3)
{
// Draw invalid area (right).
DrawContext.DrawBox(X2 + 1.0f, Y, X3 - X2 - 1.0f, H, BackgroundAreaBrush, InvalidAreaColor);
// Draw the right edge (end time).
DrawContext.DrawBox(X2, Y, 1.0f, H, BackgroundAreaBrush, EdgeColor);
}
float ValidAreaX = FMath::Max(X1, X0);
float ValidAreaW = FMath::Min(X2, X3) - ValidAreaX;
if (X1 >= X0)
{
// Draw the left edge (start time).
DrawContext.DrawBox(X1, Y, 1.0f, H, BackgroundAreaBrush, EdgeColor);
// Adjust valid area to not overlap the left edge.
ValidAreaX += 1.0f;
ValidAreaW -= 1.0f;
}
if (ValidAreaW > 0.0f)
{
// Draw valid area.
DrawContext.DrawBox(ValidAreaX, Y, ValidAreaW, H, BackgroundAreaBrush, ValidAreaColor);
}
OutValidAreaX = ValidAreaX;
OutValidAreaW = ValidAreaW;
}
DrawContext.LayerId++;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawBackground(const UE::Insights::FDrawContext& DrawContext,
const FSlateBrush* BackgroundAreaBrush,
const float X0,
const float X1,
const float X2,
const float X3,
const float Y,
const float H)
{
const FLinearColor ValidAreaColor(0.07f, 0.07f, 0.07f, 1.0f);
const FLinearColor InvalidAreaColor(0.1f, 0.07f, 0.07f, 1.0f);
const FLinearColor EdgeColor(0.05f, 0.05f, 0.05f, 1.0f);
float ValidAreaX, ValidAreaW;
FDrawHelpers::DrawBackground(DrawContext, BackgroundAreaBrush, ValidAreaColor, InvalidAreaColor, EdgeColor, X0, X1, X2, X3, Y, H, ValidAreaX, ValidAreaW);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawBackground(const UE::Insights::FDrawContext& DrawContext,
const FSlateBrush* BackgroundAreaBrush,
const FTimingTrackViewport& Viewport,
const float Y,
const float H)
{
const FLinearColor ValidAreaColor(0.07f, 0.07f, 0.07f, 1.0f);
const FLinearColor InvalidAreaColor(0.1f, 0.07f, 0.07f, 1.0f);
const FLinearColor EdgeColor(0.05f, 0.05f, 0.05f, 1.0f);
const float X0 = 0.0f;
const float X1 = Viewport.TimeToSlateUnitsRounded(Viewport.GetMinValidTime());
const float X2 = Viewport.TimeToSlateUnitsRounded(Viewport.GetMaxValidTime());
const float X3 = FMath::CeilToFloat(Viewport.GetWidth());
float ValidAreaX, ValidAreaW;
FDrawHelpers::DrawBackground(DrawContext, BackgroundAreaBrush, ValidAreaColor, InvalidAreaColor, EdgeColor, X0, X1, X2, X3, Y, H, ValidAreaX, ValidAreaW);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawBackground(const UE::Insights::FDrawContext& DrawContext,
const FSlateBrush* BackgroundAreaBrush,
const FTimingTrackViewport& Viewport,
const float Y,
const float H,
float& OutValidAreaX,
float& OutValidAreaW)
{
const FLinearColor ValidAreaColor(0.07f, 0.07f, 0.07f, 1.0f);
const FLinearColor InvalidAreaColor(0.1f, 0.07f, 0.07f, 1.0f);
const FLinearColor EdgeColor(0.05f, 0.05f, 0.05f, 1.0f);
const float X0 = 0.0f;
const float X1 = Viewport.TimeToSlateUnitsRounded(Viewport.GetMinValidTime());
const float X2 = Viewport.TimeToSlateUnitsRounded(Viewport.GetMaxValidTime());
const float X3 = FMath::CeilToFloat(Viewport.GetWidth());
FDrawHelpers::DrawBackground(DrawContext, BackgroundAreaBrush, ValidAreaColor, InvalidAreaColor, EdgeColor, X0, X1, X2, X3, Y, H, OutValidAreaX, OutValidAreaW);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawTimeRangeSelection(
const UE::Insights::FDrawContext& DrawContext,
const FTimingTrackViewport& Viewport,
const double StartTime,
const double EndTime,
const FSlateBrush* Brush,
const FSlateFontInfo& Font)
{
if (EndTime > StartTime)
{
const float MinX = 0.0f;
const float MaxX = Viewport.GetWidth();
float SelectionX1 = Viewport.TimeToSlateUnitsRounded(StartTime);
float SelectionX2 = Viewport.TimeToSlateUnitsRounded(EndTime);
if (SelectionX1 <= MaxX && SelectionX2 >= MinX)
{
const float Y = Viewport.GetPosY();
const float H = Viewport.GetHeight();
const double Duration = EndTime - StartTime;
const FString Text = UE::Insights::FormatTimeAuto(Duration);
DrawSelection(DrawContext, MinX, MaxX, SelectionX1, SelectionX2, Y, H, 6.0f, Text, Brush, Font);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FDrawHelpers::DrawSelection(
const UE::Insights::FDrawContext& DrawContext,
const float MinX,
const float MaxX,
float SelectionX1,
float SelectionX2,
const float Y,
const float H,
const float TextY,
const FString Text,
const FSlateBrush* Brush,
const FSlateFontInfo& Font)
{
float ClipLeft = 0.0f;
float ClipRight = 0.0f;
if (SelectionX1 < MinX)
{
ClipLeft = MinX - SelectionX1;
SelectionX1 = MinX;
}
if (SelectionX2 > MaxX)
{
ClipRight = SelectionX2 - MaxX;
SelectionX2 = MaxX;
}
const FLinearColor BackgroundColor(0.25f, 0.5f, 1.0f, 0.25f);
// Draw selection area.
DrawContext.DrawBox(SelectionX1, Y, SelectionX2 - SelectionX1, H, Brush, BackgroundColor);
DrawContext.LayerId++;
const FColor ArrowFillColor(32, 64, 128, 255);
const FLinearColor ArrowColor(ArrowFillColor);
if (SelectionX1 > MinX)
{
// Draw left side (vertical line).
DrawContext.DrawBox(SelectionX1 - 1.0f, Y, 1.0f, H, Brush, ArrowColor);
}
if (SelectionX2 < MaxX)
{
// Draw right side (vertical line).
DrawContext.DrawBox(SelectionX2, Y, 1.0f, H, Brush, ArrowColor);
}
DrawContext.LayerId++;
const float ArrowSize = 6.0f;
const float ArrowY = Y + TextY;
if (SelectionX2 - SelectionX1 > 2 * ArrowSize)
{
// Draw horizontal line.
float HorizLineX1 = SelectionX1;
if (ClipLeft == 0.0f)
{
HorizLineX1 += 1.0f;
}
float HorizLineX2 = SelectionX2;
if (ClipRight == 0.0f)
{
HorizLineX2 -= 1.0f;
}
DrawContext.DrawBox(HorizLineX1, ArrowY - 1.0f, HorizLineX2 - HorizLineX1, 3.0f, Brush, ArrowColor);
if (ClipLeft < ArrowSize)
{
// Draw left arrow.
for (float AH = 0.0f; AH < ArrowSize; AH += 1.0f)
{
DrawContext.DrawBox(SelectionX1 - ClipLeft + AH, ArrowY - AH, 1.0f, 2.0f * AH + 1.0f, Brush, ArrowColor);
}
}
if (ClipRight < ArrowSize)
{
// Draw right arrow.
for (float AH = 0.0f; AH < ArrowSize; AH += 1.0f)
{
DrawContext.DrawBox(SelectionX2 + ClipRight - AH - 1.0f, ArrowY - AH, 1.0f, 2.0f * AH + 1.0f, Brush, ArrowColor);
}
}
DrawContext.LayerId++;
#if 0
//im: This should be a more efficeint way top draw the arrows, but it renders them with artifacts (missing vertical lines; shader bug?)!
const FSlateBrush* MyBrush = WhiteBrush;
FSlateResourceHandle ResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(*MyBrush);
const FSlateShaderResourceProxy* ResourceProxy = ResourceHandle.GetResourceProxy();
FVector2D AtlasOffset = ResourceProxy ? ResourceProxy->StartUV : FVector2D(0.0f, 0.0f);
FVector2D AtlasUVSize = ResourceProxy ? ResourceProxy->SizeUV : FVector2D(1.0f, 1.0f);
const FVector2D Pos = AllottedGeometry.GetAbsolutePosition() + FVector2D(0.0f, 40.0f);
const float Scale = AllottedGeometry.Scale;
FSlateRenderTransform RenderTransform;
TArray<FSlateVertex> Verts;
Verts.Reserve(6);
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX1 + ArrowSize, 0.5f + ArrowY + ArrowSize) * Scale, AtlasOffset + FVector2D(0.0f, 1.0f) * AtlasUVSize, ArrowFillColor));
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX1, 0.5f + ArrowY) * Scale, AtlasOffset + FVector2D(1.0f, 0.5f) * AtlasUVSize, ArrowFillColor));
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX1 + ArrowSize, 0.5f + ArrowY - ArrowSize) * Scale, AtlasOffset + FVector2D(0.0f, 0.0f) * AtlasUVSize, ArrowFillColor));
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX2 - ArrowSize, 0.5f + ArrowY - ArrowSize) * Scale, AtlasOffset + FVector2D(0.0f, 0.0f) * AtlasUVSize, ArrowFillColor));
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX2, 0.5f + ArrowY) * Scale, AtlasOffset + FVector2D(1.0f, 0.5f) * AtlasUVSize, ArrowFillColor));
Verts.Add(FSlateVertex::Make<ESlateVertexRounding::Disabled>(RenderTransform, Pos + FVector2D(0.5f + SelectionX2 - ArrowSize, 0.5f + ArrowY + ArrowSize) * Scale, AtlasOffset + FVector2D(0.0f, 1.0f) * AtlasUVSize, ArrowFillColor));
TArray<SlateIndex> Indices;
Indices.Reserve(6);
if (ClipLeft < ArrowSize)
{
Indices.Add(0);
Indices.Add(1);
Indices.Add(2);
}
if (ClipRight < ArrowSize)
{
Indices.Add(3);
Indices.Add(4);
Indices.Add(5);
}
FSlateDrawElement::MakeCustomVerts(
OutDrawElements,
LayerId,
ResourceHandle,
Verts,
Indices,
nullptr,
0,
0,
ESlateDrawEffect::PreMultipliedAlpha);
DrawContext.LayerId++;
#endif
}
//////////////////////////////////////////////////
// Draw text info for selected interval.
if (!Text.IsEmpty())
{
const TSharedRef<FSlateFontMeasure> FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
const float FontScale = DrawContext.Geometry.Scale;
const float TextWidth = static_cast<float>(FontMeasureService->Measure(Text, Font, FontScale).X / FontScale);
const float CenterX = (SelectionX1 + SelectionX2) / 2.0f;
DrawContext.DrawBox(CenterX - TextWidth / 2.0f - 2.0f, ArrowY - 6.0f, TextWidth + 4.0f, 13.0f, Brush, ArrowColor);
DrawContext.LayerId++;
DrawContext.DrawText(CenterX - TextWidth / 2.0f, ArrowY - 6.0f, Text, Font, FLinearColor::White);
DrawContext.LayerId++;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////