// Copyright Epic Games, Inc. All Rights Reserved. #include "ThumbnailRendering/BlueprintThumbnailRenderer.h" #include "ShowFlags.h" #include "SceneView.h" #include "Misc/App.h" #include "Engine/InheritableComponentHandler.h" #include "Engine/SCS_Node.h" UBlueprintThumbnailRenderer::UBlueprintThumbnailRenderer(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } bool UBlueprintThumbnailRenderer::CanVisualizeAsset(UObject* Object) { UBlueprint* Blueprint = Cast(Object); // Only visualize actor based blueprints if (Blueprint && Blueprint->GeneratedClass && Blueprint->GeneratedClass->IsChildOf(AActor::StaticClass())) { // Try to find any visible primitive components in the native class' CDO AActor* CDO = Blueprint->GeneratedClass->GetDefaultObject(); for (UActorComponent* Component: CDO->GetComponents()) { if (FBlueprintThumbnailScene::IsValidComponentForVisualization(Component)) { return true; } } UBlueprint* BlueprintToHarvestComponents = Blueprint; TSet AllVisitedBlueprints; while (BlueprintToHarvestComponents) { AllVisitedBlueprints.Add(BlueprintToHarvestComponents); // Try to find any visible primitive components in the simple construction script if (BlueprintToHarvestComponents->SimpleConstructionScript) { for (USCS_Node* Node: BlueprintToHarvestComponents->SimpleConstructionScript->GetAllNodes()) { if (FBlueprintThumbnailScene::IsValidComponentForVisualization(Node->ComponentTemplate)) { return true; } } } // Check if any inheritable components from parents have valid data if (BlueprintToHarvestComponents->InheritableComponentHandler) { for (TArray::TIterator InheritedComponentsIter = BlueprintToHarvestComponents->InheritableComponentHandler->CreateRecordIterator(); InheritedComponentsIter; ++InheritedComponentsIter) { if (FBlueprintThumbnailScene::IsValidComponentForVisualization(InheritedComponentsIter->ComponentTemplate)) { return true; } } } UClass* ParentClass = BlueprintToHarvestComponents->ParentClass; BlueprintToHarvestComponents = nullptr; // If the parent class was a blueprint generated class, check it's simple construction script components as well if (ParentClass) { UBlueprint* ParentBlueprint = Cast(ParentClass->ClassGeneratedBy); // Also make sure we haven't visited the blueprint already. This would only happen if there was a loop of parent classes. if (ParentBlueprint && !AllVisitedBlueprints.Contains(ParentBlueprint)) { BlueprintToHarvestComponents = ParentBlueprint; } } } } return false; } void UBlueprintThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily) { UBlueprint* Blueprint = Cast(Object); // Strict validation - it may hopefully fix UE-35705. const bool bIsBlueprintValid = IsValid(Blueprint) && IsValid(Blueprint->GeneratedClass) && Blueprint->bHasBeenRegenerated //&& Blueprint->IsUpToDate() - This condition makes the thumbnail blank whenever the BP is dirty. It seems too strict. && !Blueprint->bBeingCompiled && !Blueprint->HasAnyFlags(RF_Transient); if (bIsBlueprintValid) { TSharedRef ThumbnailScene = ThumbnailScenes.EnsureThumbnailScene(Blueprint->GeneratedClass); ThumbnailScene->SetBlueprint(Blueprint); FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(RenderTarget, ThumbnailScene->GetScene(), FEngineShowFlags(ESFIM_Game)) .SetWorldTimes(FApp::GetCurrentTime() - GStartTime, FApp::GetDeltaTime(), FApp::GetCurrentTime() - GStartTime) .SetAdditionalViewFamily(bAdditionalViewFamily)); ViewFamily.EngineShowFlags.DisableAdvancedFeatures(); ViewFamily.EngineShowFlags.MotionBlur = 0; ThumbnailScene->GetView(&ViewFamily, X, Y, Width, Height); RenderViewFamily(Canvas, &ViewFamily); } } void UBlueprintThumbnailRenderer::BeginDestroy() { ThumbnailScenes.Clear(); Super::BeginDestroy(); } void UBlueprintThumbnailRenderer::BlueprintChanged(class UBlueprint* Blueprint) { if (Blueprint && Blueprint->GeneratedClass) { TSharedPtr ThumbnailScene = ThumbnailScenes.FindThumbnailScene(Blueprint->GeneratedClass); if (ThumbnailScene.IsValid()) { ThumbnailScene->BlueprintChanged(Blueprint); } } }