EM_Task/UnrealEd/Private/DistanceFieldBuildNotification.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

133 lines
4.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "Stats/Stats.h"
#include "TickableEditorObject.h"
#include "DistanceFieldAtlas.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Templates/UniquePtr.h"
/** Notification class for asynchronous distance field building. */
class FDistanceFieldBuildNotificationImpl
: public FTickableEditorObject
{
public:
FDistanceFieldBuildNotificationImpl()
{
LastEnableTime = 0;
}
/** Starts the notification. */
void DistanceFieldBuildStarted();
/** Ends the notification. */
void DistanceFieldBuildFinished();
protected:
/** FTickableEditorObject interface */
virtual void Tick(float DeltaTime) override;
virtual ETickableTickType GetTickableTickType() const override
{
return ETickableTickType::Always;
}
virtual TStatId GetStatId() const override;
private:
/** Tracks the last time the notification was started, used to avoid spamming. */
double LastEnableTime;
/** In progress message */
TWeakPtr<SNotificationItem> DistanceFieldNotificationPtr;
};
/** Global notification object. */
TUniquePtr<FDistanceFieldBuildNotificationImpl> GDistanceFieldBuildNotification;
void SetupDistanceFieldBuildNotification()
{
// Create explicitly to avoid relying on static initialization order
GDistanceFieldBuildNotification = MakeUnique<FDistanceFieldBuildNotificationImpl>();
}
void TearDownDistanceFieldBuildNotification()
{
GDistanceFieldBuildNotification = nullptr;
}
void FDistanceFieldBuildNotificationImpl::DistanceFieldBuildStarted()
{
LastEnableTime = FPlatformTime::Seconds();
// Starting a new request! Notify the UI.
if (DistanceFieldNotificationPtr.IsValid())
{
DistanceFieldNotificationPtr.Pin()->ExpireAndFadeout();
}
FNotificationInfo Info(NSLOCTEXT("DistanceFieldBuild", "DistanceFieldBuildInProgress", "Building Mesh Distance Fields"));
Info.bFireAndForget = false;
// Setting fade out and expire time to 0 as the expire message is currently very obnoxious
Info.FadeOutDuration = 0.0f;
Info.ExpireDuration = 0.0f;
DistanceFieldNotificationPtr = FSlateNotificationManager::Get().AddNotification(Info);
if (DistanceFieldNotificationPtr.IsValid())
{
DistanceFieldNotificationPtr.Pin()->SetCompletionState(SNotificationItem::CS_Pending);
}
}
void FDistanceFieldBuildNotificationImpl::DistanceFieldBuildFinished()
{
// Finished all requests! Notify the UI.
TSharedPtr<SNotificationItem> NotificationItem = DistanceFieldNotificationPtr.Pin();
if (NotificationItem.IsValid())
{
NotificationItem->SetText(NSLOCTEXT("DistanceFieldBuild", "DistanceFieldBuildFinished", "Finished building Distance Fields!"));
NotificationItem->SetCompletionState(SNotificationItem::CS_Success);
NotificationItem->ExpireAndFadeout();
DistanceFieldNotificationPtr.Reset();
}
}
void FDistanceFieldBuildNotificationImpl::Tick(float DeltaTime)
{
if (GDistanceFieldAsyncQueue)
{
// Trigger a new notification if we are doing an async build, and we haven't displayed the notification recently
if (GDistanceFieldAsyncQueue->GetNumOutstandingTasks() > 0 && !DistanceFieldNotificationPtr.IsValid() && (FPlatformTime::Seconds() - LastEnableTime) > 5)
{
DistanceFieldBuildStarted();
}
// Disable the notification when we are no longer doing an async compile
else if (GDistanceFieldAsyncQueue->GetNumOutstandingTasks() == 0 && DistanceFieldNotificationPtr.IsValid())
{
DistanceFieldBuildFinished();
}
else if (GDistanceFieldAsyncQueue->GetNumOutstandingTasks() > 0 && DistanceFieldNotificationPtr.IsValid())
{
TSharedPtr<SNotificationItem> NotificationItem = DistanceFieldNotificationPtr.Pin();
if (NotificationItem.IsValid())
{
FFormatNamedArguments Args;
Args.Add(TEXT("BuildTasks"), FText::AsNumber(GDistanceFieldAsyncQueue->GetNumOutstandingTasks()));
FText ProgressMessage = FText::Format(NSLOCTEXT("DistanceFieldBuild", "DistanceFieldBuildInProgressFormat", "Building Mesh Distance Fields ({BuildTasks})"), Args);
NotificationItem->SetText(ProgressMessage);
}
}
}
}
TStatId FDistanceFieldBuildNotificationImpl::GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FDistanceFieldBuildNotificationImpl, STATGROUP_Tickables);
}