Files
UnrealEngineUWP/Engine/Source/Editor/StaticMeshEditor/Private/StaticMeshEditor.cpp

1789 lines
54 KiB
C++
Raw Normal View History

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "StaticMeshEditorModule.h"
#include "AssetRegistryModule.h"
#include "StaticMeshEditor.h"
#include "SStaticMeshEditorViewport.h"
#include "StaticMeshEditorViewportClient.h"
#include "StaticMeshEditorTools.h"
#include "StaticMeshEditorActions.h"
#include "UnrealEd.h"
#include "StaticMeshResources.h"
#include "ISocketManager.h"
#include "PreviewScene.h"
#include "ScopedTransaction.h"
#include "BusyCursor.h"
#include "FbxMeshUtils.h"
#include "../Private/GeomFitUtils.h"
#include "EditorViewportCommands.h"
#include "Editor/UnrealEd/Private/ConvexDecompTool.h"
#include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
#include "Runtime/Analytics/Analytics/Public/Interfaces/IAnalyticsProvider.h"
#include "EngineAnalytics.h"
#define LOCTEXT_NAMESPACE "StaticMeshEditor"
DEFINE_LOG_CATEGORY_STATIC(LogStaticMeshEditor, Log, All);
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" ) );
const FName FStaticMeshEditor::GenerateUniqueUVsTabId( TEXT( "StaticMeshEditor_GenerateUniqueUVs" ) );
void FStaticMeshEditor::RegisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
{
FAssetEditorToolkit::RegisterTabSpawners(TabManager);
const IWorkspaceMenuStructure& MenuStructure = WorkspaceMenu::GetMenuStructure();
TabManager->RegisterTabSpawner( ViewportTabId, FOnSpawnTab::CreateSP(this, &FStaticMeshEditor::SpawnTab_Viewport) )
.SetDisplayName( LOCTEXT("ViewportTab", "Viewport") )
.SetGroup( MenuStructure.GetAssetEditorCategory() );
TabManager->RegisterTabSpawner( PropertiesTabId, FOnSpawnTab::CreateSP(this, &FStaticMeshEditor::SpawnTab_Properties) )
.SetDisplayName( LOCTEXT("PropertiesTab", "Details") )
.SetGroup( MenuStructure.GetAssetEditorCategory() );
TabManager->RegisterTabSpawner( SocketManagerTabId, FOnSpawnTab::CreateSP(this, &FStaticMeshEditor::SpawnTab_SocketManager) )
.SetDisplayName( LOCTEXT("SocketManagerTab", "Socket Manager") )
.SetGroup( MenuStructure.GetAssetEditorCategory() );
TabManager->RegisterTabSpawner( CollisionTabId, FOnSpawnTab::CreateSP(this, &FStaticMeshEditor::SpawnTab_Collision) )
.SetDisplayName( LOCTEXT("CollisionTab", "Convex Decomposition") )
.SetGroup( MenuStructure.GetAssetEditorCategory() );
TabManager->RegisterTabSpawner( GenerateUniqueUVsTabId, FOnSpawnTab::CreateSP(this, &FStaticMeshEditor::SpawnTab_GenerateUniqueUVs) )
.SetDisplayName( LOCTEXT("GenerateUniqueUVsTab", "Generate Unique UVs") )
.SetGroup( MenuStructure.GetAssetEditorCategory() );
}
void FStaticMeshEditor::UnregisterTabSpawners(const TSharedRef<class FTabManager>& TabManager)
{
FAssetEditorToolkit::UnregisterTabSpawners(TabManager);
TabManager->UnregisterTabSpawner( ViewportTabId );
TabManager->UnregisterTabSpawner( PropertiesTabId );
TabManager->UnregisterTabSpawner( SocketManagerTabId );
TabManager->UnregisterTabSpawner( CollisionTabId );
TabManager->UnregisterTabSpawner( GenerateUniqueUVsTabId );
}
FStaticMeshEditor::~FStaticMeshEditor()
{
FReimportManager::Instance()->OnPostReimport().RemoveAll(this);
GEditor->UnregisterForUndo( this );
GEditor->OnObjectReimported().RemoveAll(this);
}
void FStaticMeshEditor::InitStaticMeshEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UStaticMesh* ObjectToEdit )
{
FReimportManager::Instance()->OnPostReimport().AddRaw(this, &FStaticMeshEditor::OnPostReimport);
// Support undo/redo
ObjectToEdit->SetFlags( RF_Transactional );
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.
GEditor->OnObjectReimported().AddSP(this, &FStaticMeshEditor::OnObjectReimported);
BindCommands();
Viewport = SNew(SStaticMeshEditorViewport)
.StaticMeshEditor(SharedThis(this))
.ObjectToEdit(ObjectToEdit);
FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>(TEXT("PropertyEditor"));
FDetailsViewArgs DetailsViewArgs;
DetailsViewArgs.bAllowSearch = true;
DetailsViewArgs.bLockable = false;
DetailsViewArgs.bUpdatesFromSelection = false;
DetailsViewArgs.bHideActorNameArea = true;
DetailsViewArgs.bObjectsUseNameArea = false;
DetailsViewArgs.NotifyHook = this;
StaticMeshDetailsView = PropertyEditorModule.CreateDetailView( DetailsViewArgs );
FOnGetDetailCustomizationInstance LayoutCustomStaticMeshProperties = FOnGetDetailCustomizationInstance::CreateSP( this, &FStaticMeshEditor::MakeStaticMeshDetails );
StaticMeshDetailsView->RegisterInstancedCustomPropertyLayout( UStaticMesh::StaticClass(), LayoutCustomStaticMeshProperties );
SetEditorMesh(ObjectToEdit);
BuildSubTools();
const TSharedRef<FTabManager::FLayout> StandaloneDefaultLayout = FTabManager::NewLayout( "Standalone_StaticMeshEditor_Layout_v3" )
->AddArea
(
FTabManager::NewPrimaryArea() ->SetOrientation(Orient_Vertical)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.1f)
->SetHideTabWell( true )
->AddTab(GetToolbarTabId(), ETabState::OpenedTab)
)
->Split
(
FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(0.9f)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.6f)
->AddTab(ViewportTabId, ETabState::OpenedTab) ->SetHideTabWell( true )
)
->Split
(
FTabManager::NewSplitter() ->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.2f)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.5f)
->AddTab(PropertiesTabId, ETabState::OpenedTab)
)
->Split
(
FTabManager::NewStack()
->SetSizeCoefficient(0.5f)
->AddTab(SocketManagerTabId, ETabState::ClosedTab)
->AddTab(CollisionTabId, ETabState::ClosedTab)
->AddTab(GenerateUniqueUVsTabId, ETabState::ClosedTab)
)
)
)
);
const bool bCreateDefaultStandaloneMenu = true;
const bool bCreateDefaultToolbar = true;
FAssetEditorToolkit::InitAssetEditor( Mode, InitToolkitHost, StaticMeshEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultToolbar, bCreateDefaultStandaloneMenu, ObjectToEdit );
ExtendMenu();
ExtendToolBar();
RegenerateMenusAndToolbars();
}
TSharedRef<IDetailCustomization> FStaticMeshEditor::MakeStaticMeshDetails()
{
TSharedRef<FStaticMeshDetails> NewDetails = MakeShareable( new FStaticMeshDetails( *this ) );
StaticMeshDetails = NewDetails;
return NewDetails;
}
void FStaticMeshEditor::ExtendMenu()
{
struct Local
{
static void FillEditMenu( FMenuBuilder& InMenuBuilder )
{
InMenuBuilder.BeginSection("Sockets", LOCTEXT("EditStaticMeshSockets", "Sockets"));
{
InMenuBuilder.AddMenuEntry( FGenericCommands::Get().Delete, "DeleteSocket", LOCTEXT("DeleteSocket", "Delete Socket"), LOCTEXT("DeleteSocketToolTip", "Deletes the selected socket from the mesh.") );
InMenuBuilder.AddMenuEntry( FGenericCommands::Get().Duplicate, "DuplicateSocket", LOCTEXT("DuplicateSocket", "Duplicate Socket"), LOCTEXT("DuplicateSocketToolTip", "Duplicates the selected socket.") );
}
InMenuBuilder.EndSection();
}
static void FillMeshMenu( FMenuBuilder& InMenuBuilder )
{
// @todo mainframe: These menus, and indeed all menus like them, should be updated with extension points, plus expose public module
// access to extending the menus. They may also need to extend the command list, or be able to PUSH a command list of their own.
// If we decide to only allow PUSHING, then nothing else should be needed (happens by extender automatically). But if we want to
// augment the asset editor's existing command list, then we need to think about how to expose support for that.
InMenuBuilder.BeginSection("MeshFindSource");
{
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().FindSource);
}
InMenuBuilder.EndSection();
InMenuBuilder.BeginSection("MeshChange");
{
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().ChangeMesh);
}
InMenuBuilder.EndSection();
}
static void FillCollisionMenu( FMenuBuilder& InMenuBuilder )
{
InMenuBuilder.BeginSection("CollisionEditCollision");
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateSphereCollision);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateSphylCollision);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateBoxCollision);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateDOP10X);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateDOP10Y);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateDOP10Z);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateDOP18);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateDOP26);
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().ConvertBoxesToConvex);
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().RemoveCollision);
InMenuBuilder.AddMenuEntry(FGenericCommands::Get().Delete, "DeleteCollision", LOCTEXT("DeleteCollision", "Delete Selected Collision"), LOCTEXT("DeleteCollisionToolTip", "Deletes the selected Collision from the mesh."));
InMenuBuilder.AddMenuEntry(FGenericCommands::Get().Duplicate, "DuplicateCollision", LOCTEXT("DuplicateCollision", "Duplicate Selected Collision"), LOCTEXT("DuplicateCollisionToolTip", "Duplicates the selected Collision."));
}
InMenuBuilder.EndSection();
InMenuBuilder.BeginSection("CollisionAutoConvexCollision");
{
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CreateAutoConvexCollision);
}
InMenuBuilder.EndSection();
InMenuBuilder.BeginSection("CollisionCopy");
{
InMenuBuilder.AddMenuEntry(FStaticMeshEditorCommands::Get().CopyCollisionFromSelectedMesh);
}
InMenuBuilder.EndSection();
}
static void GenerateMeshAndCollisionMenuBars( FMenuBarBuilder& InMenuBarBuilder)
{
InMenuBarBuilder.AddPullDownMenu(
LOCTEXT("StaticMeshEditorMeshMenu", "Mesh"),
LOCTEXT("StaticMeshEditorMeshMenu_ToolTip", "Opens a menu with commands for altering this mesh"),
FNewMenuDelegate::CreateStatic(&Local::FillMeshMenu),
"Mesh");
InMenuBarBuilder.AddPullDownMenu(
LOCTEXT("StaticMeshEditorCollisionMenu", "Collision"),
LOCTEXT("StaticMeshEditorCollisionMenu_ToolTip", "Opens a menu with commands for editing this mesh's collision"),
FNewMenuDelegate::CreateStatic(&Local::FillCollisionMenu),
"Collision");
}
};
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender);
MenuExtender->AddMenuExtension(
"EditHistory",
EExtensionHook::After,
GetToolkitCommands(),
FMenuExtensionDelegate::CreateStatic( &Local::FillEditMenu ) );
MenuExtender->AddMenuBarExtension(
"Asset",
EExtensionHook::After,
GetToolkitCommands(),
FMenuBarExtensionDelegate::CreateStatic( &Local::GenerateMeshAndCollisionMenuBars )
);
AddMenuExtender(MenuExtender);
IStaticMeshEditorModule* StaticMeshEditorModule = &FModuleManager::LoadModuleChecked<IStaticMeshEditorModule>( "StaticMeshEditor" );
AddMenuExtender(StaticMeshEditorModule->GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
}
void FStaticMeshEditor::AddReferencedObjects( FReferenceCollector& Collector )
{
Collector.AddReferencedObject( StaticMesh );
}
TSharedRef<SDockTab> FStaticMeshEditor::SpawnTab_Viewport( const FSpawnTabArgs& Args )
{
check( Args.GetTabId() == ViewportTabId );
TSharedRef<SDockTab> SpawnedTab =
SNew(SDockTab)
.Label( LOCTEXT("StaticMeshViewport_TabTitle", "Viewport") )
[
Viewport.ToSharedRef()
];
Viewport->SetParentTab( SpawnedTab );
return SpawnedTab;
}
TSharedRef<SDockTab> FStaticMeshEditor::SpawnTab_Properties( const FSpawnTabArgs& Args )
{
check( Args.GetTabId() == PropertiesTabId );
return SNew(SDockTab)
.Icon( FEditorStyle::GetBrush("StaticMeshEditor.Tabs.Properties") )
.Label( LOCTEXT("StaticMeshProperties_TabTitle", "Details") )
[
StaticMeshDetailsView.ToSharedRef()
];
}
TSharedRef<SDockTab> FStaticMeshEditor::SpawnTab_SocketManager( const FSpawnTabArgs& Args )
{
check( Args.GetTabId() == SocketManagerTabId );
return SNew(SDockTab)
.Label( LOCTEXT("StaticMeshSocketManager_TabTitle", "Socket Manager") )
[
SocketManager.ToSharedRef()
];
}
TSharedRef<SDockTab> FStaticMeshEditor::SpawnTab_Collision( const FSpawnTabArgs& Args )
{
check( Args.GetTabId() == CollisionTabId );
return SNew(SDockTab)
.Label( LOCTEXT("StaticMeshConvexDecomp_TabTitle", "Convex Decomposition") )
[
ConvexDecomposition.ToSharedRef()
];
}
TSharedRef<SDockTab> FStaticMeshEditor::SpawnTab_GenerateUniqueUVs( const FSpawnTabArgs& Args )
{
check( Args.GetTabId() == GenerateUniqueUVsTabId );
#if !PLATFORM_WINDOWS
FText ErrorMessage = FText::Format( LOCTEXT("StaticMeshGenerateUniqueUVs_Unsupported", "Generate Unique UVs not yet implemented for {0}."), FText::FromString( FPlatformProperties::IniPlatformName() ) );
OpenMsgDlgInt( EAppMsgType::Ok, ErrorMessage, LOCTEXT("StaticMeshGenerateUniqueUVs_UnsupportedErrorCaption", "Error") );
#endif
return SNew(SDockTab)
.Label( LOCTEXT("StaticMeshGenerateUniqueUVs_TabTitle", "Generate Unique UVs") )
[
#if PLATFORM_WINDOWS
GenerateUniqueUVs.ToSharedRef()
#else
SNew(STextBlock)
.Text( ErrorMessage )
#endif
];
}
void FStaticMeshEditor::BindCommands()
{
const FStaticMeshEditorCommands& Commands = FStaticMeshEditorCommands::Get();
const TSharedRef<FUICommandList>& UICommandList = GetToolkitCommands();
UICommandList->MapAction( FGenericCommands::Get().Delete,
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
FExecuteAction::CreateSP( this, &FStaticMeshEditor::DeleteSelected ),
FCanExecuteAction::CreateSP(this, &FStaticMeshEditor::CanDeleteSelected));
UICommandList->MapAction( FGenericCommands::Get().Undo,
FExecuteAction::CreateSP( this, &FStaticMeshEditor::UndoAction ) );
UICommandList->MapAction( FGenericCommands::Get().Redo,
FExecuteAction::CreateSP( this, &FStaticMeshEditor::RedoAction ) );
UICommandList->MapAction(
FGenericCommands::Get().Duplicate,
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
FExecuteAction::CreateSP(this, &FStaticMeshEditor::DuplicateSelected),
FCanExecuteAction::CreateSP(this, &FStaticMeshEditor::CanDuplicateSelected));
UICommandList->MapAction(
FGenericCommands::Get().Rename,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::RequestRenameSelectedSocket),
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
FCanExecuteAction::CreateSP(this, &FStaticMeshEditor::CanRenameSelected));
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));
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
UICommandList->MapAction(
Commands.CreateBoxCollision,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnCollisionBox));
UICommandList->MapAction(
Commands.CreateSphereCollision,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnCollisionSphere));
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
UICommandList->MapAction(
Commands.CreateSphylCollision,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnCollisionSphyl));
UICommandList->MapAction(
Commands.RemoveCollision,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnRemoveCollision));
UICommandList->MapAction(
Commands.ConvertBoxesToConvex,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnConvertBoxToConvexCollision));
UICommandList->MapAction(
Commands.CopyCollisionFromSelectedMesh,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnCopyCollisionFromSelectedStaticMesh));
// Mesh menu
UICommandList->MapAction(
Commands.FindSource,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::ExecuteFindInExplorer),
FCanExecuteAction::CreateSP(this, &FStaticMeshEditor::CanExecuteSourceCommands));
UICommandList->MapAction(
Commands.ChangeMesh,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnChangeMesh));
// Collision Menu
UICommandList->MapAction(
Commands.CreateAutoConvexCollision,
FExecuteAction::CreateSP(this, &FStaticMeshEditor::OnConvexDecomposition));
}
void FStaticMeshEditor::ExtendToolBar()
{
struct Local
{
static void FillToolbar(FToolBarBuilder& ToolbarBuilder, TSharedPtr< class STextComboBox > UVChannelCombo, TSharedPtr< class STextComboBox > LODLevelCombo)
{
ToolbarBuilder.BeginSection("Realtime");
{
ToolbarBuilder.AddToolBarButton(FEditorViewportCommands::Get().ToggleRealTime);
}
ToolbarBuilder.EndSection();
ToolbarBuilder.BeginSection("Command");
{
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowSockets);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowWireframe);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowVertexColor);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowGrid);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowBounds);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowCollision);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowPivot);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowNormals);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowTangents);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetShowBinormals);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetDrawUVs);
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().SetDrawAdditionalData);
}
ToolbarBuilder.EndSection();
ToolbarBuilder.BeginSection("UV");
{
ToolbarBuilder.AddWidget(UVChannelCombo.ToSharedRef());
}
ToolbarBuilder.EndSection();
ToolbarBuilder.BeginSection("Camera");
{
ToolbarBuilder.AddToolBarButton(FStaticMeshEditorCommands::Get().ResetCamera);
}
ToolbarBuilder.EndSection();
ToolbarBuilder.BeginSection("LOD");
{
ToolbarBuilder.AddWidget(LODLevelCombo.ToSharedRef());
}
ToolbarBuilder.EndSection();
}
};
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension(
"Asset",
EExtensionHook::After,
Viewport->GetCommandList(),
FToolBarExtensionDelegate::CreateStatic( &Local::FillToolbar, UVChannelCombo, LODLevelCombo )
);
AddToolbarExtender(ToolbarExtender);
IStaticMeshEditorModule* StaticMeshEditorModule = &FModuleManager::LoadModuleChecked<IStaticMeshEditorModule>( "StaticMeshEditor" );
AddToolbarExtender(StaticMeshEditorModule->GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
}
void FStaticMeshEditor::BuildSubTools()
{
FSimpleDelegate OnSocketSelectionChanged = FSimpleDelegate::CreateSP( SharedThis(this), &FStaticMeshEditor::OnSocketSelectionChanged );
SocketManager = ISocketManager::CreateSocketManager( SharedThis(this) , OnSocketSelectionChanged );
SAssignNew( ConvexDecomposition, SConvexDecomposition )
.StaticMeshEditorPtr(SharedThis(this));
SAssignNew(GenerateUniqueUVs, SGenerateUniqueUVs)
.StaticMeshEditorPtr(SharedThis(this));
// Build toolbar widgets
UVChannelCombo = SNew(STextComboBox)
.OptionsSource(&UVChannels)
.OnSelectionChanged(this, &FStaticMeshEditor::ComboBoxSelectionChanged)
.IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() );
if(UVChannels.IsValidIndex(0))
{
UVChannelCombo->SetSelectedItem(UVChannels[0]);
}
LODLevelCombo = SNew(STextComboBox)
.OptionsSource(&LODLevels)
.OnSelectionChanged(this, &FStaticMeshEditor::LODLevelsSelectionChanged)
.IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() );
if(LODLevels.IsValidIndex(0))
{
LODLevelCombo->SetSelectedItem(LODLevels[0]);
}
}
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
{
return Viewport->GetStaticMeshComponent();
}
void FStaticMeshEditor::SetSelectedSocket(UStaticMeshSocket* InSelectedSocket)
{
SocketManager->SetSelectedSocket(InSelectedSocket);
}
UStaticMeshSocket* FStaticMeshEditor::GetSelectedSocket() const
{
check(SocketManager.IsValid());
return SocketManager->GetSelectedSocket();
}
void FStaticMeshEditor::DuplicateSelectedSocket()
{
SocketManager->DuplicateSelectedSocket();
}
void FStaticMeshEditor::RequestRenameSelectedSocket()
{
SocketManager->RequestRenameSelectedSocket();
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
bool FStaticMeshEditor::IsPrimValid(const FPrimData& InPrimData) const
{
if (StaticMesh->BodySetup)
{
const FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
switch (InPrimData.PrimType)
{
case KPT_Sphere:
return AggGeom->SphereElems.IsValidIndex(InPrimData.PrimIndex);
case KPT_Box:
return AggGeom->BoxElems.IsValidIndex(InPrimData.PrimIndex);
case KPT_Sphyl:
return AggGeom->SphylElems.IsValidIndex(InPrimData.PrimIndex);
case KPT_Convex:
return AggGeom->ConvexElems.IsValidIndex(InPrimData.PrimIndex);
}
}
return false;
}
bool FStaticMeshEditor::HasSelectedPrims() const
{
return (SelectedPrims.Num() > 0 ? true : false);
}
void FStaticMeshEditor::AddSelectedPrim(const FPrimData& InPrimData)
{
check(IsPrimValid(InPrimData));
SelectedPrims.Add(InPrimData);
}
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)
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_DuplicateSelectedPrims", "Duplicate Collision"));
StaticMesh->BodySetup->Modify();
//Clear the cache (PIE may have created some data), create new GUID
StaticMesh->BodySetup->InvalidatePhysicsData();
for (int32 PrimIdx = 0; PrimIdx < SelectedPrims.Num(); PrimIdx++)
{
FPrimData& PrimData = SelectedPrims[PrimIdx];
check(IsPrimValid(PrimData));
switch (PrimData.PrimType)
{
case KPT_Sphere:
{
const FKSphereElem SphereElem = AggGeom->SphereElems[PrimData.PrimIndex];
PrimData.PrimIndex = AggGeom->SphereElems.Add(SphereElem);
}
break;
case KPT_Box:
{
const FKBoxElem BoxElem = AggGeom->BoxElems[PrimData.PrimIndex];
PrimData.PrimIndex = AggGeom->BoxElems.Add(BoxElem);
}
break;
case KPT_Sphyl:
{
const FKSphylElem SphylElem = AggGeom->SphylElems[PrimData.PrimIndex];
PrimData.PrimIndex = AggGeom->SphylElems.Add(SphylElem);
}
break;
case KPT_Convex:
{
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
RefreshCollisionChange(StaticMesh);
GEditor->EndTransaction();
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh->MarkPackageDirty();
// Update views/property windows
Viewport->RefreshViewport();
}
}
void FStaticMeshEditor::TranslateSelectedPrims(const FVector& InDrag)
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
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);
}
}
void FStaticMeshEditor::RotateSelectedPrims(const FRotator& InRot)
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
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);
}
}
void FStaticMeshEditor::ScaleSelectedPrims(const FVector& InScale)
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
FVector ModifiedScale = InScale;
if (GEditor->UsePercentageBasedScaling())
{
ModifiedScale = InScale * ((GEditor->GetScaleGridSize() / 100.0f) / GEditor->GetGridSize());
}
for (int32 PrimIdx = 0; PrimIdx < SelectedPrims.Num(); PrimIdx++)
{
const FPrimData& PrimData = SelectedPrims[PrimIdx];
check(IsPrimValid(PrimData));
switch (PrimData.PrimType)
{
case KPT_Sphere:
AggGeom->SphereElems[PrimData.PrimIndex].ScaleElem(InScale, MinPrimSize);
break;
case KPT_Box:
AggGeom->BoxElems[PrimData.PrimIndex].ScaleElem(InScale, MinPrimSize);
break;
case KPT_Sphyl:
AggGeom->SphylElems[PrimData.PrimIndex].ScaleElem(InScale, MinPrimSize);
break;
case KPT_Convex:
AggGeom->ConvexElems[PrimData.PrimIndex].ScaleElem(ModifiedScale, MinPrimSize);
break;
}
}
}
bool FStaticMeshEditor::CalcSelectedPrimsAABB(FBox &OutBox) const
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
for (int32 PrimIdx = 0; PrimIdx < SelectedPrims.Num(); PrimIdx++)
{
const FPrimData& PrimData = SelectedPrims[PrimIdx];
check(IsPrimValid(PrimData));
switch (PrimData.PrimType)
{
case KPT_Sphere:
OutBox += AggGeom->SphereElems[PrimData.PrimIndex].CalcAABB(FTransform::Identity, 1.f);
break;
case KPT_Box:
OutBox += AggGeom->BoxElems[PrimData.PrimIndex].CalcAABB(FTransform::Identity, 1.f);
break;
case KPT_Sphyl:
OutBox += AggGeom->SphylElems[PrimData.PrimIndex].CalcAABB(FTransform::Identity, 1.f);
break;
case KPT_Convex:
OutBox += AggGeom->ConvexElems[PrimData.PrimIndex].CalcAABB(FTransform::Identity, FVector(1.f));
break;
}
}
return HasSelectedPrims();
}
bool FStaticMeshEditor::GetLastSelectedPrimTransform(FTransform& OutTransform) const
{
if (SelectedPrims.Num() > 0)
{
check(StaticMesh->BodySetup);
const FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
const FPrimData& PrimData = SelectedPrims.Last();
check(IsPrimValid(PrimData));
switch (PrimData.PrimType)
{
case KPT_Sphere:
OutTransform = AggGeom->SphereElems[PrimData.PrimIndex].GetTransform();
break;
case KPT_Box:
OutTransform = AggGeom->BoxElems[PrimData.PrimIndex].GetTransform();
break;
case KPT_Sphyl:
OutTransform = AggGeom->SphylElems[PrimData.PrimIndex].GetTransform();
break;
case KPT_Convex:
OutTransform = AggGeom->ConvexElems[PrimData.PrimIndex].GetTransform();
break;
}
}
return HasSelectedPrims();
}
FTransform FStaticMeshEditor::GetPrimTransform(const FPrimData& InPrimData) const
{
check(StaticMesh->BodySetup);
const FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
check(IsPrimValid(InPrimData));
switch (InPrimData.PrimType)
{
case KPT_Sphere:
return AggGeom->SphereElems[InPrimData.PrimIndex].GetTransform();
case KPT_Box:
return AggGeom->BoxElems[InPrimData.PrimIndex].GetTransform();
case KPT_Sphyl:
return AggGeom->SphylElems[InPrimData.PrimIndex].GetTransform();
case KPT_Convex:
return AggGeom->ConvexElems[InPrimData.PrimIndex].GetTransform();
}
return FTransform::Identity;
}
void FStaticMeshEditor::SetPrimTransform(const FPrimData& InPrimData, const FTransform& InPrimTransform) const
{
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
check(IsPrimValid(InPrimData));
switch (InPrimData.PrimType)
{
case KPT_Sphere:
AggGeom->SphereElems[InPrimData.PrimIndex].SetTransform(InPrimTransform);
break;
case KPT_Box:
AggGeom->BoxElems[InPrimData.PrimIndex].SetTransform(InPrimTransform);
break;
case KPT_Sphyl:
AggGeom->SphylElems[InPrimData.PrimIndex].SetTransform(InPrimTransform);
break;
case KPT_Convex:
AggGeom->ConvexElems[InPrimData.PrimIndex].SetTransform(InPrimTransform);
break;
}
}
void FStaticMeshEditor::RefreshTool()
{
int32 NumLODs = StaticMesh->GetNumLODs();
for (int32 LODIndex = 0; LODIndex < NumLODs; ++LODIndex)
{
UpdateLODStats(LODIndex);
}
bool bForceRefresh = true;
StaticMeshDetailsView->SetObject( StaticMesh, bForceRefresh );
RegenerateLODComboList();
RegenerateUVChannelComboList();
RefreshViewport();
}
void FStaticMeshEditor::RefreshViewport()
{
Viewport->RefreshViewport();
}
void FStaticMeshEditor::RegenerateLODComboList()
{
if( StaticMesh->RenderData )
{
int32 OldLOD = GetCurrentLODLevel();
NumLODLevels = StaticMesh->RenderData->LODResources.Num();
// Fill out the LOD level combo.
LODLevels.Empty();
LODLevels.Add( MakeShareable( new FString( LOCTEXT("AutoLOD", "Auto LOD").ToString() ) ) );
LODLevels.Add( MakeShareable( new FString( LOCTEXT("BaseLOD", "Base LOD").ToString() ) ) );
for(int32 LODLevelID = 1; LODLevelID < NumLODLevels; ++LODLevelID)
{
LODLevels.Add( MakeShareable( new FString( FString::Printf(*LOCTEXT("LODLevel_ID", "LOD Level %d").ToString(), LODLevelID ) ) ) );
}
if( LODLevelCombo.IsValid() )
{
LODLevelCombo->RefreshOptions();
if( OldLOD < LODLevels.Num() )
{
LODLevelCombo->SetSelectedItem(LODLevels[OldLOD]);
}
else
{
LODLevelCombo->SetSelectedItem(LODLevels[0]);
}
}
}
else
{
NumLODLevels = 0;
LODLevels.Empty();
LODLevels.Add( MakeShareable( new FString( LOCTEXT("AutoLOD", "Auto LOD").ToString() ) ) );
}
}
void FStaticMeshEditor::RegenerateUVChannelComboList()
{
int32 OldUVChannel = GetCurrentUVChannel();
// Fill out the UV channels combo.
UVChannels.Empty();
int32 MaxUVChannels = FMath::Max<int32>(GetNumUVChannels(),1);
for(int32 UVChannelID = 0; UVChannelID < MaxUVChannels; ++UVChannelID)
{
UVChannels.Add( MakeShareable( new FString( FText::Format( LOCTEXT("UVChannel_ID", "UV Channel {0}"), FText::AsNumber( UVChannelID ) ).ToString() ) ) );
}
if(UVChannelCombo.IsValid())
{
UVChannelCombo->RefreshOptions();
if( OldUVChannel >= 0 && OldUVChannel < GetNumUVChannels() )
{
UVChannelCombo->SetSelectedItem(UVChannels[OldUVChannel]);
}
else
{
UVChannelCombo->SetSelectedItem(UVChannels[0]);
}
}
}
void FStaticMeshEditor::UpdateLODStats(int32 CurrentLOD)
{
NumTriangles[CurrentLOD] = 0;
NumVertices[CurrentLOD] = 0;
NumUVChannels[CurrentLOD] = 0;
NumLODLevels = 0;
if( StaticMesh->RenderData )
{
NumLODLevels = StaticMesh->RenderData->LODResources.Num();
if (CurrentLOD >= 0 && CurrentLOD < NumLODLevels)
{
FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[CurrentLOD];
NumTriangles[CurrentLOD] = LODModel.GetNumTriangles();
NumVertices[CurrentLOD] = LODModel.GetNumVertices();
NumUVChannels[CurrentLOD] = LODModel.VertexBuffer.GetNumTexCoords();
}
}
}
void FStaticMeshEditor::ComboBoxSelectionChanged( TSharedPtr<FString> NewSelection, ESelectInfo::Type /*SelectInfo*/ )
{
Viewport->RefreshViewport();
}
void FStaticMeshEditor::LODLevelsSelectionChanged( TSharedPtr<FString> NewSelection, ESelectInfo::Type /*SelectInfo*/ )
{
int32 CurrentLOD = GetCurrentLODLevel();
UpdateLODStats( CurrentLOD > 0? CurrentLOD - 1 : 0 );
Viewport->ForceLODLevel(CurrentLOD);
}
int32 FStaticMeshEditor::GetCurrentUVChannel()
{
int32 Index = 0;
UVChannels.Find(UVChannelCombo->GetSelectedItem(), Index);
return Index;
}
int32 FStaticMeshEditor::GetCurrentLODLevel()
{
int32 Index = 0;
LODLevels.Find(LODLevelCombo->GetSelectedItem(), Index);
return Index;
}
int32 FStaticMeshEditor::GetCurrentLODIndex()
{
int32 Index = LODLevels.Find(LODLevelCombo->GetSelectedItem());
return Index == 0? 0 : Index - 1;
}
void FStaticMeshEditor::GenerateKDop(const FVector* Directions, uint32 NumDirections)
{
TArray<FVector> DirArray;
for(uint32 DirectionIndex = 0;DirectionIndex < NumDirections;DirectionIndex++)
{
DirArray.Add(Directions[DirectionIndex]);
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_GenerateKDop", "Create Convex Collision"));
const int32 PrimIndex = GenerateKDopAsSimpleCollision(StaticMesh, DirArray);
GEditor->EndTransaction();
if (PrimIndex != INDEX_NONE)
{
if (FEngineAnalytics::IsAvailable())
{
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Collision"), TEXT("Type"), TEXT("KDop Collision"));
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
AddSelectedPrim(FPrimData(KPT_Convex, PrimIndex));
}
Viewport->RefreshViewport();
}
void FStaticMeshEditor::OnCollisionBox()
{
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_OnCollisionBox", "Create Box Collision"));
const int32 PrimIndex = GenerateBoxAsSimpleCollision(StaticMesh);
GEditor->EndTransaction();
if (PrimIndex != INDEX_NONE)
{
if (FEngineAnalytics::IsAvailable())
{
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Collision"), TEXT("Type"), TEXT("Box Collision"));
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
AddSelectedPrim(FPrimData(KPT_Box, PrimIndex));
}
Viewport->RefreshViewport();
}
void FStaticMeshEditor::OnCollisionSphere()
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_OnCollisionSphere", "Create Sphere Collision"));
const int32 PrimIndex = GenerateSphereAsSimpleCollision(StaticMesh);
GEditor->EndTransaction();
if (PrimIndex != INDEX_NONE)
{
if (FEngineAnalytics::IsAvailable())
{
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Collision"), TEXT("Type"), TEXT("Sphere Collision"));
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
AddSelectedPrim(FPrimData(KPT_Sphere, PrimIndex));
}
Viewport->RefreshViewport();
}
void FStaticMeshEditor::OnCollisionSphyl()
{
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_OnCollisionSphyl", "Create Capsule Collision"));
const int32 PrimIndex = GenerateSphylAsSimpleCollision(StaticMesh);
GEditor->EndTransaction();
if (PrimIndex != INDEX_NONE)
{
if (FEngineAnalytics::IsAvailable())
{
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.Collision"), TEXT("Type"), TEXT("Capsule Collision"));
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
AddSelectedPrim(FPrimData(KPT_Sphyl, PrimIndex));
}
Viewport->RefreshViewport();
}
void FStaticMeshEditor::OnRemoveCollision(void)
{
// If we have a collision model for this staticmesh, ask if we want to replace it.
UBodySetup* BS = StaticMesh->BodySetup;
if (BS != NULL && (BS->AggGeom.GetElementCount() > 0))
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
int32 ShouldReplace = FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("RemoveCollisionPrompt", "Are you sure you want to remove all the collision meshes?"));
if (ShouldReplace == EAppReturnType::Yes)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands();
StaticMesh->BodySetup->RemoveSimpleCollision();
// refresh collision change back to staticmesh components
RefreshCollisionChange(StaticMesh);
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh->MarkPackageDirty();
// Update views/property windows
Viewport->RefreshViewport();
}
}
}
/** Util for adding vertex to an array if it is not already present. */
static void AddVertexIfNotPresent(TArray<FVector>& Vertices, const FVector& NewVertex)
{
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::CreateBoxVertsFromBoxCollision(const FKBoxElem& BoxElem, TArray<FVector>& Verts, float Scale)
{
FVector B[2], P, Q, Radii;
// X,Y,Z member variables are LENGTH not RADIUS
Radii.X = Scale*0.5f*BoxElem.X;
Radii.Y = Scale*0.5f*BoxElem.Y;
Radii.Z = Scale*0.5f*BoxElem.Z;
B[0] = Radii; // max
B[1] = -1.0f * Radii; // min
FTransform BoxElemTM = BoxElem.GetTransform();
for( int32 i=0; i<2; i++ )
{
for( int32 j=0; j<2; j++ )
{
P.X=B[i].X; Q.X=B[i].X;
P.Y=B[j].Y; Q.Y=B[j].Y;
P.Z=B[0].Z; Q.Z=B[1].Z;
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(P));
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(Q));
P.Y=B[i].Y; Q.Y=B[i].Y;
P.Z=B[j].Z; Q.Z=B[j].Z;
P.X=B[0].X; Q.X=B[1].X;
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(P));
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(Q));
P.Z=B[i].Z; Q.Z=B[i].Z;
P.X=B[j].X; Q.X=B[j].X;
P.Y=B[0].Y; Q.Y=B[1].Y;
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(P));
AddVertexIfNotPresent(Verts, BoxElemTM.TransformPosition(Q));
}
}
}
void FStaticMeshEditor::OnConvertBoxToConvexCollision()
{
// If we have a collision model for this staticmesh, ask if we want to replace it.
if (StaticMesh->BodySetup != NULL)
{
int32 ShouldReplace = FMessageDialog::Open( EAppMsgType::YesNo, LOCTEXT("ConvertBoxCollisionPrompt", "Are you sure you want to convert all box collision?") );
if (ShouldReplace == EAppReturnType::Yes)
{
UBodySetup* BodySetup = StaticMesh->BodySetup;
int32 NumBoxElems = BodySetup->AggGeom.BoxElems.Num();
if (NumBoxElems > 0)
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
// 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();
NewConvexColl->Reset();
//Fill the convex verts from the box elem collision and generate the convex hull
CreateBoxVertsFromBoxCollision(BoxColl, NewConvexColl->VertexData, 1.0f);
NewConvexColl->UpdateElemBox();
}
//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();
// Mark static mesh as dirty, to help make sure it gets saved.
StaticMesh->MarkPackageDirty();
// Update views/property windows
Viewport->RefreshViewport();
}
}
}
}
void FStaticMeshEditor::OnCopyCollisionFromSelectedStaticMesh()
{
// Find currently selected mesh from content browser
FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
TArray<FAssetData> SelectedAssetData;
ContentBrowserModule.Get().GetSelectedAssets(SelectedAssetData);
UStaticMesh * SelectedMesh = NULL;
if ( SelectedAssetData.Num() > 0 )
{
// find the first staticmesh we can find
for ( auto AssetIt = SelectedAssetData.CreateConstIterator(); AssetIt; ++AssetIt )
{
const FAssetData & Asset = (*AssetIt);
// if staticmesh
if ( Asset.GetClass() == UStaticMesh::StaticClass() )
{
SelectedMesh = Cast<UStaticMesh>(Asset.GetAsset());
}
}
}
// If we have a collision model for this staticmesh, ask if we want to replace it.
if (SelectedMesh && SelectedMesh != StaticMesh &&
SelectedMesh->BodySetup != NULL)
{
int32 ShouldReplace = FMessageDialog::Open( EAppMsgType::YesNo, FText::Format( LOCTEXT("CopyCollisionFromMeshPrompt", "Are you sure you want to copy collision from {0}?"), FText::FromString( SelectedMesh->GetName() ) ) );
if (ShouldReplace == EAppReturnType::Yes)
{
UBodySetup* BodySetup = StaticMesh->BodySetup;
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands();
// copy body properties from
BodySetup->CopyBodyPropertiesFrom(SelectedMesh->BodySetup);
//Invalidate physics data
BodySetup->InvalidatePhysicsData();
// 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
Viewport->RefreshViewport();
}
}
else
{
FNotificationInfo Info( LOCTEXT("InvalidMeshSelectionCollisionCopyFromPrompt", "Invalid asset to copy collision from. Select valid StaticMesh in Content Browser.") );
Info.ExpireDuration = 2.0f;
FSlateNotificationManager::Get().AddNotification( Info );
}
}
void FStaticMeshEditor::SetEditorMesh(UStaticMesh* InStaticMesh)
{
StaticMesh = InStaticMesh;
//Init stat arrays. A static mesh can have up to three level of details beyond the base mesh.
const int32 ArraySize = 4;
NumVertices.Empty(ArraySize);
NumVertices.AddZeroed(ArraySize);
NumTriangles.Empty(ArraySize);
NumTriangles.AddZeroed(ArraySize);
NumUVChannels.Empty(ArraySize);
NumUVChannels.AddZeroed(ArraySize);
// Always default the LOD to 0 when setting the mesh.
UpdateLODStats(0);
// Fill out the LOD level combo.
LODLevels.Empty();
LODLevels.Add( MakeShareable( new FString( LOCTEXT("AutoLOD", "Auto LOD").ToString() ) ) );
LODLevels.Add( MakeShareable( new FString( LOCTEXT("BaseLOD", "Base LOD").ToString() ) ) );
for(int32 LODLevelID = 1; LODLevelID < NumLODLevels; ++LODLevelID)
{
LODLevels.Add( MakeShareable( new FString( FString::Printf(*LOCTEXT("LODLevel_ID", "LOD Level %d").ToString(), LODLevelID ) ) ) );
//Update LOD stats for each level
UpdateLODStats(LODLevelID);
}
// Fill out the UV channels combo.
UVChannels.Empty();
for(int32 UVChannelID = 0; UVChannelID < GetNumUVChannels(0); ++UVChannelID)
{
UVChannels.Add( MakeShareable( new FString( FText::Format( LOCTEXT("UVChannel_ID", "UV Channel {0}"), FText::AsNumber( UVChannelID ) ).ToString() ) ) );
}
if( UVChannelCombo.IsValid() )
{
UVChannelCombo->RefreshOptions();
if(UVChannels.Num())
{
UVChannelCombo->SetSelectedItem(UVChannels[0]);
}
}
if( LODLevelCombo.IsValid() )
{
LODLevelCombo->RefreshOptions();
if(LODLevels.Num())
{
LODLevelCombo->SetSelectedItem(LODLevels[0]);
}
}
// Set the details view.
StaticMeshDetailsView->SetObject(StaticMesh);
Viewport->UpdatePreviewMesh(StaticMesh);
Viewport->RefreshViewport();
}
void FStaticMeshEditor::OnChangeMesh()
{
FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast();
UStaticMesh* SelectedMesh = GEditor->GetSelectedObjects()->GetTop<UStaticMesh>();
if(SelectedMesh && SelectedMesh != StaticMesh)
{
RemoveEditingObject(StaticMesh);
AddEditingObject(SelectedMesh);
SetEditorMesh(SelectedMesh);
// Refresh the tool so it will update it's LOD list.
if(GenerateUniqueUVs.IsValid())
{
GenerateUniqueUVs->RefreshTool();
}
if(SocketManager.IsValid())
{
SocketManager->UpdateStaticMesh();
}
}
}
void FStaticMeshEditor::DoDecomp(int32 InMaxHullCount, int32 InMaxHullVerts)
{
// Check we have a selected StaticMesh
if(StaticMesh && StaticMesh->RenderData)
{
FStaticMeshLODResources& LODModel = StaticMesh->RenderData->LODResources[0];
// Start a busy cursor so the user has feedback while waiting
const FScopedBusyCursor BusyCursor;
// Make vertex buffer
int32 NumVerts = LODModel.VertexBuffer.GetNumVertices();
TArray<FVector> Verts;
for(int32 i=0; i<NumVerts; i++)
{
FVector Vert = LODModel.PositionVertexBuffer.VertexPosition(i);
Verts.Add(Vert);
}
// Make index buffer
TArray<uint32> Indices;
LODModel.IndexBuffer.GetCopy(Indices);
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
ClearSelectedPrims();
// 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
UBodySetup* bs = StaticMesh->BodySetup;
if(bs)
{
bs->RemoveSimpleCollision();
}
else
{
// Otherwise, create one here.
StaticMesh->CreateBodySetup();
bs = StaticMesh->BodySetup;
}
// Run actual util to do the work
DecomposeMeshToHulls(bs, Verts, Indices, InMaxHullCount, InMaxHullVerts);
// refresh collision change back to staticmesh components
RefreshCollisionChange(StaticMesh);
// Mark mesh as dirty
StaticMesh->MarkPackageDirty();
// Update screen.
Viewport->RefreshViewport();
}
}
void FStaticMeshEditor::OnExportLightmapMesh( bool IsFBX )
{
check(StaticMesh); //must have a mesh to perform this operation
TArray <UStaticMesh*> StaticMeshArray;
StaticMeshArray.Add(StaticMesh);
FString Directory;
if (PromptUserForDirectory(Directory, *LOCTEXT("StaticMeshEditor_ExportToPromptTitle", "Export to...").ToString(), *FEditorDirectories::Get().GetLastDirectory(ELastDirectory::MESH_IMPORT_EXPORT)))
{
FEditorDirectories::Get().SetLastDirectory(ELastDirectory::MESH_IMPORT_EXPORT, Directory); // Save path as default for next time.
bool bAnyErrorOccurred = FbxMeshUtils::ExportAllLightmapModels(StaticMeshArray, Directory, IsFBX);
if (bAnyErrorOccurred)
{
FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT("StaticMeshEditor_LightmapExportFailure", "Some static meshes failed to export or provided warnings. Please check the Log Window for details."));
}
}
}
void FStaticMeshEditor::OnImportLightmapMesh( bool IsFBX )
{
check(StaticMesh); //must have a mesh to perform this operation
TArray <UStaticMesh*> StaticMeshArray;
StaticMeshArray.Add(StaticMesh);
FString Directory;
if (PromptUserForDirectory(Directory, *LOCTEXT("ImportFrom", "Import from...").ToString(), *FEditorDirectories::Get().GetLastDirectory(ELastDirectory::MESH_IMPORT_EXPORT)))
{
FEditorDirectories::Get().SetLastDirectory(ELastDirectory::MESH_IMPORT_EXPORT, Directory); // Save path as default for next time.
bool bAnyErrorOccurred = FbxMeshUtils::ImportAllLightmapModels(StaticMeshArray, Directory, IsFBX);
if (bAnyErrorOccurred)
{
FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT("StaticMeshEditor_LightmapImportFailure", "Some static meshes failed to import or provided warnings. Please check the Log Window for details."));
}
Viewport->RefreshViewport();
}
}
TSet< int32 >& FStaticMeshEditor::GetSelectedEdges()
{
return Viewport->GetSelectedEdges();
}
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;
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
void FStaticMeshEditor::DeleteSelected()
{
if (GetSelectedSocket())
{
DeleteSelectedSockets();
}
if (HasSelectedPrims())
{
DeleteSelectedPrims();
}
}
bool FStaticMeshEditor::CanDeleteSelected() const
{
return (GetSelectedSocket() != NULL || HasSelectedPrims());
}
void FStaticMeshEditor::DeleteSelectedSockets()
{
check(SocketManager.IsValid());
SocketManager->DeleteSelectedSocket();
}
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
void FStaticMeshEditor::DeleteSelectedPrims()
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
if (SelectedPrims.Num() > 0)
{
//int32 ShouldReplace = FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("RemoveSelectedCollisionPrompt", "Are you sure you want to remove the selected collision meshes?"));
//if (ShouldReplace == EAppReturnType::Yes)
{
// Sort the selected prims by PrimIndex so when we're deleting them we don't mess up other prims indicies
struct FCompareFPrimDataPrimIndex
{
FORCEINLINE bool operator()(const FPrimData& A, const FPrimData& B) const
{
return A.PrimIndex < B.PrimIndex;
}
};
SelectedPrims.Sort(FCompareFPrimDataPrimIndex());
check(StaticMesh->BodySetup);
FKAggregateGeom* AggGeom = &StaticMesh->BodySetup->AggGeom;
GEditor->BeginTransaction(LOCTEXT("FStaticMeshEditor_DeleteSelectedPrims", "Delete Collision"));
StaticMesh->BodySetup->Modify();
for (int32 PrimIdx = SelectedPrims.Num() - 1; PrimIdx >= 0; PrimIdx--)
{
const FPrimData& PrimData = SelectedPrims[PrimIdx];
check(IsPrimValid(PrimData));
switch (PrimData.PrimType)
{
case KPT_Sphere:
AggGeom->SphereElems.RemoveAt(PrimData.PrimIndex);
break;
case KPT_Box:
AggGeom->BoxElems.RemoveAt(PrimData.PrimIndex);
break;
case KPT_Sphyl:
AggGeom->SphylElems.RemoveAt(PrimData.PrimIndex);
break;
case KPT_Convex:
AggGeom->ConvexElems.RemoveAt(PrimData.PrimIndex);
break;
}
}
GEditor->EndTransaction();
ClearSelectedPrims();
// Make sure rendering is done - so we are not changing data being used by collision drawing.
FlushRenderingCommands();
// refresh collision change back to staticmesh components
RefreshCollisionChange(StaticMesh);
// Mark staticmesh as dirty, to help make sure it gets saved.
StaticMesh->MarkPackageDirty();
// Update views/property windows
Viewport->RefreshViewport();
}
}
}
void FStaticMeshEditor::DuplicateSelected()
{
DuplicateSelectedSocket();
const FVector InitialOffset(20.f);
DuplicateSelectedPrims(&InitialOffset);
}
bool FStaticMeshEditor::CanDuplicateSelected() const
{
return (GetSelectedSocket() != NULL || HasSelectedPrims());
}
bool FStaticMeshEditor::CanRenameSelected() const
{
return (GetSelectedSocket() != NULL);
}
void FStaticMeshEditor::ExecuteFindInExplorer()
{
if ( ensure(StaticMesh->AssetImportData) )
{
const FString SourceFilePath = FReimportManager::ResolveImportFilename(StaticMesh->AssetImportData->SourceFilePath, StaticMesh);
if ( SourceFilePath.Len() && IFileManager::Get().FileSize( *SourceFilePath ) != INDEX_NONE )
{
FPlatformProcess::ExploreFolder( *FPaths::GetPath(SourceFilePath) );
}
}
}
bool FStaticMeshEditor::CanExecuteSourceCommands() const
{
if ( !StaticMesh->AssetImportData )
{
return false;
}
const FString& SourceFilePath = FReimportManager::ResolveImportFilename(StaticMesh->AssetImportData->SourceFilePath, StaticMesh);
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)
{
SetEditorMesh(Cast<UStaticMesh>(InObject));
}
}
void FStaticMeshEditor::OnConvexDecomposition()
{
TabManager->InvokeTab(CollisionTabId);
}
bool FStaticMeshEditor::OnRequestClose()
{
bool bAllowClose = true;
if (StaticMeshDetails.IsValid() && StaticMeshDetails.Pin()->IsApplyNeeded())
{
// 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;
}
}
return bAllowClose;
}
void FStaticMeshEditor::RegisterOnPostUndo( const FOnPostUndo& Delegate )
{
OnPostUndo.Add( Delegate );
}
void FStaticMeshEditor::UnregisterOnPostUndo( SWidget* Widget )
{
OnPostUndo.RemoveAll( Widget );
}
void FStaticMeshEditor::NotifyPostChange( const FPropertyChangedEvent& PropertyChangedEvent, UProperty* PropertyThatChanged )
{
if(StaticMesh && StaticMesh->BodySetup)
{
StaticMesh->BodySetup->CreatePhysicsMeshes();
}
}
void FStaticMeshEditor::UndoAction()
{
GEditor->UndoTransaction();
}
void FStaticMeshEditor::RedoAction()
{
GEditor->RedoTransaction();
}
void FStaticMeshEditor::PostUndo( bool bSuccess )
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
RemoveInvalidPrims();
OnPostUndo.Broadcast();
}
void FStaticMeshEditor::PostRedo( bool bSuccess )
{
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
RemoveInvalidPrims();
OnPostUndo.Broadcast();
}
void FStaticMeshEditor::OnSocketSelectionChanged()
{
UStaticMeshSocket* SelectedSocket = GetSelectedSocket();
Static mesh editor can now create Box/Sphyl and have multiple collision primitives, which can be manipulated. #ttp 334968 - TOOLS FEATURE: Add primitive collision inside the static mesh editor #branch UE4 #change GenerateSimpleCollision funcs now return true if any collision was built Moved Prompt to build collision into a func (to remove duplicate code), and modified so that the options are Yes=Replace, No=Add-To, Cancel = Cancel. Added CalcBoundingSphyl code which is loosely based on the Sphere code in that it finds the best axis to align the sphyl with (but locally rotates so it can treat the Z axis as length, regardless). It they finds the radius to best enclose the Sphyl (same as Sphere, but 2D). Then it increase the length of the Sphyl until that encapsulates all the remaining points. Replace instances of AddZeroed with Add(FKTypeElem()) so that the vtable would be created correctly if a base struct was introduced. Moved PhysX code which scales the Elems from ModifyPrimitiveSize to their own struct func (ScaleElem) so that it could be used elsewhere. Added new struct FPrimData which contains the PrimType and PrimIndex so we can look the corresponding collision Elem up in our BodySetup. The static mesh editor session which is open for a particular static mesh keeps track of these using the following: IsPrimValid û Checks to see if the prim data could be valid HasSelectedPrims û Returns true if there are any selected prims IsSelectedPrim û Check to see if the prim data is selected AddSelectedPrim û Adds prim data to our selection RemoveSelectedPrim û Removes prim data from our selection RemoveInvalidPrism - Removes any prims which are no longer valid from the selection ClearSelectedPrims û Removes all the prim data from our selection DuplicateSelectedPrims û Duplicates the selected prims TranslateSelectedPrims - Translates the selected prims by a specified amount RotateSelectedPrims - Rotates the selected prims by a specified amount ScaleSelectedPrims - Scales the selected prims by a specified amount CalcSelectedPrimsAABB - Calculates the bounding box of the selected prims DeleteSelectedPrims û Deletes the selected prims GetLastSelectedPrimTransform û Gets the transform of the last prim which was added to the selection. GetPrimTransform - Gets the transform of a specified prim SetPrimTransform - Sets the transform of a specified prim Added placeholder calls to begin/end transaction where itÆs needed whenever the bodysetup prims are modified. Added new Static Mesh Editor menu option to create a capsule/sphyl Added dedicated collision toggle flag to the Static Mesh Editor so we could manage our own handling of the draw functions in order to inject hit proxies where needed so we can test when theyÆve been clicked on in the viewport. Widget now works when selecting collision Elems. Space toggles the manipulation method. SelectedPrims can be trans/rot/scaled using the editor widget. Prims can be duplicated or deleted either using menu entries or keyboard shortcuts. Alt+drag is also supported for duplication. ProcessClick was updated so that whenever a new selection type is clicked on the previous types are deselected (sockets, prims, edges), and other code location were updated to clear the selected prims where appropriate. Modified OnFocusViewportToSelection so that it also focuses on the selected elems too Modified SetSelectedSocket so that when passing NULL it deselects all the sockets [CL 2104326 by Andrew Brown in Main branch]
2014-06-13 05:03:24 -04:00
if (SelectedSocket)
{
ClearSelectedPrims();
}
Viewport->GetViewportClient().OnSocketSelectionChanged( SelectedSocket );
}
void FStaticMeshEditor::OnPostReimport(UObject* InObject, bool bSuccess)
{
// Ignore if this is regarding a different object
if ( InObject != StaticMesh )
{
return;
}
if (bSuccess)
{
if (FEngineAnalytics::IsAvailable())
{
FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.Usage.StaticMesh.ReimportedViaEditor"));
}
RefreshTool();
}
}
#undef LOCTEXT_NAMESPACE