EM_Task/UnrealEd/Public/AssetThumbnail.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

328 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Stats/Stats.h"
#include "Misc/Attribute.h"
#include "AssetData.h"
#include "Rendering/RenderingCommon.h"
#include "Widgets/SWidget.h"
#include "TickableEditorObject.h"
class AActor;
class FAssetThumbnailPool;
class FSlateShaderResource;
class FSlateTexture2DRHIRef;
class FSlateTextureRenderTarget2DResource;
struct FPropertyChangedEvent;
namespace EThumbnailLabel
{
enum Type
{
ClassName,
AssetName,
NoLabel
};
}; // namespace EThumbnailLabel
/** A struct containing details about how the asset thumbnail should behave */
struct FAssetThumbnailConfig
{
FAssetThumbnailConfig()
: bAllowFadeIn(false), bForceGenericThumbnail(false), bAllowHintText(true), bAllowAssetSpecificThumbnailOverlay(false), ClassThumbnailBrushOverride(NAME_None), ThumbnailLabel(EThumbnailLabel::ClassName), HighlightedText(FText::GetEmpty()), HintColorAndOpacity(FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)), AssetTypeColorOverride()
{
}
bool bAllowFadeIn;
bool bForceGenericThumbnail;
bool bAllowHintText;
bool bAllowAssetSpecificThumbnailOverlay;
FName ClassThumbnailBrushOverride;
EThumbnailLabel::Type ThumbnailLabel;
TAttribute<FText> HighlightedText;
TAttribute<FLinearColor> HintColorAndOpacity;
TOptional<FLinearColor> AssetTypeColorOverride;
};
/**
* Interface for rendering a thumbnail in a slate viewport
*/
class FAssetThumbnail
: public ISlateViewport
, public TSharedFromThis<FAssetThumbnail>
{
public:
/**
* @param InAsset The asset to display a thumbnail for
* @param InWidth The width that the thumbnail should be
* @param InHeight The height that the thumbnail should be
* @param InThumbnailPool The thumbnail pool to request textures from
*/
UNREALED_API FAssetThumbnail(UObject* InAsset, uint32 InWidth, uint32 InHeight, const TSharedPtr<class FAssetThumbnailPool>& InThumbnailPool);
UNREALED_API FAssetThumbnail(const FAssetData& InAsset, uint32 InWidth, uint32 InHeight, const TSharedPtr<class FAssetThumbnailPool>& InThumbnailPool);
UNREALED_API ~FAssetThumbnail();
/**
* @return The size of the viewport (thumbnail size)
*/
virtual FIntPoint GetSize() const override;
/**
* @return The texture used to display the viewports content
*/
virtual FSlateShaderResource* GetViewportRenderTargetTexture() const override;
/**
* Returns true if the viewport should be vsynced.
*/
virtual bool RequiresVsync() const override { return false; }
/**
* @return The object we are rendering the thumbnail for
*/
UNREALED_API UObject* GetAsset() const;
/**
* @return The asset data for the object we are rendering the thumbnail for
*/
UNREALED_API const FAssetData& GetAssetData() const;
/**
* Sets the asset to render the thumnail for
*
* @param InAsset The new asset
*/
UNREALED_API void SetAsset(const UObject* InAsset);
/**
* Sets the asset to render the thumnail for
*
* @param InAssetData Asset data containin the the new asset to render
*/
UNREALED_API void SetAsset(const FAssetData& InAssetData);
/**
* @return A slate widget representing this thumbnail
*/
UNREALED_API TSharedRef<SWidget> MakeThumbnailWidget(const FAssetThumbnailConfig& InConfig = FAssetThumbnailConfig());
/** Re-renders this thumbnail */
UNREALED_API void RefreshThumbnail();
DECLARE_EVENT(FAssetThumbnail, FOnAssetDataChanged);
FOnAssetDataChanged& OnAssetDataChanged() { return AssetDataChangedEvent; }
private:
/** Thumbnail pool for rendering the thumbnail */
TWeakPtr<FAssetThumbnailPool> ThumbnailPool;
/** Triggered when the asset data changes */
FOnAssetDataChanged AssetDataChangedEvent;
/** The asset data for the object we are rendering the thumbnail for */
FAssetData AssetData;
/** Width of the thumbnail */
uint32 Width;
/** Height of the thumbnail */
uint32 Height;
};
/**
* Utility class for keeping track of, rendering, and recycling thumbnails rendered in Slate
*/
class FAssetThumbnailPool: public FTickableEditorObject
{
public:
/**
* Constructor
*
* @param InNumInPool The number of thumbnails allowed in the pool
* @param InAreRealTimeThumbnailsAllowed Attribute that determines if thumbnails should be rendered in real-time
* @param InMaxFrameTimeAllowance The maximum number of seconds per tick to spend rendering thumbnails
* @param InMaxRealTimeThumbnailsPerFrame The maximum number of real-time thumbnails to render per tick
*/
UNREALED_API FAssetThumbnailPool(uint32 InNumInPool, const TAttribute<bool>& InAreRealTimeThumbnailsAllowed = true, double InMaxFrameTimeAllowance = 0.005, uint32 InMaxRealTimeThumbnailsPerFrame = 3);
/** Destructor to free all remaining resources */
UNREALED_API ~FAssetThumbnailPool();
//~ Begin FTickableObject Interface
UNREALED_API virtual TStatId GetStatId() const override;
/** Checks if any new thumbnails are queued */
UNREALED_API virtual bool IsTickable() const override;
/** Ticks the pool, rendering new thumbnails as needed */
UNREALED_API virtual void Tick(float DeltaTime) override;
//~ End FTickableObject Interface
/**
* Accesses the texture for an object. If a thumbnail was recently rendered this function simply returns the thumbnail. If it was not, it requests a new one be generated
* No assumptions should be made about whether or not it was rendered
*
* @param Asset The asset to get the thumbnail for
* @param Width The width of the thumbnail
* @param Height The height of the thumbnail
* @return The thumbnail for the asset or NULL if one could not be produced
*/
FSlateTexture2DRHIRef* AccessTexture(const FAssetData& AssetData, uint32 Width, uint32 Height);
/**
* Adds a referencer to keep textures around as long as they are needed
*/
void AddReferencer(const FAssetThumbnail& AssetThumbnail);
/**
* Removes a referencer to clean up textures that are no longer needed
*/
void RemoveReferencer(const FAssetThumbnail& AssetThumbnail);
/** Returns true if the thumbnail for the specified asset in the specified size is in the stack of thumbnails to render */
bool IsInRenderStack(const TSharedPtr<FAssetThumbnail>& Thumbnail) const;
/** Returns true if the thumbnail for the specified asset in the specified size has been rendered */
bool IsRendered(const TSharedPtr<FAssetThumbnail>& Thumbnail) const;
/** Brings all items in ThumbnailsToPrioritize to the front of the render stack if they are actually in the stack */
UNREALED_API void PrioritizeThumbnails(const TArray<TSharedPtr<FAssetThumbnail>>& ThumbnailsToPrioritize, uint32 Width, uint32 Height);
/** Register/Unregister a callback for when thumbnails are rendered */
DECLARE_EVENT_OneParam(FAssetThumbnailPool, FThumbnailRendered, const FAssetData&);
FThumbnailRendered& OnThumbnailRendered() { return ThumbnailRenderedEvent; }
/** Register/Unregister a callback for when thumbnails fail to render */
DECLARE_EVENT_OneParam(FAssetThumbnailPool, FThumbnailRenderFailed, const FAssetData&);
FThumbnailRenderFailed& OnThumbnailRenderFailed() { return ThumbnailRenderFailedEvent; }
/** Re-renders the specified thumbnail */
UNREALED_API void RefreshThumbnail(const TSharedPtr<FAssetThumbnail>& ThumbnailToRefresh);
private:
/**
* Releases all rendering resources held by the pool
*/
void ReleaseResources();
/**
* Frees the rendering resources and clears a slot in the pool for an asset thumbnail at the specified width and height
*
* @param ObjectPath The path to the asset whose thumbnail should be free
* @param Width The width of the thumbnail to free
* @param Height The height of the thumbnail to free
*/
void FreeThumbnail(const FName& ObjectPath, uint32 Width, uint32 Height);
/** Adds the thumbnails associated with the object found at ObjectPath to the render stack */
void RefreshThumbnailsFor(FName ObjectPath);
/** Handler for when an asset is loaded */
void OnAssetLoaded(UObject* Asset);
/** Handler for when an actor is moved in a level. Used to update world asset thumbnails. */
void OnActorPostEditMove(AActor* Actor);
/** Handler for when an asset is loaded */
void OnObjectPropertyChanged(UObject* Asset, FPropertyChangedEvent& PropertyChangedEvent);
/** Handler to dirty cached thumbnails in packages to make sure they are re-rendered later */
void DirtyThumbnailForObject(UObject* ObjectBeingModified);
private:
/** Information about a thumbnail */
struct FThumbnailInfo
{
/** The object whose thumbnail is rendered */
FAssetData AssetData;
/** Rendering resource for slate */
FSlateTexture2DRHIRef* ThumbnailTexture;
/** Render target for slate */
FSlateTextureRenderTarget2DResource* ThumbnailRenderTarget;
/** The time since last access */
float LastAccessTime;
/** The time since last update */
float LastUpdateTime;
/** Width of the thumbnail */
uint32 Width;
/** Height of the thumbnail */
uint32 Height;
~FThumbnailInfo();
};
struct FThumbnailInfo_RenderThread
{
/** Rendering resource for slate */
FSlateTexture2DRHIRef* ThumbnailTexture;
/** Render target for slate */
FSlateTextureRenderTarget2DResource* ThumbnailRenderTarget;
/** Width of the thumbnail */
uint32 Width;
/** Height of the thumbnail */
uint32 Height;
FThumbnailInfo_RenderThread(const FThumbnailInfo& Info)
: ThumbnailTexture(Info.ThumbnailTexture), ThumbnailRenderTarget(Info.ThumbnailRenderTarget), Width(Info.Width), Height(Info.Height)
{}
};
/** Key for looking up thumbnails in a map */
struct FThumbId
{
FName ObjectPath;
uint32 Width;
uint32 Height;
FThumbId(const FName& InObjectPath, uint32 InWidth, uint32 InHeight)
: ObjectPath(InObjectPath), Width(InWidth), Height(InHeight)
{}
bool operator==(const FThumbId& Other) const
{
return ObjectPath == Other.ObjectPath && Width == Other.Width && Height == Other.Height;
}
friend uint32 GetTypeHash(const FThumbId& Id)
{
return GetTypeHash(Id.ObjectPath) ^ GetTypeHash(Id.Width) ^ GetTypeHash(Id.Height);
}
};
/** The delegate to execute when a thumbnail is rendered */
FThumbnailRendered ThumbnailRenderedEvent;
/** The delegate to execute when a thumbnail failed to render */
FThumbnailRenderFailed ThumbnailRenderFailedEvent;
/** A mapping of objects to their thumbnails */
TMap<FThumbId, TSharedRef<FThumbnailInfo>> ThumbnailToTextureMap;
/** List of thumbnails to render when possible */
TArray<TSharedRef<FThumbnailInfo>> ThumbnailsToRenderStack;
/** List of thumbnails that can be rendered in real-time */
TArray<TSharedRef<FThumbnailInfo>> RealTimeThumbnails;
/** List of real-time thumbnails that are queued to be rendered */
TArray<TSharedRef<FThumbnailInfo>> RealTimeThumbnailsToRender;
/** List of free thumbnails that can be reused */
TArray<TSharedRef<FThumbnailInfo>> FreeThumbnails;
/** A mapping of objects to the number of referencers */
TMap<FThumbId, int32> RefCountMap;
/** A list of object paths for recently loaded assets whose thumbnails need to be refreshed. */
TArray<FName> RecentlyLoadedAssets;
/** Attribute that determines if real-time thumbnails are allowed. Called every frame. */
TAttribute<bool> AreRealTimeThumbnailsAllowed;
/** Max number of thumbnails in the pool */
uint32 NumInPool;
/** Max number of dynamic thumbnails to update per frame */
uint32 MaxRealTimeThumbnailsPerFrame;
/** Max number of seconds per tick to spend rendering thumbnails */
double MaxFrameTimeAllowance;
};