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 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::RefreshPreviewBounds() { AActor* PreviewActor = GetPreviewActor(); if(PreviewActor) { // Compute actor bounds as the sum of its visible parts TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; PreviewActor->GetComponents(PrimitiveComponents); PreviewActorBounds = FBoxSphereBounds(ForceInitToZero); for(auto CompIt = PrimitiveComponents.CreateConstIterator(); CompIt; ++CompIt) { // Aggregate primitive components that either have collision enabled or are otherwise visible components in-game UPrimitiveComponent* PrimComp = *CompIt; if(PrimComp->IsRegistered() && (!PrimComp->bHiddenInGame || PrimComp->IsCollisionEnabled()) && PrimComp->Bounds.SphereRadius < HALF_WORLD_MAX) { PreviewActorBounds = PreviewActorBounds + PrimComp->Bounds; } } } }
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 ); } } } } }
bool UGripMotionControllerComponent::CheckComponentWithSweep(UPrimitiveComponent * ComponentToCheck, FVector Move, FRotator newOrientation, bool bSkipSimulatingComponents/*, bool &bHadBlockingHitOut*/) { TArray<FHitResult> Hits; // WARNING: HitResult is only partially initialized in some paths. All data is valid only if bFilledHitResult is true. FHitResult BlockingHit(NoInit); BlockingHit.bBlockingHit = false; BlockingHit.Time = 1.f; bool bFilledHitResult = false; bool bMoved = false; bool bIncludesOverlapsAtEnd = false; bool bRotationOnly = false; UPrimitiveComponent *root = ComponentToCheck; if (!root || !root->IsQueryCollisionEnabled()) return false; FVector start(root->GetComponentLocation()); const bool bCollisionEnabled = root->IsQueryCollisionEnabled(); if (bCollisionEnabled) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!root->IsRegistered()) { UE_LOG(LogTemp, Warning, TEXT("MovedComponent %s not initialized in grip motion controller"), *root->GetFullName()); } #endif UWorld* const MyWorld = GetWorld(); FComponentQueryParams Params(TEXT("sweep_params"), root->GetOwner()); FCollisionResponseParams ResponseParam; root->InitSweepCollisionParams(Params, ResponseParam); bool const bHadBlockingHit = MyWorld->ComponentSweepMulti(Hits, root, start, start + Move, newOrientation, Params); if (bHadBlockingHit) { int32 BlockingHitIndex = INDEX_NONE; float BlockingHitNormalDotDelta = BIG_NUMBER; for (int32 HitIdx = 0; HitIdx < Hits.Num(); HitIdx++) { const FHitResult& TestHit = Hits[HitIdx]; // Ignore the owning actor to the motion controller if (TestHit.Actor == this->GetOwner() || (bSkipSimulatingComponents && TestHit.Component->IsSimulatingPhysics())) { if (Hits.Num() == 1) { //bHadBlockingHitOut = false; return false; } else continue; } if (TestHit.bBlockingHit && TestHit.IsValidBlockingHit()) { if (TestHit.Time == 0.f) { // We may have multiple initial hits, and want to choose the one with the normal most opposed to our movement. const float NormalDotDelta = (TestHit.ImpactNormal | Move); if (NormalDotDelta < BlockingHitNormalDotDelta) { BlockingHitNormalDotDelta = NormalDotDelta; BlockingHitIndex = HitIdx; } } else if (BlockingHitIndex == INDEX_NONE) { // First non-overlapping blocking hit should be used, if an overlapping hit was not. // This should be the only non-overlapping blocking hit, and last in the results. BlockingHitIndex = HitIdx; break; } //} } } // Update blocking hit, if there was a valid one. if (BlockingHitIndex >= 0) { BlockingHit = Hits[BlockingHitIndex]; bFilledHitResult = true; } } } // Handle blocking hit notifications. Avoid if pending kill (which could happen after overlaps). if (BlockingHit.bBlockingHit && !root->IsPendingKill()) { check(bFilledHitResult); if (root->IsDeferringMovementUpdates()) { FScopedMovementUpdate* ScopedUpdate = root->GetCurrentScopedMovement(); ScopedUpdate->AppendBlockingHitAfterMove(BlockingHit); } else { if(root->GetOwner()) root->DispatchBlockingHit(*root->GetOwner(), BlockingHit); } return true; } return false; }