Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/Layers/LayersSubsystem.cpp
2025-05-18 13:04:45 +08:00

1372 lines
36 KiB
C++

// 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<ULayersSubsystem>()
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<AActor*>& 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<AActor*>(*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<UPrimitiveComponent*> Components;
Actor->GetComponents(Components);
for (UActorComponent* Component : Actor->GetComponents())
{
UPrimitiveComponent* PrimitiveComponent = Cast<UPrimitiveComponent>(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<ABrush>(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<ABrush>(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<ULayer>(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;
}