void UUnrealEdEngine::DrawComponentVisualizersHUD(const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) { // Iterate over all selected actors for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = Cast<AActor>(*It); if (Actor != NULL) { // Then iterate over components of that actor TInlineComponentArray<UActorComponent*> Components; Actor->GetComponents(Components); for (int32 CompIdx = 0; CompIdx<Components.Num(); CompIdx++) { UActorComponent* Comp = Components[CompIdx]; if (Comp->IsRegistered()) { // Try and find a visualizer TSharedPtr<FComponentVisualizer> Visualizer = FindComponentVisualizer(Comp->GetClass()); if (Visualizer.IsValid()) { Visualizer->DrawVisualizationHUD(Comp, Viewport, View, Canvas); } } } } } }
USkeleton* FAnimationTrackEditor::AcquireSkeletonFromObjectGuid(const FGuid& Guid) { TArray<UObject*> OutObjects; GetSequencer()->GetRuntimeObjects(GetSequencer()->GetFocusedMovieSceneInstance(), Guid, OutObjects); USkeleton* Skeleton = NULL; for (int32 i = 0; i < OutObjects.Num(); ++i) { AActor* Actor = Cast<AActor>(OutObjects[i]); if (Actor != NULL) { TInlineComponentArray<USkeletalMeshComponent*> SkeletalMeshComponents; Actor->GetComponents(SkeletalMeshComponents); for (int32 j = 0; j <SkeletalMeshComponents.Num(); ++j) { USkeletalMeshComponent* SkeletalMeshComp = SkeletalMeshComponents[j]; if (SkeletalMeshComp->SkeletalMesh && SkeletalMeshComp->SkeletalMesh->Skeleton) { // @todo Multiple actors, multiple components check(!Skeleton); Skeleton = SkeletalMeshComp->SkeletalMesh->Skeleton; } } } } return Skeleton; }
void UUnrealEdEngine::SetActorSelectionFlags (AActor* InActor) { TInlineComponentArray<UActorComponent*> Components; InActor->GetComponents(Components); //for every component in the actor for(int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++) { UActorComponent* Component = Components[ComponentIndex]; if (Component->IsRegistered()) { // If we have a 'child actor' component, want to update its visible selection state UChildActorComponent* ChildActorComponent = Cast<UChildActorComponent>(Component); if(ChildActorComponent != NULL && ChildActorComponent->ChildActor != NULL) { SetActorSelectionFlags(ChildActorComponent->ChildActor); } UPrimitiveComponent* PrimComponent = Cast<UPrimitiveComponent>(Component); if(PrimComponent != NULL && PrimComponent->IsRegistered()) { PrimComponent->PushSelectionToProxy(); } UDecalComponent* DecalComponent = Cast<UDecalComponent>(Component); if(DecalComponent != NULL)// && DecalComponent->IsRegistered()) { DecalComponent->PushSelectionToProxy(); } } } }
void AActor::CheckForErrors() { if ( GetClass()->HasAnyClassFlags(CLASS_Deprecated) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_ActorIsObselete_Deprecated", "{ActorName} : Obsolete and must be removed! (Class is deprecated)" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::ActorIsObselete)); return; } if ( GetClass()->HasAnyClassFlags(CLASS_Abstract) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_ActorIsObselete_Abstract", "{ActorName} : Obsolete and must be removed! (Class is abstract)" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::ActorIsObselete)); return; } UPrimitiveComponent* PrimComp = Cast<UPrimitiveComponent>(RootComponent); if( PrimComp && (PrimComp->Mobility != EComponentMobility::Movable) && PrimComp->BodyInstance.bSimulatePhysics) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Warning() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_StaticPhysNone", "{ActorName} : Static object with bSimulatePhysics set to true" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::StaticPhysNone)); } if( RootComponent && FMath::IsNearlyZero( GetRootComponent()->RelativeScale3D.X * GetRootComponent()->RelativeScale3D.Y * GetRootComponent()->RelativeScale3D.Z ) ) { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ActorName"), FText::FromString(GetName())); FMessageLog("MapCheck").Error() ->AddToken(FUObjectToken::Create(this)) ->AddToken(FTextToken::Create(FText::Format(LOCTEXT( "MapCheck_Message_InvalidDrawscale", "{ActorName} : Invalid DrawScale/DrawScale3D" ), Arguments) )) ->AddToken(FMapErrorToken::Create(FMapErrors::InvalidDrawscale)); } // Route error checking to components. TInlineComponentArray<UActorComponent*> Components; GetComponents(Components); for ( int32 ComponentIndex = 0 ; ComponentIndex < Components.Num() ; ++ComponentIndex ) { UActorComponent* ActorComponent = Components[ ComponentIndex ]; if (ActorComponent->IsRegistered()) { ActorComponent->CheckForErrors(); } } }
void FLayers::RemoveViewFromActorViewVisibility( FLevelEditorViewportClient* ViewportClient ) { const int32 ViewIndex = ViewportClient->ViewIndex; // get the bit for the view index uint64 ViewBit = ((uint64)1 << ViewIndex); // get all bits under that that we want to keep uint64 KeepBits = ViewBit - 1; // Iterate over all actors, looking for actors in the specified layers. for( FActorIterator It(ViewportClient->GetWorld()) ; It ; ++It ) { const TWeakObjectPtr< AActor > Actor = *It; if( !IsActorValidForLayer( Actor ) ) { continue; } // remember original bits uint64 OriginalHiddenViews = Actor->HiddenEditorViews; uint64 Was = Actor->HiddenEditorViews; // slide all bits higher than ViewIndex down one since the view is being removed from Editor uint64 LowBits = Actor->HiddenEditorViews & KeepBits; // now slide the top bits down by ViewIndex + 1 (chopping off ViewBit) uint64 HighBits = Actor->HiddenEditorViews >> (ViewIndex + 1); // then slide back up by ViewIndex, which will now have erased ViewBit, as well as leaving 0 in the low bits HighBits = HighBits << ViewIndex; // put it all back together Actor->HiddenEditorViews = LowBits | HighBits; // reregister if we changed the visibility bits, as the rendering thread needs them if (OriginalHiddenViews == Actor->HiddenEditorViews) { continue; } // Find all registered primitive components and update the scene proxy with the actors updated visibility map TInlineComponentArray<UPrimitiveComponent*> Components; Actor->GetComponents(Components); for( int32 ComponentIdx = 0; ComponentIdx < Components.Num(); ++ComponentIdx ) { UPrimitiveComponent* PrimitiveComponent = Components[ComponentIdx]; if (PrimitiveComponent->IsRegistered()) { // Push visibility to the render thread PrimitiveComponent->PushEditorVisibilityToProxy( Actor->HiddenEditorViews ); } } } }
void FSCSEditorViewportClient::Tick(float DeltaSeconds) { FEditorViewportClient::Tick(DeltaSeconds); // Register the selection override delegate for the preview actor's components TSharedPtr<SSCSEditor> SCSEditor = BlueprintEditorPtr.Pin()->GetSCSEditor(); AActor* PreviewActor = GetPreviewActor(); if (PreviewActor != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); for (int32 CompIdx = 0; CompIdx < PrimitiveComponents.Num(); ++CompIdx) { UPrimitiveComponent* PrimComponent = PrimitiveComponents[CompIdx]; if (!PrimComponent->SelectionOverrideDelegate.IsBound()) { SCSEditor->SetSelectionOverride(PrimComponent); } } } else { InvalidatePreview(false); } if ( PreviewActor != LastPreviewActor.Get() || PreviewActor == nullptr || IsRealtime() ) { LastPreviewActor = PreviewActor; Invalidate(); RefreshPreviewBounds(); } // Tick the preview scene world. if (!GIntraFrameDebuggingGameThread) { // Ensure that the preview actor instance is up-to-date for component editing (e.g. after compiling the Blueprint, the actor may be reinstanced outside of this class) if(PreviewActor != BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->GetComponentEditorActorInstance()) { BlueprintEditorPtr.Pin()->GetBlueprintObj()->SimpleConstructionScript->SetComponentEditorActorInstance(PreviewActor); } // Allow full tick only if preview simulation is enabled and we're not currently in an active SIE or PIE session if(bIsSimulateEnabled && GEditor->PlayWorld == NULL && !GEditor->bIsSimulatingInEditor) { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_All : LEVELTICK_TimeOnly, DeltaSeconds); } else { PreviewScene->GetWorld()->Tick(IsRealtime() ? LEVELTICK_ViewportsOnly : LEVELTICK_TimeOnly, DeltaSeconds); } } }
void USceneCaptureComponent::HideActorComponents(AActor* InActor) { if (InActor) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; InActor->GetComponents(PrimitiveComponents); for (int32 ComponentIndex = 0, NumComponents = PrimitiveComponents.Num(); ComponentIndex < NumComponents; ++ComponentIndex) { HiddenComponents.AddUnique(PrimitiveComponents[ComponentIndex]); } } }
/** * Determines if the provided actor is capable of having a material applied to it. * * @param TargetActor Actor to check for the validity of material application * * @return true if the actor is valid for material application; false otherwise */ bool FActorFactoryAssetProxy::IsActorValidForMaterialApplication( AActor* TargetActor ) { bool bIsValid = false; //@TODO: PAPER2D: Extend this to support non mesh components (or make sprites a mesh component) // Check if the actor has a mesh or fog volume density. If so, it can likely have // a material applied to it. Otherwise, it cannot. if ( TargetActor ) { TInlineComponentArray<UMeshComponent*> MeshComponents; TargetActor->GetComponents(MeshComponents); bIsValid = (MeshComponents.Num() > 0); } return bIsValid; }
void UUnrealEdEngine::SelectComponent(UActorComponent* Component, bool bInSelected, bool bNotify, bool bSelectEvenIfHidden) { // Don't do any work if the component's selection state matches the target selection state const bool bComponentSelected = GetSelectedComponents()->IsSelected(Component); if (( bComponentSelected && !bInSelected ) || ( !bComponentSelected && bInSelected )) { if (bInSelected) { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Selected Component: %s"), *Component->GetClass()->GetName()); } else { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Deselected Component: %s"), *Component->GetClass()->GetName()); } GetSelectedComponents()->Select(Component, bInSelected); // Make sure the override delegate is bound properly auto SceneComponent = Cast<USceneComponent>(Component); if (SceneComponent) { FComponentEditorUtils::BindComponentSelectionOverride(SceneComponent, true); } // Update the selection visualization AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; ComponentOwner->GetComponents(PrimitiveComponents); for (int32 Idx = 0; Idx < PrimitiveComponents.Num(); ++Idx) { PrimitiveComponents[Idx]->PushSelectionToProxy(); } } if (bNotify) { NoteSelectionChange(); } } }
void UActorRecording::ProcessNewComponentArray(TInlineComponentArray<USceneComponent*>& ProspectiveComponents) const { // Only iterate as far as the current size of the array (it may grow inside the loop) int32 LastIndex = ProspectiveComponents.Num(); for(int32 Index = 0; Index < LastIndex; ++Index) { USceneComponent* NewComponent = ProspectiveComponents[Index]; USceneComponent* Parent = ProspectiveComponents[Index]->GetAttachParent(); while (Parent) { TWeakObjectPtr<USceneComponent> WeakParent(Parent); if (TrackedComponents.Contains(WeakParent) || ProspectiveComponents.Contains(Parent) || Parent->GetOwner() != NewComponent->GetOwner()) { break; } else { ProspectiveComponents.Add(Parent); } Parent = Parent->GetAttachParent(); } } // Sort parent first, to ensure that attachments get added properly TMap<USceneComponent*, int32> AttachmentDepths; for (USceneComponent* Component : ProspectiveComponents) { AttachmentDepths.Add(Component, GetAttachmentDepth(Component)); } ProspectiveComponents.Sort( [&](USceneComponent& A, USceneComponent& B) { return *AttachmentDepths.Find(&A) < *AttachmentDepths.Find(&B); } ); }
static void DrawSnapVertices( AActor* Actor, float PointSize, FPrimitiveDrawInterface* PDI ) { TInlineComponentArray<UActorComponent*> Components; Actor->GetComponents(Components); // Get the closest vertex on each component for( int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ++ComponentIndex ) { TSharedPtr<FVertexIterator> VertexGetter = MakeVertexIterator( Cast<UPrimitiveComponent>( Components[ComponentIndex] ) ); if( VertexGetter.IsValid() ) { FVertexIterator& VertexGetterRef = *VertexGetter; for( ; VertexGetterRef; ++VertexGetterRef ) { PDI->DrawPoint( VertexGetterRef.Position(), VertexSnappingConstants::VertexHelperColor, PointSize, SDPG_World ); } } else { PDI->DrawPoint( Actor->GetActorLocation(), VertexSnappingConstants::VertexHelperColor, PointSize, SDPG_World ); } } }
bool UMatineeTrackAnimControlHelper::PreCreateKeyframe( UInterpTrack *Track, float fTime ) const { KeyframeAddAnimSequence = NULL; UInterpTrackAnimControl *AnimTrack = CastChecked<UInterpTrackAnimControl>(Track); UInterpGroup* Group = CastChecked<UInterpGroup>(Track->GetOuter()); AActor* Actor = GetGroupActor(Track); if (!Actor) { // error message UE_LOG(LogSlateMatinee, Warning, TEXT("No Actor is selected. Select actor first.")); return false; } USkeletalMeshComponent * SkelMeshComp = NULL; TInlineComponentArray<USkeletalMeshComponent*> SkeletalMeshComponents; Actor->GetComponents(SkeletalMeshComponents); for (int32 I=0; I<SkeletalMeshComponents.Num(); ++I) { USkeletalMeshComponent * CurSkelMeshComp = SkeletalMeshComponents[I]; // if qualified to play animation, break if (CurSkelMeshComp->SkeletalMesh && CurSkelMeshComp->SkeletalMesh->Skeleton) { SkelMeshComp = CurSkelMeshComp; break; } } if (!SkelMeshComp) { UE_LOG(LogSlateMatinee, Warning, TEXT("SkeletalMeshComponent isn't found in the selected actor or it does not have Mesh/Skeleton set up in order to play animation")); return false; } USkeleton* Skeleton = SkelMeshComp->SkeletalMesh->Skeleton; if ( Skeleton ) { // Show the dialog. FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); check(Mode->InterpEd != NULL); TSharedPtr< SWindow > Parent = FSlateApplication::Get().GetActiveTopLevelWindow(); if ( Parent.IsValid() ) { FAssetPickerConfig AssetPickerConfig; AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateUObject( this, &UMatineeTrackAnimControlHelper::OnAddKeyTextEntry, Mode->InterpEd, Track ); AssetPickerConfig.bAllowNullSelection = false; AssetPickerConfig.InitialAssetViewType = EAssetViewType::List; // Filter config AssetPickerConfig.Filter.ClassNames.Add(UAnimSequence::StaticClass()->GetFName()); AssetPickerConfig.Filter.TagsAndValues.Add(TEXT("Skeleton"), FAssetData(Skeleton).GetExportTextName()); FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser")); FMenuBuilder MenuBuilder(true, NULL); MenuBuilder.BeginSection(NAME_None, LOCTEXT("MatineeAnimPicker", "Browse")); { TSharedPtr<SBox> MenuEntry = SNew(SBox) .WidthOverride(300.0f) .HeightOverride(300.f) [ ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig) ]; MenuBuilder.AddWidget(MenuEntry.ToSharedRef(), FText::GetEmpty(), true); } MenuBuilder.EndSection(); EntryMenu = FSlateApplication::Get().PushMenu( Parent.ToSharedRef(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect(FPopupTransitionEffect::TypeInPopup) ); } } else { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "NoAnimSeqsFound", "No AnimSequences Found. Make sure to load AnimSequences.") ); } return false; }
void UUnrealEdEngine::UpdateVolumeActorVisibility( UClass* InVolumeActorClass, FLevelEditorViewportClient* InViewport ) { TSubclassOf<AActor> VolumeClassToCheck = InVolumeActorClass ? InVolumeActorClass : AVolume::StaticClass(); // Build a list of actors that need to be updated. Only take actors of the passed in volume class. UWorld* World = InViewport ? InViewport->GetWorld() : GWorld; TArray< AActor *> ActorsToUpdate; for( TActorIterator<AActor> It( World, VolumeClassToCheck ); It; ++It) { ActorsToUpdate.Add(*It); } if( ActorsToUpdate.Num() > 0 ) { TArray< AActor* > ActorsThatChanged; if( !InViewport ) { // Update the visibility state of each actor for each viewport for( int32 ViewportIdx = 0; ViewportIdx < LevelViewportClients.Num(); ++ViewportIdx ) { FLevelEditorViewportClient& ViewClient = *LevelViewportClients[ViewportIdx]; { // Only update the editor frame clients as those are the only viewports right now that show volumes. InternalUpdateVolumeActorVisibility( ActorsToUpdate, ViewClient, ActorsThatChanged ); if( ActorsThatChanged.Num() ) { // If actor visibility changed in the viewport, it needs to be redrawn ViewClient.Invalidate(); } } } } else { // Only update the editor frame clients as those are the only viewports right now that show volumes. InternalUpdateVolumeActorVisibility( ActorsToUpdate, *InViewport, ActorsThatChanged ); if( ActorsThatChanged.Num() ) { // If actor visibility changed in the viewport, it needs to be redrawn InViewport->Invalidate(); } } // Push all changes in the actors to the scene proxy so the render thread correctly updates visibility for( int32 ActorIdx = 0; ActorIdx < ActorsThatChanged.Num(); ++ActorIdx ) { AActor* ActorToUpdate = ActorsThatChanged[ ActorIdx ]; // Find all registered primitive components and update the scene proxy with the actors updated visibility map TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; ActorToUpdate->GetComponents(PrimitiveComponents); for( int32 ComponentIdx = 0; ComponentIdx < PrimitiveComponents.Num(); ++ComponentIdx ) { UPrimitiveComponent* PrimitiveComponent = PrimitiveComponents[ComponentIdx]; if (PrimitiveComponent->IsRegistered()) { // Push visibility to the render thread PrimitiveComponent->PushEditorVisibilityToProxy( ActorToUpdate->HiddenEditorViews ); } } } } }
void ADebugCameraHUD::PostRender() { Super::PostRender(); if (bShowHUD) { ADebugCameraController* DCC = Cast<ADebugCameraController>( PlayerOwner ); UFont* RenderFont = GEngine->GetSmallFont(); if( DCC != NULL ) { FFontRenderInfo FontRenderInfo = Canvas->CreateFontRenderInfo(false, true); Canvas->SetDrawColor(64, 64, 255, 255); FString MyText = TEXT("Debug Camera"); float xl, yl; Canvas->StrLen(RenderFont, MyText, xl, yl); float X = Canvas->SizeX * 0.05f; float Y = yl;//*1.67; yl += 2*Y; Canvas->DrawText(RenderFont, MyText, X, yl, 1.f, 1.f, FontRenderInfo); Canvas->SetDrawColor(200, 200, 128, 255); FVector const CamLoc = DCC->PlayerCameraManager->GetCameraLocation(); FRotator const CamRot = DCC->PlayerCameraManager->GetCameraRotation(); float const CamFOV = DCC->PlayerCameraManager->GetFOVAngle(); yl += Y; FString const LocRotString = FString::Printf(TEXT("Loc=(%.1f, %.1f, %.1f) Rot=(%.1f, %.1f, %.1f)"), CamLoc.X, CamLoc.Y, CamLoc.Z, CamRot.Pitch, CamRot.Yaw, CamRot.Roll); Canvas->DrawText(RenderFont, LocRotString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const FOVString = FString::Printf(TEXT("HFOV=%.1f"), CamFOV); Canvas->DrawText(RenderFont, FOVString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const SpeedScaleString = FString::Printf(TEXT("SpeedScale=%.2fx"), DCC->SpeedScale); Canvas->DrawText(RenderFont, SpeedScaleString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; FString const SpeedString = FString::Printf(TEXT("MaxSpeed=%.1f"), DCC->GetSpectatorPawn() && DCC->GetSpectatorPawn()->GetMovementComponent() ? DCC->GetSpectatorPawn()->GetMovementComponent()->GetMaxSpeed() : 0.f); Canvas->DrawText(RenderFont, SpeedString, X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; //Canvas->DrawText(FString::Printf(TEXT("CamLoc:%s CamRot:%s"), *CamLoc.ToString(), *CamRot.ToString() )); const TCHAR* CVarComplexName = TEXT("g.DebugCameraTraceComplex"); bool bTraceComplex = true; #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bTraceComplex = CVarDebugCameraTraceComplex.GetValueOnGameThread() != 0; #endif FCollisionQueryParams TraceParams(NAME_None, bTraceComplex, this); FHitResult Hit; bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("Trace info (%s = %d):"), CVarComplexName, bTraceComplex ? 1 : 0), X, yl, 1.f, 1.f, FontRenderInfo); if( bHit ) { AActor* HitActor = Hit.GetActor(); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitLoc:%s HitNorm:%s"), *Hit.Location.ToString(), *Hit.Normal.ToString() ), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitDist: %f"), Hit.Distance), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActor: '%s'"), HitActor ? *HitActor->GetFName().ToString() : TEXT("<NULL>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitComponent: '%s'"), Hit.Component.Get() ? *Hit.Component.Get()->GetFName().ToString() : TEXT("<NULL>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActor Class: '%s'"), HitActor && HitActor->GetClass() ? *HitActor->GetClass()->GetName() : TEXT("<Not Found>") ), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("HitActorPath: '%s'"), HitActor ? *HitActor->GetPathName() : TEXT("<Not Found>")), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; bool bFoundMaterial = false; if ( Hit.Component != NULL ) { bFoundMaterial = DisplayMaterials( X, yl, Y, Cast<UMeshComponent>(Hit.Component.Get()) ); } else { TInlineComponentArray<UMeshComponent*> Components; GetComponents(Components); for ( int32 i=0; i<Components.Num(); i++ ) { UMeshComponent* MeshComp = Components[i]; if ( MeshComp->IsRegistered() ) { bFoundMaterial = bFoundMaterial || DisplayMaterials( X, yl, Y, MeshComp ); } } } if ( bFoundMaterial == false ) { yl += Y; Canvas->DrawText(RenderFont, "Material: NULL", X + Y, yl, 1.f, 1.f, FontRenderInfo ); } DrawDebugLine( GetWorld(), Hit.Location, Hit.Location+Hit.Normal*30.f, FColor::White ); } else { yl += Y; Canvas->DrawText( RenderFont, TEXT("No trace Hit"), X, yl, 1.f, 1.f, FontRenderInfo); } if ( DCC->bShowSelectedInfo && DCC->SelectedActor != NULL ) { yl += Y; Canvas->DrawText(RenderFont, FString::Printf(TEXT("Selected actor: '%s'"), *DCC->SelectedActor->GetFName().ToString()), X, yl, 1.f, 1.f, FontRenderInfo); DisplayMaterials( X, yl, Y, Cast<UMeshComponent>(DCC->SelectedComponent) ); } // controls display yl += Y*15; Canvas->SetDrawColor(64, 64, 255, 255); Canvas->DrawText(RenderFont, TEXT("Controls"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->SetDrawColor(200, 200, 128, 255); Canvas->DrawText(RenderFont, TEXT("FOV +/-: ,/. or DPad Up/Down"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Speed +/-: MouseWheel or +/- or LB/RB"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Freeze Rendering: F or YButton"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; Canvas->DrawText(RenderFont, TEXT("Toggle Display: BackSpace or XButton"), X, yl, 1.f, 1.f, FontRenderInfo); yl += Y; } } }
FSnappingVertex FVertexSnappingImpl::GetClosestVertex( const TArray<FSnapActor>& Actors, const FVertexSnappingArgs& InArgs ) { // The current closest distance float ClosestDistance = FLT_MAX; const FPlane& ActorPlane = InArgs.ActorPlane; EAxisList::Type CurrentAxis = InArgs.CurrentAxis; const FSceneView* View = InArgs.SceneView; const FVector& CurrentLocation = InArgs.CurrentLocation; const FVector2D& MousePosition = InArgs.MousePosition; FSnappingVertex ClosestLocation( CurrentLocation ); AActor* ClosestActor = NULL; // Find the closest vertex on each actor and then from that list find the closest vertex for( int32 ActorIndex = 0; ActorIndex < Actors.Num(); ++ActorIndex ) { const FSnapActor& SnapActor = Actors[ActorIndex]; AActor* Actor = SnapActor.Actor; // Get the closest vertex on each component TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; Actor->GetComponents(PrimitiveComponents); for( int32 ComponentIndex = 0; ComponentIndex < PrimitiveComponents.Num(); ++ComponentIndex ) { FSnappingVertex ClosestLocationOnComponent( CurrentLocation ); if( !GetClosestVertexOnComponent( SnapActor, PrimitiveComponents[ComponentIndex], InArgs, ClosestLocationOnComponent ) ) { ClosestLocationOnComponent.Position = Actor->GetActorLocation(); ClosestLocationOnComponent.Normal = FVector::ZeroVector; } float Distance = 0; if( CurrentAxis != EAxisList::Screen ) { // Compute the distance from the point being snapped. When not in screen space we snap to the plane created by the current closest vertex Distance = ActorPlane.PlaneDot( ClosestLocationOnComponent.Position ); } else { // Favor the vertex closest to the mouse in screen space FVector2D ComponentLocPixel; if( View->WorldToPixel( ClosestLocationOnComponent.Position, ComponentLocPixel ) ) { Distance = FVector::DistSquared( FVector( MousePosition, 0 ), FVector( ComponentLocPixel, 0 ) ); } } if( // A close vertex must have been found ClosestLocationOnComponent.Position != CurrentLocation // we must have made some movement && !FMath::IsNearlyZero(Distance) // If not in screen space the vertex cannot be behind the point being snapped && ( CurrentAxis == EAxisList::Screen || !FMath::IsNegativeFloat( Distance ) ) // The vertex must be closer than the current closest vertex && Distance < ClosestDistance ) { ClosestActor = Actor; ClosestDistance = Distance; ClosestLocation = ClosestLocationOnComponent; } } } if( InArgs.bDrawVertexHelpers ) { if(ActorVertsToDraw.IsValid()) { ActorVertsToFade.Add(ActorVertsToDraw, FApp::GetCurrentTime()); } ActorVertsToFade.Remove(ClosestActor); ActorVertsToDraw = ClosestActor; } else { ActorVertsToDraw = nullptr; ActorVertsToFade.Empty(); } return ClosestLocation; }
USceneComponent* USimpleConstructionScript::GetSceneRootComponentTemplate(USCS_Node** OutSCSNode) const { UBlueprint* Blueprint = GetBlueprint(); UClass* GeneratedClass = GetOwnerClass(); if(OutSCSNode) { *OutSCSNode = nullptr; } // Get the Blueprint class default object AActor* CDO = nullptr; if(GeneratedClass != nullptr) { CDO = Cast<AActor>(GeneratedClass->GetDefaultObject(false)); } // If the generated class does not yet have a CDO, defer to the parent class if(CDO == nullptr && Blueprint->ParentClass != nullptr) { CDO = Cast<AActor>(Blueprint->ParentClass->GetDefaultObject(false)); } // Check to see if we already have a native root component template USceneComponent* RootComponentTemplate = nullptr; if(CDO != nullptr) { // If the root component property is not set, the first available scene component will be used as the root. This matches what's done in the SCS editor. RootComponentTemplate = CDO->GetRootComponent(); if(!RootComponentTemplate) { TInlineComponentArray<USceneComponent*> SceneComponents; CDO->GetComponents(SceneComponents); if(SceneComponents.Num() > 0) { RootComponentTemplate = SceneComponents[0]; } } } // Don't add the default scene root if we already have a native scene root component if(!RootComponentTemplate) { // Get the Blueprint hierarchy TArray<UBlueprint*> BPStack; if(Blueprint->GeneratedClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->GeneratedClass, BPStack); } else if(Blueprint->ParentClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->ParentClass, BPStack); } // Note: Normally if the Blueprint has a parent, we can assume that the parent already has a scene root component set, // ...but we'll run through the hierarchy just in case there are legacy BPs out there that might not adhere to this assumption. TArray<const USimpleConstructionScript*> SCSStack; SCSStack.Add(this); for(int32 StackIndex = 0; StackIndex < BPStack.Num(); ++StackIndex) { if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript && !SCSStack.Contains(BPStack[StackIndex]->SimpleConstructionScript)) { // UBlueprint::GetBlueprintHierarchyFromClass returns first children then parents. So we need to revert the order. SCSStack.Insert(BPStack[StackIndex]->SimpleConstructionScript, 0); } } for(int32 StackIndex = 0; StackIndex < SCSStack.Num() && !RootComponentTemplate; ++StackIndex) { // Check for any scene component nodes in the root set that are not the default scene root const TArray<USCS_Node*>& SCSRootNodes = SCSStack[StackIndex]->GetRootNodes(); for(int32 RootNodeIndex = 0; RootNodeIndex < SCSRootNodes.Num() && RootComponentTemplate == nullptr; ++RootNodeIndex) { USCS_Node* RootNode = SCSRootNodes[RootNodeIndex]; if(RootNode != nullptr && RootNode != DefaultSceneRootNode && RootNode->ComponentTemplate != nullptr && RootNode->ComponentTemplate->IsA<USceneComponent>()) { if(OutSCSNode) { *OutSCSNode = RootNode; } RootComponentTemplate = Cast<USceneComponent>(RootNode->ComponentTemplate); } } } } return RootComponentTemplate; }
void USimpleConstructionScript::ExecuteScriptOnActor(AActor* Actor, const FTransform& RootTransform, bool bIsDefaultTransform) { if(RootNodes.Num() > 0) { TSet<UActorComponent*> AllComponentsCreatedBySCS; TInlineComponentArray<UActorComponent*> InstancedComponents; for(auto NodeIt = RootNodes.CreateIterator(); NodeIt; ++NodeIt) { USCS_Node* RootNode = *NodeIt; if(RootNode != nullptr) { // Get all native scene components TInlineComponentArray<USceneComponent*> Components; Actor->GetComponents(Components); for (int32 Index = Components.Num()-1; Index >= 0; --Index) { USceneComponent* SceneComponent = Components[Index]; if (SceneComponent->CreationMethod == EComponentCreationMethod::Instance) { Components.RemoveAt(Index); } else { // Handle the native sub-component of an instance component case USceneComponent* ParentSceneComponent = SceneComponent->GetTypedOuter<USceneComponent>(); if (ParentSceneComponent && ParentSceneComponent->CreationMethod == EComponentCreationMethod::Instance) { Components.RemoveAt(Index); } } } // Get the native root component; if it's not set, the first native scene component will be used as root. This matches what's done in the SCS editor. USceneComponent* RootComponent = Actor->GetRootComponent(); if(RootComponent == nullptr && Components.Num() > 0) { RootComponent = Components[0]; } // If the root node specifies that it has a parent USceneComponent* ParentComponent = nullptr; if(RootNode->ParentComponentOrVariableName != NAME_None) { // Get the Actor class object UClass* ActorClass = Actor->GetClass(); check(ActorClass != nullptr); // If the root node is parented to a "native" component (i.e. in the 'Components' array) if(RootNode->bIsParentComponentNative) { for(int32 CompIndex = 0; CompIndex < Components.Num(); ++CompIndex) { // If we found a match, remember the index if(Components[CompIndex]->GetFName() == RootNode->ParentComponentOrVariableName) { ParentComponent = Components[CompIndex]; break; } } } else { // In the non-native case, the SCS node's variable name property is used as the parent identifier UObjectPropertyBase* Property = FindField<UObjectPropertyBase>(ActorClass, RootNode->ParentComponentOrVariableName); if(Property != nullptr) { // If we found a matching property, grab its value and use that as the parent for this node ParentComponent = Cast<USceneComponent>(Property->GetObjectPropertyValue_InContainer(Actor)); } } } // Create the new component instance and any child components it may have UActorComponent* InstancedComponent = RootNode->ExecuteNodeOnActor(Actor, ParentComponent != nullptr ? ParentComponent : RootComponent, &RootTransform, bIsDefaultTransform); if(InstancedComponent != nullptr) { InstancedComponents.Add(InstancedComponent); } // get list of every component SCS created, in case some of them aren't in the attachment hierarchy any more (e.g. rigid bodies) TInlineComponentArray<USceneComponent*> ComponentsAfterSCS; Actor->GetComponents(ComponentsAfterSCS); for (USceneComponent* C : ComponentsAfterSCS) { if (Components.Contains(C) == false) { AllComponentsCreatedBySCS.Add(C); } } } } // Register all instanced SCS components once SCS execution has finished; sorted in order to register the scene component hierarchy first, followed by the remaining actor components (in case they happen to depend on something in the scene hierarchy) InstancedComponents.Sort([](const UActorComponent& A, const UActorComponent& B) { return A.IsA<USceneComponent>(); }); for(auto InstancedComponent : InstancedComponents) { RegisterInstancedComponent(InstancedComponent); } // now that the instanced components in the attachment hierarchy are registered, register any other components that SCS made but aren't in the attachment hierarchy for whatever reason. for (auto C : AllComponentsCreatedBySCS) { if (C->IsRegistered() == false) { C->RegisterComponent(); } } } else if(Actor->GetRootComponent() == NULL) // Must have a root component at the end of SCS, so if we don't have one already (from base class), create a SceneComponent now { USceneComponent* SceneComp = NewObject<USceneComponent>(Actor); SceneComp->SetFlags(RF_Transactional); SceneComp->CreationMethod = EComponentCreationMethod::SimpleConstructionScript; SceneComp->SetWorldTransform(RootTransform); Actor->SetRootComponent(SceneComp); SceneComp->RegisterComponent(); } }
/** * Attempts to apply the material to the specified actor. * * @param TargetActor the actor to apply the material to * @param MaterialToApply the material to apply to the actor * @param OptionalMaterialSlot the material slot to apply to. * * @return true if the material was successfully applied to the actor */ bool FActorFactoryAssetProxy::ApplyMaterialToActor( AActor* TargetActor, UMaterialInterface* MaterialToApply, int32 OptionalMaterialSlot ) { bool bResult = false; if ( TargetActor != NULL && MaterialToApply != NULL ) { ALandscapeProxy* Landscape = Cast<ALandscapeProxy>(TargetActor); if (Landscape != NULL) { UProperty* MaterialProperty = FindField<UProperty>(ALandscapeProxy::StaticClass(), "LandscapeMaterial"); Landscape->PreEditChange(MaterialProperty); Landscape->LandscapeMaterial = MaterialToApply; FPropertyChangedEvent PropertyChangedEvent(MaterialProperty); Landscape->PostEditChangeProperty(PropertyChangedEvent); bResult = true; } else { TArray<UActorComponent*> EditableComponents; FActorEditorUtils::GetEditableComponents( TargetActor, EditableComponents ); // Some actors could potentially have multiple mesh components, so we need to store all of the potentially valid ones // (or else perform special cases with IsA checks on the target actor) TArray<USceneComponent*> FoundMeshComponents; // Find which mesh the user clicked on first. TInlineComponentArray<USceneComponent*> SceneComponents; TargetActor->GetComponents(SceneComponents); for ( int32 ComponentIdx=0; ComponentIdx < SceneComponents.Num(); ComponentIdx++ ) { USceneComponent* SceneComp = SceneComponents[ComponentIdx]; // Only apply the material to editable components. Components which are not exposed are not intended to be changed. if( EditableComponents.Contains( SceneComp ) ) { UMeshComponent* MeshComponent = Cast<UMeshComponent>(SceneComp); if((MeshComponent && MeshComponent->IsRegistered()) || SceneComp->IsA<UDecalComponent>()) { // Intentionally do not break the loop here, as there could be potentially multiple mesh components FoundMeshComponents.AddUnique( SceneComp ); } } } if ( FoundMeshComponents.Num() > 0 ) { // Check each component that was found for ( TArray<USceneComponent*>::TConstIterator MeshCompIter( FoundMeshComponents ); MeshCompIter; ++MeshCompIter ) { USceneComponent* SceneComp = *MeshCompIter; bResult = FComponentEditorUtils::AttemptApplyMaterialToComponent(SceneComp, MaterialToApply, OptionalMaterialSlot); } } } } return bResult; }
int32 FComponentEditorUtils::DeleteComponents(const TArray<UActorComponent*>& ComponentsToDelete, UActorComponent*& OutComponentToSelect) { int32 NumDeletedComponents = 0; TArray<AActor*> ActorsToReconstruct; for (auto ComponentToDelete : ComponentsToDelete) { if (ComponentToDelete->CreationMethod != EComponentCreationMethod::Instance) { // We can only delete instance components, so retain selection on the un-deletable component OutComponentToSelect = ComponentToDelete; continue; } AActor* Owner = ComponentToDelete->GetOwner(); check(Owner != nullptr); // If necessary, determine the component that should be selected following the deletion of the indicated component if (!OutComponentToSelect || ComponentToDelete == OutComponentToSelect) { USceneComponent* RootComponent = Owner->GetRootComponent(); if (RootComponent != ComponentToDelete) { // Worst-case, the root can be selected OutComponentToSelect = RootComponent; if (auto ComponentToDeleteAsSceneComp = Cast<USceneComponent>(ComponentToDelete)) { if (USceneComponent* ParentComponent = ComponentToDeleteAsSceneComp->GetAttachParent()) { // The component to delete has a parent, so we select that in the absence of an appropriate sibling OutComponentToSelect = ParentComponent; // Try to select the sibling that immediately precedes the component to delete TArray<USceneComponent*> Siblings; ParentComponent->GetChildrenComponents(false, Siblings); for (int32 i = 0; i < Siblings.Num() && ComponentToDelete != Siblings[i]; ++i) { if (!Siblings[i]->IsPendingKill()) { OutComponentToSelect = Siblings[i]; } } } } else { // For a non-scene component, try to select the preceding non-scene component TInlineComponentArray<UActorComponent*> ActorComponents; Owner->GetComponents(ActorComponents); for (int32 i = 0; i < ActorComponents.Num() && ComponentToDelete != ActorComponents[i]; ++i) { if (!ActorComponents[i]->IsA(USceneComponent::StaticClass())) { OutComponentToSelect = ActorComponents[i]; } } } } else { OutComponentToSelect = nullptr; } } // Defer reconstruction ActorsToReconstruct.AddUnique(Owner); // Actually delete the component ComponentToDelete->Modify(); ComponentToDelete->DestroyComponent(true); NumDeletedComponents++; } // Reconstruct owner instance(s) after deletion for(auto ActorToReconstruct : ActorsToReconstruct) { ActorToReconstruct->RerunConstructionScripts(); } return NumDeletedComponents; }