// Copyright Epic Games, Inc. All Rights Reserved. #include "Layers/LayersSubsystem.h" #include "Engine/Brush.h" #include "Components/PrimitiveComponent.h" #include "Layers/Layer.h" #include "LevelEditorViewport.h" #include "Misc/IFilter.h" #include "Engine/Selection.h" #include "Engine/World.h" #include "EngineUtils.h" #include "Editor.h" #include "ActorEditorUtils.h" #include "Model.h" class FLayersBroadcast { public: /** * Constructor */ FLayersBroadcast(ULayersSubsystem* InLayersSubsystem); /** * Destructor */ ~FLayersBroadcast(); void Deinitialize(); private: void Initialize(); /** * Delegate handler for FEditorDelegates::MapChange. It internally calls LayersSubsystem->EditorMapChange(). **/ void OnEditorMapChange(uint32 MapChangeFlags = 0); /** * Delegate handler for FEditorDelegates::RefreshLayerBrowser. It internally calls LayersSubsystem->EditorRefreshLayerBrowser() to refresh the actors of each layer. **/ void OnEditorRefreshLayerBrowser(); /** * Delegate handler for FEditorDelegates::PostUndoRedo. It internally calls LayersSubsystem->PostUndoRedo() to refresh the actors of each layer. **/ void OnPostUndoRedo(); ULayersSubsystem* LayersSubsystem; bool bIsInitialized; }; FLayersBroadcast::FLayersBroadcast(ULayersSubsystem* InLayersSubsystem) : LayersSubsystem(InLayersSubsystem) , bIsInitialized(false) { Initialize(); } FLayersBroadcast::~FLayersBroadcast() { Deinitialize(); } void FLayersBroadcast::Deinitialize() { if (bIsInitialized) { bIsInitialized = false; // Remove all callback functions from FEditorDelegates::MapChange.Broadcast() and FEditorDelegates::RefreshLayerBrowser.Broadcast() FEditorDelegates::MapChange.RemoveAll(this); FEditorDelegates::RefreshLayerBrowser.RemoveAll(this); FEditorDelegates::PostUndoRedo.RemoveAll(this); } } void FLayersBroadcast::Initialize() { if (!bIsInitialized) { bIsInitialized = true; // Add callback function to FEditorDelegates::MapChange.Broadcast() and FEditorDelegates::RefreshLayerBrowser.Broadcast() FEditorDelegates::MapChange.AddRaw(this, &FLayersBroadcast::OnEditorMapChange); FEditorDelegates::RefreshLayerBrowser.AddRaw(this, &FLayersBroadcast::OnEditorRefreshLayerBrowser); FEditorDelegates::PostUndoRedo.AddRaw(this, &FLayersBroadcast::OnPostUndoRedo); } } void FLayersBroadcast::OnEditorMapChange(uint32 MapChangeFlags) { LayersSubsystem->EditorMapChange(); } void FLayersBroadcast::OnEditorRefreshLayerBrowser() { LayersSubsystem->EditorRefreshLayerBrowser(); } void FLayersBroadcast::OnPostUndoRedo() { LayersSubsystem->PostUndoRedo(); } void ULayersSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); // Subsystems are loaded, so we can set up the broadcast functions for GetEditorSubsystem() LayersBroadcast = MakeShareable(new FLayersBroadcast(this)); } void ULayersSubsystem::Deinitialize() { Super::Deinitialize(); LayersBroadcast->Deinitialize(); } ULayersSubsystem::~ULayersSubsystem() { } void ULayersSubsystem::EditorMapChange() { LayersChanged.Broadcast( ELayersAction::Reset, NULL, NAME_None ); } void ULayersSubsystem::EditorRefreshLayerBrowser() { // bNotifySelectionChange is false because the functions calling FEditorDelegates::RefreshLayerBrowser.Broadcast usually call GEditor->NoteSelectionChange const bool bNotifySelectionChange = false; const bool bRedrawViewports = false; UpdateAllActorsVisibility(bNotifySelectionChange, bRedrawViewports); } void ULayersSubsystem::PostUndoRedo() { LayersChanged.Broadcast(ELayersAction::Reset, NULL, NAME_None); UpdateAllActorsVisibility(true, true); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on Levels // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ULayersSubsystem::AddLevelLayerInformation(ULevel* Level) { if (Level) { for (auto ActorIter = Level->Actors.CreateConstIterator(); ActorIter; ++ActorIter) { InitializeNewActorLayers(*ActorIter); } } } void ULayersSubsystem::RemoveLevelLayerInformation(ULevel* Level) { if (Level) { for (auto ActorIter = Level->Actors.CreateConstIterator(); ActorIter; ++ActorIter) { DisassociateActorFromLayers(*ActorIter); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on an individual actor. // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ULayersSubsystem::IsActorValidForLayer(AActor* Actor) { return Actor && Actor->GetClass() && Actor->GetWorld() && Actor->SupportsLayers(); } bool ULayersSubsystem::InitializeNewActorLayers(AActor* Actor) { if( !IsActorValidForLayer( Actor ) ) { return false; } for( auto LayerNameIt = Actor->Layers.CreateConstIterator(); LayerNameIt; ++LayerNameIt ) { const FName LayerName = *LayerNameIt; ULayer* Layer = EnsureLayerExists( LayerName ); Layer->Modify(); AddActorToStats( Layer, Actor); } // update per-view visibility info UpdateActorAllViewsVisibility(Actor); // update general actor visibility bool bActorModified = false; bool bActorSelectionChanged = false; const bool bActorNotifySelectionChange = true; const bool bActorRedrawViewports = false; UpdateActorVisibility(Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports); return Actor->Layers.Num() > 0; } bool ULayersSubsystem::DisassociateActorFromLayers(AActor* Actor) { TArray< AActor* > Actors; Actors.Add(Actor); return DisassociateActorsFromLayers(Actors); } UWorld* ULayersSubsystem::GetWorld() const { return GWorld; } bool ULayersSubsystem::AddActorToLayer(AActor* Actor, const FName& LayerName) { TArray< AActor* > Actors; Actors.Add(Actor); TArray< FName > LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorToLayers(AActor* Actor, const TArray< FName >& LayerNames) { TArray< AActor* > Actors; Actors.Add(Actor); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayer(const TArray< AActor* >& Actors, const FName& LayerName) { TArray< FName > LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayer(const TArray< TWeakObjectPtr< AActor > >& Actors, const FName& LayerName) { TArray< FName > LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayers( const TArray< AActor* >& Actors, const TArray< FName >& LayerNames ) { bool bChangesOccurred = false; if ( LayerNames.Num() > 0 ) { GEditor->GetSelectedActors()->BeginBatchSelectOperation(); for( auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt ) { AActor* Actor = *ActorIt; if ( !IsActorValidForLayer( Actor ) ) { continue; } bool bActorWasModified = false; for( auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt ) { const FName& LayerName = *LayerNameIt; if( !Actor->Layers.Contains( LayerName ) ) { if( !bActorWasModified ) { Actor->Modify(); bActorWasModified = true; } ULayer* Layer = EnsureLayerExists( LayerName ); Actor->Layers.Add( LayerName ); Layer->Modify(); AddActorToStats( Layer, Actor); ActorsLayersChanged.Broadcast( Actor ); } } //END Iteration over Layers if( bActorWasModified ) { // update per-view visibility info UpdateActorAllViewsVisibility(Actor); // update general actor visibility bool bActorModified = false; bool bActorSelectionChanged = false; const bool bActorNotifySelectionChange = true; const bool bActorRedrawViewports = false; UpdateActorVisibility( Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports ); bChangesOccurred = true; } } //END Iteration over Actors GEditor->GetSelectedActors()->EndBatchSelectOperation(); } return bChangesOccurred; } bool ULayersSubsystem::AddActorsToLayers(const TArray< TWeakObjectPtr< AActor > >& Actors, const TArray< FName >& LayerNames) { TArray< AActor* > ActorsRawPtr; for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt) { AActor* Actor = (*ActorIt).Get(); ActorsRawPtr.Add(Actor); } return AddActorsToLayers(ActorsRawPtr, LayerNames); } bool ULayersSubsystem::DisassociateActorsFromLayers(const TArray& Actors) { bool bChangesOccurred = false; for(AActor* Actor : Actors) { if (!IsActorValidForLayer(Actor)) { continue; } for(const FName& LayerName : Actor->Layers) { ULayer* Layer = EnsureLayerExists(LayerName); Layer->Modify(); RemoveActorFromStats(Layer, Actor); bChangesOccurred = true; } } return bChangesOccurred; } bool ULayersSubsystem::RemoveActorFromLayer(AActor* Actor, const FName& LayerName, const bool bUpdateStats) { TArray< AActor* > Actors; Actors.Add(Actor); TArray< FName > LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorFromLayers(AActor* Actor, const TArray< FName >& LayerNames, const bool bUpdateStats) { TArray< AActor* > Actors; Actors.Add(Actor); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayer(const TArray< AActor* >& Actors, const FName& LayerName, const bool bUpdateStats) { TArray< FName > LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayer(const TArray< TWeakObjectPtr< AActor > >& Actors, const FName& LayerName, const bool bUpdateStats) { TArray< FName > LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayers( const TArray< AActor* >& Actors, const TArray< FName >& LayerNames, const bool bUpdateStats ) { GEditor->GetSelectedActors()->BeginBatchSelectOperation(); bool bChangesOccurred = false; for( auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt ) { AActor* Actor = *ActorIt; if ( !IsActorValidForLayer( Actor ) ) { continue; } bool ActorWasModified = false; for( auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt ) { const FName& LayerName = *LayerNameIt; if( Actor->Layers.Contains( LayerName ) ) { if( !ActorWasModified ) { Actor->Modify(); ActorWasModified = true; } Actor->Layers.Remove( LayerName ); ULayer* Layer; if( bUpdateStats && TryGetLayer( LayerName, Layer )) { Layer->Modify(); RemoveActorFromStats( Layer, Actor); } ActorsLayersChanged.Broadcast( Actor ); } } //END Iteration over Layers if( ActorWasModified ) { // update per-view visibility info UpdateActorAllViewsVisibility(Actor); // update general actor visibility bool bActorModified = false; bool bActorSelectionChanged = false; const bool bActorNotifySelectionChange = true; const bool bActorRedrawViewports = false; UpdateActorVisibility( Actor, bActorSelectionChanged, bActorModified, bActorNotifySelectionChange, bActorRedrawViewports ); bChangesOccurred = true; } } //END Iteration over Actors GEditor->GetSelectedActors()->EndBatchSelectOperation(); return bChangesOccurred; } bool ULayersSubsystem::RemoveActorsFromLayers(const TArray< TWeakObjectPtr< AActor > >& Actors, const TArray< FName >& LayerNames, const bool bUpdateStats) { TArray< AActor* > ActorsRawPtr; for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt) { AActor* Actor = (*ActorIt).Get(); ActorsRawPtr.Add(Actor); } return RemoveActorsFromLayers(ActorsRawPtr, LayerNames, bUpdateStats); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on selected actors. // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TArray< AActor* > ULayersSubsystem::GetSelectedActors() const { // Unfortunately, the batch selection operation is not entirely effective // and the result can be that the iterator becomes invalid when adding an actor to a layer // due to unintended selection change notifications being fired. TArray< AActor* > CurrentlySelectedActors; for( FSelectionIterator It(GEditor->GetSelectedActorIterator() ); It; ++It ) { AActor* Actor = static_cast(*It); checkSlow( Actor->IsA(AActor::StaticClass()) ); CurrentlySelectedActors.Add( Actor ); } return CurrentlySelectedActors; } bool ULayersSubsystem::AddSelectedActorsToLayer( const FName& LayerName ) { return AddActorsToLayer( GetSelectedActors(), LayerName ); } bool ULayersSubsystem::RemoveSelectedActorsFromLayer( const FName& LayerName ) { return RemoveActorsFromLayer( GetSelectedActors(), LayerName ); } bool ULayersSubsystem::AddSelectedActorsToLayers( const TArray< FName >& LayerNames ) { return AddActorsToLayers( GetSelectedActors(), LayerNames ); } bool ULayersSubsystem::RemoveSelectedActorsFromLayers( const TArray< FName >& LayerNames ) { return RemoveActorsFromLayers( GetSelectedActors(), LayerNames ); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on actors in layers // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ULayersSubsystem::SelectActorsInLayer(const FName& LayerName, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden) { return SelectActorsInLayer(LayerName, bSelect, bNotify, bSelectEvenIfHidden, nullptr); } bool ULayersSubsystem::SelectActorsInLayer(const FName& LayerName, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden, const TSharedPtr< ActorFilter >& Filter) { GEditor->GetSelectedActors()->BeginBatchSelectOperation(); bool bChangesOccurred = false; // Iterate over all actors, looking for actors in the specified layers. for (FActorIterator It(GetWorld()); It; ++It) { AActor* Actor = *It; if (!IsActorValidForLayer(Actor)) { continue; } if (Filter.IsValid() && !Filter->PassesFilter(Actor)) { continue; } if (Actor->Layers.Contains(LayerName)) { // The actor was found to be in a specified layer. // Set selection state and move on to the next actor. bool bNotifyForActor = false; GEditor->GetSelectedActors()->Modify(); GEditor->SelectActor(Actor, bSelect, bNotifyForActor, bSelectEvenIfHidden); bChangesOccurred = true; } } GEditor->GetSelectedActors()->EndBatchSelectOperation(); if (bNotify) { GEditor->NoteSelectionChange(); } return bChangesOccurred; } bool ULayersSubsystem::SelectActorsInLayers(const TArray< FName >& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden) { return SelectActorsInLayers(LayerNames, bSelect, bNotify, bSelectEvenIfHidden, nullptr); } bool ULayersSubsystem::SelectActorsInLayers(const TArray< FName >& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden, const TSharedPtr< ActorFilter >& Filter) { if (LayerNames.Num() == 0) { return true; } GEditor->GetSelectedActors()->BeginBatchSelectOperation(); bool bChangesOccurred = false; // Iterate over all actors, looking for actors in the specified layers. for (AActor* Actor : FActorRange(GetWorld())) { if (!IsActorValidForLayer(Actor)) { continue; } if (Filter.IsValid() && !Filter->PassesFilter(TWeakObjectPtr< AActor >(Actor))) { continue; } for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt) { if (Actor->Layers.Contains(*LayerNameIt)) { // The actor was found to be in a specified layer. // Set selection state and move on to the next actor. bool bNotifyForActor = false; GEditor->GetSelectedActors()->Modify(); GEditor->SelectActor(Actor, bSelect, bNotifyForActor, bSelectEvenIfHidden); bChangesOccurred = true; break; } } } GEditor->GetSelectedActors()->EndBatchSelectOperation(); if (bNotify) { GEditor->NoteSelectionChange(); } return bChangesOccurred; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on actor viewport visibility regarding layers // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ULayersSubsystem::UpdatePerViewVisibility( FLevelEditorViewportClient* ViewportClient, const FName& LayerThatChanged ) { const int32 ViewIndex = ViewportClient->ViewIndex; // get the viewport client // Iterate over all actors, looking for actors in the specified layers. if( ViewportClient->GetWorld() == NULL ) { return; } for( FActorIterator It(ViewportClient->GetWorld()) ; It ; ++It ) { AActor* Actor = *It; if( !IsActorValidForLayer( Actor ) ) { continue; } // if the view has nothing hidden, just quickly mark the actor as visible in this view if ( ViewportClient->ViewHiddenLayers.Num() == 0) { // if the actor had this view hidden, then unhide it if ( Actor->HiddenEditorViews & ( (uint64)1 << ViewIndex ) ) { // make sure this actor doesn't have the view set Actor->HiddenEditorViews &= ~( (uint64)1 << ViewIndex ); Actor->MarkComponentsRenderStateDirty(); } } // else if we were given a name that was changed, only update actors with that name in their layers, // otherwise update all actors else if ( LayerThatChanged == NAME_Skip || Actor->Layers.Contains( LayerThatChanged ) ) { UpdateActorViewVisibility(ViewportClient, Actor); } } // make sure we redraw the viewport ViewportClient->Invalidate(); } void ULayersSubsystem::UpdateAllViewVisibility( const FName& LayerThatChanged ) { // update all views's hidden layers if they had this one for (FLevelEditorViewportClient* ViewportClient : GEditor->GetLevelViewportClients()) { UpdatePerViewVisibility( ViewportClient, LayerThatChanged ); } } void ULayersSubsystem::UpdateActorViewVisibility(FLevelEditorViewportClient* ViewportClient, AActor* Actor, bool bReregisterIfDirty) { // get the viewport client const int32 ViewIndex = ViewportClient->ViewIndex; int32 NumHiddenLayers = 0; // look for which of the actor layers are hidden for (int32 LayerIndex = 0; LayerIndex < Actor->Layers.Num(); LayerIndex++) { // if its in the view hidden list, this layer is hidden for this actor if (ViewportClient->ViewHiddenLayers.Find( Actor->Layers[ LayerIndex ] ) != -1) { NumHiddenLayers++; // right now, if one is hidden, the actor is hidden break; } } uint64 OriginalHiddenViews = Actor->HiddenEditorViews; // right now, if one is hidden, the actor is hidden if (NumHiddenLayers) { Actor->HiddenEditorViews |= ((uint64)1 << ViewIndex); } else { Actor->HiddenEditorViews &= ~((uint64)1 << ViewIndex); } // reregister if we changed the visibility bits, as the rendering thread needs them if (bReregisterIfDirty && OriginalHiddenViews != Actor->HiddenEditorViews) { Actor->MarkComponentsRenderStateDirty(); // make sure we redraw the viewport ViewportClient->Invalidate(); } } void ULayersSubsystem::UpdateActorAllViewsVisibility(AActor* Actor) { uint64 OriginalHiddenViews = Actor->HiddenEditorViews; for (FLevelEditorViewportClient* ViewportClient : GEditor->GetLevelViewportClients()) { // don't have this reattach, as we can do it once for all views UpdateActorViewVisibility(ViewportClient, Actor, false); } // reregister if we changed the visibility bits, as the rendering thread needs them if (OriginalHiddenViews != Actor->HiddenEditorViews) { return; } Actor->MarkComponentsRenderStateDirty(); // redraw all viewports if the actor for (FLevelEditorViewportClient* ViewportClient : GEditor->GetLevelViewportClients()) { // make sure we redraw all viewports ViewportClient->Invalidate(); } } void ULayersSubsystem::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. if (ViewportClient->GetWorld()) { for( FActorIterator It(ViewportClient->GetWorld()) ; It ; ++It ) { 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 Components; Actor->GetComponents(Components); for (UActorComponent* Component : Actor->GetComponents()) { UPrimitiveComponent* PrimitiveComponent = Cast(Component); if (PrimitiveComponent && PrimitiveComponent->IsRegistered()) { // Push visibility to the render thread PrimitiveComponent->PushEditorVisibilityToProxy( Actor->HiddenEditorViews ); } } } } } static void UpdateBrushLayerVisibility(ABrush* Brush, bool bIsHidden) { ULevel* Level = Brush->GetLevel(); if (!Level) { return; } UModel* Model = Level->Model; if (!Model) { return; } bool bAnySurfaceWasFound = false; for (FBspSurf& Surf : Model->Surfs) { if (Surf.Actor == Brush) { Surf.bHiddenEdLayer = bIsHidden; bAnySurfaceWasFound = true; } } if (bAnySurfaceWasFound) { Level->UpdateModelComponents(); Model->InvalidSurfaces = true; } } bool ULayersSubsystem::UpdateActorVisibility(AActor* Actor, bool& bOutSelectionChanged, bool& bOutActorModified, const bool bNotifySelectionChange, const bool bRedrawViewports) { bOutActorModified = false; bOutSelectionChanged = false; if( !IsActorValidForLayer( Actor ) ) { return false; } // If the actor doesn't belong to any layers if( Actor->Layers.Num() == 0) { bOutActorModified = Actor->SetIsHiddenEdLayer(false); return bOutActorModified; } bool bActorBelongsToVisibleLayer = false; for( int32 LayerIndex = 0 ; LayerIndex < GetWorld()->Layers.Num() ; ++LayerIndex ) { ULayer* Layer = GetWorld()->Layers[ LayerIndex ]; if( !Layer->IsVisible() ) { continue; } if( Actor->Layers.Contains( Layer->GetLayerName() ) ) { if (Actor->SetIsHiddenEdLayer(false)) { bOutActorModified = true; if (ABrush* Brush = Cast(Actor)) { const bool bIsHidden = false; UpdateBrushLayerVisibility(Brush, bIsHidden); } } // Stop, because we found at least one visible layer the actor belongs to bActorBelongsToVisibleLayer = true; break; } } // If the actor isn't part of a visible layer, hide and de-select it. if( !bActorBelongsToVisibleLayer ) { if (Actor->SetIsHiddenEdLayer(true)) { bOutActorModified = true; if (ABrush* Brush = Cast(Actor)) { const bool bIsHidden = true; UpdateBrushLayerVisibility(Brush, bIsHidden); } } //if the actor was selected, mark it as unselected if ( Actor->IsSelected() ) { bool bSelect = false; bool bNotify = false; bool bIncludeHidden = true; GEditor->SelectActor( Actor, bSelect, bNotify, bIncludeHidden ); bOutSelectionChanged = true; bOutActorModified = true; } } if ( bNotifySelectionChange && bOutSelectionChanged ) { GEditor->NoteSelectionChange(); } if( bRedrawViewports ) { GEditor->RedrawLevelEditingViewports(); } return bOutActorModified || bOutSelectionChanged; } bool ULayersSubsystem::UpdateAllActorsVisibility(const bool bNotifySelectionChange, const bool bRedrawViewports) { bool bSelectionChanged = false; bool bChangesOccurred = false; for( FActorIterator It(GetWorld()) ; It ; ++It ) { AActor* Actor = *It; bool bActorModified = false; bool bActorSelectionChanged = false; const bool bActorNotifySelectionChange = false; const bool bActorRedrawViewports = false; bChangesOccurred |= UpdateActorVisibility( Actor, bActorSelectionChanged /*OUT*/, bActorModified /*OUT*/, bActorNotifySelectionChange, bActorRedrawViewports ); bSelectionChanged |= bActorSelectionChanged; } if ( bNotifySelectionChange && bSelectionChanged ) { GEditor->NoteSelectionChange(); } if( bRedrawViewports ) { GEditor->RedrawLevelEditingViewports(); } return bChangesOccurred; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Operations on layers // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray< AActor* >& InOutActors) const { AppendActorsFromLayer(LayerName, InOutActors, nullptr); } #define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1 \ for (FActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) \ { #define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2 \ if (Filter.IsValid() && !Filter->PassesFilter(Actor)) \ { \ continue; \ } \ \ if (Actor->Layers.Contains(LayerName)) \ { \ InOutActors.Add(Actor); \ } \ } void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray< AActor* >& InOutActors, const TSharedPtr< ActorFilter >& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1 AActor* Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2 } void ULayersSubsystem::AppendActorsFromLayer(const FName& LayerName, TArray< TWeakObjectPtr< AActor > >& InOutActors, const TSharedPtr< ActorFilter >& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1 const TWeakObjectPtr< AActor > Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2 } void ULayersSubsystem::AppendActorsFromLayers(const TArray< FName >& LayerNames, TArray< AActor* >& InOutActors) const { AppendActorsFromLayers(LayerNames, InOutActors, nullptr); } #define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1 \ for (FActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) \ { #define LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2 \ if (Filter.IsValid() && !Filter->PassesFilter(Actor)) \ { \ continue; \ } \ \ for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt) \ { \ const FName& LayerName = *LayerNameIt; \ \ if (Actor->Layers.Contains(LayerName)) \ { \ InOutActors.Add(Actor); \ break; \ } \ } \ } void ULayersSubsystem::AppendActorsFromLayers(const TArray< FName >& LayerNames, TArray< AActor* >& InOutActors, const TSharedPtr< ActorFilter >& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1 AActor* Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2 } void ULayersSubsystem::AppendActorsFromLayers(const TArray< FName >& LayerNames, TArray< TWeakObjectPtr< AActor > >& InOutActors, const TSharedPtr< ActorFilter >& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1 const TWeakObjectPtr< AActor > Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2 } TArray< AActor* > ULayersSubsystem::GetActorsFromLayer(const FName& LayerName) const { TArray< AActor* > OutActors; AppendActorsFromLayer(LayerName, OutActors); return OutActors; } TArray< AActor* > ULayersSubsystem::GetActorsFromLayer(const FName& LayerName, const TSharedPtr< ActorFilter >& Filter) const { TArray< AActor* > OutActors; AppendActorsFromLayer(LayerName, OutActors, Filter); return OutActors; } TArray< AActor* > ULayersSubsystem::GetActorsFromLayers(const TArray< FName >& LayerNames) const { TArray< AActor* > OutActors; AppendActorsFromLayers(LayerNames, OutActors); return OutActors; } TArray< AActor* > ULayersSubsystem::GetActorsFromLayers(const TArray< FName >& LayerNames, const TSharedPtr< ActorFilter >& Filter) const { TArray< AActor* > OutActors; AppendActorsFromLayers(LayerNames, OutActors, Filter); return OutActors; } void ULayersSubsystem::SetLayerVisibility( const FName& LayerName, const bool bIsVisible ) { SetLayersVisibility( { LayerName }, bIsVisible ); } void ULayersSubsystem::SetLayersVisibility( const TArray< FName >& LayerNames, const bool bIsVisible ) { bool bChangeOccurred = false; for( const auto& LayerName : LayerNames ) { ULayer* Layer = EnsureLayerExists( LayerName ); check( Layer != NULL ); if( Layer->IsVisible() != bIsVisible ) { Layer->Modify(); Layer->SetVisible(bIsVisible); LayersChanged.Broadcast( ELayersAction::Modify, Layer, "bIsVisible" ); bChangeOccurred = true; } } if( bChangeOccurred ) { UpdateAllActorsVisibility( true, true ); } } void ULayersSubsystem::ToggleLayerVisibility( const FName& LayerName ) { ULayer* Layer = EnsureLayerExists( LayerName ); check( Layer != NULL ); Layer->Modify(); Layer->SetVisible(!Layer->IsVisible()); LayersChanged.Broadcast( ELayersAction::Modify, Layer, "bIsVisible" ); UpdateAllActorsVisibility( true, true ); } void ULayersSubsystem::ToggleLayersVisibility( const TArray< FName >& LayerNames ) { if( LayerNames.Num() == 0 ) { return; } for( auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt ) { ULayer* Layer = EnsureLayerExists( *LayerNameIt ); check( Layer != NULL ); Layer->Modify(); Layer->SetVisible(!Layer->IsVisible()); LayersChanged.Broadcast( ELayersAction::Modify, Layer, "bIsVisible" ); } UpdateAllActorsVisibility( true, true ); } void ULayersSubsystem::MakeAllLayersVisible() { for (auto Layer : GetWorld()->Layers) { if( !Layer->IsVisible() ) { Layer->Modify(); Layer->SetVisible(true); LayersChanged.Broadcast( ELayersAction::Modify, TWeakObjectPtr< ULayer >(Layer), "bIsVisible" ); } } UpdateAllActorsVisibility( true, true ); } ULayer* ULayersSubsystem::GetLayer(const FName& LayerName) const { for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt) { ULayer* Layer = *LayerIt; if (Layer->GetLayerName() == LayerName) { return Layer; } } return nullptr; } bool ULayersSubsystem::IsLayer(const FName& LayerName) { ULayer* OutLayer = GetLayer(LayerName); return (OutLayer != nullptr); } bool ULayersSubsystem::TryGetLayer(const FName& LayerName, ULayer*& OutLayer) { OutLayer = GetLayer(LayerName); return (OutLayer != nullptr); } void ULayersSubsystem::AddAllLayerNamesTo( TArray< FName >& OutLayers ) const { for( auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt ) { ULayer* Layer = *LayerIt; OutLayers.Add( Layer->GetLayerName() ); } } #define LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO \ for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt) \ { \ OutLayers.Add(*LayerIt); \ } void ULayersSubsystem::AddAllLayersTo(TArray< ULayer* >& OutLayers) const { LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO } void ULayersSubsystem::AddAllLayersTo(TArray< TWeakObjectPtr< ULayer > >& OutLayers) const { LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO } ULayer* ULayersSubsystem::CreateLayer(const FName& LayerName) { ULayer* NewLayer = NewObject(GetWorld(), NAME_None, RF_Transactional | RF_Transient); check(NewLayer != NULL); GetWorld()->Modify(false); GetWorld()->Layers.Add(NewLayer); NewLayer->SetLayerName(LayerName); NewLayer->SetVisible(true); LayersChanged.Broadcast(ELayersAction::Add, NewLayer, NAME_None); return NewLayer; } void ULayersSubsystem::DeleteLayers( const TArray< FName >& LayersToDelete ) { TArray< FName > ValidLayersToDelete; for( auto LayerNameIt = LayersToDelete.CreateConstIterator(); LayerNameIt; ++LayerNameIt ) { if( IsLayer( *LayerNameIt ) ) { ValidLayersToDelete.Add( *LayerNameIt ); } } // Iterate over all actors, looking for actors in the specified layers. for( FActorIterator It(GetWorld()); It ; ++It ) { AActor* Actor = *It; //The Layer must exist in order to remove actors from it, //so we have to wait to delete the ULayer object till after //all the actors have been disassociated with it. RemoveActorFromLayers( Actor, ValidLayersToDelete, false ); } bool bValidLayerExisted = false; for (int LayerIndex = GetWorld()->Layers.Num() - 1; LayerIndex >= 0 ; LayerIndex--) { if( LayersToDelete.Contains( GetWorld()->Layers[ LayerIndex]->GetLayerName() ) ) { GetWorld()->Modify(false); GetWorld()->Layers.RemoveAt( LayerIndex ); bValidLayerExisted = true; } } LayersChanged.Broadcast( ELayersAction::Delete, NULL, NAME_None ); } void ULayersSubsystem::DeleteLayer( const FName& LayerToDelete ) { if( !IsLayer( LayerToDelete ) ) { return; } // Iterate over all actors, looking for actors in the specified layer. for( FActorIterator It(GetWorld()) ; It ; ++It ) { AActor* Actor = *It; //The Layer must exist in order to remove actors from it, //so we have to wait to delete the ULayer object till after //all the actors have been disassociated with it. RemoveActorFromLayer( Actor, LayerToDelete, false ); } bool bValidLayerExisted = false; for (int LayerIndex = GetWorld()->Layers.Num() - 1; LayerIndex >= 0 ; LayerIndex--) { if( LayerToDelete == GetWorld()->Layers[ LayerIndex]->GetLayerName() ) { GetWorld()->Modify(false); GetWorld()->Layers.RemoveAt( LayerIndex ); bValidLayerExisted = true; } } LayersChanged.Broadcast( ELayersAction::Delete, NULL, NAME_None ); } bool ULayersSubsystem::RenameLayer( const FName& OriginalLayerName, const FName& NewLayerName ) { // We specifically don't pass the original LayerName by reference to avoid it changing // it's original value, in case, it would be the reference of the Layer's actually FName if ( OriginalLayerName == NewLayerName ) { return false; } ULayer* Layer; if( !TryGetLayer( OriginalLayerName, Layer ) ) { return false; } Layer->Modify(); const FName OriginalLayerNameCopy = OriginalLayerName; // Otherwise, bug if RenameLayer(Layer->LayerName, NewLayerName) after the next LayerName rename Layer->SetLayerName(NewLayerName); Layer->ClearActorStats(); // Iterate over all actors, swapping layers. for( FActorIterator It(GetWorld()) ; It ; ++It ) { AActor* Actor = *It; if( !IsActorValidForLayer( Actor ) ) { continue; } if (ULayersSubsystem::RemoveActorFromLayer(Actor, OriginalLayerNameCopy)) { // No need to mark the actor as modified these functions take care of that AddActorToLayer( Actor, NewLayerName ); } } // update all views's hidden layers if they had this one for (FLevelEditorViewportClient* ViewportClient : GEditor->GetLevelViewportClients()) { if (ViewportClient->ViewHiddenLayers.Remove(OriginalLayerNameCopy) > 0) { ViewportClient->ViewHiddenLayers.AddUnique( NewLayerName ); ViewportClient->Invalidate(); } } LayersChanged.Broadcast( ELayersAction::Rename, Layer, "LayerName" ); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Helper functions. // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ULayersSubsystem::AddActorToStats(ULayer* Layer, AActor* Actor) { if (!Actor) { return; } Layer->AddToStats(Actor); LayersChanged.Broadcast(ELayersAction::Modify, Layer, TEXT("ActorStats")); } void ULayersSubsystem::RemoveActorFromStats(ULayer* Layer, AActor* Actor) { if (!Actor) { return; } bool bFoundClassStats = Layer->RemoveFromStats(Actor); if (bFoundClassStats) { LayersChanged.Broadcast(ELayersAction::Modify, Layer, TEXT("ActorStats")); } } ULayer* ULayersSubsystem::EnsureLayerExists(const FName& LayerName) { ULayer* Layer; if (!TryGetLayer(LayerName, Layer)) { Layer = CreateLayer(LayerName); } return Layer; }