2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "StaticMeshEditor.h"
2022-05-02 18:06:48 -04:00
# include "AssetRegistry/AssetData.h"
2016-11-23 15:48:37 -05:00
# include "Misc/MessageDialog.h"
# include "HAL/FileManager.h"
# include "Misc/ScopedSlowTask.h"
# include "Modules/ModuleManager.h"
# include "Framework/Application/SlateApplication.h"
2022-05-09 13:12:28 -04:00
# include "Styling/AppStyle.h"
2016-11-23 15:48:37 -05:00
# include "EditorReimportHandler.h"
# include "Editor/UnrealEdEngine.h"
# include "EditorFramework/AssetImportData.h"
# include "Engine/StaticMesh.h"
# include "Editor.h"
# include "UnrealEdGlobals.h"
# include "StaticMeshEditorModule.h"
2019-10-27 14:20:06 -04:00
# include "AI/Navigation/NavCollisionBase.h"
2019-12-19 18:07:47 -05:00
# include "ScopedTransaction.h"
2020-10-14 13:29:31 -04:00
# include "ToolMenus.h"
2016-11-23 15:48:37 -05:00
2014-03-14 14:13:41 -04:00
# include "SStaticMeshEditorViewport.h"
2016-11-23 15:48:37 -05:00
# include "PropertyEditorModule.h"
# include "IDetailsView.h"
# include "IDetailCustomization.h"
2014-03-14 14:13:41 -04:00
# include "StaticMeshEditorTools.h"
# include "StaticMeshEditorActions.h"
Remove more headers from Engine.h (StaticMeshResources.h, AnimTree.h, SkeletalMeshTypes.h, SkeletalMeshActor.h, LightingBuildOptions.h, PixelFormat.h, WorldComposition.h, VisualLog.h, StaticLighting.h, Lightmap.h, ShadowMap.h, Model.h)
2014-05-29 17:21:47 -04:00
# include "StaticMeshResources.h"
2014-03-14 14:13:41 -04:00
# include "BusyCursor.h"
2022-09-11 18:33:06 -04:00
# include "GeomFitUtils.h"
2014-03-14 14:13:41 -04:00
# include "EditorViewportCommands.h"
2021-06-22 11:13:19 -04:00
# include "ConvexDecompTool.h"
2014-03-14 14:13:41 -04:00
2020-10-14 13:29:31 -04:00
# include "MeshMergeModule.h"
2022-09-11 18:33:06 -04:00
# include "Interfaces/IAnalyticsProvider.h"
2014-07-24 04:28:41 -04:00
# include "EngineAnalytics.h"
2016-11-23 15:48:37 -05:00
# include "Widgets/Docking/SDockTab.h"
# include "Framework/Commands/GenericCommands.h"
# include "Widgets/Input/STextComboBox.h"
# include "PhysicsEngine/ConvexElem.h"
# include "PhysicsEngine/BoxElem.h"
# include "PhysicsEngine/SphereElem.h"
# include "PhysicsEngine/SphylElem.h"
2015-06-15 09:34:39 -04:00
# include "PhysicsEngine/BodySetup.h"
2014-07-24 04:28:41 -04:00
2017-04-07 16:51:51 -04:00
# include "AdvancedPreviewSceneModule.h"
2016-06-21 12:37:19 -04:00
2017-10-06 04:43:18 -04:00
# include "ConvexDecompositionNotification.h"
2018-05-23 21:04:31 -04:00
# include "FbxMeshUtils.h"
# include "RawMesh.h"
2019-10-30 18:26:53 -04:00
# include "EditorViewportTabContent.h"
# include "EditorViewportLayout.h"
2021-04-20 18:59:52 -04:00
# include "Toolkits/AssetEditorToolkitMenuContext.h"
2021-09-16 13:57:09 -04:00
# include "EditorModeManager.h"
# include "StaticMeshEditorModeUILayer.h"
# include "AssetEditorModeManager.h"
# include "Engine/Selection.h"
2022-06-29 12:17:25 -04:00
# include "UnrealExporter.h"
# include "Exporters/Exporter.h"
# include "HAL/PlatformApplicationMisc.h"
2022-07-12 13:45:01 -04:00
# include "AssetEditorModeManager.h"
# include "StaticMeshEditorViewportClient.h"
# include "AdvancedPreviewScene.h"
2017-10-06 04:43:18 -04:00
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "StaticMeshEditor"
DEFINE_LOG_CATEGORY_STATIC ( LogStaticMeshEditor , Log , All ) ;
2015-02-21 13:20:31 -05:00
class FStaticMeshStatusMessageContext : public FScopedSlowTask
{
public :
explicit FStaticMeshStatusMessageContext ( const FText & InMessage )
: FScopedSlowTask ( 0 , InMessage )
{
UE_LOG ( LogStaticMesh , Log , TEXT ( " %s " ) , * InMessage . ToString ( ) ) ;
MakeDialog ( ) ;
}
} ;
2022-02-08 13:29:56 -05:00
namespace StaticMeshEditor
{
static void PopulateCollisionMenu ( UToolMenu * Menu )
{
{
FToolMenuSection & Section = Menu - > AddSection ( " CollisionEditCollision " , LOCTEXT ( " CollisionEditCollisionSection " , " Edit Collision " ) ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateSphereCollision ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateSphylCollision ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateBoxCollision ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateDOP10X ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateDOP10Y ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateDOP10Z ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateDOP18 ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateDOP26 ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . ConvertBoxesToConvex ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . RemoveCollision ) ;
Section . AddMenuEntry ( " DeleteCollision " , FGenericCommands : : Get ( ) . Delete , LOCTEXT ( " DeleteCollision " , " Delete Selected Collision " ) , LOCTEXT ( " DeleteCollisionToolTip " , " Deletes the selected Collision from the mesh. " ) ) ;
Section . AddMenuEntry ( " DuplicateCollision " , FGenericCommands : : Get ( ) . Duplicate , LOCTEXT ( " DuplicateCollision " , " Duplicate Selected Collision " ) , LOCTEXT ( " DuplicateCollisionToolTip " , " Duplicates the selected Collision. " ) ) ;
2022-06-29 12:17:25 -04:00
Section . AddMenuEntry ( " CopyCollision " , FGenericCommands : : Get ( ) . Copy , LOCTEXT ( " CopyCollision " , " Copy Selected Collision " ) , LOCTEXT ( " CopyCollisionToolTip " , " Copy the selected Collision to the clipboard. " ) ) ;
Section . AddMenuEntry ( " PasteCollision " , FGenericCommands : : Get ( ) . Paste , LOCTEXT ( " PasteCollision " , " Paste Copied Collision " ) , LOCTEXT ( " PasteCollisionToolTip " , " Paste coppied Collision from the clipboard. " ) ) ;
2022-02-08 13:29:56 -05:00
}
{
FToolMenuSection & Section = Menu - > AddSection ( " CollisionAutoConvexCollision " ) ;
Section . AddSeparator ( " MiscActionsSeparator " ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CreateAutoConvexCollision ) ;
}
{
FToolMenuSection & Section = Menu - > AddSection ( " CollisionCopy " ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . CopyCollisionFromSelectedMesh ) ;
}
{
FToolMenuSection & Section = Menu - > AddSection ( " MeshFindSource " ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . FindSource ) ;
}
{
FToolMenuSection & Section = Menu - > AddSection ( " MeshChange " ) ;
//Section.AddMenuEntry(FStaticMeshEditorCommands::Get().ChangeMesh);
Section . AddDynamicEntry ( " SaveGeneratedLODs " , FNewToolMenuSectionDelegate : : CreateLambda ( [ ] ( FToolMenuSection & InSection )
{
static auto * CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.StaticMesh.EnableSaveGeneratedLODsInPackage " ) ) ;
if ( CVar & & CVar - > GetValueOnGameThread ( ) ! = 0 )
{
InSection . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . SaveGeneratedLODs ) ;
}
} ) ) ;
}
}
static TSharedPtr < FStaticMeshEditor > GetStaticMeshEditorFromMenuContext ( UAssetEditorToolkitMenuContext * InContext )
{
if ( InContext )
{
if ( TSharedPtr < FAssetEditorToolkit > Toolkit = InContext - > Toolkit . Pin ( ) )
{
// Note: This will not detect subclasses of StaticMeshEditor
if ( Toolkit - > GetToolkitFName ( ) = = TEXT ( " StaticMeshEditor " ) )
{
return StaticCastSharedPtr < FStaticMeshEditor > ( Toolkit ) ;
}
}
}
return nullptr ;
}
static TSharedPtr < FStaticMeshEditor > GetStaticMeshEditorFromMenuContext ( UToolMenu * InMenu )
{
return GetStaticMeshEditorFromMenuContext ( InMenu - > FindContext < UAssetEditorToolkitMenuContext > ( ) ) ;
}
static TSharedPtr < FStaticMeshEditor > GetStaticMeshEditorFromMenuContext ( FToolMenuSection & InSection )
{
return GetStaticMeshEditorFromMenuContext ( InSection . FindContext < UAssetEditorToolkitMenuContext > ( ) ) ;
}
}
2014-03-14 14:13:41 -04:00
const FName FStaticMeshEditor : : ViewportTabId ( TEXT ( " StaticMeshEditor_Viewport " ) ) ;
const FName FStaticMeshEditor : : PropertiesTabId ( TEXT ( " StaticMeshEditor_Properties " ) ) ;
const FName FStaticMeshEditor : : SocketManagerTabId ( TEXT ( " StaticMeshEditor_SocketManager " ) ) ;
const FName FStaticMeshEditor : : CollisionTabId ( TEXT ( " StaticMeshEditor_Collision " ) ) ;
2018-11-06 10:00:36 -05:00
const FName FStaticMeshEditor : : PreviewSceneSettingsTabId ( TEXT ( " StaticMeshEditor_PreviewScene " ) ) ;
const FName FStaticMeshEditor : : SecondaryToolbarTabId ( TEXT ( " StaticMeshEditor_SecondaryToolbar " ) ) ;
2014-03-14 14:13:41 -04:00
2016-05-03 15:44:33 -04:00
void FStaticMeshEditor : : RegisterTabSpawners ( const TSharedRef < class FTabManager > & InTabManager )
2014-03-14 14:13:41 -04:00
{
2016-05-03 15:44:33 -04:00
WorkspaceMenuCategory = InTabManager - > AddLocalWorkspaceMenuCategory ( LOCTEXT ( " WorkspaceMenu_StaticMeshEditor " , " Static Mesh Editor " ) ) ;
2014-10-09 12:34:55 -04:00
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory . ToSharedRef ( ) ;
2014-03-14 14:13:41 -04:00
2016-05-03 15:44:33 -04:00
FAssetEditorToolkit : : RegisterTabSpawners ( InTabManager ) ;
2014-03-14 14:13:41 -04:00
2016-05-03 15:44:33 -04:00
InTabManager - > RegisterTabSpawner ( ViewportTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_Viewport ) )
2014-03-14 14:13:41 -04:00
. SetDisplayName ( LOCTEXT ( " ViewportTab " , " Viewport " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " LevelEditor.Tabs.Viewports " ) ) ;
2014-10-09 12:34:55 -04:00
2016-05-03 15:44:33 -04:00
InTabManager - > RegisterTabSpawner ( PropertiesTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_Properties ) )
2014-03-14 14:13:41 -04:00
. SetDisplayName ( LOCTEXT ( " PropertiesTab " , " Details " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " LevelEditor.Tabs.Details " ) ) ;
2014-10-09 12:34:55 -04:00
2016-05-03 15:44:33 -04:00
InTabManager - > RegisterTabSpawner ( SocketManagerTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_SocketManager ) )
2014-03-14 14:13:41 -04:00
. SetDisplayName ( LOCTEXT ( " SocketManagerTab " , " Socket Manager " ) )
2015-04-30 16:52:00 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " StaticMeshEditor.Tabs.SocketManager " ) ) ;
2014-10-09 12:34:55 -04:00
2016-05-03 15:44:33 -04:00
InTabManager - > RegisterTabSpawner ( CollisionTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_Collision ) )
2014-03-14 14:13:41 -04:00
. SetDisplayName ( LOCTEXT ( " CollisionTab " , " Convex Decomposition " ) )
2015-04-30 16:52:00 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " StaticMeshEditor.Tabs.ConvexDecomposition " ) ) ;
2016-06-21 12:37:19 -04:00
2018-11-06 10:00:36 -05:00
InTabManager - > RegisterTabSpawner ( PreviewSceneSettingsTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_PreviewSceneSettings ) )
. SetDisplayName ( LOCTEXT ( " PreviewSceneTab " , " Preview Scene Settings " ) )
2016-06-21 12:37:19 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " LevelEditor.Tabs.Details " ) ) ;
2018-11-06 10:00:36 -05:00
FTabSpawnerEntry & MenuEntry = InTabManager - > RegisterTabSpawner ( SecondaryToolbarTabId , FOnSpawnTab : : CreateSP ( this , & FStaticMeshEditor : : SpawnTab_SecondaryToolbar ) )
. SetDisplayName ( LOCTEXT ( " ToolbarTab " , " Secondary Toolbar " ) )
. SetGroup ( WorkspaceMenuCategoryRef )
2020-10-14 13:29:31 -04:00
. SetIcon ( FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " Toolbar.Icon " ) ) ;
2018-11-06 10:00:36 -05:00
// Hide the menu item by default. It will be enabled only if the secondary toolbar is populated with extensions
SecondaryToolbarEntry = & MenuEntry ;
SecondaryToolbarEntry - > SetMenuType ( ETabSpawnerMenuType : : Hidden ) ;
2019-06-07 11:22:52 -04:00
OnRegisterTabSpawners ( ) . Broadcast ( InTabManager ) ;
2014-03-14 14:13:41 -04:00
}
2016-05-03 15:44:33 -04:00
void FStaticMeshEditor : : UnregisterTabSpawners ( const TSharedRef < class FTabManager > & InTabManager )
2014-03-14 14:13:41 -04:00
{
2016-05-03 15:44:33 -04:00
FAssetEditorToolkit : : UnregisterTabSpawners ( InTabManager ) ;
2014-03-14 14:13:41 -04:00
2016-05-03 15:44:33 -04:00
InTabManager - > UnregisterTabSpawner ( ViewportTabId ) ;
InTabManager - > UnregisterTabSpawner ( PropertiesTabId ) ;
InTabManager - > UnregisterTabSpawner ( SocketManagerTabId ) ;
InTabManager - > UnregisterTabSpawner ( CollisionTabId ) ;
2016-06-21 12:37:19 -04:00
InTabManager - > UnregisterTabSpawner ( PreviewSceneSettingsTabId ) ;
2018-11-06 10:00:36 -05:00
InTabManager - > UnregisterTabSpawner ( SecondaryToolbarTabId ) ;
2019-06-07 11:22:52 -04:00
OnUnregisterTabSpawners ( ) . Broadcast ( InTabManager ) ;
2014-03-14 14:13:41 -04:00
}
FStaticMeshEditor : : ~ FStaticMeshEditor ( )
{
2020-10-22 19:19:16 -04:00
if ( StaticMesh )
{
StaticMesh - > GetOnMeshChanged ( ) . RemoveAll ( this ) ;
}
2019-12-19 18:07:47 -05:00
if ( ViewportTabContent . IsValid ( ) )
{
ViewportTabContent - > OnViewportTabContentLayoutChanged ( ) . RemoveAll ( this ) ;
}
2019-06-07 11:22:52 -04:00
OnStaticMeshEditorClosed ( ) . Broadcast ( ) ;
2017-10-06 04:43:18 -04:00
# if USE_ASYNC_DECOMP
/** If there is an active instance of the asynchronous convex decomposition interface, release it here. */
if ( GConvexDecompositionNotificationState )
{
GConvexDecompositionNotificationState - > IsActive = false ;
}
if ( DecomposeMeshToHullsAsync )
{
DecomposeMeshToHullsAsync - > Release ( ) ;
}
# endif
2014-04-25 06:23:34 -04:00
FReimportManager : : Instance ( ) - > OnPostReimport ( ) . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
GEditor - > UnregisterForUndo ( this ) ;
2019-01-15 13:41:40 -05:00
GEditor - > GetEditorSubsystem < UImportSubsystem > ( ) - > OnAssetReimport . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
}
2019-06-07 11:22:52 -04:00
void FStaticMeshEditor : : InitEditorForStaticMesh ( UStaticMesh * ObjectToEdit )
2014-03-14 14:13:41 -04:00
{
2014-04-25 06:23:34 -04:00
FReimportManager : : Instance ( ) - > OnPostReimport ( ) . AddRaw ( this , & FStaticMeshEditor : : OnPostReimport ) ;
2014-03-14 14:13:41 -04:00
// Support undo/redo
ObjectToEdit - > SetFlags ( RF_Transactional ) ;
2020-10-22 19:19:16 -04:00
if ( ObjectToEdit - > GetNavCollision ( ) )
2019-10-27 14:20:06 -04:00
{
2020-10-22 19:19:16 -04:00
ObjectToEdit - > GetNavCollision ( ) - > SetFlags ( RF_Transactional ) ;
2019-10-27 14:20:06 -04:00
}
2014-03-14 14:13:41 -04:00
GEditor - > RegisterForUndo ( this ) ;
// Register our commands. This will only register them if not previously registered
FStaticMeshEditorCommands : : Register ( ) ;
// Register to be notified when an object is reimported.
2019-01-15 13:41:40 -05:00
GEditor - > GetEditorSubsystem < UImportSubsystem > ( ) - > OnAssetReimport . AddSP ( this , & FStaticMeshEditor : : OnObjectReimported ) ;
2014-03-14 14:13:41 -04:00
BindCommands ( ) ;
2019-10-30 18:26:53 -04:00
// The tab must be created before the viewport layout because the layout needs them
TSharedRef < SDockTab > DockableTab =
2021-05-10 14:19:15 -04:00
SNew ( SDockTab ) ;
2019-10-30 18:26:53 -04:00
2014-03-14 14:13:41 -04:00
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : LoadModuleChecked < FPropertyEditorModule > ( TEXT ( " PropertyEditor " ) ) ;
2018-06-07 18:49:50 -04:00
2014-03-14 14:13:41 -04:00
FDetailsViewArgs DetailsViewArgs ;
DetailsViewArgs . bAllowSearch = true ;
DetailsViewArgs . bLockable = false ;
DetailsViewArgs . bUpdatesFromSelection = false ;
2015-01-26 17:14:50 -05:00
DetailsViewArgs . NameAreaSettings = FDetailsViewArgs : : HideNameArea ;
2014-03-14 14:13:41 -04:00
DetailsViewArgs . NotifyHook = this ;
StaticMeshDetailsView = PropertyEditorModule . CreateDetailView ( DetailsViewArgs ) ;
FOnGetDetailCustomizationInstance LayoutCustomStaticMeshProperties = FOnGetDetailCustomizationInstance : : CreateSP ( this , & FStaticMeshEditor : : MakeStaticMeshDetails ) ;
StaticMeshDetailsView - > RegisterInstancedCustomPropertyLayout ( UStaticMesh : : StaticClass ( ) , LayoutCustomStaticMeshProperties ) ;
2020-09-01 14:07:48 -04:00
StaticMesh = ObjectToEdit ;
2021-01-08 19:56:07 -04:00
IStaticMeshEditorModule * StaticMeshEditorModule = & FModuleManager : : LoadModuleChecked < IStaticMeshEditorModule > ( " StaticMeshEditor " ) ;
StaticMeshEditorModule - > OnStaticMeshEditorOpened ( ) . Broadcast ( SharedThis ( this ) ) ;
2019-06-07 11:22:52 -04:00
}
void FStaticMeshEditor : : InitStaticMeshEditor ( const EToolkitMode : : Type Mode , const TSharedPtr < class IToolkitHost > & InitToolkitHost , UStaticMesh * ObjectToEdit )
{
2020-09-24 00:43:27 -04:00
InitEditorForStaticMesh ( ObjectToEdit ) ;
2019-06-07 11:22:52 -04:00
TSharedRef < FTabManager : : FStack > ExtentionTabStack (
FTabManager : : NewStack ( )
- > SetSizeCoefficient ( 0.3f )
- > AddTab ( SocketManagerTabId , ETabState : : OpenedTab )
- > AddTab ( CollisionTabId , ETabState : : ClosedTab ) ) ;
//Let additional extensions dock themselves to this TabStack of tools
OnStaticMeshEditorDockingExtentionTabs ( ) . Broadcast ( ExtentionTabStack ) ;
2021-11-22 15:40:02 -05:00
const TSharedRef < FTabManager : : FLayout > StandaloneDefaultLayout = FTabManager : : NewLayout ( " Standalone_StaticMeshEditor_Layout_v6 " )
2014-03-14 14:13:41 -04:00
- > AddArea
(
FTabManager : : NewPrimaryArea ( ) - > SetOrientation ( Orient_Vertical )
- > Split
(
2015-03-09 17:10:09 -04:00
FTabManager : : NewSplitter ( ) - > SetOrientation ( Orient_Horizontal )
2014-03-14 14:13:41 -04:00
- > Split
2020-10-14 13:29:31 -04:00
(
FTabManager : : NewStack ( )
2020-10-28 15:17:37 -04:00
- > SetSizeCoefficient ( 0.7f )
2015-03-09 17:10:09 -04:00
- > AddTab ( ViewportTabId , ETabState : : OpenedTab )
- > SetHideTabWell ( true )
2014-03-14 14:13:41 -04:00
)
- > Split
(
2015-03-09 17:10:09 -04:00
FTabManager : : NewSplitter ( ) - > SetOrientation ( Orient_Vertical )
2020-10-28 15:17:37 -04:00
- > SetSizeCoefficient ( 0.25f )
2014-03-14 14:13:41 -04:00
- > Split
(
FTabManager : : NewStack ( )
2018-06-07 18:49:50 -04:00
- > SetSizeCoefficient ( 0.7f )
2014-03-14 14:13:41 -04:00
- > AddTab ( PropertiesTabId , ETabState : : OpenedTab )
2020-10-28 15:17:37 -04:00
- > AddTab ( SocketManagerTabId , ETabState : : OpenedTab )
- > SetForegroundTab ( PropertiesTabId )
2014-03-14 14:13:41 -04:00
)
- > Split
(
2019-06-07 11:22:52 -04:00
ExtentionTabStack
2014-03-14 14:13:41 -04:00
)
)
)
) ;
2021-10-25 20:05:28 -04:00
// Add any extenders specified by the UStaticMeshEditorUISubsystem
IStaticMeshEditorModule * StaticMeshEditorModule = & FModuleManager : : LoadModuleChecked < IStaticMeshEditorModule > ( " StaticMeshEditor " ) ;
FLayoutExtender LayoutExtender ;
StaticMeshEditorModule - > OnRegisterLayoutExtensions ( ) . Broadcast ( LayoutExtender ) ;
StandaloneDefaultLayout - > ProcessExtensions ( LayoutExtender ) ;
2014-03-14 14:13:41 -04:00
const bool bCreateDefaultStandaloneMenu = true ;
const bool bCreateDefaultToolbar = true ;
FAssetEditorToolkit : : InitAssetEditor ( Mode , InitToolkitHost , StaticMeshEditorAppIdentifier , StandaloneDefaultLayout , bCreateDefaultToolbar , bCreateDefaultStandaloneMenu , ObjectToEdit ) ;
2018-06-07 18:49:50 -04:00
2021-09-16 13:57:09 -04:00
TSharedPtr < class IToolkitHost > PinnedToolkitHost = ToolkitHost . Pin ( ) ;
check ( PinnedToolkitHost . IsValid ( ) ) ;
ModeUILayer = MakeShareable ( new FStaticMeshEditorModeUILayer ( PinnedToolkitHost . Get ( ) ) ) ;
2014-03-14 14:13:41 -04:00
ExtendMenu ( ) ;
ExtendToolBar ( ) ;
RegenerateMenusAndToolbars ( ) ;
2018-11-06 10:00:36 -05:00
GenerateSecondaryToolbar ( ) ;
}
2021-09-16 13:57:09 -04:00
void FStaticMeshEditor : : PostInitAssetEditor ( )
{
// (Copied from FUVEditorToolkit::PostInitAssetEditor)
// We need the viewport client to start out focused, or else it won't get ticked until we click inside it.
2021-12-09 18:46:39 -05:00
if ( TSharedPtr < SStaticMeshEditorViewport > StaticMeshViewport = GetStaticMeshViewport ( ) )
{
FStaticMeshEditorViewportClient & ViewportClient = StaticMeshViewport - > GetViewportClient ( ) ;
ViewportClient . ReceivedFocus ( ViewportClient . Viewport ) ;
}
2021-09-16 13:57:09 -04:00
}
2018-11-06 10:00:36 -05:00
void FStaticMeshEditor : : GenerateSecondaryToolbar ( )
{
// Generate the secondary toolbar only if there are registered extensions
TSharedPtr < SDockTab > Tab = TabManager - > FindExistingLiveTab ( SecondaryToolbarTabId ) ;
TSharedPtr < FExtender > Extender = FExtender : : Combine ( SecondaryToolbarExtenders ) ;
if ( Extender - > NumExtensions ( ) = = 0 )
{
// If the tab was previously opened, close it since it's now empty
if ( Tab )
{
Tab - > RemoveTabFromParent ( ) ;
}
return ;
}
const bool bIsFocusable = true ;
FToolBarBuilder ToolbarBuilder ( GetToolkitCommands ( ) , FMultiBoxCustomization : : AllowCustomization ( GetToolkitFName ( ) ) , Extender ) ;
ToolbarBuilder . SetIsFocusable ( bIsFocusable ) ;
ToolbarBuilder . BeginSection ( " Extensions " ) ;
{
// The secondary toolbar itself is empty but will be populated by the extensions when EndSection is called.
// The section name helps in the extenders positioning.
}
ToolbarBuilder . EndSection ( ) ;
// Setup the secondary toolbar menu entry
SecondaryToolbarEntry - > SetMenuType ( ETabSpawnerMenuType : : Enabled ) ;
SecondaryToolbarEntry - > SetDisplayName ( SecondaryToolbarDisplayName ) ;
SecondaryToolbar =
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. HAlign ( HAlign_Left )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. VAlign ( VAlign_Bottom )
[
ToolbarBuilder . MakeWidget ( )
]
] ;
if ( SecondaryToolbarWidgetContent . IsValid ( ) )
{
SecondaryToolbarWidgetContent - > SetContent ( SecondaryToolbar . ToSharedRef ( ) ) ;
}
if ( ! Tab )
{
// By default, the tab is closed but we want it to be opened when it is populated
2020-02-28 11:30:46 -05:00
Tab = TSharedPtr < SDockTab > ( TabManager - > TryInvokeTab ( SecondaryToolbarTabId ) ) ;
2018-11-06 10:00:36 -05:00
}
// Override the display name if it was set
if ( ! SecondaryToolbarDisplayName . IsEmpty ( ) )
{
Tab - > SetLabel ( SecondaryToolbarDisplayName ) ;
}
}
void FStaticMeshEditor : : AddSecondaryToolbarExtender ( TSharedPtr < FExtender > Extender )
{
SecondaryToolbarExtenders . AddUnique ( Extender ) ;
}
void FStaticMeshEditor : : RemoveSecondaryToolbarExtender ( TSharedPtr < FExtender > Extender )
{
SecondaryToolbarExtenders . Remove ( Extender ) ;
}
void FStaticMeshEditor : : SetSecondaryToolbarDisplayName ( FText DisplayName )
{
SecondaryToolbarDisplayName = DisplayName ;
2014-03-14 14:13:41 -04:00
}
TSharedRef < IDetailCustomization > FStaticMeshEditor : : MakeStaticMeshDetails ( )
{
TSharedRef < FStaticMeshDetails > NewDetails = MakeShareable ( new FStaticMeshDetails ( * this ) ) ;
StaticMeshDetails = NewDetails ;
return NewDetails ;
}
void FStaticMeshEditor : : ExtendMenu ( )
{
{
2022-02-08 13:29:56 -05:00
UToolMenu * Menu = UToolMenus : : Get ( ) - > ExtendMenu ( " AssetEditor.StaticMeshEditor.MainMenu.Edit " ) ;
FToolMenuSection & Section = Menu - > AddSection ( " Sockets " , LOCTEXT ( " EditStaticMeshSockets " , " Sockets " ) ) ;
Section . InsertPosition = FToolMenuInsert ( " EditHistory " , EToolMenuInsertType : : After ) ;
Section . AddMenuEntry ( " DeleteSocket " , FGenericCommands : : Get ( ) . Delete , LOCTEXT ( " DeleteSocket " , " Delete Socket " ) , LOCTEXT ( " DeleteSocketToolTip " , " Deletes the selected socket from the mesh. " ) ) ;
Section . AddMenuEntry ( " DuplicateSocket " , FGenericCommands : : Get ( ) . Duplicate , LOCTEXT ( " DuplicateSocket " , " Duplicate Socket " ) , LOCTEXT ( " DuplicateSocketToolTip " , " Duplicates the selected socket. " ) ) ;
}
{
if ( ! UToolMenus : : Get ( ) - > IsMenuRegistered ( " StaticMeshEditor.Collision " ) )
2014-03-14 14:13:41 -04:00
{
2022-02-08 13:29:56 -05:00
StaticMeshEditor : : PopulateCollisionMenu ( UToolMenus : : Get ( ) - > RegisterMenu ( " StaticMeshEditor.Collision " ) ) ;
2014-03-14 14:13:41 -04:00
}
2022-02-08 13:29:56 -05:00
if ( ! UToolMenus : : Get ( ) - > IsMenuRegistered ( " AssetEditor.StaticMeshEditor.MainMenu.Collision " ) )
2014-03-14 14:13:41 -04:00
{
2022-02-08 13:29:56 -05:00
UToolMenus : : Get ( ) - > RegisterMenu ( " AssetEditor.StaticMeshEditor.MainMenu.Collision " , " StaticMeshEditor.Collision " ) ;
2014-03-14 14:13:41 -04:00
}
{
2022-02-08 13:29:56 -05:00
UToolMenu * Menu = UToolMenus : : Get ( ) - > ExtendMenu ( " AssetEditor.StaticMeshEditor.MainMenu " ) ;
FToolMenuSection & Section = Menu - > FindOrAddSection ( NAME_None ) ;
FToolMenuEntry & Entry = Section . AddSubMenu ( " Collision " ,
2014-03-14 14:13:41 -04:00
LOCTEXT ( " StaticMeshEditorCollisionMenu " , " Collision " ) ,
LOCTEXT ( " StaticMeshEditorCollisionMenu_ToolTip " , " Opens a menu with commands for editing this mesh's collision " ) ,
2022-02-08 13:29:56 -05:00
FNewToolMenuChoice ( ) ) ;
Entry . InsertPosition = FToolMenuInsert ( " Asset " , EToolMenuInsertType : : After ) ;
2014-03-14 14:13:41 -04:00
}
2022-02-08 13:29:56 -05:00
}
2018-06-07 18:49:50 -04:00
2014-03-14 14:13:41 -04:00
IStaticMeshEditorModule * StaticMeshEditorModule = & FModuleManager : : LoadModuleChecked < IStaticMeshEditorModule > ( " StaticMeshEditor " ) ;
AddMenuExtender ( StaticMeshEditorModule - > GetMenuExtensibilityManager ( ) - > GetAllExtenders ( GetToolkitCommands ( ) , GetEditingObjects ( ) ) ) ;
2020-10-14 13:29:31 -04:00
2022-02-08 13:29:56 -05:00
UToolMenu * AssetMenu = UToolMenus : : Get ( ) - > ExtendMenu ( " AssetEditor.StaticMeshEditor.MainMenu.Asset " ) ;
2021-04-20 18:59:52 -04:00
FToolMenuSection & AssetSection = AssetMenu - > FindOrAddSection ( " AssetEditorActions " ) ;
2022-02-08 13:29:56 -05:00
FToolMenuEntry & Entry = AssetSection . AddDynamicEntry ( " AssetManagerEditorStaticMeshCommands " , FNewToolMenuSectionDelegate : : CreateLambda ( [ ] ( FToolMenuSection & InSection )
{
InSection . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . FindSource ) ;
InSection . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . SetDrawAdditionalData ) ;
InSection . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . BakeMaterials ) ;
InSection . AddDynamicEntry ( " SaveGeneratedLODs " , FNewToolMenuSectionDelegate : : CreateLambda ( [ ] ( FToolMenuSection & InSection )
2021-04-20 18:59:52 -04:00
{
2022-02-08 13:29:56 -05:00
static auto * CVar = IConsoleManager : : Get ( ) . FindTConsoleVariableDataInt ( TEXT ( " r.StaticMesh.EnableSaveGeneratedLODsInPackage " ) ) ;
if ( CVar & & CVar - > GetValueOnGameThread ( ) ! = 0 )
2021-04-20 18:59:52 -04:00
{
2022-02-08 13:29:56 -05:00
InSection . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . SaveGeneratedLODs ) ;
2021-04-20 18:59:52 -04:00
}
2022-02-08 13:29:56 -05:00
} ) ) ;
} ) ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : AddReferencedObjects ( FReferenceCollector & Collector )
{
Collector . AddReferencedObject ( StaticMesh ) ;
}
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_Viewport ( const FSpawnTabArgs & Args )
{
2019-10-30 18:26:53 -04:00
TSharedRef < SDockTab > DockableTab =
2021-05-10 14:19:15 -04:00
SNew ( SDockTab ) ;
2018-06-07 18:49:50 -04:00
2020-09-01 14:07:48 -04:00
TWeakPtr < IStaticMeshEditor > WeakSharedThis ( SharedThis ( this ) ) ;
MakeViewportFunc = [ WeakSharedThis ] ( const FAssetEditorViewportConstructionArgs & InArgs )
{
return SNew ( SStaticMeshEditorViewport )
. StaticMeshEditor ( WeakSharedThis ) ;
} ;
// Create a new tab
ViewportTabContent = MakeShareable ( new FEditorViewportTabContent ( ) ) ;
ViewportTabContent - > OnViewportTabContentLayoutChanged ( ) . AddRaw ( this , & FStaticMeshEditor : : OnEditorLayoutChanged ) ;
2019-10-30 18:26:53 -04:00
const FString LayoutId = FString ( " StaticMeshEditorViewport " ) ;
2020-09-01 14:07:48 -04:00
ViewportTabContent - > Initialize ( MakeViewportFunc , DockableTab , LayoutId ) ;
2014-03-14 14:13:41 -04:00
2022-10-07 19:43:21 -04:00
GetStaticMeshViewport ( ) - > SetParentTab ( DockableTab ) ;
2019-10-30 18:26:53 -04:00
return DockableTab ;
2014-03-14 14:13:41 -04:00
}
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_Properties ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = PropertiesTabId ) ;
return SNew ( SDockTab )
. Label ( LOCTEXT ( " StaticMeshProperties_TabTitle " , " Details " ) )
[
StaticMeshDetailsView . ToSharedRef ( )
] ;
}
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_SocketManager ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = SocketManagerTabId ) ;
2020-10-14 13:29:31 -04:00
if ( ! SocketManager )
{
FSimpleDelegate OnSocketSelectionChanged = FSimpleDelegate : : CreateSP ( SharedThis ( this ) , & FStaticMeshEditor : : OnSocketSelectionChanged ) ;
SocketManager = ISocketManager : : CreateSocketManager ( SharedThis ( this ) , OnSocketSelectionChanged ) ;
}
2014-03-14 14:13:41 -04:00
return SNew ( SDockTab )
. Label ( LOCTEXT ( " StaticMeshSocketManager_TabTitle " , " Socket Manager " ) )
[
SocketManager . ToSharedRef ( )
] ;
}
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_Collision ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = CollisionTabId ) ;
2020-10-14 13:29:31 -04:00
if ( ! ConvexDecomposition )
{
SAssignNew ( ConvexDecomposition , SConvexDecomposition )
. StaticMeshEditorPtr ( SharedThis ( this ) ) ;
}
2014-03-14 14:13:41 -04:00
return SNew ( SDockTab )
. Label ( LOCTEXT ( " StaticMeshConvexDecomp_TabTitle " , " Convex Decomposition " ) )
[
ConvexDecomposition . ToSharedRef ( )
] ;
}
2018-11-06 10:00:36 -05:00
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_PreviewSceneSettings ( const FSpawnTabArgs & Args )
2016-06-21 12:37:19 -04:00
{
2018-11-06 10:00:36 -05:00
check ( Args . GetTabId ( ) = = PreviewSceneSettingsTabId ) ;
2021-02-03 14:57:28 -04:00
return SAssignNew ( PreviewSceneDockTab , SDockTab )
2018-11-06 10:00:36 -05:00
. Label ( LOCTEXT ( " StaticMeshPreviewScene_TabTitle " , " Preview Scene Settings " ) )
2016-06-21 12:37:19 -04:00
[
2021-02-03 14:57:28 -04:00
AdvancedPreviewSettingsWidget . IsValid ( ) ? AdvancedPreviewSettingsWidget . ToSharedRef ( ) : SNullWidget : : NullWidget
2016-06-21 12:37:19 -04:00
] ;
}
2018-11-06 10:00:36 -05:00
TSharedRef < SDockTab > FStaticMeshEditor : : SpawnTab_SecondaryToolbar ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = SecondaryToolbarTabId ) ;
2019-02-27 10:40:32 -05:00
FText TabLabel = ! SecondaryToolbarDisplayName . IsEmpty ( ) ? SecondaryToolbarDisplayName : LOCTEXT ( " SecondaryToolbar_TabTitle " , " Secondary Toolbar " ) ;
2018-11-06 10:00:36 -05:00
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
2019-02-27 10:40:32 -05:00
. Label ( TabLabel )
2018-11-06 10:00:36 -05:00
. ShouldAutosize ( true )
[
SAssignNew ( SecondaryToolbarWidgetContent , SBorder )
. Padding ( 0 )
2022-05-09 13:12:28 -04:00
. BorderImage ( FAppStyle : : GetBrush ( " NoBorder " ) )
2018-11-06 10:00:36 -05:00
] ;
if ( SecondaryToolbar . IsValid ( ) )
{
SecondaryToolbarWidgetContent - > SetContent ( SecondaryToolbar . ToSharedRef ( ) ) ;
}
return SpawnedTab ;
}
2020-09-01 14:07:48 -04:00
TSharedPtr < SStaticMeshEditorViewport > FStaticMeshEditor : : GetStaticMeshViewport ( ) const
2019-10-30 18:26:53 -04:00
{
2020-09-01 14:07:48 -04:00
if ( ViewportTabContent . IsValid ( ) )
{
// we can use static cast here b/c we know in this editor we will have a static mesh viewport
return StaticCastSharedPtr < SStaticMeshEditorViewport > ( ViewportTabContent - > GetFirstViewport ( ) ) ;
}
return TSharedPtr < SStaticMeshEditorViewport > ( ) ;
2019-10-30 18:26:53 -04:00
}
2019-12-19 18:07:47 -05:00
void FStaticMeshEditor : : OnEditorLayoutChanged ( )
{
2020-09-01 14:07:48 -04:00
SetEditorMesh ( StaticMesh ) ;
BuildSubTools ( ) ;
bool LocalDrawGrids = false ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > CheckShowGridFunc =
[ this , & LocalDrawGrids ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
LocalDrawGrids | = StaticMeshEditorViewportClient . IsSetShowGridChecked ( ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( CheckShowGridFunc ) ;
bDrawGrids = LocalDrawGrids ;
2019-12-19 18:07:47 -05:00
OnPreviewSceneChangedDelegate . Broadcast ( GetStaticMeshViewport ( ) - > GetPreviewScene ( ) ) ;
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : BindCommands ( )
{
const FStaticMeshEditorCommands & Commands = FStaticMeshEditorCommands : : Get ( ) ;
const TSharedRef < FUICommandList > & UICommandList = GetToolkitCommands ( ) ;
2019-10-30 18:26:53 -04:00
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction ( FGenericCommands : : Get ( ) . Delete ,
2014-06-13 05:03:24 -04:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : DeleteSelected ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanDeleteSelected ) ) ;
2014-03-14 14:13:41 -04:00
2018-06-07 18:49:50 -04:00
UICommandList - > MapAction ( FGenericCommands : : Get ( ) . Undo ,
2014-03-14 14:13:41 -04:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : UndoAction ) ) ;
2018-06-07 18:49:50 -04:00
UICommandList - > MapAction ( FGenericCommands : : Get ( ) . Redo ,
2014-03-14 14:13:41 -04:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : RedoAction ) ) ;
UICommandList - > MapAction (
FGenericCommands : : Get ( ) . Duplicate ,
2014-06-13 05:03:24 -04:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : DuplicateSelected ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanDuplicateSelected ) ) ;
2014-03-14 14:13:41 -04:00
2022-06-29 12:17:25 -04:00
UICommandList - > MapAction (
FGenericCommands : : Get ( ) . Copy ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CopySelected ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanCopySelected ) ) ;
UICommandList - > MapAction (
FGenericCommands : : Get ( ) . Paste ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : PasteCopied ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanPasteCopied ) ) ;
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction (
FGenericCommands : : Get ( ) . Rename ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : RequestRenameSelectedSocket ) ,
2014-06-13 05:03:24 -04:00
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanRenameSelected ) ) ;
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction (
Commands . CreateDOP10X ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : GenerateKDop , KDopDir10X , ( uint32 ) 10 ) ) ;
UICommandList - > MapAction (
Commands . CreateDOP10Y ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : GenerateKDop , KDopDir10Y , ( uint32 ) 10 ) ) ;
UICommandList - > MapAction (
Commands . CreateDOP10Z ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : GenerateKDop , KDopDir10Z , ( uint32 ) 10 ) ) ;
UICommandList - > MapAction (
Commands . CreateDOP18 ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : GenerateKDop , KDopDir18 , ( uint32 ) 18 ) ) ;
UICommandList - > MapAction (
Commands . CreateDOP26 ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : GenerateKDop , KDopDir26 , ( uint32 ) 26 ) ) ;
2014-06-13 05:03:24 -04:00
UICommandList - > MapAction (
Commands . CreateBoxCollision ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnCollisionBox ) ) ;
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction (
Commands . CreateSphereCollision ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnCollisionSphere ) ) ;
2014-06-13 05:03:24 -04:00
UICommandList - > MapAction (
Commands . CreateSphylCollision ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnCollisionSphyl ) ) ;
2019-10-30 18:26:53 -04:00
UICommandList - > MapAction ( Commands . ToggleShowNormals ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowNormals ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowNormalsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowTangents ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowTangents ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowTangentsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowBinormals ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowBinormals ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowBinormalsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowPivots ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowPivots ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowPivotsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowVertices ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowVertices ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowVerticesChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowGrids ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowGrids ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowGridsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowBounds ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowBounds ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowBoundsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowSimpleCollisions ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowSimpleCollisions ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowSimpleCollisionsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowComplexCollisions ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowComplexCollisions ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowComplexCollisionsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowSockets ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowSockets ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowSocketsChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowWireframes ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowWireframes ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowWireframesChecked ) ) ;
UICommandList - > MapAction ( Commands . ToggleShowVertexColors ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleShowVertexColors ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsShowVertexColorsChecked ) ) ;
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction (
Commands . RemoveCollision ,
2015-01-06 14:54:09 -05:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnRemoveCollision ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanRemoveCollision ) ) ;
2014-03-14 14:13:41 -04:00
UICommandList - > MapAction (
Commands . ConvertBoxesToConvex ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnConvertBoxToConvexCollision ) ) ;
UICommandList - > MapAction (
Commands . CopyCollisionFromSelectedMesh ,
2014-12-19 12:47:41 -05:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnCopyCollisionFromSelectedStaticMesh ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanCopyCollisionFromSelectedStaticMesh ) ) ;
2014-03-14 14:13:41 -04:00
// Mesh menu
UICommandList - > MapAction (
Commands . FindSource ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ExecuteFindInExplorer ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanExecuteSourceCommands ) ) ;
UICommandList - > MapAction (
Commands . ChangeMesh ,
2014-12-19 12:47:41 -05:00
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnChangeMesh ) ,
FCanExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : CanChangeMesh ) ) ;
2014-03-14 14:13:41 -04:00
2015-02-21 13:20:31 -05:00
UICommandList - > MapAction (
Commands . SaveGeneratedLODs ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnSaveGeneratedLODs ) ) ;
2022-02-08 13:29:56 -05:00
UICommandList - > MapAction (
Commands . ReimportMesh ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : HandleReimportMesh ) ) ;
UICommandList - > MapAction (
Commands . ReimportAllMesh ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : HandleReimportAllMesh ) ) ;
2014-03-14 14:13:41 -04:00
// Collision Menu
UICommandList - > MapAction (
Commands . CreateAutoConvexCollision ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : OnConvexDecomposition ) ) ;
2019-10-30 18:26:53 -04:00
2020-03-17 15:11:19 -04:00
// Viewport Camera
UICommandList - > MapAction (
Commands . ResetCamera ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ResetCamera ) ) ;
2020-04-14 16:54:46 -04:00
// Draw additional data
UICommandList - > MapAction (
Commands . SetDrawAdditionalData ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : ToggleDrawAdditionalData ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FStaticMeshEditor : : IsDrawAdditionalDataChecked ) ) ;
2020-10-14 13:29:31 -04:00
// Bake Materials
UICommandList - > MapAction (
Commands . BakeMaterials ,
FExecuteAction : : CreateSP ( this , & FStaticMeshEditor : : BakeMaterials ) ,
FCanExecuteAction ( ) ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : ExtendToolBar ( )
{
2022-02-08 13:29:56 -05:00
if ( ! UToolMenus : : Get ( ) - > IsMenuRegistered ( " AssetEditor.StaticMeshEditor.ToolBar.Collision " ) )
2014-03-14 14:13:41 -04:00
{
2022-02-08 13:29:56 -05:00
UToolMenus : : Get ( ) - > RegisterMenu ( " AssetEditor.StaticMeshEditor.ToolBar.Collision " , " StaticMeshEditor.Collision " ) ;
}
// Toolbar
{
UToolMenu * Menu = UToolMenus : : Get ( ) - > ExtendMenu ( " AssetEditor.StaticMeshEditor.ToolBar " ) ;
auto ConstructReimportContextMenu = [ ] ( UToolMenu * InMenu )
2014-03-14 14:13:41 -04:00
{
2022-02-08 13:29:56 -05:00
FToolMenuSection & Section = InMenu - > AddSection ( " Reimport " ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . ReimportMesh ) ;
Section . AddMenuEntry ( FStaticMeshEditorCommands : : Get ( ) . ReimportAllMesh ) ;
} ;
2018-05-23 21:04:31 -04:00
2022-02-08 13:29:56 -05:00
{
FToolMenuSection & Section = Menu - > AddSection ( " Mesh " ) ;
Section . InsertPosition = FToolMenuInsert ( " Asset " , EToolMenuInsertType : : After ) ;
2019-10-30 18:26:53 -04:00
2022-02-08 13:29:56 -05:00
FToolMenuEntry & ReimportMeshEntry = Section . AddEntry ( FToolMenuEntry : : InitToolBarButton ( FStaticMeshEditorCommands : : Get ( ) . ReimportMesh ) ) ;
ReimportMeshEntry . StyleNameOverride = " CalloutToolbar " ;
FToolMenuEntry & ReimportContextMenuEntry = Section . AddEntry ( FToolMenuEntry : : InitComboButton (
" ReimportContextMenu " ,
FUIAction ( ) ,
FNewToolMenuDelegate : : CreateLambda ( ConstructReimportContextMenu ) ,
TAttribute < FText > ( ) ,
TAttribute < FText > ( ) ,
TAttribute < FSlateIcon > ( ) ,
true
) ) ;
ReimportContextMenuEntry . StyleNameOverride = " CalloutToolbar " ;
2014-03-14 14:13:41 -04:00
}
2022-02-08 13:29:56 -05:00
{
FToolMenuSection & Section = Menu - > AddSection ( " Command " ) ;
Section . InsertPosition = FToolMenuInsert ( " Asset " , EToolMenuInsertType : : After ) ;
FToolMenuEntry & CollisionEntry = Section . AddEntry ( FToolMenuEntry : : InitComboButton (
" Collision " ,
FUIAction ( ) ,
FNewToolMenuChoice ( ) , // let registered menu be looked up by name "AssetEditor.StaticMeshEditor.ToolBar.Collision"
LOCTEXT ( " Collision_Label " , " Collision " ) ,
LOCTEXT ( " Collision_Tooltip " , " Collision drawing options " ) ,
2022-05-09 13:31:58 -04:00
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " StaticMeshEditor.SetShowCollision " )
2022-02-08 13:29:56 -05:00
) ) ;
CollisionEntry . StyleNameOverride = " CalloutToolbar " ;
Section . AddDynamicEntry ( " UVToolbarDynamic " , FNewToolMenuSectionDelegate : : CreateLambda ( [ ] ( FToolMenuSection & InSection )
{
if ( TSharedPtr < FStaticMeshEditor > StaticMeshEditor = StaticMeshEditor : : GetStaticMeshEditorFromMenuContext ( InSection ) )
{
FToolMenuEntry & UVToolbarEntry = InSection . AddEntry ( FToolMenuEntry : : InitComboButton (
" UVToolbar " ,
FUIAction ( ) ,
FNewToolMenuDelegate : : CreateSP ( StaticMeshEditor . ToSharedRef ( ) , & FStaticMeshEditor : : GenerateUVChannelComboList ) ,
LOCTEXT ( " UVToolbarText " , " UV " ) ,
LOCTEXT ( " UVToolbarTooltip " , " Toggles display of the static mesh's UVs for the specified channel. " ) ,
2022-05-09 13:31:58 -04:00
FSlateIcon ( FAppStyle : : GetAppStyleSetName ( ) , " StaticMeshEditor.SetDrawUVs " )
2022-02-08 13:29:56 -05:00
) ) ;
UVToolbarEntry . StyleNameOverride = " CalloutToolbar " ;
}
} ) ) ;
}
}
2019-10-30 18:26:53 -04:00
{
IStaticMeshEditorModule * StaticMeshEditorModule = & FModuleManager : : LoadModuleChecked < IStaticMeshEditorModule > ( " StaticMeshEditor " ) ;
2021-09-16 13:57:09 -04:00
TArray < IStaticMeshEditorModule : : FStaticMeshEditorToolbarExtender > ToolbarExtenderDelegates = StaticMeshEditorModule - > GetAllStaticMeshEditorToolbarExtenders ( ) ;
for ( auto & ToolbarExtenderDelegate : ToolbarExtenderDelegates )
{
if ( ToolbarExtenderDelegate . IsBound ( ) )
{
AddToolbarExtender ( ToolbarExtenderDelegate . Execute ( GetToolkitCommands ( ) , SharedThis ( this ) ) ) ;
}
}
2019-06-07 11:22:52 -04:00
EditorToolbarExtender = StaticMeshEditorModule - > GetToolBarExtensibilityManager ( ) - > GetAllExtenders ( GetToolkitCommands ( ) , GetEditingObjects ( ) ) ;
AddToolbarExtender ( EditorToolbarExtender ) ;
2018-11-06 10:00:36 -05:00
AddSecondaryToolbarExtender ( StaticMeshEditorModule - > GetSecondaryToolBarExtensibilityManager ( ) - > GetAllExtenders ( GetToolkitCommands ( ) , GetEditingObjects ( ) ) ) ;
2019-10-30 18:26:53 -04:00
}
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : BuildSubTools ( )
{
2017-04-07 16:51:51 -04:00
FAdvancedPreviewSceneModule & AdvancedPreviewSceneModule = FModuleManager : : LoadModuleChecked < FAdvancedPreviewSceneModule > ( " AdvancedPreviewScene " ) ;
2019-12-19 18:07:47 -05:00
TArray < FAdvancedPreviewSceneModule : : FDetailDelegates > Delegates ;
Delegates . Add ( { OnPreviewSceneChangedDelegate } ) ;
AdvancedPreviewSettingsWidget = AdvancedPreviewSceneModule . CreateAdvancedPreviewSceneSettingsWidget ( GetStaticMeshViewport ( ) - > GetPreviewScene ( ) , nullptr , TArray < FAdvancedPreviewSceneModule : : FDetailCustomizationInfo > ( ) , TArray < FAdvancedPreviewSceneModule : : FPropertyTypeCustomizationInfo > ( ) , Delegates ) ;
2021-02-03 14:57:28 -04:00
if ( PreviewSceneDockTab . IsValid ( ) )
{
PreviewSceneDockTab . Pin ( ) - > SetContent ( AdvancedPreviewSettingsWidget . ToSharedRef ( ) ) ;
}
2014-03-14 14:13:41 -04:00
}
FName FStaticMeshEditor : : GetToolkitFName ( ) const
{
return FName ( " StaticMeshEditor " ) ;
}
FText FStaticMeshEditor : : GetBaseToolkitName ( ) const
{
return LOCTEXT ( " AppLabel " , " StaticMesh Editor " ) ;
}
FString FStaticMeshEditor : : GetWorldCentricTabPrefix ( ) const
{
return LOCTEXT ( " WorldCentricTabPrefix " , " StaticMesh " ) . ToString ( ) ;
}
FLinearColor FStaticMeshEditor : : GetWorldCentricTabColorScale ( ) const
{
return FLinearColor ( 0.3f , 0.2f , 0.5f , 0.5f ) ;
}
UStaticMeshComponent * FStaticMeshEditor : : GetStaticMeshComponent ( ) const
{
2020-09-01 14:07:48 -04:00
return GetStaticMeshViewport ( ) . IsValid ( ) ? GetStaticMeshViewport ( ) - > GetStaticMeshComponent ( ) : nullptr ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : SetSelectedSocket ( UStaticMeshSocket * InSelectedSocket )
{
SocketManager - > SetSelectedSocket ( InSelectedSocket ) ;
}
UStaticMeshSocket * FStaticMeshEditor : : GetSelectedSocket ( ) const
{
2019-01-14 16:55:55 -05:00
return SocketManager . IsValid ( ) ? SocketManager - > GetSelectedSocket ( ) : nullptr ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : DuplicateSelectedSocket ( )
{
SocketManager - > DuplicateSelectedSocket ( ) ;
}
void FStaticMeshEditor : : RequestRenameSelectedSocket ( )
{
SocketManager - > RequestRenameSelectedSocket ( ) ;
}
2014-06-13 05:03:24 -04:00
bool FStaticMeshEditor : : IsPrimValid ( const FPrimData & InPrimData ) const
{
2020-10-22 19:19:16 -04:00
if ( StaticMesh - > GetBodySetup ( ) )
2014-06-13 05:03:24 -04:00
{
2020-10-22 19:19:16 -04:00
const FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
switch ( InPrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-06-13 05:03:24 -04:00
return AggGeom - > SphereElems . IsValidIndex ( InPrimData . PrimIndex ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
return AggGeom - > BoxElems . IsValidIndex ( InPrimData . PrimIndex ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
return AggGeom - > SphylElems . IsValidIndex ( InPrimData . PrimIndex ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
return AggGeom - > ConvexElems . IsValidIndex ( InPrimData . PrimIndex ) ;
}
}
return false ;
}
bool FStaticMeshEditor : : HasSelectedPrims ( ) const
{
return ( SelectedPrims . Num ( ) > 0 ? true : false ) ;
}
2014-09-22 10:43:45 -04:00
void FStaticMeshEditor : : AddSelectedPrim ( const FPrimData & InPrimData , bool bClearSelection )
2014-06-13 05:03:24 -04:00
{
check ( IsPrimValid ( InPrimData ) ) ;
2014-09-16 04:20:39 -04:00
// Enable collision, if not already
2019-10-30 18:26:53 -04:00
if ( ! GetStaticMeshViewport ( ) - > GetViewportClient ( ) . IsShowSimpleCollisionChecked ( ) )
2014-09-16 04:20:39 -04:00
{
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . ToggleShowSimpleCollision ( ) ;
2014-09-16 04:20:39 -04:00
}
2014-09-22 10:43:45 -04:00
if ( bClearSelection )
{
ClearSelectedPrims ( ) ;
}
2018-06-07 18:49:50 -04:00
SelectedPrims . Add ( InPrimData ) ;
2014-06-13 05:03:24 -04:00
}
void FStaticMeshEditor : : RemoveSelectedPrim ( const FPrimData & InPrimData )
{
SelectedPrims . Remove ( InPrimData ) ;
}
void FStaticMeshEditor : : RemoveInvalidPrims ( )
{
for ( int32 PrimIdx = SelectedPrims . Num ( ) - 1 ; PrimIdx > = 0 ; PrimIdx - - )
{
FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
if ( ! IsPrimValid ( PrimData ) )
{
SelectedPrims . RemoveAt ( PrimIdx ) ;
}
}
}
bool FStaticMeshEditor : : IsSelectedPrim ( const FPrimData & InPrimData ) const
{
return SelectedPrims . Contains ( InPrimData ) ;
}
void FStaticMeshEditor : : ClearSelectedPrims ( )
{
SelectedPrims . Empty ( ) ;
}
void FStaticMeshEditor : : DuplicateSelectedPrims ( const FVector * InOffset )
{
if ( SelectedPrims . Num ( ) > 0 )
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_DuplicateSelectedPrims " , " Duplicate Collision " ) ) ;
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > Modify ( ) ;
2014-06-13 05:03:24 -04:00
//Clear the cache (PIE may have created some data), create new GUID
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
2014-06-13 05:03:24 -04:00
for ( int32 PrimIdx = 0 ; PrimIdx < SelectedPrims . Num ( ) ; PrimIdx + + )
{
FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
check ( IsPrimValid ( PrimData ) ) ;
switch ( PrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2018-06-07 18:49:50 -04:00
{
2014-06-13 05:03:24 -04:00
const FKSphereElem SphereElem = AggGeom - > SphereElems [ PrimData . PrimIndex ] ;
PrimData . PrimIndex = AggGeom - > SphereElems . Add ( SphereElem ) ;
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
{
const FKBoxElem BoxElem = AggGeom - > BoxElems [ PrimData . PrimIndex ] ;
PrimData . PrimIndex = AggGeom - > BoxElems . Add ( BoxElem ) ;
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
{
const FKSphylElem SphylElem = AggGeom - > SphylElems [ PrimData . PrimIndex ] ;
PrimData . PrimIndex = AggGeom - > SphylElems . Add ( SphylElem ) ;
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
{
const FKConvexElem ConvexElem = AggGeom - > ConvexElems [ PrimData . PrimIndex ] ;
PrimData . PrimIndex = AggGeom - > ConvexElems . Add ( ConvexElem ) ;
}
break ;
}
// If specified, offset the duplicate by a specific amount
if ( InOffset )
{
FTransform PrimTransform = GetPrimTransform ( PrimData ) ;
FVector PrimLocation = PrimTransform . GetLocation ( ) ;
PrimLocation + = * InOffset ;
PrimTransform . SetLocation ( PrimLocation ) ;
SetPrimTransform ( PrimData , PrimTransform ) ;
}
}
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-06-13 05:03:24 -04:00
GEditor - > EndTransaction ( ) ;
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh - > MarkPackageDirty ( ) ;
// Update views/property windows
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-09-10 17:19:28 -04:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-06-13 05:03:24 -04:00
}
}
2022-06-29 12:17:25 -04:00
int32 FStaticMeshEditor : : CopySelectedPrims ( ) const
{
int32 OutNumPrimsCopied = 0 ;
if ( CanCopySelected ( ) )
{
// Clear the mark state for saving.
UnMarkAllObjects ( EObjectMark ( OBJECTMARK_TagExp | OBJECTMARK_TagImp ) ) ;
// Make a temp bodysetup to house all the selected shapes
UBodySetup * NewBodySetup = NewObject < UBodySetup > ( ) ;
NewBodySetup - > AddToRoot ( ) ;
if ( StaticMesh )
{
if ( const UBodySetup * OldBodySetup = StaticMesh - > GetBodySetup ( ) )
{
const FKAggregateGeom & AggGeom = OldBodySetup - > AggGeom ;
for ( const FPrimData & Prim : SelectedPrims )
{
if ( IsPrimValid ( Prim ) )
{
if ( NewBodySetup - > AddCollisionElemFrom ( AggGeom , Prim . PrimType , Prim . PrimIndex ) )
{
+ + OutNumPrimsCopied ;
}
}
}
}
}
// Export the new bodysetup to the clipboard as text
if ( OutNumPrimsCopied > 0 )
{
FStringOutputDevice Archive ;
const FExportObjectInnerContext Context ;
UExporter : : ExportToOutputDevice ( & Context , NewBodySetup , NULL , Archive , TEXT ( " copy " ) , 0 , PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited , false ) ;
FString ExportedText = Archive ;
FPlatformApplicationMisc : : ClipboardCopy ( * ExportedText ) ;
}
// Allow the temp bodysetup to get deleted by garbage collection
NewBodySetup - > RemoveFromRoot ( ) ;
}
return OutNumPrimsCopied ;
}
int32 FStaticMeshEditor : : PasteCopiedPrims ( )
{
int32 OutNumPrimsPasted = 0 ;
FString TextToImport ;
FPlatformApplicationMisc : : ClipboardPaste ( TextToImport ) ;
if ( ! TextToImport . IsEmpty ( ) )
{
UPackage * TempPackage = NewObject < UPackage > ( nullptr , TEXT ( " /Engine/Editor/StaticMeshEditor/Transient " ) , RF_Transient ) ;
TempPackage - > AddToRoot ( ) ;
{
// Turn the text buffer into objects
FBodySetupObjectTextFactory Factory ;
Factory . ProcessBuffer ( TempPackage , RF_Transactional , TextToImport ) ;
if ( Factory . NewBodySetups . Num ( ) > 0 )
{
if ( UBodySetup * BodySetup = StaticMesh - > GetBodySetup ( ) )
{
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_PasteCopiedPrims " , " Paste Collision " ) ) ;
BodySetup - > Modify ( ) ;
BodySetup - > InvalidatePhysicsData ( ) ;
// Copy primitives from each bodysetup that was pasted
for ( const UBodySetup * NewBodySetup : Factory . NewBodySetups )
{
BodySetup - > AddCollisionFrom ( NewBodySetup - > AggGeom ) ;
OutNumPrimsPasted + = NewBodySetup - > AggGeom . GetElementCount ( ) ;
}
RefreshCollisionChange ( * StaticMesh ) ;
GEditor - > EndTransaction ( ) ;
StaticMesh - > MarkPackageDirty ( ) ;
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
StaticMesh - > bCustomizedCollision = true ;
}
}
}
// Remove the temp package from the root now that it has served its purpose
TempPackage - > RemoveFromRoot ( ) ;
}
return OutNumPrimsPasted ;
}
2014-06-13 05:03:24 -04:00
void FStaticMeshEditor : : TranslateSelectedPrims ( const FVector & InDrag )
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
StaticMesh - > GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
2014-12-01 11:19:18 -05:00
2014-06-13 05:03:24 -04:00
for ( int32 PrimIdx = 0 ; PrimIdx < SelectedPrims . Num ( ) ; PrimIdx + + )
{
const FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
FTransform PrimTransform = GetPrimTransform ( PrimData ) ;
FVector PrimLocation = PrimTransform . GetLocation ( ) ;
PrimLocation + = InDrag ;
PrimTransform . SetLocation ( PrimLocation ) ;
SetPrimTransform ( PrimData , PrimTransform ) ;
}
2014-12-01 11:19:18 -05:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-06-13 05:03:24 -04:00
}
void FStaticMeshEditor : : RotateSelectedPrims ( const FRotator & InRot )
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
StaticMesh - > GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
2014-12-01 11:19:18 -05:00
2014-06-13 05:03:24 -04:00
const FQuat DeltaQ = InRot . Quaternion ( ) ;
for ( int32 PrimIdx = 0 ; PrimIdx < SelectedPrims . Num ( ) ; PrimIdx + + )
{
const FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
FTransform PrimTransform = GetPrimTransform ( PrimData ) ;
FRotator ActorRotWind , ActorRotRem ;
PrimTransform . Rotator ( ) . GetWindingAndRemainder ( ActorRotWind , ActorRotRem ) ;
const FQuat ActorQ = ActorRotRem . Quaternion ( ) ;
FRotator NewActorRotRem = FRotator ( DeltaQ * ActorQ ) ;
NewActorRotRem . Normalize ( ) ;
PrimTransform . SetRotation ( NewActorRotRem . Quaternion ( ) ) ;
SetPrimTransform ( PrimData , PrimTransform ) ;
}
2014-12-01 11:19:18 -05:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-06-13 05:03:24 -04:00
}
void FStaticMeshEditor : : ScaleSelectedPrims ( const FVector & InScale )
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
StaticMesh - > GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
FVector ModifiedScale = InScale ;
if ( GEditor - > UsePercentageBasedScaling ( ) )
{
ModifiedScale = InScale * ( ( GEditor - > GetScaleGridSize ( ) / 100.0f ) / GEditor - > GetGridSize ( ) ) ;
}
2015-01-06 14:54:09 -05:00
//Multiply in estimated size of the mesh so scaling of sphere, box and sphyl is similar speed to other scaling
2022-09-29 23:43:57 -04:00
float SimplePrimitiveScaleSpeedFactor = static_cast < float > ( StaticMesh - > GetBounds ( ) . SphereRadius ) ;
2015-01-06 14:54:09 -05:00
2014-06-13 05:03:24 -04:00
for ( int32 PrimIdx = 0 ; PrimIdx < SelectedPrims . Num ( ) ; PrimIdx + + )
{
const FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
check ( IsPrimValid ( PrimData ) ) ;
switch ( PrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2015-01-06 14:54:09 -05:00
AggGeom - > SphereElems [ PrimData . PrimIndex ] . ScaleElem ( SimplePrimitiveScaleSpeedFactor * ModifiedScale , MinPrimSize ) ;
2014-06-13 05:03:24 -04:00
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2015-01-06 14:54:09 -05:00
AggGeom - > BoxElems [ PrimData . PrimIndex ] . ScaleElem ( SimplePrimitiveScaleSpeedFactor * ModifiedScale , MinPrimSize ) ;
2014-06-13 05:03:24 -04:00
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2015-01-06 14:54:09 -05:00
AggGeom - > SphylElems [ PrimData . PrimIndex ] . ScaleElem ( SimplePrimitiveScaleSpeedFactor * ModifiedScale , MinPrimSize ) ;
2014-06-13 05:03:24 -04:00
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
AggGeom - > ConvexElems [ PrimData . PrimIndex ] . ScaleElem ( ModifiedScale , MinPrimSize ) ;
break ;
}
2014-09-10 17:19:28 -04:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-06-13 05:03:24 -04:00
}
2014-12-01 11:19:18 -05:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-06-13 05:03:24 -04:00
}
bool FStaticMeshEditor : : CalcSelectedPrimsAABB ( FBox & OutBox ) const
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
for ( int32 PrimIdx = 0 ; PrimIdx < SelectedPrims . Num ( ) ; PrimIdx + + )
{
const FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
check ( IsPrimValid ( PrimData ) ) ;
switch ( PrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-06-13 05:03:24 -04:00
OutBox + = AggGeom - > SphereElems [ PrimData . PrimIndex ] . CalcAABB ( FTransform : : Identity , 1.f ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
OutBox + = AggGeom - > BoxElems [ PrimData . PrimIndex ] . CalcAABB ( FTransform : : Identity , 1.f ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
OutBox + = AggGeom - > SphylElems [ PrimData . PrimIndex ] . CalcAABB ( FTransform : : Identity , 1.f ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
OutBox + = AggGeom - > ConvexElems [ PrimData . PrimIndex ] . CalcAABB ( FTransform : : Identity , FVector ( 1.f ) ) ;
break ;
}
}
return HasSelectedPrims ( ) ;
}
bool FStaticMeshEditor : : GetLastSelectedPrimTransform ( FTransform & OutTransform ) const
{
if ( SelectedPrims . Num ( ) > 0 )
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
const FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
const FPrimData & PrimData = SelectedPrims . Last ( ) ;
2021-02-01 19:20:35 -04:00
// The SME is not notified of external changes to Simple Collision of the active object, and the UBodySetup
// does not have any kind of change notification to hook into to do this. So, the SelectedPrims can become
// invalid if an external change is made. In that case we will just return false here and hope that the
// FStaticMeshEditorViewportClient caller will error-handle correctly.
if ( IsPrimValid ( PrimData ) = = false )
{
return false ;
}
2014-06-13 05:03:24 -04:00
switch ( PrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-06-13 05:03:24 -04:00
OutTransform = AggGeom - > SphereElems [ PrimData . PrimIndex ] . GetTransform ( ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
OutTransform = AggGeom - > BoxElems [ PrimData . PrimIndex ] . GetTransform ( ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
OutTransform = AggGeom - > SphylElems [ PrimData . PrimIndex ] . GetTransform ( ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
OutTransform = AggGeom - > ConvexElems [ PrimData . PrimIndex ] . GetTransform ( ) ;
break ;
}
}
return HasSelectedPrims ( ) ;
}
FTransform FStaticMeshEditor : : GetPrimTransform ( const FPrimData & InPrimData ) const
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
const FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
check ( IsPrimValid ( InPrimData ) ) ;
switch ( InPrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-06-13 05:03:24 -04:00
return AggGeom - > SphereElems [ InPrimData . PrimIndex ] . GetTransform ( ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
return AggGeom - > BoxElems [ InPrimData . PrimIndex ] . GetTransform ( ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
return AggGeom - > SphylElems [ InPrimData . PrimIndex ] . GetTransform ( ) ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
return AggGeom - > ConvexElems [ InPrimData . PrimIndex ] . GetTransform ( ) ;
}
return FTransform : : Identity ;
}
void FStaticMeshEditor : : SetPrimTransform ( const FPrimData & InPrimData , const FTransform & InPrimTransform ) const
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
check ( IsPrimValid ( InPrimData ) ) ;
switch ( InPrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-06-13 05:03:24 -04:00
AggGeom - > SphereElems [ InPrimData . PrimIndex ] . SetTransform ( InPrimTransform ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-06-13 05:03:24 -04:00
AggGeom - > BoxElems [ InPrimData . PrimIndex ] . SetTransform ( InPrimTransform ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-06-13 05:03:24 -04:00
AggGeom - > SphylElems [ InPrimData . PrimIndex ] . SetTransform ( InPrimTransform ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-06-13 05:03:24 -04:00
AggGeom - > ConvexElems [ InPrimData . PrimIndex ] . SetTransform ( InPrimTransform ) ;
break ;
}
2014-09-10 17:19:28 -04:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-06-13 05:03:24 -04:00
}
2014-09-16 04:20:39 -04:00
bool FStaticMeshEditor : : OverlapsExistingPrim ( const FPrimData & InPrimData ) const
{
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-09-16 04:20:39 -04:00
2020-10-22 19:19:16 -04:00
const FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-09-16 04:20:39 -04:00
// Assume that if the transform of the prim is the same, then it overlaps (FKConvexElem doesn't have an operator==, and no shape takes tolerances into account)
check ( IsPrimValid ( InPrimData ) ) ;
switch ( InPrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2014-09-16 04:20:39 -04:00
{
const FKSphereElem InSphereElem = AggGeom - > SphereElems [ InPrimData . PrimIndex ] ;
const FTransform InElemTM = InSphereElem . GetTransform ( ) ;
for ( int32 i = 0 ; i < AggGeom - > SphereElems . Num ( ) ; + + i )
{
if ( i = = InPrimData . PrimIndex )
{
continue ;
}
const FKSphereElem & SphereElem = AggGeom - > SphereElems [ i ] ;
const FTransform ElemTM = SphereElem . GetTransform ( ) ;
if ( InElemTM . Equals ( ElemTM ) )
{
return true ;
}
}
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2014-09-16 04:20:39 -04:00
{
const FKBoxElem InBoxElem = AggGeom - > BoxElems [ InPrimData . PrimIndex ] ;
const FTransform InElemTM = InBoxElem . GetTransform ( ) ;
for ( int32 i = 0 ; i < AggGeom - > BoxElems . Num ( ) ; + + i )
{
if ( i = = InPrimData . PrimIndex )
{
continue ;
}
const FKBoxElem & BoxElem = AggGeom - > BoxElems [ i ] ;
const FTransform ElemTM = BoxElem . GetTransform ( ) ;
if ( InElemTM . Equals ( ElemTM ) )
{
return true ;
}
}
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2014-09-16 04:20:39 -04:00
{
const FKSphylElem InSphylElem = AggGeom - > SphylElems [ InPrimData . PrimIndex ] ;
const FTransform InElemTM = InSphylElem . GetTransform ( ) ;
for ( int32 i = 0 ; i < AggGeom - > SphylElems . Num ( ) ; + + i )
{
if ( i = = InPrimData . PrimIndex )
{
continue ;
}
const FKSphylElem & SphylElem = AggGeom - > SphylElems [ i ] ;
const FTransform ElemTM = SphylElem . GetTransform ( ) ;
if ( InElemTM . Equals ( ElemTM ) )
{
return true ;
}
}
}
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2014-09-16 04:20:39 -04:00
{
const FKConvexElem InConvexElem = AggGeom - > ConvexElems [ InPrimData . PrimIndex ] ;
const FTransform InElemTM = InConvexElem . GetTransform ( ) ;
for ( int32 i = 0 ; i < AggGeom - > ConvexElems . Num ( ) ; + + i )
{
if ( i = = InPrimData . PrimIndex )
{
continue ;
}
const FKConvexElem & ConvexElem = AggGeom - > ConvexElems [ i ] ;
const FTransform ElemTM = ConvexElem . GetTransform ( ) ;
if ( InElemTM . Equals ( ElemTM ) )
{
return true ;
}
}
}
break ;
}
return false ;
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : RefreshTool ( )
{
int32 NumLODs = StaticMesh - > GetNumLODs ( ) ;
for ( int32 LODIndex = 0 ; LODIndex < NumLODs ; + + LODIndex )
{
UpdateLODStats ( LODIndex ) ;
}
2017-06-14 08:40:01 -04:00
OnSelectedLODChangedResetOnRefresh . Clear ( ) ;
2014-03-14 14:13:41 -04:00
bool bForceRefresh = true ;
StaticMeshDetailsView - > SetObject ( StaticMesh , bForceRefresh ) ;
RefreshViewport ( ) ;
}
void FStaticMeshEditor : : RefreshViewport ( )
{
2020-09-01 14:07:48 -04:00
if ( GetStaticMeshViewport ( ) . IsValid ( ) )
{
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2022-02-08 13:29:56 -05:00
void FStaticMeshEditor : : GenerateUVChannelComboList ( UToolMenu * InMenu )
2014-03-14 14:13:41 -04:00
{
2017-06-19 20:27:30 -04:00
FUIAction DrawUVsAction ;
2019-10-30 18:26:53 -04:00
FStaticMeshEditorViewportClient & ViewportClient = GetStaticMeshViewport ( ) - > GetViewportClient ( ) ;
2017-06-19 20:27:30 -04:00
DrawUVsAction . ExecuteAction = FExecuteAction : : CreateRaw ( & ViewportClient , & FStaticMeshEditorViewportClient : : SetDrawUVOverlay , false ) ;
// Note, the logic is inversed here. We show the radio button as checked if no uv channels are being shown
DrawUVsAction . GetActionCheckState = FGetActionCheckState : : CreateLambda ( [ & ViewportClient ] ( ) { return ViewportClient . IsDrawUVOverlayChecked ( ) ? ECheckBoxState : : Unchecked : ECheckBoxState : : Checked ; } ) ;
2019-06-07 11:22:52 -04:00
// Add UV display functions
2014-03-14 14:13:41 -04:00
{
2022-02-08 13:29:56 -05:00
FToolMenuSection & Section = InMenu - > AddSection ( " UVDisplayOptions " ) ;
Section . AddMenuEntry (
" ShowUVSToggle " ,
2019-06-07 11:22:52 -04:00
LOCTEXT ( " ShowUVSToggle " , " None " ) ,
LOCTEXT ( " ShowUVSToggle_Tooltip " , " Toggles display of the static mesh's UVs. " ) ,
2017-06-19 20:27:30 -04:00
FSlateIcon ( ) ,
2019-06-07 11:22:52 -04:00
DrawUVsAction ,
2017-06-19 20:27:30 -04:00
EUserInterfaceActionType : : RadioButton
) ;
2019-06-07 11:22:52 -04:00
2022-02-08 13:29:56 -05:00
Section . AddSeparator ( " ShowUVSToggleSeperator " ) ;
2019-06-07 11:22:52 -04:00
// Fill out the UV channels combo.
int32 MaxUVChannels = FMath : : Max < int32 > ( GetNumUVChannels ( ) , 1 ) ;
2022-02-08 13:29:56 -05:00
FName UVChannelIDName ( " UVChannel_ID " ) ;
2019-06-07 11:22:52 -04:00
for ( int32 UVChannelID = 0 ; UVChannelID < MaxUVChannels ; + + UVChannelID )
{
FUIAction MenuAction ;
MenuAction . ExecuteAction . BindSP ( this , & FStaticMeshEditor : : SetCurrentViewedUVChannel , UVChannelID ) ;
MenuAction . GetActionCheckState . BindSP ( this , & FStaticMeshEditor : : GetUVChannelCheckState , UVChannelID ) ;
2022-02-08 13:29:56 -05:00
UVChannelIDName . SetNumber ( UVChannelID + 1 ) ;
Section . AddMenuEntry (
UVChannelIDName ,
2019-06-07 11:22:52 -04:00
FText : : Format ( LOCTEXT ( " UVChannel_ID " , " UV Channel {0} " ) , FText : : AsNumber ( UVChannelID ) ) ,
FText : : Format ( LOCTEXT ( " UVChannel_ID_ToolTip " , " Overlay UV Channel {0} on the viewport " ) , FText : : AsNumber ( UVChannelID ) ) ,
FSlateIcon ( ) ,
MenuAction ,
EUserInterfaceActionType : : RadioButton
) ;
}
2014-03-14 14:13:41 -04:00
}
2018-11-06 10:00:36 -05:00
// Add UV editing functions
{
2022-02-08 13:29:56 -05:00
FToolMenuSection & Section = InMenu - > AddSection ( " UVActionOptions " ) ;
2018-11-06 10:00:36 -05:00
FUIAction MenuAction ;
MenuAction . ExecuteAction . BindSP ( this , & FStaticMeshEditor : : RemoveCurrentUVChannel ) ;
MenuAction . CanExecuteAction . BindSP ( this , & FStaticMeshEditor : : CanRemoveUVChannel ) ;
2022-02-08 13:29:56 -05:00
Section . AddMenuEntry (
" Remove_UVChannel " ,
2018-11-06 10:00:36 -05:00
LOCTEXT ( " Remove_UVChannel " , " Remove Selected " ) ,
LOCTEXT ( " Remove_UVChannel_ToolTip " , " Remove currently selected UV channel from the static mesh " ) ,
FSlateIcon ( ) ,
MenuAction ,
EUserInterfaceActionType : : Button
) ;
}
2014-03-14 14:13:41 -04:00
}
2018-06-07 18:49:50 -04:00
void FStaticMeshEditor : : UpdateLODStats ( int32 CurrentLOD )
2014-03-14 14:13:41 -04:00
{
2018-03-19 14:16:59 -04:00
NumTriangles [ CurrentLOD ] = 0 ; //-V781
NumVertices [ CurrentLOD ] = 0 ; //-V781
NumUVChannels [ CurrentLOD ] = 0 ; //-V781
2017-12-14 10:07:13 -05:00
int32 NumLODLevels = 0 ;
2014-03-14 14:13:41 -04:00
2020-10-22 19:19:16 -04:00
if ( StaticMesh - > GetRenderData ( ) )
2014-03-14 14:13:41 -04:00
{
2020-10-22 19:19:16 -04:00
NumLODLevels = StaticMesh - > GetRenderData ( ) - > LODResources . Num ( ) ;
2014-03-14 14:13:41 -04:00
if ( CurrentLOD > = 0 & & CurrentLOD < NumLODLevels )
{
2020-10-22 19:19:16 -04:00
FStaticMeshLODResources & LODModel = StaticMesh - > GetRenderData ( ) - > LODResources [ CurrentLOD ] ;
2014-03-14 14:13:41 -04:00
NumTriangles [ CurrentLOD ] = LODModel . GetNumTriangles ( ) ;
NumVertices [ CurrentLOD ] = LODModel . GetNumVertices ( ) ;
2017-10-13 11:32:28 -04:00
NumUVChannels [ CurrentLOD ] = LODModel . VertexBuffers . StaticMeshVertexBuffer . GetNumTexCoords ( ) ;
2014-03-14 14:13:41 -04:00
}
}
}
void FStaticMeshEditor : : ComboBoxSelectionChanged ( TSharedPtr < FString > NewSelection , ESelectInfo : : Type /*SelectInfo*/ )
{
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-03-14 14:13:41 -04:00
}
2018-05-23 21:04:31 -04:00
void FStaticMeshEditor : : HandleReimportMesh ( )
{
// Reimport the asset
if ( StaticMesh )
{
2022-10-19 15:15:54 -04:00
FReimportManager : : Instance ( ) - > ReimportAsync ( StaticMesh , true ) ;
2018-05-23 21:04:31 -04:00
}
}
void FStaticMeshEditor : : HandleReimportAllMesh ( )
{
// Reimport the asset
if ( StaticMesh )
{
//Reimport base LOD, generated mesh will be rebuild here, the static mesh is always using the base mesh to reduce LOD
if ( FReimportManager : : Instance ( ) - > Reimport ( StaticMesh , true ) )
{
//Reimport all custom LODs
for ( int32 LodIndex = 1 ; LodIndex < StaticMesh - > GetNumLODs ( ) ; + + LodIndex )
{
//Skip LOD import in the same file as the base mesh, they are already re-import
2021-02-16 15:14:02 -04:00
if ( StaticMesh - > GetSourceModel ( LodIndex ) . bImportWithBaseMesh )
2018-05-23 21:04:31 -04:00
{
continue ;
}
2019-01-14 16:55:55 -05:00
2019-10-01 20:41:42 -04:00
bool bHasBeenSimplified = ! StaticMesh - > IsMeshDescriptionValid ( LodIndex ) | | StaticMesh - > IsReductionActive ( LodIndex ) ;
2018-05-23 21:04:31 -04:00
if ( ! bHasBeenSimplified )
{
FbxMeshUtils : : ImportMeshLODDialog ( StaticMesh , LodIndex ) ;
}
}
}
}
}
2014-03-14 14:13:41 -04:00
int32 FStaticMeshEditor : : GetCurrentUVChannel ( )
{
2017-06-19 20:27:30 -04:00
return FMath : : Min ( CurrentViewedUVChannel , GetNumUVChannels ( ) ) ;
2014-03-14 14:13:41 -04:00
}
int32 FStaticMeshEditor : : GetCurrentLODLevel ( )
{
2017-12-14 10:07:13 -05:00
if ( GetStaticMeshComponent ( ) )
2017-06-14 08:40:01 -04:00
{
2017-12-14 10:07:13 -05:00
return GetStaticMeshComponent ( ) - > ForcedLodModel ;
2017-06-14 08:40:01 -04:00
}
2017-12-14 10:07:13 -05:00
return 0 ;
2014-03-14 14:13:41 -04:00
}
int32 FStaticMeshEditor : : GetCurrentLODIndex ( )
{
2017-06-14 08:40:01 -04:00
int32 Index = GetCurrentLODLevel ( ) ;
2014-03-14 14:13:41 -04:00
return Index = = 0 ? 0 : Index - 1 ;
}
2018-05-23 21:04:31 -04:00
int32 FStaticMeshEditor : : GetCustomData ( const int32 Key ) const
{
if ( ! CustomEditorData . Contains ( Key ) )
{
return INDEX_NONE ;
}
return CustomEditorData [ Key ] ;
}
void FStaticMeshEditor : : SetCustomData ( const int32 Key , const int32 CustomData )
{
CustomEditorData . FindOrAdd ( Key ) = CustomData ;
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : GenerateKDop ( const FVector * Directions , uint32 NumDirections )
{
TArray < FVector > DirArray ;
for ( uint32 DirectionIndex = 0 ; DirectionIndex < NumDirections ; DirectionIndex + + )
{
DirArray . Add ( Directions [ DirectionIndex ] ) ;
}
2014-06-13 05:03:24 -04:00
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_GenerateKDop " , " Create Convex Collision " ) ) ;
const int32 PrimIndex = GenerateKDopAsSimpleCollision ( StaticMesh , DirArray ) ;
2020-06-23 18:40:00 -04:00
if ( PrimIndex ! = INDEX_NONE )
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > AggGeom . ConvexElems [ PrimIndex ] . bIsGenerated = true ;
2020-06-23 18:40:00 -04:00
}
2014-06-13 05:03:24 -04:00
GEditor - > EndTransaction ( ) ;
if ( PrimIndex ! = INDEX_NONE )
{
2014-07-24 04:28:41 -04:00
if ( FEngineAnalytics : : IsAvailable ( ) )
{
2014-08-01 05:31:22 -04:00
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Collision " ) , TEXT ( " Type " ) , TEXT ( " KDop Collision " ) ) ;
2014-07-24 04:28:41 -04:00
}
2017-09-04 04:17:46 -04:00
const FPrimData PrimData = FPrimData ( EAggCollisionShape : : Convex , PrimIndex ) ;
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-09-22 10:43:45 -04:00
AddSelectedPrim ( PrimData , true ) ;
2016-02-16 13:35:21 -05:00
// Don't 'nudge' KDop prims, as they are fitted specifically around the geometry
2014-06-13 05:03:24 -04:00
}
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-06-13 05:03:24 -04:00
}
void FStaticMeshEditor : : OnCollisionBox ( )
{
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_OnCollisionBox " , " Create Box Collision " ) ) ;
const int32 PrimIndex = GenerateBoxAsSimpleCollision ( StaticMesh ) ;
2020-06-23 18:40:00 -04:00
if ( PrimIndex ! = INDEX_NONE )
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > AggGeom . BoxElems [ PrimIndex ] . bIsGenerated = true ;
2020-06-23 18:40:00 -04:00
}
2014-06-13 05:03:24 -04:00
GEditor - > EndTransaction ( ) ;
if ( PrimIndex ! = INDEX_NONE )
{
2014-07-24 04:28:41 -04:00
if ( FEngineAnalytics : : IsAvailable ( ) )
{
2014-08-01 05:31:22 -04:00
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Collision " ) , TEXT ( " Type " ) , TEXT ( " Box Collision " ) ) ;
2014-07-24 04:28:41 -04:00
}
2017-09-04 04:17:46 -04:00
const FPrimData PrimData = FPrimData ( EAggCollisionShape : : Box , PrimIndex ) ;
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-09-22 10:43:45 -04:00
AddSelectedPrim ( PrimData , true ) ;
2014-09-16 04:20:39 -04:00
while ( OverlapsExistingPrim ( PrimData ) )
{
TranslateSelectedPrims ( OverlapNudge ) ;
}
2014-06-13 05:03:24 -04:00
}
2014-03-14 14:13:41 -04:00
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : OnCollisionSphere ( )
{
2014-06-13 05:03:24 -04:00
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_OnCollisionSphere " , " Create Sphere Collision " ) ) ;
const int32 PrimIndex = GenerateSphereAsSimpleCollision ( StaticMesh ) ;
2020-06-23 18:40:00 -04:00
if ( PrimIndex ! = INDEX_NONE )
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > AggGeom . SphereElems [ PrimIndex ] . bIsGenerated = true ;
2020-06-23 18:40:00 -04:00
}
2014-06-13 05:03:24 -04:00
GEditor - > EndTransaction ( ) ;
if ( PrimIndex ! = INDEX_NONE )
{
2014-07-24 04:28:41 -04:00
if ( FEngineAnalytics : : IsAvailable ( ) )
{
2014-08-01 05:31:22 -04:00
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Collision " ) , TEXT ( " Type " ) , TEXT ( " Sphere Collision " ) ) ;
2014-07-24 04:28:41 -04:00
}
2017-09-04 04:17:46 -04:00
const FPrimData PrimData = FPrimData ( EAggCollisionShape : : Sphere , PrimIndex ) ;
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-09-22 10:43:45 -04:00
AddSelectedPrim ( PrimData , true ) ;
2014-09-16 04:20:39 -04:00
while ( OverlapsExistingPrim ( PrimData ) )
{
TranslateSelectedPrims ( OverlapNudge ) ;
}
2014-06-13 05:03:24 -04:00
}
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-06-13 05:03:24 -04:00
}
void FStaticMeshEditor : : OnCollisionSphyl ( )
{
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_OnCollisionSphyl " , " Create Capsule Collision " ) ) ;
const int32 PrimIndex = GenerateSphylAsSimpleCollision ( StaticMesh ) ;
2020-06-23 18:40:00 -04:00
if ( PrimIndex ! = INDEX_NONE )
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > AggGeom . SphylElems [ PrimIndex ] . bIsGenerated = true ;
2020-06-23 18:40:00 -04:00
}
2014-06-13 05:03:24 -04:00
GEditor - > EndTransaction ( ) ;
if ( PrimIndex ! = INDEX_NONE )
{
2014-07-24 04:28:41 -04:00
if ( FEngineAnalytics : : IsAvailable ( ) )
{
2014-08-01 05:31:22 -04:00
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Collision " ) , TEXT ( " Type " ) , TEXT ( " Capsule Collision " ) ) ;
2014-07-24 04:28:41 -04:00
}
2017-09-04 04:17:46 -04:00
const FPrimData PrimData = FPrimData ( EAggCollisionShape : : Sphyl , PrimIndex ) ;
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-09-22 10:43:45 -04:00
AddSelectedPrim ( PrimData , true ) ;
2014-09-16 04:20:39 -04:00
while ( OverlapsExistingPrim ( PrimData ) )
{
TranslateSelectedPrims ( OverlapNudge ) ;
}
2014-06-13 05:03:24 -04:00
}
2014-03-14 14:13:41 -04:00
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : OnRemoveCollision ( void )
{
2020-10-22 19:19:16 -04:00
UBodySetup * BS = StaticMesh - > GetBodySetup ( ) ;
2015-01-06 14:54:09 -05:00
check ( BS ! = NULL & & BS - > AggGeom . GetElementCount ( ) > 0 ) ;
2014-06-13 05:03:24 -04:00
2015-01-06 14:54:09 -05:00
ClearSelectedPrims ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-06 14:54:09 -05:00
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-06 14:54:09 -05:00
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_RemoveCollision " , " Remove Collision " ) ) ;
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > Modify ( ) ;
2014-03-14 14:13:41 -04:00
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > RemoveSimpleCollision ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-06 14:54:09 -05:00
GEditor - > EndTransaction ( ) ;
2014-09-10 17:19:28 -04:00
2015-01-06 14:54:09 -05:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2015-01-06 14:54:09 -05:00
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh - > MarkPackageDirty ( ) ;
// Update views/property windows
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2015-01-06 14:54:09 -05:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
}
bool FStaticMeshEditor : : CanRemoveCollision ( )
{
2020-10-22 19:19:16 -04:00
UBodySetup * BS = StaticMesh - > GetBodySetup ( ) ;
2015-01-06 14:54:09 -05:00
return ( BS ! = NULL & & BS - > AggGeom . GetElementCount ( ) > 0 ) ;
2014-03-14 14:13:41 -04:00
}
/** Util for adding vertex to an array if it is not already present. */
2021-05-05 15:07:25 -04:00
static void AddVertexIfNotPresent ( TArray < FVector3f > & Vertices , const FVector3f & NewVertex )
2014-03-14 14:13:41 -04:00
{
bool bIsPresent = false ;
for ( int32 i = 0 ; i < Vertices . Num ( ) ; i + + )
{
float diffSqr = ( NewVertex - Vertices [ i ] ) . SizeSquared ( ) ;
if ( diffSqr < 0.01f * 0.01f )
{
bIsPresent = 1 ;
break ;
}
}
if ( ! bIsPresent )
{
Vertices . Add ( NewVertex ) ;
}
}
void FStaticMeshEditor : : OnConvertBoxToConvexCollision ( )
{
// If we have a collision model for this staticmesh, ask if we want to replace it.
2020-10-22 19:19:16 -04:00
if ( StaticMesh - > GetBodySetup ( ) )
2014-03-14 14:13:41 -04:00
{
int32 ShouldReplace = FMessageDialog : : Open ( EAppMsgType : : YesNo , LOCTEXT ( " ConvertBoxCollisionPrompt " , " Are you sure you want to convert all box collision? " ) ) ;
if ( ShouldReplace = = EAppReturnType : : Yes )
{
2020-10-22 19:19:16 -04:00
UBodySetup * BodySetup = StaticMesh - > GetBodySetup ( ) ;
2014-03-14 14:13:41 -04:00
int32 NumBoxElems = BodySetup - > AggGeom . BoxElems . Num ( ) ;
if ( NumBoxElems > 0 )
{
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-03-14 14:13:41 -04:00
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
FKConvexElem * NewConvexColl = NULL ;
//For each box elem, calculate the new convex collision representation
//Stored in a temp array so we can undo on failure.
TArray < FKConvexElem > TempArray ;
for ( int32 i = 0 ; i < NumBoxElems ; i + + )
{
const FKBoxElem & BoxColl = BodySetup - > AggGeom . BoxElems [ i ] ;
//Create a new convex collision element
NewConvexColl = new ( TempArray ) FKConvexElem ( ) ;
2016-10-06 12:11:11 -04:00
NewConvexColl - > ConvexFromBoxElem ( BoxColl ) ;
2014-03-14 14:13:41 -04:00
}
//Clear the cache (PIE may have created some data), create new GUID
BodySetup - > InvalidatePhysicsData ( ) ;
//Copy the new data into the static mesh
BodySetup - > AggGeom . ConvexElems . Append ( TempArray ) ;
//Clear out what we just replaced
BodySetup - > AggGeom . BoxElems . Empty ( ) ;
BodySetup - > CreatePhysicsMeshes ( ) ;
2014-09-16 04:20:39 -04:00
// Select the new prims
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-09-16 04:20:39 -04:00
for ( int32 i = 0 ; i < NumBoxElems ; + + i )
{
2017-09-04 04:17:46 -04:00
AddSelectedPrim ( FPrimData ( EAggCollisionShape : : Convex , ( AggGeom - > ConvexElems . Num ( ) - ( i + 1 ) ) ) , false ) ;
2014-09-16 04:20:39 -04:00
}
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-03-14 14:13:41 -04:00
// Mark static mesh as dirty, to help make sure it gets saved.
StaticMesh - > MarkPackageDirty ( ) ;
// Update views/property windows
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-09-10 17:19:28 -04:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-03-14 14:13:41 -04:00
}
}
}
}
void FStaticMeshEditor : : OnCopyCollisionFromSelectedStaticMesh ( )
{
2014-12-19 12:47:41 -05:00
UStaticMesh * SelectedMesh = GetFirstSelectedStaticMeshInContentBrowser ( ) ;
2020-10-22 19:19:16 -04:00
check ( SelectedMesh & & SelectedMesh ! = StaticMesh & & SelectedMesh - > GetBodySetup ( ) ) ;
2014-12-19 12:47:41 -05:00
2020-10-22 19:19:16 -04:00
UBodySetup * BodySetup = StaticMesh - > GetBodySetup ( ) ;
2014-12-19 12:47:41 -05:00
ClearSelectedPrims ( ) ;
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_CopyCollisionFromSelectedStaticMesh " , " Copy Collision from Selected Static Mesh " ) ) ;
BodySetup - > Modify ( ) ;
// Copy body properties from
2020-10-22 19:19:16 -04:00
BodySetup - > CopyBodyPropertiesFrom ( SelectedMesh - > GetBodySetup ( ) ) ;
2014-12-19 12:47:41 -05:00
// Enable collision, if not already
2019-10-30 18:26:53 -04:00
if ( ! GetStaticMeshViewport ( ) - > GetViewportClient ( ) . IsShowSimpleCollisionChecked ( ) )
2014-03-14 14:13:41 -04:00
{
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . ToggleShowSimpleCollision ( ) ;
2014-12-19 12:47:41 -05:00
}
// Invalidate physics data and create new meshes
BodySetup - > InvalidatePhysicsData ( ) ;
2018-06-07 18:49:50 -04:00
BodySetup - > CreatePhysicsMeshes ( ) ;
2014-12-19 12:47:41 -05:00
GEditor - > EndTransaction ( ) ;
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-12-19 12:47:41 -05:00
// Mark static mesh as dirty, to help make sure it gets saved.
StaticMesh - > MarkPackageDirty ( ) ;
// Redraw level editor viewports, in case the asset's collision is visible in a viewport and the viewport isn't set to realtime.
// Note: This could be more intelligent and only trigger a redraw if the asset is referenced in the world.
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
// Update views/property windows
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-12-19 12:47:41 -05:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
}
bool FStaticMeshEditor : : CanCopyCollisionFromSelectedStaticMesh ( ) const
{
bool CanCopy = false ;
TArray < FAssetData > SelectedAssets ;
GEditor - > GetContentBrowserSelections ( SelectedAssets ) ;
if ( SelectedAssets . Num ( ) = = 1 )
{
FAssetData & Asset = SelectedAssets [ 0 ] ;
if ( Asset . GetClass ( ) = = UStaticMesh : : StaticClass ( ) )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
UStaticMesh * SelectedMesh = Cast < UStaticMesh > ( Asset . GetAsset ( ) ) ;
2020-10-22 19:19:16 -04:00
if ( SelectedMesh & & SelectedMesh ! = StaticMesh & & SelectedMesh - > GetBodySetup ( ) )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
CanCopy = true ;
2014-03-14 14:13:41 -04:00
}
}
}
2014-12-19 12:47:41 -05:00
return CanCopy ;
}
UStaticMesh * FStaticMeshEditor : : GetFirstSelectedStaticMeshInContentBrowser ( ) const
{
TArray < FAssetData > SelectedAssets ;
GEditor - > GetContentBrowserSelections ( SelectedAssets ) ;
for ( auto & Asset : SelectedAssets )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
UStaticMesh * SelectedMesh = Cast < UStaticMesh > ( Asset . GetAsset ( ) ) ;
if ( SelectedMesh )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
return SelectedMesh ;
2014-03-14 14:13:41 -04:00
}
}
2014-12-19 12:47:41 -05:00
return NULL ;
2014-03-14 14:13:41 -04:00
}
2017-01-31 15:22:49 -05:00
void FStaticMeshEditor : : SetEditorMesh ( UStaticMesh * InStaticMesh , bool bResetCamera /*=true*/ )
2014-03-14 14:13:41 -04:00
{
2015-06-15 11:48:12 -04:00
ClearSelectedPrims ( ) ;
2020-10-22 19:19:16 -04:00
if ( StaticMesh )
{
StaticMesh - > GetOnMeshChanged ( ) . RemoveAll ( this ) ;
}
2014-03-14 14:13:41 -04:00
StaticMesh = InStaticMesh ;
2015-04-29 13:13:37 -04:00
//Init stat arrays.
const int32 ArraySize = MAX_STATIC_MESH_LODS ;
2014-03-14 14:13:41 -04:00
NumVertices . Empty ( ArraySize ) ;
NumVertices . AddZeroed ( ArraySize ) ;
NumTriangles . Empty ( ArraySize ) ;
NumTriangles . AddZeroed ( ArraySize ) ;
NumUVChannels . Empty ( ArraySize ) ;
NumUVChannels . AddZeroed ( ArraySize ) ;
2018-02-22 11:25:06 -05:00
if ( StaticMesh )
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetOnMeshChanged ( ) . AddRaw ( this , & FStaticMeshEditor : : OnMeshChanged ) ;
2018-02-22 11:25:06 -05:00
int32 NumLODs = StaticMesh - > GetNumLODs ( ) ;
for ( int32 LODIndex = 0 ; LODIndex < NumLODs ; + + LODIndex )
{
UpdateLODStats ( LODIndex ) ;
}
}
2014-03-14 14:13:41 -04:00
// Set the details view.
StaticMeshDetailsView - > SetObject ( StaticMesh ) ;
2021-11-18 14:37:34 -05:00
if ( SStaticMeshEditorViewport * StaticMeshViewport = GetStaticMeshViewport ( ) . Get ( ) )
2020-09-01 14:07:48 -04:00
{
2021-11-18 14:37:34 -05:00
StaticMeshViewport - > UpdatePreviewMesh ( StaticMesh , bResetCamera ) ;
StaticMeshViewport - > RefreshViewport ( ) ;
if ( EditorModeManager )
{
// update the selection
if ( USelection * ComponentSet = EditorModeManager - > GetSelectedComponents ( ) )
{
ComponentSet - > BeginBatchSelectOperation ( ) ;
ComponentSet - > DeselectAll ( ) ;
ComponentSet - > Select ( StaticMeshViewport - > GetStaticMeshComponent ( ) , true ) ;
ComponentSet - > EndBatchSelectOperation ( ) ;
}
}
2020-09-01 14:07:48 -04:00
}
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : OnChangeMesh ( )
{
2014-12-19 12:47:41 -05:00
UStaticMesh * SelectedMesh = GetFirstSelectedStaticMeshInContentBrowser ( ) ;
check ( SelectedMesh ! = NULL & & SelectedMesh ! = StaticMesh ) ;
RemoveEditingObject ( StaticMesh ) ;
AddEditingObject ( SelectedMesh ) ;
SetEditorMesh ( SelectedMesh ) ;
// Clear selections made on previous mesh
ClearSelectedPrims ( ) ;
GetSelectedEdges ( ) . Empty ( ) ;
if ( SocketManager . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
SocketManager - > UpdateStaticMesh ( ) ;
}
}
2014-03-14 14:13:41 -04:00
2014-12-19 12:47:41 -05:00
bool FStaticMeshEditor : : CanChangeMesh ( ) const
{
bool CanChange = false ;
2014-03-14 14:13:41 -04:00
2014-12-19 12:47:41 -05:00
TArray < FAssetData > SelectedAssets ;
GEditor - > GetContentBrowserSelections ( SelectedAssets ) ;
if ( SelectedAssets . Num ( ) = = 1 )
{
FAssetData & Asset = SelectedAssets [ 0 ] ;
if ( Asset . GetClass ( ) = = UStaticMesh : : StaticClass ( ) )
2014-03-14 14:13:41 -04:00
{
2014-12-19 12:47:41 -05:00
UStaticMesh * SelectedMesh = Cast < UStaticMesh > ( Asset . GetAsset ( ) ) ;
if ( SelectedMesh & & SelectedMesh ! = StaticMesh )
{
CanChange = true ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-12-19 12:47:41 -05:00
return CanChange ;
2014-03-14 14:13:41 -04:00
}
2015-02-21 13:20:31 -05:00
void FStaticMeshEditor : : OnSaveGeneratedLODs ( )
{
if ( StaticMesh )
{
StaticMesh - > GenerateLodsInPackage ( ) ;
// Update editor UI as we modified LOD groups
auto Selected = StaticMeshDetailsView - > GetSelectedObjects ( ) ;
StaticMeshDetailsView - > SetObjects ( Selected , true ) ;
// Update screen
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2015-02-21 13:20:31 -05:00
}
}
2017-10-06 04:43:18 -04:00
void FStaticMeshEditor : : DoDecomp ( uint32 InHullCount , int32 InMaxHullVerts , uint32 InHullPrecision )
2014-03-14 14:13:41 -04:00
{
// Check we have a selected StaticMesh
2020-10-22 19:19:16 -04:00
if ( StaticMesh & & StaticMesh - > GetRenderData ( ) )
2014-03-14 14:13:41 -04:00
{
2020-10-22 19:19:16 -04:00
FStaticMeshLODResources & LODModel = StaticMesh - > GetRenderData ( ) - > LODResources [ 0 ] ;
2014-03-14 14:13:41 -04:00
// Start a busy cursor so the user has feedback while waiting
const FScopedBusyCursor BusyCursor ;
// Make vertex buffer
2017-10-13 11:32:28 -04:00
int32 NumVerts = LODModel . VertexBuffers . StaticMeshVertexBuffer . GetNumVertices ( ) ;
2021-09-07 14:54:16 -04:00
TArray < FVector3f > Verts ;
Verts . SetNumUninitialized ( NumVerts ) ;
2014-03-14 14:13:41 -04:00
for ( int32 i = 0 ; i < NumVerts ; i + + )
{
2021-09-07 14:54:16 -04:00
const FVector3f & Vert = LODModel . VertexBuffers . PositionVertexBuffer . VertexPosition ( i ) ;
Verts [ i ] = Vert ;
2014-03-14 14:13:41 -04:00
}
2015-06-19 09:43:01 -04:00
// Grab all indices
TArray < uint32 > AllIndices ;
LODModel . IndexBuffer . GetCopy ( AllIndices ) ;
// Only copy indices that have collision enabled
TArray < uint32 > CollidingIndices ;
for ( const FStaticMeshSection & Section : LODModel . Sections )
{
if ( Section . bEnableCollision )
{
for ( uint32 IndexIdx = Section . FirstIndex ; IndexIdx < Section . FirstIndex + ( Section . NumTriangles * 3 ) ; IndexIdx + + )
{
CollidingIndices . Add ( AllIndices [ IndexIdx ] ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2014-06-13 05:03:24 -04:00
ClearSelectedPrims ( ) ;
2014-03-14 14:13:41 -04:00
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
// Get the BodySetup we are going to put the collision into
2020-10-22 19:19:16 -04:00
UBodySetup * bs = StaticMesh - > GetBodySetup ( ) ;
2014-03-14 14:13:41 -04:00
if ( bs )
{
bs - > RemoveSimpleCollision ( ) ;
}
else
{
// Otherwise, create one here.
StaticMesh - > CreateBodySetup ( ) ;
2020-10-22 19:19:16 -04:00
bs = StaticMesh - > GetBodySetup ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-07-24 10:04:30 -04:00
// Run actual util to do the work (if we have some valid input)
if ( Verts . Num ( ) > = 3 & & CollidingIndices . Num ( ) > = 3 )
{
2017-10-06 04:43:18 -04:00
# if USE_ASYNC_DECOMP
// If there is currently a decomposition already in progress we release it.
if ( DecomposeMeshToHullsAsync )
{
DecomposeMeshToHullsAsync - > Release ( ) ;
}
// Begin the convex decomposition process asynchronously
DecomposeMeshToHullsAsync = CreateIDecomposeMeshToHullAsync ( ) ;
2021-09-07 14:54:16 -04:00
DecomposeMeshToHullsAsync - > DecomposeMeshToHullsAsyncBegin ( bs , MoveTemp ( Verts ) , MoveTemp ( CollidingIndices ) , InHullCount , InMaxHullVerts , InHullPrecision ) ;
2017-10-06 04:43:18 -04:00
# else
DecomposeMeshToHulls ( bs , Verts , CollidingIndices , InHullCount , InMaxHullVerts , InHullPrecision ) ;
# endif
2015-07-24 10:04:30 -04:00
}
2014-03-14 14:13:41 -04:00
2014-09-16 04:20:39 -04:00
// Enable collision, if not already
2019-10-30 18:26:53 -04:00
if ( ! GetStaticMeshViewport ( ) - > GetViewportClient ( ) . IsShowSimpleCollisionChecked ( ) )
2014-09-16 04:20:39 -04:00
{
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . ToggleShowSimpleCollision ( ) ;
2014-09-16 04:20:39 -04:00
}
2014-03-14 14:13:41 -04:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2014-03-14 14:13:41 -04:00
// Mark mesh as dirty
StaticMesh - > MarkPackageDirty ( ) ;
// Update screen.
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2014-09-10 17:19:28 -04:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-03-14 14:13:41 -04:00
}
}
TSet < int32 > & FStaticMeshEditor : : GetSelectedEdges ( )
{
2019-10-30 18:26:53 -04:00
return GetStaticMeshViewport ( ) - > GetSelectedEdges ( ) ;
2014-03-14 14:13:41 -04:00
}
int32 FStaticMeshEditor : : GetNumTriangles ( int32 LODLevel ) const
{
return NumTriangles . IsValidIndex ( LODLevel ) ? NumTriangles [ LODLevel ] : 0 ;
}
int32 FStaticMeshEditor : : GetNumVertices ( int32 LODLevel ) const
{
return NumVertices . IsValidIndex ( LODLevel ) ? NumVertices [ LODLevel ] : 0 ;
}
int32 FStaticMeshEditor : : GetNumUVChannels ( int32 LODLevel ) const
{
return NumUVChannels . IsValidIndex ( LODLevel ) ? NumUVChannels [ LODLevel ] : 0 ;
}
2014-06-13 05:03:24 -04:00
void FStaticMeshEditor : : DeleteSelected ( )
{
if ( GetSelectedSocket ( ) )
{
DeleteSelectedSockets ( ) ;
}
2018-06-07 18:49:50 -04:00
2014-06-13 05:03:24 -04:00
if ( HasSelectedPrims ( ) )
{
DeleteSelectedPrims ( ) ;
}
}
bool FStaticMeshEditor : : CanDeleteSelected ( ) const
{
return ( GetSelectedSocket ( ) ! = NULL | | HasSelectedPrims ( ) ) ;
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : DeleteSelectedSockets ( )
{
check ( SocketManager . IsValid ( ) ) ;
SocketManager - > DeleteSelectedSocket ( ) ;
}
2014-06-13 05:03:24 -04:00
void FStaticMeshEditor : : DeleteSelectedPrims ( )
2014-03-14 14:13:41 -04:00
{
2014-06-13 05:03:24 -04:00
if ( SelectedPrims . Num ( ) > 0 )
{
2015-01-06 14:54:09 -05:00
// Sort the selected prims by PrimIndex so when we're deleting them we don't mess up other prims indicies
struct FCompareFPrimDataPrimIndex
2014-06-13 05:03:24 -04:00
{
2015-01-06 14:54:09 -05:00
FORCEINLINE bool operator ( ) ( const FPrimData & A , const FPrimData & B ) const
2014-06-13 05:03:24 -04:00
{
2015-01-06 14:54:09 -05:00
return A . PrimIndex < B . PrimIndex ;
2014-06-13 05:03:24 -04:00
}
2015-01-06 14:54:09 -05:00
} ;
SelectedPrims . Sort ( FCompareFPrimDataPrimIndex ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
check ( StaticMesh - > GetBodySetup ( ) ) ;
2014-06-13 05:03:24 -04:00
2020-10-22 19:19:16 -04:00
FKAggregateGeom * AggGeom = & StaticMesh - > GetBodySetup ( ) - > AggGeom ;
2014-06-13 05:03:24 -04:00
2015-01-06 14:54:09 -05:00
GEditor - > BeginTransaction ( LOCTEXT ( " FStaticMeshEditor_DeleteSelectedPrims " , " Delete Collision " ) ) ;
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > Modify ( ) ;
2014-06-13 05:03:24 -04:00
2015-01-06 14:54:09 -05:00
for ( int32 PrimIdx = SelectedPrims . Num ( ) - 1 ; PrimIdx > = 0 ; PrimIdx - - )
{
const FPrimData & PrimData = SelectedPrims [ PrimIdx ] ;
2014-09-09 12:34:40 -04:00
2015-01-06 14:54:09 -05:00
check ( IsPrimValid ( PrimData ) ) ;
switch ( PrimData . PrimType )
{
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphere :
2015-01-06 14:54:09 -05:00
AggGeom - > SphereElems . RemoveAt ( PrimData . PrimIndex ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Box :
2015-01-06 14:54:09 -05:00
AggGeom - > BoxElems . RemoveAt ( PrimData . PrimIndex ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Sphyl :
2015-01-06 14:54:09 -05:00
AggGeom - > SphylElems . RemoveAt ( PrimData . PrimIndex ) ;
break ;
2017-09-04 04:17:46 -04:00
case EAggCollisionShape : : Convex :
2015-01-06 14:54:09 -05:00
AggGeom - > ConvexElems . RemoveAt ( PrimData . PrimIndex ) ;
break ;
}
2014-06-13 05:03:24 -04:00
}
2015-01-06 14:54:09 -05:00
GEditor - > EndTransaction ( ) ;
ClearSelectedPrims ( ) ;
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands ( ) ;
// Make sure to invalidate cooked data
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > InvalidatePhysicsData ( ) ;
2015-01-06 14:54:09 -05:00
// refresh collision change back to staticmesh components
2016-12-08 16:58:18 -05:00
RefreshCollisionChange ( * StaticMesh ) ;
2015-01-06 14:54:09 -05:00
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh - > MarkPackageDirty ( ) ;
// Update views/property windows
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > RefreshViewport ( ) ;
2015-01-06 14:54:09 -05:00
StaticMesh - > bCustomizedCollision = true ; //mark the static mesh for collision customization
2014-06-13 05:03:24 -04:00
}
}
void FStaticMeshEditor : : DuplicateSelected ( )
{
DuplicateSelectedSocket ( ) ;
const FVector InitialOffset ( 20.f ) ;
DuplicateSelectedPrims ( & InitialOffset ) ;
}
bool FStaticMeshEditor : : CanDuplicateSelected ( ) const
{
return ( GetSelectedSocket ( ) ! = NULL | | HasSelectedPrims ( ) ) ;
}
2022-06-29 12:17:25 -04:00
void FStaticMeshEditor : : CopySelected ( )
{
CopySelectedPrims ( ) ;
}
bool FStaticMeshEditor : : CanCopySelected ( ) const
{
return HasSelectedPrims ( ) ;
}
void FStaticMeshEditor : : PasteCopied ( )
{
PasteCopiedPrims ( ) ;
}
bool FStaticMeshEditor : : CanPasteCopied ( ) const
{
FString TextToImport ;
FPlatformApplicationMisc : : ClipboardPaste ( TextToImport ) ;
FBodySetupObjectTextFactory Factory ;
return Factory . CanCreateObjectsFromText ( TextToImport ) ;
}
2014-06-13 05:03:24 -04:00
bool FStaticMeshEditor : : CanRenameSelected ( ) const
{
return ( GetSelectedSocket ( ) ! = NULL ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : ExecuteFindInExplorer ( )
{
if ( ensure ( StaticMesh - > AssetImportData ) )
{
2015-05-27 16:16:21 -04:00
const FString SourceFilePath = StaticMesh - > AssetImportData - > GetFirstFilename ( ) ;
2014-03-14 14:13:41 -04:00
if ( SourceFilePath . Len ( ) & & IFileManager : : Get ( ) . FileSize ( * SourceFilePath ) ! = INDEX_NONE )
{
FPlatformProcess : : ExploreFolder ( * FPaths : : GetPath ( SourceFilePath ) ) ;
}
}
}
bool FStaticMeshEditor : : CanExecuteSourceCommands ( ) const
{
if ( ! StaticMesh - > AssetImportData )
{
return false ;
}
2015-05-27 16:16:21 -04:00
const FString & SourceFilePath = StaticMesh - > AssetImportData - > GetFirstFilename ( ) ;
2014-03-14 14:13:41 -04:00
return SourceFilePath . Len ( ) & & IFileManager : : Get ( ) . FileSize ( * SourceFilePath ) ! = INDEX_NONE ;
}
void FStaticMeshEditor : : OnObjectReimported ( UObject * InObject )
{
// Make sure we are using the object that is being reimported, otherwise a lot of needless work could occur.
if ( StaticMesh = = InObject )
{
2017-01-31 15:22:49 -05:00
//When we re-import we want to avoid moving the camera in the staticmesh editor
bool bResetCamera = false ;
SetEditorMesh ( Cast < UStaticMesh > ( InObject ) , bResetCamera ) ;
2016-12-09 15:05:28 -05:00
if ( SocketManager . IsValid ( ) )
{
SocketManager - > UpdateStaticMesh ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2016-10-07 10:20:36 -04:00
EViewModeIndex FStaticMeshEditor : : GetViewMode ( ) const
{
2019-10-30 18:26:53 -04:00
if ( GetStaticMeshViewport ( ) . IsValid ( ) )
2016-10-07 10:20:36 -04:00
{
2019-10-30 18:26:53 -04:00
const FStaticMeshEditorViewportClient & ViewportClient = GetStaticMeshViewport ( ) - > GetViewportClient ( ) ;
2016-10-07 10:20:36 -04:00
return ViewportClient . GetViewMode ( ) ;
}
else
{
return VMI_Unknown ;
}
}
2016-09-21 10:07:18 -04:00
2018-06-07 18:49:50 -04:00
FEditorViewportClient & FStaticMeshEditor : : GetViewportClient ( )
2017-06-19 20:27:30 -04:00
{
2019-10-30 18:26:53 -04:00
return GetStaticMeshViewport ( ) - > GetViewportClient ( ) ;
2017-06-19 20:27:30 -04:00
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : OnConvexDecomposition ( )
{
2020-02-28 11:30:46 -05:00
TabManager - > TryInvokeTab ( CollisionTabId ) ;
2014-03-14 14:13:41 -04:00
}
2023-05-03 14:45:26 -04:00
bool FStaticMeshEditor : : OnRequestClose ( EAssetEditorCloseReason InCloseReason )
2014-03-14 14:13:41 -04:00
{
bool bAllowClose = true ;
2023-05-03 14:45:26 -04:00
if ( InCloseReason ! = EAssetEditorCloseReason : : AssetForceDeleted & & StaticMeshDetails . IsValid ( ) & & StaticMeshDetails . Pin ( ) - > IsApplyNeeded ( ) )
2014-03-14 14:13:41 -04:00
{
// find out the user wants to do with this dirty material
EAppReturnType : : Type YesNoCancelReply = FMessageDialog : : Open (
EAppMsgType : : YesNoCancel ,
FText : : Format ( LOCTEXT ( " ShouldApplyLODChanges " , " Would you like to apply level of detail changes to {0}? \n \n (No will lose all changes!) " ) , FText : : FromString ( StaticMesh - > GetName ( ) ) )
) ;
switch ( YesNoCancelReply )
{
case EAppReturnType : : Yes :
StaticMeshDetails . Pin ( ) - > ApplyChanges ( ) ;
bAllowClose = true ;
break ;
case EAppReturnType : : No :
// Do nothing, changes will be abandoned.
bAllowClose = true ;
break ;
case EAppReturnType : : Cancel :
// Don't exit.
bAllowClose = false ;
break ;
}
}
2022-01-13 13:39:41 -05:00
bAllowClose & = GetEditorModeManager ( ) . OnRequestClose ( ) ;
2021-10-25 20:05:28 -04:00
// Give any active modes a chance to shutdown while the toolkit host is still alive
if ( bAllowClose )
{
GetEditorModeManager ( ) . ActivateDefaultMode ( ) ;
}
2014-03-14 14:13:41 -04:00
return bAllowClose ;
}
void FStaticMeshEditor : : RegisterOnPostUndo ( const FOnPostUndo & Delegate )
{
OnPostUndo . Add ( Delegate ) ;
}
void FStaticMeshEditor : : UnregisterOnPostUndo ( SWidget * Widget )
{
OnPostUndo . RemoveAll ( Widget ) ;
}
2020-01-07 15:54:23 -05:00
void FStaticMeshEditor : : NotifyPostChange ( const FPropertyChangedEvent & PropertyChangedEvent , FProperty * PropertyThatChanged )
2014-03-14 14:13:41 -04:00
{
2020-10-22 19:19:16 -04:00
if ( StaticMesh & & StaticMesh - > GetBodySetup ( ) )
2014-03-14 14:13:41 -04:00
{
2020-10-22 19:19:16 -04:00
StaticMesh - > GetBodySetup ( ) - > CreatePhysicsMeshes ( ) ;
2019-12-19 18:07:47 -05:00
RemoveInvalidPrims ( ) ;
2018-06-11 13:17:15 -04:00
if ( GET_MEMBER_NAME_CHECKED ( UStaticMesh , LODGroup ) = = PropertyChangedEvent . GetPropertyName ( ) )
{
RefreshTool ( ) ;
}
2019-06-04 15:42:48 -04:00
else if ( PropertyChangedEvent . GetPropertyName ( ) = = TEXT ( " CollisionResponses " ) )
{
2021-01-21 16:22:06 -04:00
for ( FThreadSafeObjectIterator Iter ( UStaticMeshComponent : : StaticClass ( ) ) ; Iter ; + + Iter )
2019-06-04 15:42:48 -04:00
{
UStaticMeshComponent * StaticMeshComponent = Cast < UStaticMeshComponent > ( * Iter ) ;
if ( StaticMeshComponent - > GetStaticMesh ( ) = = StaticMesh )
{
StaticMeshComponent - > UpdateCollisionFromStaticMesh ( ) ;
StaticMeshComponent - > MarkRenderTransformDirty ( ) ;
}
}
}
2019-12-19 18:07:47 -05:00
}
else
{
RemoveInvalidPrims ( ) ;
2014-03-14 14:13:41 -04:00
}
}
void FStaticMeshEditor : : UndoAction ( )
{
GEditor - > UndoTransaction ( ) ;
}
void FStaticMeshEditor : : RedoAction ( )
{
GEditor - > RedoTransaction ( ) ;
}
void FStaticMeshEditor : : PostUndo ( bool bSuccess )
{
2014-06-13 05:03:24 -04:00
RemoveInvalidPrims ( ) ;
2016-12-09 15:05:28 -05:00
RefreshTool ( ) ;
2014-06-13 05:03:24 -04:00
2014-03-14 14:13:41 -04:00
OnPostUndo . Broadcast ( ) ;
}
void FStaticMeshEditor : : PostRedo ( bool bSuccess )
{
2014-06-13 05:03:24 -04:00
RemoveInvalidPrims ( ) ;
2016-12-09 15:05:28 -05:00
RefreshTool ( ) ;
2014-06-13 05:03:24 -04:00
2014-03-14 14:13:41 -04:00
OnPostUndo . Broadcast ( ) ;
}
2020-10-22 19:19:16 -04:00
void FStaticMeshEditor : : OnMeshChanged ( )
{
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . OnMeshChanged ( ) ;
}
2014-03-14 14:13:41 -04:00
void FStaticMeshEditor : : OnSocketSelectionChanged ( )
{
UStaticMeshSocket * SelectedSocket = GetSelectedSocket ( ) ;
2014-06-13 05:03:24 -04:00
if ( SelectedSocket )
{
ClearSelectedPrims ( ) ;
}
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . OnSocketSelectionChanged ( SelectedSocket ) ;
2014-03-14 14:13:41 -04:00
}
void FStaticMeshEditor : : OnPostReimport ( UObject * InObject , bool bSuccess )
{
// Ignore if this is regarding a different object
if ( InObject ! = StaticMesh )
{
return ;
}
2014-07-24 04:28:41 -04:00
if ( bSuccess )
{
RefreshTool ( ) ;
}
2014-03-14 14:13:41 -04:00
}
2017-06-19 20:27:30 -04:00
void FStaticMeshEditor : : SetCurrentViewedUVChannel ( int32 InNewUVChannel )
{
CurrentViewedUVChannel = FMath : : Clamp ( InNewUVChannel , 0 , GetNumUVChannels ( ) ) ;
2019-10-30 18:26:53 -04:00
GetStaticMeshViewport ( ) - > GetViewportClient ( ) . SetDrawUVOverlay ( true ) ;
2017-06-19 20:27:30 -04:00
}
ECheckBoxState FStaticMeshEditor : : GetUVChannelCheckState ( int32 TestUVChannel ) const
{
2019-10-30 18:26:53 -04:00
return CurrentViewedUVChannel = = TestUVChannel & & GetStaticMeshViewport ( ) - > GetViewportClient ( ) . IsDrawUVOverlayChecked ( ) ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2017-06-19 20:27:30 -04:00
}
2017-10-06 04:43:18 -04:00
void FStaticMeshEditor : : Tick ( float DeltaTime )
{
# if USE_ASYNC_DECOMP
/** If we have an active convex decomposition task running, we check to see if is completed and, if so, release the interface */
if ( DecomposeMeshToHullsAsync )
{
if ( DecomposeMeshToHullsAsync - > IsComplete ( ) )
{
DecomposeMeshToHullsAsync - > Release ( ) ;
DecomposeMeshToHullsAsync = nullptr ;
GConvexDecompositionNotificationState - > IsActive = false ;
}
else if ( GConvexDecompositionNotificationState )
{
GConvexDecompositionNotificationState - > IsActive = true ;
GConvexDecompositionNotificationState - > Status = DecomposeMeshToHullsAsync - > GetCurrentStatus ( ) ;
}
}
# endif
}
TStatId FStaticMeshEditor : : GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( FStaticMeshEditor , STATGROUP_TaskGraphTasks ) ;
}
2021-09-16 13:57:09 -04:00
void FStaticMeshEditor : : AddViewportOverlayWidget ( TSharedRef < SWidget > InOverlaidWidget )
{
TSharedPtr < SStaticMeshEditorViewport > Viewport = GetStaticMeshViewport ( ) ;
if ( Viewport . IsValid ( ) & & Viewport - > GetViewportOverlay ( ) . IsValid ( ) )
{
Viewport - > GetViewportOverlay ( ) - > AddSlot ( )
[
InOverlaidWidget
] ;
}
}
void FStaticMeshEditor : : RemoveViewportOverlayWidget ( TSharedRef < SWidget > InViewportOverlayWidget )
{
TSharedPtr < SStaticMeshEditorViewport > Viewport = GetStaticMeshViewport ( ) ;
if ( Viewport . IsValid ( ) & & Viewport - > GetViewportOverlay ( ) . IsValid ( ) )
{
Viewport - > GetViewportOverlay ( ) - > RemoveSlot ( InViewportOverlayWidget ) ;
}
}
void FStaticMeshEditor : : CreateEditorModeManager ( )
{
//
// This function doesn't actually create a new manager -- it assigns StaticMeshEditorViewport->GetViewportClient().GetModeTools()
// to this->EditorModeManager. This is because these two pointers should refer to the same mode manager object, and currently
// the ViewPortClient's ModeTools object is created first.
//
// This function also:
// - sets the manager's PreviewScene to be StaticMeshEditorViewport->GetPreviewScene()
// - adds StaticMeshEditorViewport->GetStaticMeshComponent() to the manager's ComponentSet (i.e. selected mesh components)
//
TSharedPtr < FAssetEditorModeManager > NewManager = MakeShared < FAssetEditorModeManager > ( ) ;
TSharedPtr < SStaticMeshEditorViewport > StaticMeshEditorViewport = GetStaticMeshViewport ( ) ;
if ( StaticMeshEditorViewport . IsValid ( ) )
{
TSharedPtr < FEditorModeTools > SharedModeTools = StaticMeshEditorViewport - > GetViewportClient ( ) . GetModeTools ( ) - > AsShared ( ) ;
NewManager = StaticCastSharedPtr < FAssetEditorModeManager > ( SharedModeTools ) ;
check ( NewManager . IsValid ( ) ) ;
TSharedRef < FAdvancedPreviewScene > PreviewScene = StaticMeshEditorViewport - > GetPreviewScene ( ) ;
NewManager - > SetPreviewScene ( & PreviewScene . Get ( ) ) ;
UStaticMeshComponent * const Component = StaticMeshEditorViewport - > GetStaticMeshComponent ( ) ;
// Copied from FPersonaEditorModeManager::SetPreviewScene(FPreviewScene * NewPreviewScene)
USelection * ComponentSet = NewManager - > GetSelectedComponents ( ) ;
ComponentSet - > BeginBatchSelectOperation ( ) ;
ComponentSet - > DeselectAll ( ) ;
ComponentSet - > Select ( Component , true ) ;
ComponentSet - > EndBatchSelectOperation ( ) ;
}
EditorModeManager = NewManager ;
}
2018-11-06 10:00:36 -05:00
bool FStaticMeshEditor : : CanRemoveUVChannel ( )
{
2019-06-04 15:42:48 -04:00
// Can remove UV channel if there's one that is currently being selected and displayed,
// and the current LOD has more than one UV channel
2019-10-30 18:26:53 -04:00
return GetStaticMeshViewport ( ) - > GetViewportClient ( ) . IsDrawUVOverlayChecked ( ) & &
2019-06-04 15:42:48 -04:00
StaticMesh - > GetNumUVChannels ( GetCurrentLODIndex ( ) ) > 1 ;
2018-11-06 10:00:36 -05:00
}
2019-10-30 18:26:53 -04:00
void FStaticMeshEditor : : ToggleShowNormals ( )
{
bDrawNormals = ! bDrawNormals ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowNormalsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowNormals ( bDrawNormals ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowNormalsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawNormals " ) , bDrawNormals ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowNormalsChecked ( ) const
{
return bDrawNormals ;
}
void FStaticMeshEditor : : ToggleShowTangents ( )
{
bDrawTangents = ! bDrawTangents ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowTangentsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowTangents ( bDrawTangents ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowTangentsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawTangents " ) , bDrawTangents ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowTangentsChecked ( ) const
{
return bDrawTangents ;
}
void FStaticMeshEditor : : ToggleShowBinormals ( )
{
bDrawBinormals = ! bDrawBinormals ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowBinormalsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowBinormals ( bDrawBinormals ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowBinormalsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawBinormals " ) , bDrawBinormals ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowBinormalsChecked ( ) const
{
return bDrawBinormals ;
}
void FStaticMeshEditor : : ToggleShowPivots ( )
{
bDrawPivots = ! bDrawPivots ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowPivotsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowPivots ( bDrawPivots ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowPivotsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawPivots " ) , bDrawPivots ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowPivotsChecked ( ) const
{
return bDrawPivots ;
}
void FStaticMeshEditor : : ToggleShowVertices ( )
{
bDrawVertices = ! bDrawVertices ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowVerticesFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowVertices ( bDrawVertices ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowVerticesFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawVertices " ) , bDrawVertices ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowVerticesChecked ( ) const
{
return bDrawVertices ;
}
void FStaticMeshEditor : : ToggleShowGrids ( )
{
2020-03-12 18:12:52 -04:00
bDrawGrids = ! IsShowGridsChecked ( ) ;
2019-10-30 18:26:53 -04:00
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowGridFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowGrids ( bDrawGrids ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowGridFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawGrids " ) , bDrawGrids ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowGridsChecked ( ) const
{
2020-03-12 18:12:52 -04:00
bool LocalDrawGrids = false ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > CheckShowGridFunc =
[ this , & LocalDrawGrids ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
LocalDrawGrids | = StaticMeshEditorViewportClient . IsSetShowGridChecked ( ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( CheckShowGridFunc ) ;
return LocalDrawGrids ;
2019-10-30 18:26:53 -04:00
}
void FStaticMeshEditor : : ToggleShowBounds ( )
{
bDrawBounds = ! bDrawBounds ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowBoundsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowBounds ( bDrawBounds ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowBoundsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawBounds " ) , bDrawBounds ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowBoundsChecked ( ) const
{
return bDrawBounds ;
}
void FStaticMeshEditor : : ToggleShowSimpleCollisions ( )
{
bDrawSimpleCollisions = ! bDrawSimpleCollisions ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowSimpleCollisionsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowSimpleCollisions ( bDrawSimpleCollisions ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowSimpleCollisionsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawSimpleCollisions " ) , bDrawSimpleCollisions ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowSimpleCollisionsChecked ( ) const
{
return bDrawSimpleCollisions ;
}
void FStaticMeshEditor : : ToggleShowComplexCollisions ( )
{
bDrawComplexCollisions = ! bDrawComplexCollisions ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowComplexCollisionsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowComplexCollisions ( bDrawComplexCollisions ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowComplexCollisionsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawComplexCollisions " ) , bDrawComplexCollisions ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowComplexCollisionsChecked ( ) const
{
return bDrawComplexCollisions ;
}
void FStaticMeshEditor : : ToggleShowSockets ( )
{
bDrawSockets = ! bDrawSockets ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowSocketsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
StaticMeshEditorViewportClient . SetShowPivots ( bDrawSockets ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowSocketsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawSockets " ) , bDrawSockets ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowSocketsChecked ( ) const
{
return bDrawSockets ;
}
void FStaticMeshEditor : : ToggleShowWireframes ( )
{
bDrawWireframes = ! bDrawWireframes ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowWireframesFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
if ( StaticMeshEditorViewport - > IsInViewModeWireframeChecked ( ) ! = bDrawWireframes )
{
StaticMeshEditorViewport - > SetViewModeWireframe ( ) ;
}
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowWireframesFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawWireframes " ) , bDrawWireframes ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowWireframesChecked ( ) const
{
return bDrawWireframes ;
}
void FStaticMeshEditor : : ToggleShowVertexColors ( )
{
bDrawVertexColors = ! bDrawVertexColors ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleShowVertexColorsFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
if ( StaticMeshEditorViewport - > IsInViewModeVertexColorChecked ( ) ! = bDrawVertexColors )
{
FStaticMeshEditorViewportClient & EditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
EditorViewportClient . EngineShowFlags . SetVertexColors ( bDrawVertexColors ) ;
EditorViewportClient . EngineShowFlags . SetLighting ( ! bDrawVertexColors ) ;
EditorViewportClient . EngineShowFlags . SetIndirectLightingCache ( ! bDrawVertexColors ) ;
EditorViewportClient . EngineShowFlags . SetPostProcessing ( ! bDrawVertexColors ) ;
EditorViewportClient . SetFloorAndEnvironmentVisibility ( ! bDrawVertexColors ) ;
GetStaticMeshComponent ( ) - > bDisplayVertexColors = bDrawVertexColors ;
GetStaticMeshComponent ( ) - > MarkRenderStateDirty ( ) ;
StaticMeshEditorViewport - > Invalidate ( ) ;
}
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleShowVertexColorsFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawVertexColors " ) , bDrawVertexColors ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsShowVertexColorsChecked ( ) const
{
return bDrawVertexColors ;
}
2020-03-17 15:11:19 -04:00
void FStaticMeshEditor : : ResetCamera ( )
{
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ResetCameraFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
StaticMeshEditorViewport - > GetViewportClient ( ) . FocusViewportOnBox ( StaticMeshEditorViewport - > GetStaticMeshComponent ( ) - > Bounds . GetBox ( ) ) ;
StaticMeshEditorViewport - > Invalidate ( ) ;
} ;
ViewportTabContent - > PerformActionOnViewports ( ResetCameraFunc ) ;
// if (FEngineAnalytics::IsAvailable())
// {
// FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Toolbar"), TEXT("ResetCamera"));
// }
}
2020-04-14 16:54:46 -04:00
void FStaticMeshEditor : : ToggleDrawAdditionalData ( )
{
bDrawAdditionalData = ! bDrawAdditionalData ;
TFunction < void ( FName , TSharedPtr < IEditorViewportLayoutEntity > ) > ToggleDrawAdditionalDataFunc =
[ this ] ( FName Name , TSharedPtr < IEditorViewportLayoutEntity > Entity )
{
TSharedRef < SStaticMeshEditorViewport > StaticMeshEditorViewport = StaticCastSharedRef < SStaticMeshEditorViewport > ( Entity - > AsWidget ( ) ) ;
FStaticMeshEditorViewportClient & StaticMeshEditorViewportClient = StaticMeshEditorViewport - > GetViewportClient ( ) ;
if ( StaticMeshEditorViewportClient . IsDrawAdditionalDataChecked ( ) ! = bDrawAdditionalData )
{
StaticMeshEditorViewportClient . ToggleDrawAdditionalData ( ) ;
}
} ;
ViewportTabContent - > PerformActionOnViewports ( ToggleDrawAdditionalDataFunc ) ;
if ( FEngineAnalytics : : IsAvailable ( ) )
{
FEngineAnalytics : : GetProvider ( ) . RecordEvent ( TEXT ( " Editor.Usage.StaticMesh.Toolbar " ) , TEXT ( " bDrawAdditionalData " ) , bDrawAdditionalData ? TEXT ( " True " ) : TEXT ( " False " ) ) ;
}
}
bool FStaticMeshEditor : : IsDrawAdditionalDataChecked ( ) const
{
return bDrawAdditionalData ;
}
2020-10-14 13:29:31 -04:00
void FStaticMeshEditor : : BakeMaterials ( )
{
if ( StaticMesh ! = nullptr )
{
const IMeshMergeModule & Module = FModuleManager : : Get ( ) . LoadModuleChecked < IMeshMergeModule > ( " MeshMergeUtilities " ) ;
Module . GetUtilities ( ) . BakeMaterialsForMesh ( StaticMesh ) ;
}
}
2018-11-06 10:00:36 -05:00
void FStaticMeshEditor : : RemoveCurrentUVChannel ( )
{
if ( ! StaticMesh )
{
return ;
}
int32 UVChannelIndex = GetCurrentUVChannel ( ) ;
int32 LODIndex = GetCurrentLODIndex ( ) ;
FText RemoveUVChannelText = FText : : Format ( LOCTEXT ( " ConfirmRemoveUVChannel " , " Please confirm removal of UV Channel {0} from LOD {1} of {2}? " ) , UVChannelIndex , LODIndex , FText : : FromString ( StaticMesh - > GetName ( ) ) ) ;
if ( FMessageDialog : : Open ( EAppMsgType : : YesNo , RemoveUVChannelText ) = = EAppReturnType : : Yes )
{
2019-07-31 03:40:45 -04:00
FMeshBuildSettings & LODBuildSettings = StaticMesh - > GetSourceModel ( LODIndex ) . BuildSettings ;
2018-11-06 10:00:36 -05:00
if ( LODBuildSettings . bGenerateLightmapUVs )
{
FText LightmapText ;
if ( UVChannelIndex = = LODBuildSettings . SrcLightmapIndex )
{
LightmapText = FText : : Format ( LOCTEXT ( " ConfirmDisableSourceLightmap " , " UV Channel {0} is currently used as source for lightmap UVs. Please change the \" Source Lightmap Index \" value or disable \" Generate Lightmap UVs \" in the Build Settings. " ) , UVChannelIndex ) ;
}
else if ( UVChannelIndex = = LODBuildSettings . DstLightmapIndex )
{
LightmapText = FText : : Format ( LOCTEXT ( " ConfirmDisableDestLightmap " , " UV Channel {0} is currently used as destination for lightmap UVs. Please change the \" Destination Lightmap Index \" value or disable \" Generate Lightmap UVs \" in the Build Settings. " ) , UVChannelIndex ) ;
}
if ( ! LightmapText . IsEmpty ( ) )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , LightmapText ) ;
return ;
}
}
2019-12-19 18:07:47 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " RemoveUVChannel " , " Remove UV Channel " ) ) ;
2018-11-06 10:00:36 -05:00
if ( StaticMesh - > RemoveUVChannel ( LODIndex , UVChannelIndex ) )
{
RefreshTool ( ) ;
}
}
}
2017-10-06 04:43:18 -04:00
2021-09-16 13:57:09 -04:00
void FStaticMeshEditor : : OnToolkitHostingStarted ( const TSharedRef < IToolkit > & Toolkit )
{
ModeUILayer - > OnToolkitHostingStarted ( Toolkit ) ;
}
void FStaticMeshEditor : : OnToolkitHostingFinished ( const TSharedRef < IToolkit > & Toolkit )
{
ModeUILayer - > OnToolkitHostingFinished ( Toolkit ) ;
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE