// 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" 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(); 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); } } 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); } } void FLayersBroadcast::OnEditorMapChange(uint32 MapChangeFlags) { LayersSubsystem->EditorMapChange(); } void FLayersBroadcast::OnEditorRefreshLayerBrowser() { LayersSubsystem->EditorRefreshLayerBrowser(); } 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); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // 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) { if (!Actor || Actor->GetClass() == nullptr || Actor->GetWorld() == nullptr) { return false; } const bool bIsBuilderBrush = FActorEditorUtils::IsABuilderBrush(Actor); const bool bIsHidden = (Actor->GetClass()->GetDefaultObject()->bHiddenEd == true); const bool bIsInEditorWorld = (Actor->GetWorld()->WorldType == EWorldType::Editor); const bool bIsValid = !bIsHidden && !bIsBuilderBrush && bIsInEditorWorld; return bIsValid; } 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) { if (!IsActorValidForLayer(Actor)) { return false; } bool bChangeOccurred = false; for (auto LayerNameIt = Actor->Layers.CreateConstIterator(); LayerNameIt; ++LayerNameIt) { const FName LayerName = *LayerNameIt; ULayer* Layer = EnsureLayerExists(LayerName); Layer->Modify(); RemoveActorFromStats(Layer, Actor); bChangeOccurred = true; } return bChangeOccurred; } UWorld* ULayersSubsystem::GetWorld() const { return GWorld; } bool ULayersSubsystem::AddActorToLayer(AActor* Actor, const FName& LayerName) { TArray Actors; Actors.Add(Actor); TArray LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorToLayers(AActor* Actor, const TArray& LayerNames) { TArray Actors; Actors.Add(Actor); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayer(const TArray& Actors, const FName& LayerName) { TArray LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayer(const TArray>& Actors, const FName& LayerName) { TArray LayerNames; LayerNames.Add(LayerName); return AddActorsToLayers(Actors, LayerNames); } bool ULayersSubsystem::AddActorsToLayers(const TArray& Actors, const TArray& 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); } } // 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>& Actors, const TArray& LayerNames) { TArray ActorsRawPtr; for (auto ActorIt = Actors.CreateConstIterator(); ActorIt; ++ActorIt) { AActor* Actor = (*ActorIt).Get(); ActorsRawPtr.Add(Actor); } return AddActorsToLayers(ActorsRawPtr, LayerNames); } bool ULayersSubsystem::RemoveActorFromLayer(AActor* Actor, const FName& LayerName, const bool bUpdateStats) { TArray Actors; Actors.Add(Actor); TArray LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorFromLayers(AActor* Actor, const TArray& LayerNames, const bool bUpdateStats) { TArray Actors; Actors.Add(Actor); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayer(const TArray& Actors, const FName& LayerName, const bool bUpdateStats) { TArray LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayer(const TArray>& Actors, const FName& LayerName, const bool bUpdateStats) { TArray LayerNames; LayerNames.Add(LayerName); return RemoveActorsFromLayers(Actors, LayerNames, bUpdateStats); } bool ULayersSubsystem::RemoveActorsFromLayers(const TArray& Actors, const TArray& 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); } } } // 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>& Actors, const TArray& LayerNames, const bool bUpdateStats) { TArray 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 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 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& LayerNames) { return AddActorsToLayers(GetSelectedActors(), LayerNames); } bool ULayersSubsystem::RemoveSelectedActorsFromLayers(const TArray& 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& 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& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden) { return SelectActorsInLayers(LayerNames, bSelect, bNotify, bSelectEvenIfHidden, nullptr); } bool ULayersSubsystem::SelectActorsInLayers(const TArray& LayerNames, const bool bSelect, const bool bNotify, const bool bSelectEvenIfHidden, const TSharedPtr& 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(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. 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) { // If the actor is also hidden if (Actor->bHiddenEdLayer) { // Actors that don't belong to any layer shouldn't be hidden Actor->bHiddenEdLayer = false; Actor->MarkComponentsRenderStateDirty(); bOutActorModified = true; } return bOutActorModified; } bool bActorBelongsToVisibleLayer = false; for (int32 LayerIndex = 0; LayerIndex < GetWorld()->Layers.Num(); ++LayerIndex) { ULayer* Layer = GetWorld()->Layers[LayerIndex]; if (!Layer->bIsVisible) { continue; } if (Actor->Layers.Contains(Layer->LayerName)) { if (Actor->bHiddenEdLayer) { Actor->bHiddenEdLayer = false; Actor->MarkComponentsRenderStateDirty(); 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->bHiddenEdLayer) { Actor->bHiddenEdLayer = true; Actor->MarkComponentsRenderStateDirty(); 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& 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& InOutActors, const TSharedPtr& 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>& InOutActors, const TSharedPtr& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_1 const TWeakObjectPtr Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYER_PART_2 } void ULayersSubsystem::AppendActorsFromLayers(const TArray& LayerNames, TArray& 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& LayerNames, TArray& InOutActors, const TSharedPtr& 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& LayerNames, TArray>& InOutActors, const TSharedPtr& Filter) const { LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_1 const TWeakObjectPtr Actor = *ActorIt; LAYERS_SUBSYSTEM_APPEND_ACTORS_FOR_LAYERS_PART_2 } TArray ULayersSubsystem::GetActorsFromLayer(const FName& LayerName) const { TArray OutActors; AppendActorsFromLayer(LayerName, OutActors); return OutActors; } TArray ULayersSubsystem::GetActorsFromLayer(const FName& LayerName, const TSharedPtr& Filter) const { TArray OutActors; AppendActorsFromLayer(LayerName, OutActors, Filter); return OutActors; } TArray ULayersSubsystem::GetActorsFromLayers(const TArray& LayerNames) const { TArray OutActors; AppendActorsFromLayers(LayerNames, OutActors); return OutActors; } TArray ULayersSubsystem::GetActorsFromLayers(const TArray& LayerNames, const TSharedPtr& Filter) const { TArray OutActors; AppendActorsFromLayers(LayerNames, OutActors, Filter); return OutActors; } void ULayersSubsystem::SetLayerVisibility(const FName& LayerName, const bool bIsVisible) { ULayer* Layer = EnsureLayerExists(LayerName); check(Layer != nullptr); Layer->Modify(); Layer->bIsVisible = bIsVisible; LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible"); UpdateAllActorsVisibility(true, true); } void ULayersSubsystem::SetLayersVisibility(const TArray& LayerNames, const bool bIsVisible) { if (LayerNames.Num() == 0) { return; } bool bChangeOccurred = false; for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt) { ULayer* Layer = EnsureLayerExists(*LayerNameIt); check(Layer != NULL); if (Layer->bIsVisible != bIsVisible) { Layer->Modify(); Layer->bIsVisible = 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->bIsVisible = !Layer->bIsVisible; LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible"); UpdateAllActorsVisibility(true, true); } void ULayersSubsystem::ToggleLayersVisibility(const TArray& LayerNames) { if (LayerNames.Num() == 0) { return; } for (auto LayerNameIt = LayerNames.CreateConstIterator(); LayerNameIt; ++LayerNameIt) { ULayer* Layer = EnsureLayerExists(*LayerNameIt); check(Layer != NULL); Layer->Modify(); Layer->bIsVisible = !Layer->bIsVisible; LayersChanged.Broadcast(ELayersAction::Modify, Layer, "bIsVisible"); } UpdateAllActorsVisibility(true, true); } void ULayersSubsystem::MakeAllLayersVisible() { TArray AllLayerNames; ULayersSubsystem::AddAllLayerNamesTo(AllLayerNames); for (auto LayerIt = GetWorld()->Layers.CreateIterator(); LayerIt; ++LayerIt) { ULayer* Layer = *LayerIt; if (!Layer->bIsVisible) { Layer->Modify(); Layer->bIsVisible = true; LayersChanged.Broadcast(ELayersAction::Modify, TWeakObjectPtr(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->LayerName == 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& OutLayers) const { for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt) { ULayer* Layer = *LayerIt; OutLayers.Add(Layer->LayerName); } } #define LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO \ for (auto LayerIt = GetWorld()->Layers.CreateConstIterator(); LayerIt; ++LayerIt) \ { \ OutLayers.Add(*LayerIt); \ } void ULayersSubsystem::AddAllLayersTo(TArray& OutLayers) const { LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO } void ULayersSubsystem::AddAllLayersTo(TArray>& OutLayers) const { LAYERS_SUBSYSTEM_ADD_ALL_LAYERS_TO} ULayer* ULayersSubsystem::CreateLayer(const FName& LayerName) { ULayer* NewLayer = NewObject(GetWorld(), NAME_None, RF_Transactional); check(NewLayer != NULL); GetWorld()->Modify(); GetWorld()->Layers.Add(NewLayer); NewLayer->LayerName = LayerName; NewLayer->bIsVisible = true; LayersChanged.Broadcast(ELayersAction::Add, NewLayer, NAME_None); return NewLayer; } void ULayersSubsystem::DeleteLayers(const TArray& LayersToDelete) { TArray 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]->LayerName)) { GetWorld()->Modify(); 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]->LayerName) { GetWorld()->Modify(); 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->LayerName = NewLayerName; Layer->ActorStats.Empty(); // 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; } UClass* ActorClass = Actor->GetClass(); bool bFoundClassStats = false; for (auto StatsIt = Layer->ActorStats.CreateIterator(); StatsIt; ++StatsIt) { FLayerActorStats& Stats = *StatsIt; if (Stats.Type == ActorClass) { Stats.Total++; bFoundClassStats = true; break; } } if (!bFoundClassStats) { FLayerActorStats NewActorStats; NewActorStats.Total = 1; NewActorStats.Type = ActorClass; Layer->ActorStats.Add(NewActorStats); } LayersChanged.Broadcast(ELayersAction::Modify, Layer, TEXT("ActorStats")); } void ULayersSubsystem::RemoveActorFromStats(ULayer* Layer, AActor* Actor) { if (!Actor) { return; } UClass* ActorClass = Actor->GetClass(); bool bFoundClassStats = false; for (int StatsIndex = 0; StatsIndex < Layer->ActorStats.Num(); StatsIndex++) { FLayerActorStats& Stats = Layer->ActorStats[StatsIndex]; if (Stats.Type == ActorClass) { bFoundClassStats = true; --Stats.Total; if (Stats.Total == 0) { Layer->ActorStats.RemoveAt(StatsIndex); } break; } } 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; }