diff --git a/Source/PrefabricatorEditor/PrefabricatorEditor.Build.cs b/Source/PrefabricatorEditor/PrefabricatorEditor.Build.cs index 6a2eb3d0..6f105964 100644 --- a/Source/PrefabricatorEditor/PrefabricatorEditor.Build.cs +++ b/Source/PrefabricatorEditor/PrefabricatorEditor.Build.cs @@ -39,6 +39,7 @@ public PrefabricatorEditor(ReadOnlyTargetRules Target) : base(Target) "Kismet", "PlacementMode", "EditorWidgets", + "RHI" } ); diff --git a/Source/PrefabricatorEditor/Private/PrefabricatorEditorModule.cpp b/Source/PrefabricatorEditor/Private/PrefabricatorEditorModule.cpp index f7b3e084..44198dfd 100644 --- a/Source/PrefabricatorEditor/Private/PrefabricatorEditorModule.cpp +++ b/Source/PrefabricatorEditor/Private/PrefabricatorEditorModule.cpp @@ -62,13 +62,6 @@ class FPrefabricatorEditorModule : public IPrefabricatorEditorModule // Override the prefabricator service with the editor version, so the runtime module can access it FPrefabricatorService::Set(MakeShareable(new FPrefabricatorEditorService)); - - const UPrefabricatorSettings* PS = GetDefault(); - if (PS->bShowAssetThumbnails) - { - // Setup the thumbnail renderer for the prefab asset - UThumbnailManager::Get().RegisterCustomRenderer(UPrefabricatorAsset::StaticClass(), UPrefabricatorAssetThumbnailRenderer::StaticClass()); - } } virtual void ShutdownModule() override { diff --git a/Source/PrefabricatorEditor/Private/UI/PrefabCustomization.cpp b/Source/PrefabricatorEditor/Private/UI/PrefabCustomization.cpp index 1f59e940..b5e37b2e 100644 --- a/Source/PrefabricatorEditor/Private/UI/PrefabCustomization.cpp +++ b/Source/PrefabricatorEditor/Private/UI/PrefabCustomization.cpp @@ -146,22 +146,6 @@ void FPrefabActorCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBui .Text(LOCTEXT("PrefabCollectionCommand_RecreateCollection", "Reload Prefab")) .OnClicked(FOnClicked::CreateStatic(&FPrefabActorCustomization::HandleLoadFromAsset, &DetailBuilder)) ]; - - } - - - const UPrefabricatorSettings* PS = GetDefault(); - if (!PS->bShowAssetThumbnails) - { - // Add an option to save the viewport image as a thumbnail for the asset - IDetailCategoryBuilder& Category = DetailBuilder.EditCategory("Prefab Collection Actions", FText::GetEmpty(), ECategoryPriority::Important); - Category.AddCustomRow(LOCTEXT("PrefabThumb_Filter", "thumbnail thumb")) - .WholeRowContent() - [ - SNew(SButton) - .Text(LOCTEXT("PrefabThumbCommand_SaveThumbnail", "Update Thumbnail")) - .OnClicked(FOnClicked::CreateStatic(&FPrefabActorCustomization::UpdateThumbFromViewport, &DetailBuilder)) - ]; } } @@ -200,8 +184,7 @@ FReply FPrefabActorCustomization::HandleSaveToNewAsset(IDetailLayoutBuilder* Det TArray Children; PrefabActor->GetAttachedActors(Children); - if(Children.Num() > 0) - { + if(Children.Num() > 0) { FPrefabTools::UnlinkAndDestroyPrefabActor(PrefabActor); FPrefabTools::CreatePrefabFromActors(Children); } @@ -252,23 +235,6 @@ FReply FPrefabActorCustomization::UnlinkPrefab(IDetailLayoutBuilder* DetailBuild return FReply::Handled(); } -FReply FPrefabActorCustomization::UpdateThumbFromViewport(IDetailLayoutBuilder* DetailBuilder) -{ - if (GEditor) { - TArray PrefabActors = GetDetailObject(DetailBuilder); - for (APrefabActor* PrefabActor : PrefabActors) { - if (PrefabActor) { - UPrefabricatorAsset* Asset = PrefabActor->GetPrefabAsset(); - IContentBrowserSingleton& ContentBrowser = FModuleManager::LoadModuleChecked("ContentBrowser").Get(); - TArray AssetList; - AssetList.Add(FAssetData(Asset)); - ContentBrowser.CaptureThumbnailFromViewport(GEditor->GetActiveViewport(), AssetList); - } - } - } - return FReply::Handled(); -} - ///////////////////////////////// FPrefabRandomizerCustomization ///////////////////////////////// void FPrefabRandomizerCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) diff --git a/Source/PrefabricatorEditor/Private/Utils/PrefabEditorTools.cpp b/Source/PrefabricatorEditor/Private/Utils/PrefabEditorTools.cpp index 98f8ff1e..3d101847 100644 --- a/Source/PrefabricatorEditor/Private/Utils/PrefabEditorTools.cpp +++ b/Source/PrefabricatorEditor/Private/Utils/PrefabEditorTools.cpp @@ -9,6 +9,15 @@ #include "EditorViewportClient.h" #include "EngineUtils.h" #include "Framework/Notifications/NotificationManager.h" +#include "ObjectTools.h" +#include "AssetData.h" +#include "Asset/PrefabricatorAsset.h" +#include "Kismet/KismetRenderingLibrary.h" +#include "Engine/TextureRenderTarget2D.h" +#include "Asset/Thumbnail/PrefabricatorAssetThumbnailScene.h" +#include "EngineModule.h" +#include "LegacyScreenPercentageDriver.h" +#include "Engine/Canvas.h" void FPrefabEditorTools::ReloadPrefabsInLevel(UWorld* World, UPrefabricatorAsset* InAsset) { @@ -59,3 +68,106 @@ void FPrefabEditorTools::SwitchLevelViewportToRealtimeMode() } } +void FPrefabEditorTools::CapturePrefabAssetThumbnail(UPrefabricatorAsset* InAsset) +{ + int32 ThumbSize = 512; + + TArray Bitmap; + { + FPrefabricatorAssetThumbnailScene ThumbnailScene; + UWorld* World = ThumbnailScene.GetWorld(); + ThumbnailScene.SetPrefabAsset(InAsset); + + UTextureRenderTarget2D* RTT = UKismetRenderingLibrary::CreateRenderTarget2D(World, ThumbSize, ThumbSize, RTF_RGBA32f); + FTextureRenderTargetResource* RTTResource = RTT->GameThread_GetRenderTargetResource(); + + FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(RTTResource, ThumbnailScene.GetScene(), FEngineShowFlags(ESFIM_Game)) + .SetWorldTimes(FApp::GetCurrentTime() - GStartTime, FApp::GetDeltaTime(), FApp::GetCurrentTime() - GStartTime)); + + ViewFamily.EngineShowFlags.DisableAdvancedFeatures(); + ViewFamily.EngineShowFlags.MotionBlur = 0; + ViewFamily.EngineShowFlags.LOD = 0; + + ThumbnailScene.GetView(&ViewFamily, 0, 0, ThumbSize, ThumbSize); + + ViewFamily.EngineShowFlags.ScreenPercentage = false; + ViewFamily.SetScreenPercentageInterface(new FLegacyScreenPercentageDriver( + ViewFamily, /* GlobalResolutionFraction = */ 1.0f, /* AllowPostProcessSettingsScreenPercentage = */ false)); + + FVector2D CanvasSize; + UCanvas* Canvas = nullptr; + FDrawToRenderTargetContext RenderContext; + UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(World, RTT, Canvas, CanvasSize, RenderContext); + + GetRendererModule().BeginRenderingViewFamily(Canvas->Canvas, &ViewFamily); + Canvas->Canvas->Flush_GameThread(true); + + ENQUEUE_RENDER_COMMAND(UpdateThumbnailRTCommand)( + [RTTResource](FRHICommandListImmediate& RHICmdList) + { + // Copy (resolve) the rendered thumbnail from the render target to its texture + RHICmdList.CopyToResolveTarget( + RTTResource->GetRenderTargetTexture(), // Source texture + RTTResource->TextureRHI, // Dest texture + FResolveParams() ); // Resolve parameters + }); + + + RTTResource->ReadPixels(Bitmap); + check(Bitmap.Num() == ThumbSize * ThumbSize); + + UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(World, RenderContext); + UKismetRenderingLibrary::ReleaseRenderTarget2D(RTT); + } + /* + Bitmap.AddUninitialized(ThumbSize * ThumbSize); + for (int i = 0; i < Bitmap.Num(); i++) { + Bitmap[i] = FColor::Blue; + } + */ + + //setup actual thumbnail + FObjectThumbnail TempThumbnail; + TempThumbnail.SetImageSize(ThumbSize, ThumbSize); + TArray& ThumbnailByteArray = TempThumbnail.AccessImageData(); + + // Copy scaled image into destination thumb + int32 MemorySize = ThumbSize * ThumbSize * sizeof(FColor); + ThumbnailByteArray.AddUninitialized(MemorySize); + FMemory::Memcpy(&(ThumbnailByteArray[0]), &(Bitmap[0]), MemorySize); + + FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); + + //check if each asset should receive the new thumb nail + { + const FAssetData CurrentAsset = FAssetData(InAsset); + + //assign the thumbnail and dirty + const FString ObjectFullName = CurrentAsset.GetFullName(); + const FString PackageName = CurrentAsset.PackageName.ToString(); + + UPackage* AssetPackage = FindObject(NULL, *PackageName); + if (ensure(AssetPackage)) + { + FObjectThumbnail* NewThumbnail = ThumbnailTools::CacheThumbnail(ObjectFullName, &TempThumbnail, AssetPackage); + if (ensure(NewThumbnail)) + { + //we need to indicate that the package needs to be re-saved + AssetPackage->MarkPackageDirty(); + + // Let the content browser know that we've changed the thumbnail + NewThumbnail->MarkAsDirty(); + + // Signal that the asset was changed if it is loaded so thumbnail pools will update + if (CurrentAsset.IsAssetLoaded()) + { + CurrentAsset.GetAsset()->PostEditChange(); + } + + //Set that thumbnail as a valid custom thumbnail so it'll be saved out + NewThumbnail->SetCreatedAfterCustomThumbsEnabled(); + } + } + } +} + diff --git a/Source/PrefabricatorEditor/Private/Utils/PrefabricatorEditorService.cpp b/Source/PrefabricatorEditor/Private/Utils/PrefabricatorEditorService.cpp index c799d03a..ea82d00c 100644 --- a/Source/PrefabricatorEditor/Private/Utils/PrefabricatorEditorService.cpp +++ b/Source/PrefabricatorEditor/Private/Utils/PrefabricatorEditorService.cpp @@ -150,3 +150,9 @@ void FPrefabricatorEditorService::RunGC() CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); } +void FPrefabricatorEditorService::CaptureThumb(UPrefabricatorAsset* PrefabAsset) +{ + // Save the thumbnail + FPrefabEditorTools::CapturePrefabAssetThumbnail(PrefabAsset); +} + diff --git a/Source/PrefabricatorEditor/Public/UI/PrefabCustomization.h b/Source/PrefabricatorEditor/Public/UI/PrefabCustomization.h index fbb2881d..0bcaa303 100644 --- a/Source/PrefabricatorEditor/Public/UI/PrefabCustomization.h +++ b/Source/PrefabricatorEditor/Public/UI/PrefabCustomization.h @@ -18,7 +18,6 @@ class PREFABRICATOREDITOR_API FPrefabActorCustomization : public IDetailCustomiz static FReply HandleLoadFromAsset(IDetailLayoutBuilder* DetailBuilder); static FReply RandomizePrefabCollection(IDetailLayoutBuilder* DetailBuilder); static FReply UnlinkPrefab(IDetailLayoutBuilder* DetailBuilder); - static FReply UpdateThumbFromViewport(IDetailLayoutBuilder* DetailBuilder); }; class PREFABRICATOREDITOR_API FPrefabRandomizerCustomization : public IDetailCustomization { diff --git a/Source/PrefabricatorEditor/Public/Utils/PrefabEditorTools.h b/Source/PrefabricatorEditor/Public/Utils/PrefabEditorTools.h index 4aebfc0e..8b62cfa6 100644 --- a/Source/PrefabricatorEditor/Public/Utils/PrefabEditorTools.h +++ b/Source/PrefabricatorEditor/Public/Utils/PrefabEditorTools.h @@ -18,6 +18,8 @@ class PREFABRICATOREDITOR_API FPrefabEditorTools { static void SwitchLevelViewportToRealtimeMode(); + static void CapturePrefabAssetThumbnail(UPrefabricatorAsset* InAsset); + template static T* CreateAssetOnContentBrowser(const FString& InAssetName, bool bSyncBrowserToAsset) { diff --git a/Source/PrefabricatorEditor/Public/Utils/PrefabricatorEditorService.h b/Source/PrefabricatorEditor/Public/Utils/PrefabricatorEditorService.h index 3f85e47e..bf576de7 100644 --- a/Source/PrefabricatorEditor/Public/Utils/PrefabricatorEditorService.h +++ b/Source/PrefabricatorEditor/Public/Utils/PrefabricatorEditorService.h @@ -17,5 +17,6 @@ class PREFABRICATOREDITOR_API FPrefabricatorEditorService : public IPrefabricato virtual void BeginTransaction(const FText& Description) override; virtual void EndTransaction() override; virtual void RunGC() override; + virtual void CaptureThumb(UPrefabricatorAsset* PrefabAsset) override; }; diff --git a/Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp b/Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp index 3ea3f894..e1a0891f 100644 --- a/Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp +++ b/Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp @@ -134,18 +134,18 @@ namespace { } } -void FPrefabTools::CreatePrefabFromActors(const TArray& InActors) +APrefabActor* FPrefabTools::CreatePrefabFromActors(const TArray& InActors) { TArray Actors; SanitizePrefabActorsForCreation(InActors, Actors); if (Actors.Num() == 0) { - return; + return nullptr; } UPrefabricatorAsset* PrefabAsset = CreatePrefabAsset(); if (!PrefabAsset) { - return; + return nullptr; } TSharedPtr Service = FPrefabricatorService::Get(); @@ -176,6 +176,7 @@ void FPrefabTools::CreatePrefabFromActors(const TArray& InActors) SelectPrefabActor(PrefabActor); + return PrefabActor; } void FPrefabTools::AssignAssetUserData(AActor* InActor, const FGuid& InItemID, APrefabActor* Prefab) @@ -254,6 +255,11 @@ void FPrefabTools::SaveStateToPrefabAsset(APrefabActor* PrefabActor) PrefabAsset->LastUpdateID = FGuid::NewGuid(); PrefabActor->LastUpdateID = PrefabAsset->LastUpdateID; PrefabAsset->Modify(); + + TSharedPtr Service = FPrefabricatorService::Get(); + if (Service.IsValid()) { + Service->CaptureThumb(PrefabAsset); + } } namespace { diff --git a/Source/PrefabricatorRuntime/Public/Prefab/PrefabTools.h b/Source/PrefabricatorRuntime/Public/Prefab/PrefabTools.h index 95057678..3e72f20b 100644 --- a/Source/PrefabricatorRuntime/Public/Prefab/PrefabTools.h +++ b/Source/PrefabricatorRuntime/Public/Prefab/PrefabTools.h @@ -27,7 +27,7 @@ class PREFABRICATORRUNTIME_API FPrefabTools { public: static bool CanCreatePrefab(); static void CreatePrefab(); - static void CreatePrefabFromActors(const TArray& Actors); + static APrefabActor* CreatePrefabFromActors(const TArray& Actors); static void AssignAssetUserData(AActor* InActor, const FGuid& InItemID, APrefabActor* Prefab); static void SaveStateToPrefabAsset(APrefabActor* PrefabActor); diff --git a/Source/PrefabricatorRuntime/Public/PrefabricatorSettings.h b/Source/PrefabricatorRuntime/Public/PrefabricatorSettings.h index e7c2d914..f112a3a4 100644 --- a/Source/PrefabricatorRuntime/Public/PrefabricatorSettings.h +++ b/Source/PrefabricatorRuntime/Public/PrefabricatorSettings.h @@ -30,9 +30,6 @@ class PREFABRICATORRUNTIME_API UPrefabricatorSettings : public UDeveloperSetting UPROPERTY(EditAnywhere, BlueprintReadOnly, config, Category = "Settings") bool bAllowDynamicUpdate = true; - UPROPERTY(EditAnywhere, BlueprintReadOnly, config, Category = "Settings", meta = (ConfigRestartRequired = true)) - bool bShowAssetThumbnails = true; - public: UPrefabricatorSettings(); diff --git a/Source/PrefabricatorRuntime/Public/Utils/PrefabricatorService.h b/Source/PrefabricatorRuntime/Public/Utils/PrefabricatorService.h index 839c1a75..cf0c3594 100644 --- a/Source/PrefabricatorRuntime/Public/Utils/PrefabricatorService.h +++ b/Source/PrefabricatorRuntime/Public/Utils/PrefabricatorService.h @@ -39,6 +39,7 @@ class PREFABRICATORRUNTIME_API IPrefabricatorService { virtual void BeginTransaction(const FText& Description) {} virtual void EndTransaction() {} virtual void RunGC() {} + virtual void CaptureThumb(UPrefabricatorAsset* PrefabAsset) {} }; class PREFABRICATORRUNTIME_API FPrefabricatorRuntimeService : public IPrefabricatorService {