77#include " HAL/PlatformProcess.h"
88#include " IESConverter.h"
99#include " ImageUtils.h"
10- #include " TextureCompiler.h"
1110#if WITH_EDITOR
1211#include " Factories/TextureFactory.h"
13- #include " ThumbnailRendering/ThumbnailManager.h"
1412#endif
1513
1614// RapyutaSimulationPlugins
2624#include " Core/RRThreadUtils.h"
2725#include " Core/RRTypeUtils.h"
2826#include " Core/RRUObjectUtils.h"
27+ #include " RapyutaSimulationPlugins.h"
28+
29+
2930
3031IImageWrapperModule* URRCoreUtils::SImageWrapperModule = nullptr ;
3132TMap<ERRFileType, TSharedPtr<IImageWrapper>> URRCoreUtils::SImageWrappers;
@@ -303,6 +304,12 @@ bool URRCoreUtils::CheckWithTimeOut(const TFunctionRef<bool()>& InCondition,
303304//
304305UTexture2D* URRCoreUtils::LoadImageToTexture (const FString& InFullFilePath, const FString& InTextureName, const bool bInSaveToAsset)
305306{
307+ if (InTextureName.IsEmpty ())
308+ {
309+ UE_LOG_WITH_INFO_SHORT (LogRapyutaCore, Error, TEXT (" Image path [%s] - InTextureName is empty" ));
310+ return nullptr ;
311+ }
312+
306313 if (bInSaveToAsset)
307314 {
308315#if WITH_EDITOR
@@ -316,7 +323,7 @@ UTexture2D* URRCoreUtils::LoadImageToTexture(const FString& InFullFilePath, cons
316323 // Save [texture] to uasset file on disk, logged here-in
317324 return URRAssetUtils::SavePackageToAsset (texturePkg, texture) ? texture : nullptr ;
318325#else
319- UE_LOG_WITH_INFO (LogTemp , Error, TEXT (" Texture saving to uasset is Editor-only feature" ));
326+ UE_LOG_WITH_INFO_SHORT (LogRapyutaCore , Error, TEXT (" Texture saving to uasset is Editor-only feature" ));
320327 return nullptr ;
321328#endif
322329 }
@@ -333,6 +340,7 @@ UTexture2D* URRCoreUtils::LoadImageToTexture(const FString& InFullFilePath, cons
333340 texture = FImageUtils::ImportFileAsTexture2D (InFullFilePath);
334341 if (texture)
335342 {
343+ texture = FImageUtils::ImportFileAsTexture2D (InFullFilePath);
336344 texture->Rename (*InTextureName);
337345 }
338346 return texture;
@@ -487,173 +495,3 @@ bool URRCoreUtils::LoadIESProfilesFromFolder(const FString& InFolderPath,
487495
488496 return bResult;
489497}
490-
491- // -------------------------------------------------------------------------------------------------------------------------
492- // GRAPHICS UTILS --
493- //
494- #if WITH_EDITOR
495- bool URRCoreUtils::RenderThumbnail (UObject* InObject,
496- uint32 InImageWidth,
497- uint32 InImageHeight,
498- const ThumbnailTools::EThumbnailTextureFlushMode::Type InFlushMode,
499- FObjectThumbnail* OutThumbnail)
500- {
501- // Renderer must be initialized before generating thumbnails
502- if (!ensure (FApp::CanEverRender ()))
503- {
504- return false ;
505- }
506- if (!ensure (GIsRHIInitialized))
507- {
508- return false ;
509- }
510-
511- // Get the rendering info for this object
512- FThumbnailRenderingInfo* renderInfo = UThumbnailManager::Get ().GetRenderingInfo (InObject);
513- if ((nullptr == renderInfo) || (nullptr == renderInfo->Renderer ))
514- {
515- UE_LOG_WITH_INFO_SHORT (LogRapyutaCore,
516- Error,
517- TEXT (" [ThumbnailManager] No rendering info found for class [%s]" ),
518- *InObject->GetClass ()->GetName ());
519- return false ;
520- }
521-
522- if (false == renderInfo->Renderer ->CanVisualizeAsset (InObject))
523- {
524- UE_LOG_WITH_INFO_SHORT (LogRapyutaCore,
525- Error,
526- TEXT (" [%s] cannot be visualized, probably due to invalid rendering resource" ),
527- *InObject->GetName ());
528- return false ;
529- }
530-
531- // Thumbnail size
532- if (OutThumbnail)
533- {
534- OutThumbnail->SetImageSize (InImageWidth, InImageHeight);
535- }
536-
537- // Create a static texture render target, as commonly used for all thumbnails
538- static UTextureRenderTarget2D* sThumbnailRenderTarget = []()
539- {
540- // Create thumbnail render target
541- UTextureRenderTarget2D* renderTarget = NewObject<UTextureRenderTarget2D>(GetTransientPackage ());
542- renderTarget->AddToRoot ();
543- renderTarget->ClearColor = FLinearColor::Transparent;
544- renderTarget->TargetGamma = GEngine->GetDisplayGamma ();
545- renderTarget->RenderTargetFormat = RTF_RGBA8;
546- return renderTarget;
547- }();
548- sThumbnailRenderTarget ->InitAutoFormat (InImageWidth, InImageHeight);
549- auto * renderTargetResource = sThumbnailRenderTarget ->GameThread_GetRenderTargetResource ();
550-
551- // Create a canvas for the render target and clear it to black
552- FCanvas canvas (renderTargetResource, nullptr , FGameTime::GetTimeSinceAppStart (), GMaxRHIFeatureLevel);
553- canvas.Clear (FLinearColor::Transparent);
554-
555- // Wait for all textures to be streamed in before rendering the thumbnail
556- // @todo CB: This helps but doesn't 100% guarantee fully-streamed-in resources!
557- if (ThumbnailTools::EThumbnailTextureFlushMode::AlwaysFlush == InFlushMode)
558- {
559- if (GShaderCompilingManager)
560- {
561- GShaderCompilingManager->ProcessAsyncResults (false , true );
562- }
563-
564- if (UTexture* texture = Cast<UTexture>(InObject))
565- {
566- FTextureCompilingManager::Get ().FinishCompilation ({texture});
567- }
568-
569- FlushAsyncLoading ();
570- IStreamingManager::Get ().StreamAllResources (100 .f );
571- }
572-
573- // Make sure we suppress any message dialogs that might result from constructing
574- // or initializing any of the renderable objects.
575- {
576- TGuardValue<bool > Unattended (GIsRunningUnattendedScript, true );
577-
578- // Draw thumbnail onto [canvas]
579- renderInfo->Renderer ->Draw (
580- InObject, 0 , 0 , InImageWidth, InImageHeight, renderTargetResource, &canvas, false /* bAdditionalViewFamily*/ );
581- }
582-
583- // Flush [canvas], tell rendering thread to finish drawing batched elements
584- canvas.Flush_GameThread ();
585- {
586- ENQUEUE_RENDER_COMMAND (UpdateThumbnailRTCommand)
587- (
588- [renderTargetResource](FRHICommandListImmediate& RHICmdList) {
589- TransitionAndCopyTexture (
590- RHICmdList, renderTargetResource->GetRenderTargetTexture (), renderTargetResource->TextureRHI , {});
591- });
592-
593- if (OutThumbnail)
594- {
595- const FIntRect thumbnailRect (0 , 0 , OutThumbnail->GetImageWidth (), OutThumbnail->GetImageHeight ());
596- TArray<uint8>& outThumbnailData = OutThumbnail->AccessImageData ();
597-
598- outThumbnailData.Empty ();
599- outThumbnailData.AddUninitialized (OutThumbnail->GetImageWidth () * OutThumbnail->GetImageHeight () * sizeof (FColor));
600-
601- // Read remote texture's contents (GPU) back to system memory (CPU)
602- renderTargetResource->ReadPixelsPtr ((FColor*)outThumbnailData.GetData (), FReadSurfaceDataFlags (), thumbnailRect);
603- }
604- }
605- return true ;
606- }
607- #endif
608-
609- bool URRCoreUtils::GenerateThumbnail (UObject* InObject, uint32 InImageWidth, uint32 InImageHeight, const FString& InSaveImagePath)
610- {
611- if (IsRunningCommandlet () && !IsAllowCommandletRendering ())
612- {
613- UE_LOG_WITH_INFO_SHORT (
614- LogRapyutaCore,
615- Warning,
616- TEXT (" [%s] is running without [-AllowCommandletRendering], thus unable to generate [%s]'s thumbnail!" ),
617- *GetRunningCommandletClass ()->GetName (),
618- *InObject->GetName ());
619- return false ;
620- }
621- #if WITH_EDITOR
622- FObjectThumbnail thumbnail;
623- // Already logged here-in
624- if (false == URRCoreUtils::RenderThumbnail (
625- InObject, InImageWidth, InImageHeight, ThumbnailTools::EThumbnailTextureFlushMode::AlwaysFlush, &thumbnail))
626- {
627- return false ;
628- }
629-
630- // Ref: FImageUtils::ThumbnailCompressImageArray()
631- #if RAPYUTA_SIM_DEBUG
632- FColor* thumbnailColorData = (FColor*)thumbnail.AccessImageData ().GetData ();
633- // Thumbnails are saved as RGBA but FColors are stored as BGRA. An option to swap the order upon compression may be added at
634- // some point. At the moment, manually swapping Red and Blue
635- for (int32 i = 0 ; i < InImageWidth * InImageHeight; ++i)
636- {
637- Swap (thumbnailColorData[i].R , thumbnailColorData[i].B );
638- }
639- #endif
640-
641- // Compress thumbnail data & save to disk
642- thumbnail.CompressImageData ();
643- if (FFileHelper::SaveArrayToFile (thumbnail.AccessCompressedImageData (), *InSaveImagePath))
644- {
645- UE_LOG_WITH_INFO_SHORT (
646- LogRapyutaCore, Log, TEXT (" [%s]'s thumbnail has been saved to file [%s]" ), *InObject->GetName (), *InSaveImagePath);
647- return true ;
648- }
649- else
650- {
651- UE_LOG_WITH_INFO_SHORT (
652- LogRapyutaCore, Error, TEXT (" Failed saving [%s]'s thumbnail to file [%s]" ), *InObject->GetName (), *InSaveImagePath);
653- return false ;
654- }
655- #else
656- UE_LOG_WITH_INFO_SHORT (LogRapyutaCore, Error, TEXT (" Editor-only API" ));
657- return false ;
658- #endif
659- }
0 commit comments