// 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 HighlightedText; TAttribute HintColorAndOpacity; TOptional AssetTypeColorOverride; }; /** * Interface for rendering a thumbnail in a slate viewport */ class FAssetThumbnail : public ISlateViewport , public TSharedFromThis { 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& InThumbnailPool); UNREALED_API FAssetThumbnail(const FAssetData& InAsset, uint32 InWidth, uint32 InHeight, const TSharedPtr& 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 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 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& 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& Thumbnail) const; /** Returns true if the thumbnail for the specified asset in the specified size has been rendered */ bool IsRendered(const TSharedPtr& 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>& 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& 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> ThumbnailToTextureMap; /** List of thumbnails to render when possible */ TArray> ThumbnailsToRenderStack; /** List of thumbnails that can be rendered in real-time */ TArray> RealTimeThumbnails; /** List of real-time thumbnails that are queued to be rendered */ TArray> RealTimeThumbnailsToRender; /** List of free thumbnails that can be reused */ TArray> FreeThumbnails; /** A mapping of objects to the number of referencers */ TMap RefCountMap; /** A list of object paths for recently loaded assets whose thumbnails need to be refreshed. */ TArray RecentlyLoadedAssets; /** Attribute that determines if real-time thumbnails are allowed. Called every frame. */ TAttribute 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; };