You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This change makes it possible to remove the layout and painting overhead that Slate performs every frame. The system is off by default as we continue to iterate on it. However, this includes massive changes to batching, rendering, hit testing, and invalidation panels which are permanent changes and cannot be disabled. #rb chris.gagnon, nick.darnell [CODEREVIEW] nick.darnell #ROBOMERGE-OWNER: matt.kuhlenschmidt #ROBOMERGE-AUTHOR: matt.kuhlenschmidt #ROBOMERGE-SOURCE: CL 7232617 via CL 7235502 #ROBOMERGE-BOT: (v367-6836689) [CL 7235503 by matt kuhlenschmidt in Main branch]
206 lines
5.9 KiB
C++
206 lines
5.9 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "VisualTreeCapture.h"
|
|
#include "Debugging/SlateDebugging.h"
|
|
#include "Rendering/SlateRenderTransform.h"
|
|
#include "Rendering/DrawElements.h"
|
|
#include "Widgets/SWidget.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "Types/InvisibleToWidgetReflectorMetaData.h"
|
|
|
|
static float VectorSign(const FVector2D& Vec, const FVector2D& A, const FVector2D& B)
|
|
{
|
|
return FMath::Sign((B.X - A.X) * (Vec.Y - A.Y) - (B.Y - A.Y) * (Vec.X - A.X));
|
|
}
|
|
|
|
// Returns true when the point is inside the triangle
|
|
// Should not return true when the point is on one of the edges
|
|
static bool IsPointInTriangle(const FVector2D& TestPoint, const FVector2D& A, const FVector2D& B, const FVector2D& C)
|
|
{
|
|
float BA = VectorSign(B, A, TestPoint);
|
|
float CB = VectorSign(C, B, TestPoint);
|
|
float AC = VectorSign(A, C, TestPoint);
|
|
|
|
// point is in the same direction of all 3 tri edge lines
|
|
// must be inside, regardless of tri winding
|
|
return BA == CB && CB == AC;
|
|
}
|
|
|
|
FVisualEntry::FVisualEntry(int32 InElementIndex)
|
|
: ElementIndex(InElementIndex)
|
|
{
|
|
}
|
|
|
|
void FVisualEntry::Resolve(const FSlateWindowElementList& ElementList)
|
|
{
|
|
const FSlateDrawElement& Element = ElementList.GetUncachedDrawElements()[ElementIndex];
|
|
const FSlateRenderTransform& Transform = Element.GetRenderTransform();
|
|
const FVector2D& LocalSize = Element.GetLocalSize();
|
|
|
|
TopLeft = Transform.TransformPoint(FVector2D(0, 0));
|
|
TopRight = Transform.TransformPoint(FVector2D(LocalSize.X, 0));
|
|
BottomLeft = Transform.TransformPoint(FVector2D(0, LocalSize.Y));
|
|
BottomRight = Transform.TransformPoint(LocalSize);
|
|
|
|
LayerId = Element.GetLayer();
|
|
ClippingIndex = Element.GetPrecachedClippingIndex();
|
|
}
|
|
|
|
bool FVisualEntry::IsPointInside(const FVector2D& Point) const
|
|
{
|
|
if (IsPointInTriangle(Point, TopLeft, TopRight, BottomLeft) || IsPointInTriangle(Point, BottomLeft, TopRight, BottomRight))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
TSharedPtr<const SWidget> FVisualTreeSnapshot::Pick(FVector2D Point)
|
|
{
|
|
for (int Index = Entries.Num() - 1; Index >= 0; Index--)
|
|
{
|
|
const FVisualEntry& Entry = Entries[Index];
|
|
if (Entry.ClippingIndex != -1 && !ClippingStates[Entry.ClippingIndex].IsPointInside(Point))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!Entry.IsPointInside(Point))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TSharedPtr<const SWidget> Widget = Entry.Widget.Pin();
|
|
|
|
//if (Widget->GetVisibility() == EVisibility::HitTestInvisible)
|
|
//{
|
|
// continue;
|
|
//}
|
|
|
|
// Build List.
|
|
return Widget;
|
|
}
|
|
|
|
return TSharedPtr<const SWidget>();
|
|
}
|
|
|
|
FVisualTreeCapture::FVisualTreeCapture()
|
|
{
|
|
}
|
|
|
|
FVisualTreeCapture::~FVisualTreeCapture()
|
|
{
|
|
Disable();
|
|
}
|
|
|
|
void FVisualTreeCapture::Enable()
|
|
{
|
|
#if WITH_SLATE_DEBUGGING
|
|
FSlateApplication::Get().OnWindowBeingDestroyed().AddRaw(this, &FVisualTreeCapture::OnWindowBeingDestroyed);
|
|
FSlateDebugging::BeginWindow.AddRaw(this, &FVisualTreeCapture::BeginWindow);
|
|
FSlateDebugging::EndWindow.AddRaw(this, &FVisualTreeCapture::EndWindow);
|
|
FSlateDebugging::BeginWidgetPaint.AddRaw(this, &FVisualTreeCapture::BeginWidgetPaint);
|
|
FSlateDebugging::EndWidgetPaint.AddRaw(this, &FVisualTreeCapture::EndWidgetPaint);
|
|
FSlateDebugging::ElementAdded.AddRaw(this, &FVisualTreeCapture::ElementAdded);
|
|
#endif
|
|
}
|
|
|
|
void FVisualTreeCapture::Disable()
|
|
{
|
|
#if WITH_SLATE_DEBUGGING
|
|
if (FSlateApplication::IsInitialized())
|
|
{
|
|
FSlateApplication::Get().OnWindowBeingDestroyed().RemoveAll(this);
|
|
}
|
|
FSlateDebugging::BeginWindow.RemoveAll(this);
|
|
FSlateDebugging::EndWindow.RemoveAll(this);
|
|
FSlateDebugging::BeginWidgetPaint.RemoveAll(this);
|
|
FSlateDebugging::EndWidgetPaint.RemoveAll(this);
|
|
FSlateDebugging::ElementAdded.RemoveAll(this);
|
|
#endif
|
|
}
|
|
|
|
void FVisualTreeCapture::Reset()
|
|
{
|
|
VisualTrees.Reset();
|
|
}
|
|
|
|
TSharedPtr<FVisualTreeSnapshot> FVisualTreeCapture::GetVisualTreeForWindow(SWindow* InWindow)
|
|
{
|
|
return VisualTrees.FindRef(InWindow);
|
|
}
|
|
|
|
void FVisualTreeCapture::BeginWindow(const FSlateWindowElementList& ElementList)
|
|
{
|
|
TSharedPtr<FVisualTreeSnapshot> Tree = VisualTrees.FindRef(ElementList.GetPaintWindow());
|
|
if (!Tree.IsValid())
|
|
{
|
|
Tree = MakeShared<FVisualTreeSnapshot>();
|
|
VisualTrees.Add(ElementList.GetPaintWindow(), Tree);
|
|
}
|
|
|
|
Tree->Entries.Reset();
|
|
Tree->ClippingStates.Reset();
|
|
}
|
|
|
|
void FVisualTreeCapture::EndWindow(const FSlateWindowElementList& ElementList)
|
|
{
|
|
TSharedPtr<FVisualTreeSnapshot> Tree = VisualTrees.FindRef(ElementList.GetPaintWindow());
|
|
if (Tree.IsValid())
|
|
{
|
|
for (FVisualEntry& Entry : Tree->Entries)
|
|
{
|
|
Entry.Resolve(ElementList);
|
|
}
|
|
|
|
Tree->ClippingStates = ElementList.GetClippingManager().GetClippingStates();
|
|
Tree->Entries.Sort([](const FVisualEntry& A, const FVisualEntry& B) {
|
|
return A.LayerId < B.LayerId;
|
|
});
|
|
}
|
|
}
|
|
|
|
void FVisualTreeCapture::BeginWidgetPaint(const SWidget* Widget, const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, const FSlateWindowElementList& ElementList, int32 LayerId)
|
|
{
|
|
TSharedPtr<FVisualTreeSnapshot> Tree = VisualTrees.FindRef(ElementList.GetPaintWindow());
|
|
if (Tree.IsValid())
|
|
{
|
|
Tree->WidgetStack.Push(Widget->AsShared());
|
|
}
|
|
}
|
|
|
|
void FVisualTreeCapture::EndWidgetPaint(const SWidget* Widget, const FSlateWindowElementList& ElementList, int32 LayerId)
|
|
{
|
|
TSharedPtr<FVisualTreeSnapshot> Tree = VisualTrees.FindRef(ElementList.GetPaintWindow());
|
|
if (Tree.IsValid())
|
|
{
|
|
Tree->WidgetStack.Pop();
|
|
}
|
|
}
|
|
|
|
void FVisualTreeCapture::ElementAdded(const FSlateWindowElementList& ElementList, int32 InElementIndex)
|
|
{
|
|
TSharedPtr<FVisualTreeSnapshot> Tree = VisualTrees.FindRef(ElementList.GetPaintWindow());
|
|
if (Tree.IsValid())
|
|
{
|
|
if (Tree->WidgetStack.Num() > 0)
|
|
{
|
|
// Ignore any element added from a widget that's invisible to the widget reflector.
|
|
if (Tree->WidgetStack.Top().Pin()->GetMetaData<FInvisibleToWidgetReflectorMetaData>())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FVisualEntry Entry(InElementIndex);
|
|
Entry.Widget = Tree->WidgetStack.Top();
|
|
Tree->Entries.Add(Entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FVisualTreeCapture::OnWindowBeingDestroyed(const SWindow& WindowBeingDestoyed)
|
|
{
|
|
VisualTrees.Remove(&WindowBeingDestoyed);
|
|
}
|