// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Array.h" #include "Containers/BitArray.h" #include "Containers/Map.h" #include "Containers/Set.h" #include "Containers/SparseArray.h" #include "Containers/UnrealString.h" #include "Delegates/Delegate.h" #include "EditorUndoClient.h" #include "HAL/Platform.h" #include "HAL/PlatformCrt.h" #include "Input/Reply.h" #include "Internationalization/Text.h" #include "Misc/Attribute.h" #include "Misc/NotifyHook.h" #include "Misc/Optional.h" #include "Templates/SharedPointer.h" #include "Templates/TypeHash.h" #include "Templates/UnrealTemplate.h" #include "TreeItemID.h" #include "Types/SlateEnums.h" #include "UObject/WeakObjectPtrTemplates.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SCompoundWidget.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STreeView.h" class AActor; class ALODActor; class AWorldSettings; class FActiveTimerHandle; class FDragDropEvent; class IDetailsView; class IHierarchicalLODUtilities; class ITableRow; class SVerticalBox; class SWidget; class ULevel; class UObject; class UWorld; struct FGeometry; struct FKeyEvent; struct FPointerEvent; namespace HLODOutliner { struct FTreeItemID; struct ITreeItem; typedef TSharedPtr FTreeItemPtr; typedef TSharedRef FTreeItemRef; /** * Outliner action class used for making changing to the Outliner's treeview */ struct FOutlinerAction { enum ActionType { AddItem, RemoveItem, MoveItem }; FOutlinerAction(ActionType InType, FTreeItemPtr InItem) : Type(InType), Item(InItem) {}; FOutlinerAction(ActionType InType, FTreeItemPtr InItem, FTreeItemPtr InParentItem) : Type(InType), Item(InItem), ParentItem( InParentItem) {}; ActionType Type; FTreeItemPtr Item; FTreeItemPtr ParentItem; }; /** * Implements the profiler window. */ class SHLODOutliner : public SCompoundWidget, public FNotifyHook, public FEditorUndoClient { typedef STreeView SHLODTree; friend struct FLODActorItem; friend struct FHLODTreeWidgetItem; friend struct FStaticMeshActorItem; friend struct FLODLevelItem; friend class SHLODWidgetItem; public: /** Default constructor. */ SHLODOutliner(); /** Virtual destructor. */ virtual ~SHLODOutliner(); SLATE_BEGIN_ARGS(SHLODOutliner){} SLATE_END_ARGS() /** * Constructs this widget. */ void Construct(const FArguments& InArgs); /** Create the panel's forced HLOD level viewer */ TSharedRef CreateForcedViewWidget(); /** Creates the panel's main button widget rows */ TSharedRef CreateMainButtonWidgets(); /** Creates the panel's button widgets for cluster operations */ TSharedRef CreateClusterButtonWidgets(); /** Creates the panel's Tree view widget*/ TSharedRef CreateTreeviewWidget(); /** Initializes and creates the settings view */ void CreateSettingsView(); //~ Begin SCompoundWidget Interface virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; //~ End SCompoundWidget Interface //~ Begin FEditorUndoClient Interface virtual void PostUndo(bool bSuccess) override; virtual void PostRedo(bool bSuccess) override { PostUndo(bSuccess); } // End of FEditorUndoClient /** Button handlers */ FText GetForceBuildText() const; FText GetForceBuildToolTip() const; FText GetBuildText() const; FReply HandleDeleteHLODs(); bool CanDeleteHLODs() const; FReply HandlePreviewHLODs(); FReply RetrieveActors(); FReply HandleBuildLODActors(); bool CanBuildLODActors() const; FText GetBuildLODActorsTooltipText() const; FReply HandleForceBuildLODActors(); FReply HandleForceRefresh(); FReply HandleSaveAll(); FText GetGenerateClustersText() const; FText GetGenerateClustersTooltip() const; FText GetRegenerateClustersText() const; FText GetRegenerateClustersTooltip() const; /** End button handlers */ private: /** Registers all the callback delegates required for keeping the treeview sync */ void RegisterDelegates(); /** De-registers all the callback delegates required for keeping the treeview sync */ void DeregisterDelegates(); /** Builds the toolbar */ TSharedRef MakeToolBar(); /** Callbacks to make interaction from UI uniform vs. UI updates*/ FReply GenerateClustersFromUI(); FReply GenerateProxyMeshesFromUI(); FReply BuildClustersAndMeshesFromUI(); /** Helper function used to determine whether there are any LOD actors present */ bool HasHLODActors() const; protected: /** Forces viewing the mesh of a Cluster (LODActor) */ void ForceViewLODActor(); /** * Returns whether or not all HLODs in the level are build * * @return bool */ bool AreHLODsBuild() const; /** * Returns FText with information about current forced HLOD level "None", "1" etc. * * @return FText */ FText HandleForceLevelText() const; /** Build the forced level widget */ TSharedRef GetForceLevelMenuContent() const; /** * Restores the forced viewing state for the given LOD levle * * @param LODLevel - LOD level to force */ void RestoreForcedLODLevel(int32 LODLevel); /** * Forces LODActors within the given LODLevel to show their meshes (other levels hide theirs) * * @param LODLevel - LOD level to force */ void SetForcedLODLevel(int32 LODLevel); /** Resets the forced LOD level */ void ResetLODLevelForcing(); /** Creates a Hierarchical LOD Volume for the given LODActorItem, volume bounds correspond to those of the LODActor's SubActors */ void CreateHierarchicalVolumeForActor(); protected: /** Builds the HLOD mesh for the given ALODActor (cluster) */ void BuildLODActor(); /** Rebuilds the HLOD mesh for the given ALODActor (cluster) */ void RebuildLODActor(); /** Select the LODActor in the Editor Viewport */ void SelectLODActor(); /** Deletes a cluster (LODActor) */ void DeleteCluster(); /** Selects the contained actors (SubActors) for a specific LODActor */ void SelectContainedActors(); /** Removes the given StaticMeshActor from its parent's (ALODActor) sub-actors array */ void RemoveStaticMeshActorFromCluster(); /* Removes the given StaticMeshActor from its parent's (ALODActor) sub-actors array and excludes it from cluster generation */ void ExcludeFromClusterGeneration(); /** Removes the given LODActor from its parent's (ALODActor) sub-actors array */ void RemoveLODActorFromCluster(); /** Creates a cluster from a set of actors for the given lod level index */ void CreateClusterFromActors(const TArray& Actors, uint32 LODLevelIndex); /** * Updates the DrawDistance value for all the LODActors with the given LODLevelIndex * * @param LODLevelIndex - */ void UpdateDrawDistancesForLODLevel(const uint32 LODLevelIndex); /** * Removes LODActors within the given HLODLevel * * @param LODLevelIndex - */ void RemoveLODLevelActors(const int32 HLODLevelIndex); /** Handle splitting horizontally or vertically based on dimensions */ int32 GetSpitterWidgetIndex() const; protected: /** Tree view callbacks */ /** * Generates a Tree view row for the given Tree view Node * * @param InReflectorNode - Node to generate a row for * @param OwnerTable - Owning table of the InReflectorNode * @return TSharedRef */ TSharedRef OnOutlinerGenerateRow(FTreeItemPtr InReflectorNode, const TSharedRef& OwnerTable); /** * Treeview callback for retrieving the children of a specific TreeItem * * @param InParent - Parent item to return the children from * @param OutChildren - InOut array for the children */ void OnOutlinerGetChildren(FTreeItemPtr InParent, TArray& OutChildren); /** * Handles the event fired when selection with the HLOD Tree view changes * * @param TreeItem - Selected node(s) * @param SelectionInfo - Type of selection change */ void OnOutlinerSelectionChanged(FTreeItemPtr TreeItem, ESelectInfo::Type /*SelectionInfo*/); /** * Handles double click events from the HLOD Tree view * * @param TreeItem - Node which was double-clicked */ void OnOutlinerDoubleClick(FTreeItemPtr TreeItem); /** Open a context menu for this scene outliner */ TSharedPtr OnOpenContextMenu(); /** * Handles item expansion events from the HLOD tree view * * @param TreeItem - Item which expansion state was changed * @param bIsExpanded - New expansion state */ void OnItemExpansionChanged(FTreeItemPtr TreeItem, bool bIsExpanded); /** End of Tree view callbacks */ private: /** Starts the Editor selection batch */ void StartSelection(); /** Empties the current Editor selection */ void EmptySelection(); /** Destroys the created selection actors */ void DestroySelectionActors(); /** * Selects an Actor in the Editor viewport * * @param Actor - AActor to select inside the viewport * @param SelectionDepth - (recursive) */ void SelectActorInViewport(AActor* Actor, const uint32 SelectionDepth = 0); /** * Selects actors and sub-actors and the given LODActor * * @param LODActor - Actor to select + subactors * @param SelectionDepth - (recursive) */ void SelectLODActorAndContainedActorsInViewport(ALODActor* LODActor, const uint32 SelectionDepth = 0); /** * Selects actors and sub-actors for the given LODActor * * @param LODActor - Actor to select + subactors * @param SelectionDepth - (recursive) */ void SelectContainedActorsInViewport(ALODActor* LODActor, const uint32 SelectionDepth = 0); /** * Creates a ASelectionActor for the given actor, "procedurally" drawing its bounds * * @param Actor - Actor to create the SelectionActor for * @return UDrawSphereComponent* */ void AddLODActorForBoundsDrawing(AActor* Actor); /** Ends the Editor selection batch, bChange determines whether or not there was an actual change and call NoteSelectionChange */ void EndSelection(const bool bChange); protected: /** Broadcast event delegates */ /** Called by USelection::SelectionChangedEvent delegate when the level's selection changes */ void OnLevelSelectionChanged(UObject* Obj); /** Called by the engine when a level is added to the world. */ void OnLevelAdded(ULevel* InLevel, UWorld* InWorld); /** Called by the engine when a level is removed from the world. */ void OnLevelRemoved(ULevel* InLevel, UWorld* InWorld); /** Called by the engine when an actor is added to the world. */ void OnLevelActorsAdded(AActor* InActor); /** Called by the engine when an actor is remove from the world. */ void OnLevelActorsRemoved(AActor* InActor); /** Called when the map has changed*/ void OnMapChange(uint32 MapFlags); /** Called when the current level has changed */ void OnNewCurrentLevel(); /** Called when a new map is being loaded */ void OnMapLoaded(const FString& Filename, bool bAsTemplate); /** Called when a HLODActor is moved between clusters */ void OnHLODActorMovedEvent(const AActor* InActor, const AActor* ParentActor); /** Called when an Actor is moved inside of the level */ void OnActorMovedEvent(AActor* InActor); /** Called when and HLODActor is added to the level */ void OnHLODActorAddedEvent(const AActor* InActor, const AActor* ParentActor); /** Called when a DrawDistance value within WorldSettings changed */ void OnHLODTransitionScreenSizeChangedEvent(); /** Called when the HLOD Levels array within WorldSettings changed */ void OnHLODLevelsArrayChangedEvent(); /** Called when an Actor is removed from a cluster */ void OnHLODActorRemovedFromClusterEvent(const AActor* InActor, const AActor* ParentActor); /** End of Broadcast event delegates */ /** Callback function used to check if Hierarchical LOD functionality is enabled in the current world settings */ bool OutlinerEnabled() const; /** Called when a PIE session is beginning */ void OnBeginPieEvent(bool bIsSimulating); /** Called when a PIE session is ending */ void OnEndPieEvent(bool bIsSimulating); private: /** Tells the scene outliner that it should do a full refresh, which will clear the entire tree and rebuild it from scratch. */ void FullRefresh(); /** Retrieves and updates the current world and world settings pointers (returns whether or not a world was found) */ const bool UpdateCurrentWorldAndSettings(); /** Populates the HLODTreeRoot array and consequently the Treeview */ void Populate(); /** Clears and resets all arrays and maps containing cached/temporary data */ void ResetCachedData(); /** Structure containing information relating to the expansion state of parent items in the tree */ typedef TMap FParentsExpansionState; /** Gets the current expansion state of parent items */ TMap GetParentsExpansionState() const; /** Updates the expansion state of parent items after a repopulate, according to the previous state */ void SetParentsExpansionState(const FParentsExpansionState& ExpansionStateInfo) const; /** * Adds a new Treeview item * * @param InItem - Item to add * @param InParentItem - Optional parent item to add it to * @return const bool */ const bool AddItemToTree(FTreeItemPtr InItem, FTreeItemPtr InParentItem); /** * Moves a TreeView item around * * @param InItem - Item to move * @param InParentItem - New parent for InItem to move to */ void MoveItemInTree(FTreeItemPtr InItem, FTreeItemPtr InParentItem); /** * Removes a TreeView item * * @param InItem - Item to remove */ void RemoveItemFromTree(FTreeItemPtr InItem); /** * Selects a Treeview item * * @param InItem - Item to select */ void SelectItemInTree(FTreeItemPtr InItem); /** Timer to update cached 'needs build' flag */ EActiveTimerReturnType UpdateNeedsBuildFlagTimer(double InCurrentTime, float InDeltaTime); /** Closes asset editors showing HLOD data */ void CloseOpenAssetEditors(); private: /** Whether or not we need to do a refresh of the Tree view*/ bool bNeedsRefresh; /** World instance we are currently representing/mirroring in the panel */ TWeakObjectPtr CurrentWorld; /** World settings found in CurrentWorld */ AWorldSettings* CurrentWorldSettings; /** Tree view nodes */ TArray HLODTreeRoot; /** Currently selected Tree view nodes*/ TArray SelectedNodes; /** HLOD Treeview widget*/ TSharedPtr TreeView; /** Property viewing widget */ TSharedPtr SettingsView; /** Content panel widget */ TSharedPtr MainContentPanel; /** Attribute determining if the outliner UI is enabled*/ TAttribute EnabledAttribute; /** Map containing all the nodes with their corresponding keys */ TMultiMap TreeItemsMap; /** Array of pending OutlinerActions */ TArray PendingActions; /** Array containing all the nodes */ TArray AllNodes; /** Array of currently selected LODActors */ TArray SelectedLODActors; /** Currently forced LOD level*/ int32 ForcedLODLevel; /** Array with flags for each LOD level (whether or not all their Clusters/LODActors have their meshes built) */ TArray LODLevelBuildFlags; /** Array of LODActors/Cluster per LOD level*/ TArray>> LODLevelActors; /** Array of TransitionScreenSizes for each LOD Level*/ TArray LODLevelTransitionScreenSizes; /** Cached pointer to HLOD utilities */ IHierarchicalLODUtilities* HierarchicalLODUtilities; /** Update active timer handle */ TSharedPtr ActiveTimerHandle; /** Cached flag to see if we need to generate meshes (any actors are dirty) */ bool bCachedNeedsBuild; /** Whether to arrange the main UI horizontally or vertically */ bool bArrangeHorizontally; }; };