// Copyright 2019-Present LexLiu. All Rights Reserved. #include "Thumbnail/LGUIPrefabThumbnailScene.h" #include "Components/PrimitiveComponent.h" #include "ThumbnailRendering/SceneThumbnailInfo.h" #include "Core/ActorComponent/LGUICanvas.h" #include "LGUIEditorModule.h" #include "Core/Actor/UIContainerActor.h" #include "Core/ActorComponent/UIItem.h" #include "Utils/LGUIUtils.h" FLGUIPrefabInstanceThumbnailScene::FLGUIPrefabInstanceThumbnailScene() { InstancedThumbnailScenes.Reserve(MAX_NUM_SCENES); } TSharedPtr FLGUIPrefabInstanceThumbnailScene::FindThumbnailScene(const FString& InPrefabPath)const { return InstancedThumbnailScenes.FindRef(InPrefabPath); } TSharedRef FLGUIPrefabInstanceThumbnailScene::EnsureThumbnailScene(const FString& InPrefabPath) { TSharedPtr ExistingThumbnailScene = InstancedThumbnailScenes.FindRef(InPrefabPath); if (!ExistingThumbnailScene.IsValid()) { if (InstancedThumbnailScenes.Num() >= MAX_NUM_SCENES) { InstancedThumbnailScenes.Reset(); } ExistingThumbnailScene = MakeShareable(new FLGUIPrefabThumbnailScene()); InstancedThumbnailScenes.Add(InPrefabPath, ExistingThumbnailScene); } return ExistingThumbnailScene.ToSharedRef(); } void FLGUIPrefabInstanceThumbnailScene::Clear() { InstancedThumbnailScenes.Reset(); } FLGUIPrefabThumbnailScene::FLGUIPrefabThumbnailScene() :FThumbnailPreviewScene() , NumStartingActors(0) , CurrentPrefab(nullptr) { NumStartingActors = GetWorld()->GetCurrentLevel()->Actors.Num(); } void FLGUIPrefabThumbnailScene::SpawnPreviewActor() { if (CurrentPrefab.IsValid()) { if (auto RootActor = CurrentPrefab->LoadPrefabInEditor(GetWorld(), nullptr)) { if (auto PrefabRootUIItem = Cast(RootActor->GetRootComponent())) { auto RootCanvas = RootActor->FindComponentByClass(); auto CanvasSize = CurrentPrefab->PrefabDataForPrefabEditor.CanvasSize; auto AgentRootActor = GetWorld()->SpawnActor(); if (!RootCanvas) { RootCanvas = NewObject(AgentRootActor); RootCanvas->RegisterComponent(); RootActor->AddInstanceComponent(RootCanvas); } RootActor->AttachToComponent(AgentRootActor->GetUIItem(), FAttachmentTransformRules::KeepRelativeTransform); RootCanvas->MarkCanvasUpdate(true, true, true, true); RootCanvas->SetRenderMode(ELGUIRenderMode::WorldSpace); if (PrefabRootUIItem) { AgentRootActor->GetUIItem()->SetWidth(CanvasSize.X); AgentRootActor->GetUIItem()->SetHeight(CanvasSize.Y); } bIsUI = true; } else { bIsUI = false; } bool isFirstBounds = true; GetBoundsRecursive(RootActor->GetRootComponent(), PreviewActorsBound, isFirstBounds); if (isFirstBounds) { PreviewActorsBound = FBoxSphereBounds(EForceInit::ForceInitToZero); } if (PreviewActorsBound.SphereRadius < KINDA_SMALL_NUMBER)//if bounds is too small, set to 1x1 box { PreviewActorsBound = FBoxSphereBounds(FBox(FVector(-0.5f, -0.5f, -0.5f), FVector(0.5f, 0.5f, 0.5f))); } } } } void FLGUIPrefabThumbnailScene::GetBoundsRecursive(USceneComponent* RootComp, FBoxSphereBounds& OutBounds, bool& IsFirstPrimitive)const { if (!IsValid(RootComp))return; if (RootComp->IsA())return; if (RootComp->IsVisualizationComponent())return; FBoxSphereBounds Bounds = FBoxSphereBounds(EForceInit::ForceInitToZero); bool bIsValidBounds = false; if (RootComp->IsRegistered()) { auto UIItem = Cast(RootComp); if (UIItem != nullptr) { if (UIItem->GetIsUIActiveInHierarchy()) { Bounds = UIItem->Bounds; bIsValidBounds = true; } } else { Bounds = RootComp->Bounds; bIsValidBounds = true; } if (bIsValidBounds) { if (IsFirstPrimitive) { OutBounds = Bounds; IsFirstPrimitive = false; } else { OutBounds = OutBounds + Bounds; } } } auto childrenArray = RootComp->GetAttachChildren(); for (auto childComp : childrenArray) { GetBoundsRecursive(childComp, OutBounds, IsFirstPrimitive); } } void FLGUIPrefabThumbnailScene::ClearOldActors() { auto Level = GetWorld()->GetCurrentLevel(); for (int i = NumStartingActors; i < Level->Actors.Num(); i++) { if (Level->Actors[i]) { Level->Actors[i]->Destroy(); } } } bool FLGUIPrefabThumbnailScene::IsValidForVisualization() { if (CurrentPrefab.Get()) { if (CurrentPrefab->BinaryData.Num() == 0) return false; } if (PreviewActorsBound.ContainsNaN()) { UE_LOG(LGUIEditor, Warning, TEXT("[FLGUIPrefabThumbnailScene::IsValidForVisualization]prefab:%s bounds is invalid!"), *(CurrentPrefab->GetPathName())); return false; } return true; } void FLGUIPrefabThumbnailScene::GetViewMatrixParameters(const float InFOVDegrees, FVector& OutOrigin, float& OutOrbitPitch, float& OutOrbitYaw, float& OutOrbitZoom)const { const float HalfFOVRadians = FMath::DegreesToRadians(InFOVDegrees) * 0.5f; const float PreviewSize = PreviewActorsBound.SphereRadius * 1.2f; const float BoundsZOffset = GetBoundsZOffset(PreviewActorsBound); const float TargetDistance = PreviewSize / FMath::Tan(HalfFOVRadians); USceneThumbnailInfo* ThumbnailInfo = GetSceneThumbnailInfo(TargetDistance); check(ThumbnailInfo); OutOrigin = -1 * PreviewActorsBound.Origin; OutOrbitPitch = ThumbnailInfo->OrbitPitch; OutOrbitYaw = ThumbnailInfo->OrbitYaw; OutOrbitZoom = TargetDistance + ThumbnailInfo->OrbitZoom; } void FLGUIPrefabThumbnailScene::SetPrefab(class ULGUIPrefab* Prefab) { if (!CurrentPrefab.IsValid()) { CurrentPrefab = nullptr; ClearOldActors(); } if (CurrentPrefab.IsValid() && IsValid(Prefab)) { if (CurrentPrefab == Prefab && !CurrentPrefab->ThumbnailDirty) { return; } ClearOldActors(); } CurrentPrefab = Prefab; CurrentPrefab->ThumbnailDirty = false; if (IsValid(Prefab)) { SpawnPreviewActor(); } } USceneThumbnailInfo* FLGUIPrefabThumbnailScene::GetSceneThumbnailInfo(const float TargetDistance)const { ULGUIPrefab* Prefab = CurrentPrefab.Get(); check(Prefab); USceneThumbnailInfo* ThumbnailInfo = Cast(Prefab->ThumbnailInfo); if (!IsValid(ThumbnailInfo)) { ThumbnailInfo = NewObject(Prefab); Prefab->ThumbnailInfo = ThumbnailInfo; } if (bIsUI) { ThumbnailInfo->OrbitPitch = 0; ThumbnailInfo->OrbitYaw = 90.0f; ThumbnailInfo->OrbitZoom = 0; } else { ThumbnailInfo->OrbitPitch = -11.25f; ThumbnailInfo->OrbitYaw = -157.5f; ThumbnailInfo->OrbitZoom = 0; } return ThumbnailInfo; }