2019-01-03 19:16:26 -05:00
|
|
|
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
2014-03-14 14:13:41 -04:00
|
|
|
|
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
|
|
|
#include "GeometryEdMode.h"
|
|
|
|
|
#include "EditorViewportClient.h"
|
|
|
|
|
#include "Misc/FeedbackContext.h"
|
|
|
|
|
#include "Modules/ModuleManager.h"
|
|
|
|
|
#include "EditorStyleSet.h"
|
2018-02-14 14:13:42 -05:00
|
|
|
#include "Classes/EditorStyleSettings.h"
|
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
|
|
|
#include "Materials/Material.h"
|
2014-11-12 04:58:53 -05:00
|
|
|
#include "Engine/Selection.h"
|
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
|
|
|
#include "EditorModeManager.h"
|
|
|
|
|
#include "EditorModes.h"
|
|
|
|
|
#include "Toolkits/ToolkitManager.h"
|
|
|
|
|
#include "BSPOps.h"
|
|
|
|
|
#include "GeometryMode.h"
|
|
|
|
|
#include "EditorGeometry.h"
|
|
|
|
|
#include "DynamicMeshBuilder.h"
|
|
|
|
|
#include "GeomModifier.h"
|
|
|
|
|
#include "GeomModifier_Edit.h"
|
|
|
|
|
#include "GeomModifier_Clip.h"
|
|
|
|
|
#include "GeomModifier_Create.h"
|
|
|
|
|
#include "GeomModifier_Delete.h"
|
|
|
|
|
#include "GeomModifier_Extrude.h"
|
|
|
|
|
#include "GeomModifier_Flip.h"
|
|
|
|
|
#include "GeomModifier_Lathe.h"
|
|
|
|
|
#include "GeomModifier_Pen.h"
|
|
|
|
|
#include "GeomModifier_Split.h"
|
|
|
|
|
#include "GeomModifier_Triangulate.h"
|
|
|
|
|
#include "GeomModifier_Optimize.h"
|
|
|
|
|
#include "GeomModifier_Turn.h"
|
|
|
|
|
#include "GeomModifier_Weld.h"
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
IMPLEMENT_MODULE( FGeometryModeModule, GeometryMode );
|
|
|
|
|
|
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogGeometryMode, Log, All);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FGeometryModeModule::StartupModule()
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEditorModeRegistry::Get().RegisterMode<FEdModeGeometry>(
|
|
|
|
|
FBuiltinEditorModes::EM_Geometry,
|
|
|
|
|
NSLOCTEXT("EditorModes", "GeometryMode", "Geometry Editing"),
|
|
|
|
|
FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.BspMode", "LevelEditor.BspMode.Small"),
|
2014-08-12 08:03:16 -04:00
|
|
|
true, 500
|
2014-06-18 10:16:16 -04:00
|
|
|
);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FGeometryModeModule::ShutdownModule()
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEditorModeRegistry::Get().UnregisterMode(FBuiltinEditorModes::EM_Geometry);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
|
Geometry Editing.
|
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
FEdModeGeometry::FEdModeGeometry()
|
|
|
|
|
{
|
|
|
|
|
Tools.Add( new FModeTool_GeometryModify() );
|
|
|
|
|
SetCurrentTool( MT_GeometryModify );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FEdModeGeometry::~FEdModeGeometry()
|
|
|
|
|
{
|
|
|
|
|
GeomObjects.Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::Render(const FSceneView* View,FViewport* Viewport,FPrimitiveDrawInterface* PDI)
|
|
|
|
|
{
|
|
|
|
|
FEdMode::Render(View,Viewport,PDI);
|
|
|
|
|
|
|
|
|
|
RenderVertex( View, PDI );
|
|
|
|
|
RenderEdge( View, PDI );
|
|
|
|
|
RenderPoly( View, Viewport, PDI );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::ShowModeWidgets() const
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::ShouldDrawBrushWireframe( AActor* InActor ) const
|
|
|
|
|
{
|
|
|
|
|
checkSlow( InActor );
|
|
|
|
|
|
|
|
|
|
// If the actor isn't selected, we don't want to interfere with it's rendering.
|
|
|
|
|
if( !GEditor->GetSelectedActors()->IsSelected( InActor ) )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;//false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::GetCustomDrawingCoordinateSystem( FMatrix& InMatrix, void* InData )
|
|
|
|
|
{
|
|
|
|
|
if( GetSelectionState() == GSS_None )
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( InData )
|
|
|
|
|
{
|
2014-11-26 07:06:03 -05:00
|
|
|
FGeomBase* GeomBase = static_cast<FGeomBase*>(InData);
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomBase->GetParentObject();
|
|
|
|
|
check(GeomObject.IsValid());
|
2014-11-26 07:06:03 -05:00
|
|
|
ABrush* Brush = GeomObject->GetActualBrush();
|
2015-03-31 18:56:31 -04:00
|
|
|
InMatrix = FRotationMatrix(GeomBase->GetNormal().Rotation()) * FQuatRotationMatrix(Brush->GetActorQuat());
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// If we don't have a specific geometry object to get the normal from
|
|
|
|
|
// use the one that was last selected.
|
|
|
|
|
|
|
|
|
|
for( int32 o = 0 ; o < GeomObjects.Num() ; ++o )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = GeomObjects[o];
|
2014-03-14 14:13:41 -04:00
|
|
|
go->CompileSelectionOrder();
|
|
|
|
|
|
|
|
|
|
if( go->SelectionOrder.Num() )
|
|
|
|
|
{
|
2014-11-26 07:06:03 -05:00
|
|
|
FGeomBase* GeomBase = go->SelectionOrder[go->SelectionOrder.Num() - 1];
|
|
|
|
|
check(GeomBase != nullptr);
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomBase->GetParentObject();
|
|
|
|
|
check(GeomObject.IsValid());
|
2014-11-26 07:06:03 -05:00
|
|
|
ABrush* Brush = GeomObject->GetActualBrush();
|
2015-03-31 18:56:31 -04:00
|
|
|
InMatrix = FRotationMatrix( go->SelectionOrder[ go->SelectionOrder.Num()-1 ]->GetWidgetRotation() ) * FQuatRotationMatrix(Brush->GetActorQuat());
|
2014-03-14 14:13:41 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::GetCustomInputCoordinateSystem( FMatrix& InMatrix, void* InData )
|
|
|
|
|
{
|
|
|
|
|
return GetCustomDrawingCoordinateSystem( InMatrix, InData );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::UsesToolkits() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::Enter()
|
|
|
|
|
{
|
|
|
|
|
FEdMode::Enter();
|
|
|
|
|
|
|
|
|
|
if (!Toolkit.IsValid())
|
|
|
|
|
{
|
|
|
|
|
Toolkit = MakeShareable(new FGeometryMode);
|
2014-11-12 22:02:17 -05:00
|
|
|
Toolkit->Init(Owner->GetToolkitHost());
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GetFromSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::Exit()
|
|
|
|
|
{
|
|
|
|
|
FToolkitManager::Get().CloseToolkit(Toolkit.ToSharedRef());
|
|
|
|
|
Toolkit.Reset();
|
|
|
|
|
|
|
|
|
|
FEdMode::Exit();
|
|
|
|
|
|
|
|
|
|
GeomObjects.Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::ActorSelectionChangeNotify()
|
|
|
|
|
{
|
|
|
|
|
GetFromSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::MapChangeNotify()
|
|
|
|
|
{
|
|
|
|
|
// If the map changes in some major way, just refresh all the geometry data.
|
|
|
|
|
GetFromSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::AddReferencedObjects( FReferenceCollector& Collector )
|
|
|
|
|
{
|
|
|
|
|
// Call parent implementation
|
|
|
|
|
FEdMode::AddReferencedObjects( Collector );
|
|
|
|
|
|
|
|
|
|
FModeTool_GeometryModify* mtgm = (FModeTool_GeometryModify*)FindTool( MT_GeometryModify );
|
|
|
|
|
for( FModeTool_GeometryModify::TModifierIterator Itor( mtgm->ModifierIterator() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
|
|
|
|
Collector.AddReferencedObject( *Itor );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the number of objects that are selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int32 FEdModeGeometry::CountObjectsSelected()
|
|
|
|
|
{
|
|
|
|
|
return GeomObjects.Num();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the number of polygons that are selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int32 FEdModeGeometry::CountSelectedPolygons()
|
|
|
|
|
{
|
|
|
|
|
int32 Count = 0;
|
|
|
|
|
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 P = 0 ; P < GeomObject->PolyPool.Num() ; ++P )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->PolyPool[P].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
Count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the polygons that are selected.
|
|
|
|
|
*
|
|
|
|
|
* @param InPolygons An array to fill with the selected polygons.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::GetSelectedPolygons( TArray<FGeomPoly*>& InPolygons )
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 P = 0 ; P < GeomObject->PolyPool.Num() ; ++P )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->PolyPool[P].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
InPolygons.Add( &GeomObject->PolyPool[P] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if the user has polygons selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::HavePolygonsSelected()
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 P = 0 ; P < GeomObject->PolyPool.Num() ; ++P )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->PolyPool[P].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the number of edges that are selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int32 FEdModeGeometry::CountSelectedEdges()
|
|
|
|
|
{
|
|
|
|
|
int32 Count = 0;
|
|
|
|
|
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 E = 0 ; E < GeomObject->EdgePool.Num() ; ++E )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->EdgePool[E].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
Count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if the user has edges selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::HaveEdgesSelected()
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 E = 0 ; E < GeomObject->EdgePool.Num() ; ++E )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->EdgePool[E].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the edges that are selected.
|
|
|
|
|
*
|
|
|
|
|
* @param InEdges An array to fill with the selected edges.
|
|
|
|
|
*/
|
|
|
|
|
void FEdModeGeometry::GetSelectedEdges( TArray<FGeomEdge*>& InEdges )
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 E = 0 ; E < GeomObject->EdgePool.Num() ; ++E )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->EdgePool[E].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
InEdges.Add( &GeomObject->EdgePool[E] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the number of vertices that are selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int32 FEdModeGeometry::CountSelectedVertices()
|
|
|
|
|
{
|
|
|
|
|
int32 Count = 0;
|
|
|
|
|
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 V = 0 ; V < GeomObject->VertexPool.Num() ; ++V )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->VertexPool[V].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
Count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if the user has vertices selected.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::HaveVerticesSelected()
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 V = 0 ; V < GeomObject->VertexPool.Num() ; ++V )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->VertexPool[V].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fills an array with all selected vertices.
|
|
|
|
|
*
|
|
|
|
|
* @param InVerts An array to fill with the unique list of selected vertices.
|
|
|
|
|
*/
|
|
|
|
|
void FEdModeGeometry::GetSelectedVertices( TArray<FGeomVertex*>& InVerts )
|
|
|
|
|
{
|
|
|
|
|
InVerts.Empty();
|
|
|
|
|
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 V = 0 ; V < GeomObject->VertexPool.Num() ; ++V )
|
|
|
|
|
{
|
|
|
|
|
if( GeomObject->VertexPool[V].IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
InVerts.Add( &GeomObject->VertexPool[V] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Utility function that allow you to poll and see if certain sub elements are currently selected.
|
|
|
|
|
*
|
|
|
|
|
* Returns a combination of the flags in ESelectionStatus.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int32 FEdModeGeometry::GetSelectionState()
|
|
|
|
|
{
|
|
|
|
|
int32 Status = 0;
|
|
|
|
|
|
|
|
|
|
if( HavePolygonsSelected() )
|
|
|
|
|
{
|
|
|
|
|
Status |= GSS_Polygon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( HaveEdgesSelected() )
|
|
|
|
|
{
|
|
|
|
|
Status |= GSS_Edge;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( HaveVerticesSelected() )
|
|
|
|
|
{
|
|
|
|
|
Status |= GSS_Vertex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FVector FEdModeGeometry::GetWidgetLocation() const
|
|
|
|
|
{
|
|
|
|
|
return FEdMode::GetWidgetLocation();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 10:16:16 -04:00
|
|
|
bool FEdModeGeometry::IsCompatibleWith(FEditorModeID OtherModeID) const
|
|
|
|
|
{
|
|
|
|
|
return OtherModeID == FBuiltinEditorModes::EM_Bsp;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-14 14:13:41 -04:00
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Deselects all edges, polygons, and vertices for all selected objects.
|
|
|
|
|
*/
|
|
|
|
|
void FEdModeGeometry::GeometrySelectNone(bool bStoreSelection, bool bResetPivot)
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
GeomObject->Select( 0 );
|
|
|
|
|
|
|
|
|
|
for( int VertexIdx = 0 ; VertexIdx < GeomObject->EdgePool.Num() ; ++VertexIdx )
|
|
|
|
|
{
|
|
|
|
|
GeomObject->EdgePool[VertexIdx].Select( 0 );
|
|
|
|
|
}
|
|
|
|
|
for( int VertexIdx = 0 ; VertexIdx < GeomObject->PolyPool.Num() ; ++VertexIdx )
|
|
|
|
|
{
|
|
|
|
|
GeomObject->PolyPool[VertexIdx].Select( 0 );
|
|
|
|
|
}
|
|
|
|
|
for( int VertexIdx = 0 ; VertexIdx < GeomObject->VertexPool.Num() ; ++VertexIdx )
|
|
|
|
|
{
|
|
|
|
|
GeomObject->VertexPool[VertexIdx].Select( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GeomObject->SelectionOrder.Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bStoreSelection)
|
|
|
|
|
{
|
|
|
|
|
FModeTool_GeometryModify* GeometryModifier = (FModeTool_GeometryModify*)FindTool(MT_GeometryModify);
|
|
|
|
|
GeometryModifier->StoreAllCurrentGeomSelections();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bResetPivot && (GeomObjects.Num() > 0))
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
Owner->SetPivotLocation(GeomObjects[0]->GetActualBrush()->GetActorLocation(), false);
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::SelectionChanged( )
|
|
|
|
|
{
|
|
|
|
|
StaticCastSharedPtr<FGeometryMode>(Toolkit)->SelectionChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::RenderPoly( const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI )
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
FLinearColor UnselectedColor = GeomObject->GetActualBrush()->GetWireColor();
|
|
|
|
|
UnselectedColor.A = .1f;
|
|
|
|
|
|
|
|
|
|
FLinearColor SelectedColor = GetDefault<UEditorStyleSettings>()->SelectionColor;
|
|
|
|
|
SelectedColor.A = .5f;
|
|
|
|
|
|
|
|
|
|
// Allocate the material proxy and register it so it can be deleted properly once the rendering is done with it.
|
2018-12-11 22:25:04 -05:00
|
|
|
FDynamicColoredMaterialRenderProxy* SelectedColorInstance = new FDynamicColoredMaterialRenderProxy(GEngine->GeomMaterial->GetRenderProxy(),SelectedColor );
|
2014-03-14 14:13:41 -04:00
|
|
|
PDI->RegisterDynamicResource( SelectedColorInstance );
|
|
|
|
|
|
2018-12-11 22:25:04 -05:00
|
|
|
FDynamicColoredMaterialRenderProxy* UnselectedColorInstance = new FDynamicColoredMaterialRenderProxy(GEngine->GeomMaterial->GetRenderProxy(),UnselectedColor);
|
2014-03-14 14:13:41 -04:00
|
|
|
PDI->RegisterDynamicResource( UnselectedColorInstance );
|
|
|
|
|
|
|
|
|
|
// Render selected filled polygons.
|
|
|
|
|
for( int32 PolyIdx = 0 ; PolyIdx < GeomObject->PolyPool.Num() ; ++PolyIdx )
|
|
|
|
|
{
|
|
|
|
|
const FGeomPoly* GeomPoly = &GeomObject->PolyPool[PolyIdx];
|
2015-04-02 16:34:30 -04:00
|
|
|
PDI->SetHitProxy( new HGeomPolyProxy(GeomPoly->GetParentObject(),PolyIdx) );
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2018-02-14 14:13:42 -05:00
|
|
|
FDynamicMeshBuilder MeshBuilder(View->GetFeatureLevel());
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
TArray<FVector> Verts;
|
|
|
|
|
|
|
|
|
|
// Look at the edge list and create a list of vertices to render from.
|
|
|
|
|
|
|
|
|
|
FVector LastPos(0);
|
|
|
|
|
|
|
|
|
|
for( int32 EdgeIdx = 0 ; EdgeIdx < GeomPoly->EdgeIndices.Num() ; ++EdgeIdx )
|
|
|
|
|
{
|
|
|
|
|
const FGeomEdge* GeomEdge = &GeomPoly->GetParentObject()->EdgePool[ GeomPoly->EdgeIndices[EdgeIdx] ];
|
|
|
|
|
|
|
|
|
|
if( EdgeIdx == 0 )
|
|
|
|
|
{
|
|
|
|
|
Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ] );
|
|
|
|
|
LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ];
|
|
|
|
|
}
|
|
|
|
|
else if( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ].Equals( LastPos ) )
|
|
|
|
|
{
|
|
|
|
|
Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[1] ] );
|
|
|
|
|
LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[1] ];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Verts.Add( GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ] );
|
|
|
|
|
LastPos = GeomPoly->GetParentObject()->VertexPool[ GeomEdge->VertexIndices[0] ];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw Polygon Triangles
|
2014-12-05 15:03:26 -05:00
|
|
|
const int32 VertexOffset = MeshBuilder.AddVertex(Verts[0], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor::White);
|
|
|
|
|
MeshBuilder.AddVertex(Verts[1], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor::White);
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 VertIdx = 2 ; VertIdx < Verts.Num() ; ++VertIdx )
|
|
|
|
|
{
|
2014-12-05 15:03:26 -05:00
|
|
|
MeshBuilder.AddVertex(Verts[VertIdx], FVector2D::ZeroVector, FVector(1,0,0), FVector(0,1,0), FVector(0,0,1), FColor::White);
|
2014-03-14 14:13:41 -04:00
|
|
|
MeshBuilder.AddTriangle( VertexOffset + VertIdx - 1, VertexOffset, VertexOffset + VertIdx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( GeomPoly->IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
MeshBuilder.Draw(PDI, GeomObject->GetActualBrush()->ActorToWorld().ToMatrixWithScale(), SelectedColorInstance, SDPG_World, false );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// We only draw unselected polygons in the perspective viewport
|
|
|
|
|
if( !Viewport->GetClient()->IsOrtho() )
|
|
|
|
|
{
|
|
|
|
|
// Unselected polygons are drawn at the world level but are bumped slightly forward to avoid z-fighting
|
|
|
|
|
MeshBuilder.Draw(PDI, GeomObject->GetActualBrush()->ActorToWorld().ToMatrixWithScale(), UnselectedColorInstance, SDPG_World, false );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PDI->SetHitProxy( NULL );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::RenderEdge( const FSceneView* View, FPrimitiveDrawInterface* PDI )
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeometryObject = GeomObjects[ObjectIdx];
|
2014-03-14 14:13:41 -04:00
|
|
|
const FColor WireColor = GeometryObject->GetActualBrush()->GetWireColor();
|
|
|
|
|
|
|
|
|
|
// Edges
|
|
|
|
|
for( int32 EdgeIdx = 0 ; EdgeIdx < GeometryObject->EdgePool.Num() ; ++EdgeIdx )
|
|
|
|
|
{
|
|
|
|
|
const FGeomEdge* GeometryEdge = &GeometryObject->EdgePool[EdgeIdx];
|
|
|
|
|
const FColor Color = GeometryEdge->IsSelected() ? FColor(255,128,64) : WireColor;
|
|
|
|
|
|
2015-04-02 16:34:30 -04:00
|
|
|
PDI->SetHitProxy( new HGeomEdgeProxy(GeometryObject,EdgeIdx) );
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
FVector V0 = GeometryObject->VertexPool[ GeometryEdge->VertexIndices[0] ];
|
|
|
|
|
FVector V1 = GeometryObject->VertexPool[ GeometryEdge->VertexIndices[1] ];
|
|
|
|
|
const FTransform ActorToWorld = GeometryObject->GetActualBrush()->ActorToWorld();
|
|
|
|
|
|
|
|
|
|
V0 = ActorToWorld.TransformPosition( V0 );
|
|
|
|
|
V1 = ActorToWorld.TransformPosition( V1 );
|
|
|
|
|
|
|
|
|
|
PDI->DrawLine( V0, V1, Color, SDPG_Foreground );
|
|
|
|
|
}
|
|
|
|
|
PDI->SetHitProxy( NULL );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::RenderVertex( const FSceneView* View, FPrimitiveDrawInterface* PDI )
|
|
|
|
|
{
|
|
|
|
|
for( int32 ObjectIdx = 0 ; ObjectIdx < GeomObjects.Num() ; ++ObjectIdx )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[ObjectIdx];
|
|
|
|
|
check(GeomObject.IsValid());
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Vertices
|
|
|
|
|
|
|
|
|
|
FColor Color;
|
|
|
|
|
float Scale;
|
|
|
|
|
FVector Location;
|
|
|
|
|
|
|
|
|
|
for( int32 VertIdx = 0 ; VertIdx < GeomObject->VertexPool.Num() ; ++VertIdx )
|
|
|
|
|
{
|
|
|
|
|
const FGeomVertex* GeomVertex = &GeomObject->VertexPool[VertIdx];
|
|
|
|
|
check(GeomVertex);
|
|
|
|
|
check(GeomObject->GetActualBrush());
|
|
|
|
|
|
|
|
|
|
Location = GeomObject->GetActualBrush()->ActorToWorld().TransformPosition( *GeomVertex );
|
2018-02-14 14:13:42 -05:00
|
|
|
Scale = View->WorldToScreen( Location ).W * ( 4.0f / View->UnscaledViewRect.Width() / View->ViewMatrices.GetProjectionMatrix().M[0][0] );
|
2014-03-14 14:13:41 -04:00
|
|
|
Color = GeomVertex->IsSelected() ? FColor(255,128,64) : GeomObject->GetActualBrush()->GetWireColor();
|
|
|
|
|
|
2015-04-02 16:34:30 -04:00
|
|
|
PDI->SetHitProxy( new HGeomVertexProxy( GeomObject, VertIdx) );
|
2014-03-14 14:13:41 -04:00
|
|
|
PDI->DrawSprite( Location, 4.f * Scale, 4.f * Scale, GEngine->DefaultBSPVertexTexture->Resource, Color, SDPG_Foreground, 0.0, 0.0, 0.0, 0.0 );
|
|
|
|
|
PDI->SetHitProxy( NULL );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Cache all the selected geometry on the object, and add to the array if any is found
|
|
|
|
|
*
|
|
|
|
|
* Return true if new object has been added to the array.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::CacheSelectedData( TArray<HGeomMidPoints>& raGeomData, const FGeomObject& rGeomObject ) const
|
|
|
|
|
{
|
|
|
|
|
// Early out if this object doesn't have a brush
|
|
|
|
|
if ( !rGeomObject.ActualBrush )
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HGeomMidPoints GeomData;
|
|
|
|
|
|
|
|
|
|
// Loop through all the verts caching their midpoint if they're selected
|
|
|
|
|
for ( int32 i=0; i<rGeomObject.VertexPool.Num(); i++ )
|
|
|
|
|
{
|
|
|
|
|
const FGeomVertex& rGeomVertex = rGeomObject.VertexPool[i];
|
|
|
|
|
if(rGeomVertex.IsSelected())
|
|
|
|
|
{
|
|
|
|
|
GeomData.VertexPool.Add( rGeomVertex.GetMidPoint() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loop through all the edges caching their midpoint if they're selected
|
|
|
|
|
for ( int32 i=0; i<rGeomObject.EdgePool.Num(); i++ )
|
|
|
|
|
{
|
|
|
|
|
const FGeomEdge& rGeomEdge = rGeomObject.EdgePool[i];
|
|
|
|
|
if(rGeomEdge.IsSelected())
|
|
|
|
|
{
|
|
|
|
|
GeomData.EdgePool.Add( rGeomEdge.GetMidPoint() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loop through all the polys caching their midpoint if they're selected
|
|
|
|
|
for ( int32 i=0; i<rGeomObject.PolyPool.Num(); i++ )
|
|
|
|
|
{
|
|
|
|
|
const FGeomPoly& rGeomPoly = rGeomObject.PolyPool[i];
|
|
|
|
|
if(rGeomPoly.IsSelected())
|
|
|
|
|
{
|
|
|
|
|
GeomData.PolyPool.Add( rGeomPoly.GetMidPoint() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only add the data to the array if there was anything that was selected
|
|
|
|
|
bool bRet = ( ( GeomData.VertexPool.Num() + GeomData.EdgePool.Num() + GeomData.PolyPool.Num() ) > 0 ? true : false );
|
|
|
|
|
if ( bRet )
|
|
|
|
|
{
|
|
|
|
|
// Make note of the brush this belongs to, then add
|
|
|
|
|
GeomData.ActualBrush = rGeomObject.ActualBrush;
|
|
|
|
|
raGeomData.Add( GeomData );
|
|
|
|
|
}
|
|
|
|
|
return bRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attempt to find all the new geometry using the cached data, and cache those new ones out
|
|
|
|
|
*
|
|
|
|
|
* Return true everything was found (or there was nothing to find)
|
|
|
|
|
*/
|
|
|
|
|
bool FEdModeGeometry::FindFromCache( TArray<HGeomMidPoints>& raGeomData, FGeomObject& rGeomObject, TArray<FGeomBase*>& raSelectedGeom ) const
|
|
|
|
|
{
|
|
|
|
|
// Early out if this object doesn't have a brush
|
|
|
|
|
if ( !rGeomObject.ActualBrush )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Early out if we don't have anything cached
|
|
|
|
|
if ( raGeomData.Num() == 0 )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loop through all the cached data, seeing if there's a match for the brush
|
|
|
|
|
// Note: if GetMidPoint wasn't pure virtual this could be much nicer
|
|
|
|
|
bool bRet = false; // True if the brush that was parsed was found and all verts/edges/polys were located
|
|
|
|
|
bool bFound = false; // True if the brush that was parsed was found
|
|
|
|
|
for( int32 i=0; i<raGeomData.Num(); i++ )
|
|
|
|
|
{
|
|
|
|
|
// Does this brush match the cached actor?
|
|
|
|
|
HGeomMidPoints& rGeomData = raGeomData[i];
|
|
|
|
|
if ( rGeomData.ActualBrush == rGeomObject.ActualBrush )
|
|
|
|
|
{
|
|
|
|
|
// Compare location of new midpoints with cached versions
|
|
|
|
|
bFound = true;
|
|
|
|
|
bool bSucess = true; // True if all verts/edges/polys were located
|
|
|
|
|
for ( int32 j=0; j<rGeomData.VertexPool.Num(); j++ )
|
|
|
|
|
{
|
|
|
|
|
const FVector& rGeomVector = rGeomData.VertexPool[j];
|
|
|
|
|
for ( int32 k=0; k<rGeomObject.VertexPool.Num(); k++ )
|
|
|
|
|
{
|
|
|
|
|
// If we have a match select it and move on to the next one
|
|
|
|
|
FGeomVertex& rGeomVertex = rGeomObject.VertexPool[k];
|
|
|
|
|
if ( rGeomVector.Equals( rGeomVertex.GetMidPoint() ) )
|
|
|
|
|
{
|
|
|
|
|
// Add the new geometry to the to-be-selected pool, and remove from the data pool
|
|
|
|
|
raSelectedGeom.Add(&rGeomVertex);
|
|
|
|
|
rGeomData.VertexPool.RemoveAt(j--);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// If we didn't locate them all inform the user
|
|
|
|
|
if ( rGeomData.VertexPool.Num() != 0 )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find %d Vertex(s) in new BSP" ), rGeomData.VertexPool.Num() );
|
|
|
|
|
bSucess = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare location of new midpoints with cached versions
|
|
|
|
|
for ( int32 j=0; j<rGeomData.EdgePool.Num(); j++ )
|
|
|
|
|
{
|
|
|
|
|
const FVector& rGeomVector = rGeomData.EdgePool[j];
|
|
|
|
|
for ( int32 k=0; k<rGeomObject.EdgePool.Num(); k++ )
|
|
|
|
|
{
|
|
|
|
|
// If we have a match select it and move on to the next one
|
|
|
|
|
FGeomEdge& rGeomEdge = rGeomObject.EdgePool[k];
|
|
|
|
|
if ( rGeomVector.Equals( rGeomEdge.GetMidPoint() ) )
|
|
|
|
|
{
|
|
|
|
|
// Add the new geometry to the to-be-selected pool, and remove from the data pool
|
|
|
|
|
raSelectedGeom.Add(&rGeomEdge);
|
|
|
|
|
rGeomData.EdgePool.RemoveAt(j--);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// If we didn't locate them all inform the user
|
|
|
|
|
if ( rGeomData.EdgePool.Num() != 0 )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find %d Edge(s) in new BSP" ), rGeomData.EdgePool.Num() );
|
|
|
|
|
bSucess = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare location of new midpoints with cached versions
|
|
|
|
|
for ( int32 j=0; j<rGeomData.PolyPool.Num(); j++ )
|
|
|
|
|
{
|
|
|
|
|
const FVector& rGeomVector = rGeomData.PolyPool[j];
|
|
|
|
|
for ( int32 k=0; k<rGeomObject.PolyPool.Num(); k++ )
|
|
|
|
|
{
|
|
|
|
|
// If we have a match select it and move on to the next one
|
|
|
|
|
FGeomPoly& rGeomPoly = rGeomObject.PolyPool[k];
|
|
|
|
|
if ( rGeomVector.Equals( rGeomPoly.GetMidPoint() ) )
|
|
|
|
|
{
|
|
|
|
|
// Add the new geometry to the to-be-selected pool, and remove from the data pool
|
|
|
|
|
raSelectedGeom.Add(&rGeomPoly);
|
|
|
|
|
rGeomData.PolyPool.RemoveAt(j--);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// If we didn't locate them all inform the user
|
|
|
|
|
if ( rGeomData.PolyPool.Num() != 0 )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find %d Poly(s) in new BSP" ), rGeomData.PolyPool.Num() );
|
|
|
|
|
bSucess = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we didn't locate them all inform the user, then remove from the data pool
|
|
|
|
|
if ( !bSucess )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to resolve %s Brush in new BSP, see above" ), *rGeomData.ActualBrush->GetName() );
|
|
|
|
|
}
|
|
|
|
|
bRet = bSucess;
|
|
|
|
|
raGeomData.RemoveAt(i--);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// If we didn't locate the brush inform the user
|
|
|
|
|
if ( !bFound )
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find %s Brush(s) in new BSP" ), *rGeomObject.ActualBrush->GetName() );
|
|
|
|
|
}
|
|
|
|
|
return bRet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Select all the verts/edges/polys that were found
|
|
|
|
|
*
|
|
|
|
|
* Return true if successful
|
|
|
|
|
*/
|
|
|
|
|
bool FEdModeGeometry::SelectCachedData( TArray<FGeomBase*>& raSelectedGeom ) const
|
|
|
|
|
{
|
|
|
|
|
// Early out if we don't have anything cached
|
|
|
|
|
if ( raSelectedGeom.Num() == 0 )
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 10:16:16 -04:00
|
|
|
check(Owner->IsModeActive(FBuiltinEditorModes::EM_Geometry));
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Backup widget position, we want it to be in the same position as it was previously too
|
2014-06-18 10:16:16 -04:00
|
|
|
FVector PivLoc = Owner->PivotLocation;
|
|
|
|
|
FVector SnapLoc = Owner->SnappedLocation;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Loop through all the geometry that should be selected
|
|
|
|
|
for( int32 i=0; i<raSelectedGeom.Num(); i++ )
|
|
|
|
|
{
|
|
|
|
|
// Does this brush match the cached actor?
|
|
|
|
|
FGeomBase* pGeom = raSelectedGeom[i];
|
|
|
|
|
if ( pGeom )
|
|
|
|
|
{
|
|
|
|
|
pGeom->Select();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore the widget position
|
2014-06-18 10:16:16 -04:00
|
|
|
Owner->SetPivotLocation( PivLoc, false );
|
|
|
|
|
Owner->SnappedLocation = SnapLoc;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
StaticCastSharedPtr<FGeometryMode>(Toolkit)->SelectionChanged();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BSP_RESELECT // Attempt to reselect any geometry that was selected prior to the BSP being rebuilt
|
|
|
|
|
#define BSP_RESELECT__ALL_OR_NOTHING // If any geometry can't be located, then don't select anything
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Compiles geometry mode information from the selected brushes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::GetFromSource()
|
|
|
|
|
{
|
|
|
|
|
GWarn->BeginSlowTask( NSLOCTEXT("EditorModes", "GeometryMode-BeginRebuildingBSPTask", "Rebuilding BSP"), false);
|
|
|
|
|
|
|
|
|
|
TArray<HGeomMidPoints> GeomData;
|
|
|
|
|
|
|
|
|
|
// Go through each brush and update its components before updating below
|
|
|
|
|
for( int32 i=0; i<GeomObjects.Num(); i++ )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = GeomObjects[i];
|
|
|
|
|
if(GeomObject.IsValid() && GeomObject->ActualBrush)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
#ifdef BSP_RESELECT
|
|
|
|
|
// Cache any information that'll help us reselect the object after it's reconstructed
|
|
|
|
|
CacheSelectedData( GeomData, *GeomObject );
|
|
|
|
|
#endif // BSP_RESELECT
|
|
|
|
|
GeomObject->ActualBrush->UnregisterAllComponents();
|
|
|
|
|
if (GeomObject->ActualBrush->GetWorld())
|
|
|
|
|
{
|
|
|
|
|
GeomObject->ActualBrush->RegisterAllComponents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GeomObjects.Empty();
|
|
|
|
|
|
|
|
|
|
TArray<FGeomBase*> SelectedGeom;
|
|
|
|
|
|
|
|
|
|
// Notify the selected actors that they have been moved.
|
|
|
|
|
bool bFound = true;
|
|
|
|
|
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
|
|
|
|
|
{
|
|
|
|
|
AActor* Actor = static_cast<AActor*>( *It );
|
|
|
|
|
checkSlow( Actor->IsA(AActor::StaticClass()) );
|
|
|
|
|
|
|
|
|
|
ABrush* BrushActor = Cast< ABrush >( Actor );
|
|
|
|
|
if ( BrushActor )
|
|
|
|
|
{
|
|
|
|
|
if( BrushActor->Brush != NULL )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr GeomObject = MakeShareable( new FGeomObject() );
|
2014-03-14 14:13:41 -04:00
|
|
|
GeomObject->SetParentObjectIndex( GeomObjects.Add( GeomObject ) );
|
|
|
|
|
GeomObject->ActualBrush = BrushActor;
|
|
|
|
|
GeomObject->GetFromSource();
|
|
|
|
|
#ifdef BSP_RESELECT
|
|
|
|
|
// Attempt to find all the previously selected geometry on this object if everything has gone OK so far
|
|
|
|
|
if ( bFound && !FindFromCache( GeomData, *GeomObject, SelectedGeom ) )
|
|
|
|
|
{
|
|
|
|
|
#ifdef BSP_RESELECT__ALL_OR_NOTHING
|
|
|
|
|
// If it didn't succeed, don't attempt to reselect anything as the user will only end up moving part of their previous selection
|
|
|
|
|
UE_LOG(LogGeometryMode, Warning, TEXT( "Unable to find all previously selected geometry data, resetting selection" ) );
|
|
|
|
|
SelectedGeom.Empty();
|
|
|
|
|
GeomData.Empty();
|
|
|
|
|
bFound = false;
|
|
|
|
|
#endif // BSP_RESELECT__ALL_OR_NOTHING
|
|
|
|
|
}
|
|
|
|
|
#endif // BSP_RESELECT
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef BSP_RESELECT
|
|
|
|
|
// Reselect anything that came close to the cached midpoints
|
|
|
|
|
SelectCachedData( SelectedGeom );
|
|
|
|
|
#endif // BSP_RESELECT
|
|
|
|
|
|
|
|
|
|
GWarn->EndSlowTask();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Changes the source brushes to match the current geometry data.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::SendToSource()
|
|
|
|
|
{
|
|
|
|
|
for( int32 o = 0 ; o < GeomObjects.Num() ; ++o )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = GeomObjects[o];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
go->SendToSource();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::FinalizeSourceData()
|
|
|
|
|
{
|
|
|
|
|
bool Result = 0;
|
|
|
|
|
|
|
|
|
|
for( int32 o = 0 ; o < GeomObjects.Num() ; ++o )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = GeomObjects[o];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
if( go->FinalizeSourceData() )
|
|
|
|
|
{
|
|
|
|
|
Result = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::PostUndo()
|
|
|
|
|
{
|
|
|
|
|
// Rebuild the geometry data from the current brush state
|
|
|
|
|
|
|
|
|
|
GetFromSource();
|
|
|
|
|
|
|
|
|
|
// Restore selection information.
|
|
|
|
|
for( int32 o = 0 ; o < GeomObjects.Num() ; ++o )
|
|
|
|
|
{
|
|
|
|
|
int32 Idx = 0;
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = GeomObjects[o];
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
ABrush* Actor = go->GetActualBrush();
|
|
|
|
|
|
|
|
|
|
// First, clear the current selection
|
|
|
|
|
go->SelectNone();
|
|
|
|
|
|
|
|
|
|
// Next, restore the cached selection
|
2015-06-22 15:05:22 -04:00
|
|
|
go->UpdateFromSelectionArray( Actor->SavedSelections );
|
2014-03-14 14:13:41 -04:00
|
|
|
int32 res = go->SetPivotFromSelectionArray( Actor->SavedSelections );
|
|
|
|
|
|
|
|
|
|
//use the centre of the actor if we didnt find a suitable selection
|
|
|
|
|
if( res == INDEX_NONE )
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
Owner->SetPivotLocation( Actor->GetActorLocation() , false );
|
2014-03-14 14:13:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
go->ForceLastSelectionIndex( res );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FEdModeGeometry::ExecDelete()
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
check( Owner->IsModeActive( FBuiltinEditorModes::EM_Geometry ) );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Find the delete modifier and execute it.
|
|
|
|
|
|
|
|
|
|
FModeTool_GeometryModify* mtgm = (FModeTool_GeometryModify*)FindTool( MT_GeometryModify );
|
|
|
|
|
|
|
|
|
|
for( FModeTool_GeometryModify::TModifierIterator Itor( mtgm->ModifierIterator() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
|
|
|
|
UGeomModifier* gm = *Itor;
|
|
|
|
|
|
|
|
|
|
if( gm->IsA( UGeomModifier_Delete::StaticClass()) )
|
|
|
|
|
{
|
|
|
|
|
if( gm->Apply() )
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FEdModeGeometry::UpdateInternalData()
|
|
|
|
|
{
|
|
|
|
|
GetFromSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
FModeTool_GeometryModify.
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::SetCurrentModifier( UGeomModifier* InModifier )
|
|
|
|
|
{
|
|
|
|
|
if( CurrentModifier )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->WasDeactivated();
|
|
|
|
|
}
|
|
|
|
|
CurrentModifier = InModifier;
|
|
|
|
|
CurrentModifier->WasActivated();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UGeomModifier* FModeTool_GeometryModify::GetCurrentModifier() { return CurrentModifier; }
|
|
|
|
|
|
|
|
|
|
int32 FModeTool_GeometryModify::GetNumModifiers() { return Modifiers.Num(); }
|
|
|
|
|
|
|
|
|
|
FModeTool_GeometryModify::FModeTool_GeometryModify()
|
|
|
|
|
{
|
|
|
|
|
ID = MT_GeometryModify;
|
|
|
|
|
|
2015-02-03 05:40:57 -05:00
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Edit::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Extrude::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Clip::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Pen::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Lathe::StaticClass() ) );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
2015-02-03 05:40:57 -05:00
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Create::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Delete::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Flip::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Split::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Triangulate::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Optimize::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Turn::StaticClass() ) );
|
|
|
|
|
Modifiers.Add( NewObject<UGeomModifier>( GetTransientPackage(), UGeomModifier_Weld::StaticClass() ) );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
CurrentModifier = NULL;
|
|
|
|
|
|
|
|
|
|
bGeomModified = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::SelectNone()
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEdModeGeometry* Mode = GLevelEditorModeTools().GetActiveModeTyped<FEdModeGeometry>(FBuiltinEditorModes::EM_Geometry);
|
2014-03-14 14:13:41 -04:00
|
|
|
check(Mode);
|
|
|
|
|
Mode->GeometrySelectNone(false, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return true if something was selected/deselected, false otherwise. */
|
|
|
|
|
bool FModeTool_GeometryModify::BoxSelect( FBox& InBox, bool InSelect )
|
|
|
|
|
{
|
|
|
|
|
bool bResult = false;
|
2014-06-18 10:16:16 -04:00
|
|
|
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Geometry ) )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEdModeGeometry* mode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_Geometry );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( FEdModeGeometry::TGeomObjectIterator Itor( mode->GeomObjectItor() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = *Itor;
|
2014-03-14 14:13:41 -04:00
|
|
|
FTransform ActorToWorld = go->GetActualBrush()->ActorToWorld();
|
|
|
|
|
|
|
|
|
|
// Only verts for box selection
|
|
|
|
|
|
|
|
|
|
for( int32 v = 0 ; v < go->VertexPool.Num() ; ++v )
|
|
|
|
|
{
|
|
|
|
|
FGeomVertex& gv = go->VertexPool[v];
|
|
|
|
|
if( FMath::PointBoxIntersection( ActorToWorld.TransformPosition( gv.GetMid() ), InBox ) )
|
|
|
|
|
{
|
|
|
|
|
gv.Select( InSelect );
|
|
|
|
|
bResult = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @return true if something was selected/deselected, false otherwise. */
|
2017-03-01 12:26:39 -05:00
|
|
|
bool FModeTool_GeometryModify::FrustumSelect( const FConvexVolume& InFrustum, FEditorViewportClient* InViewportClient, bool InSelect /* = true */ )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
bool bResult = false;
|
2014-06-18 10:16:16 -04:00
|
|
|
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Geometry ) )
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEdModeGeometry* mode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_Geometry );
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( FEdModeGeometry::TGeomObjectIterator Itor( mode->GeomObjectItor() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = *Itor;
|
2014-03-14 14:13:41 -04:00
|
|
|
FTransform ActorToWorld = go->GetActualBrush()->ActorToWorld();
|
|
|
|
|
// Check each vertex to see if its inside the frustum
|
|
|
|
|
for( int32 v = 0 ; v < go->VertexPool.Num() ; ++v )
|
|
|
|
|
{
|
|
|
|
|
FGeomVertex& gv = go->VertexPool[v];
|
|
|
|
|
if( InFrustum.IntersectBox( ActorToWorld.TransformPosition( gv.GetMid() ), FVector::ZeroVector ) )
|
|
|
|
|
{
|
|
|
|
|
gv.Select( InSelect );
|
|
|
|
|
bResult = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 10:16:16 -04:00
|
|
|
void FModeTool_GeometryModify::Tick(FEditorViewportClient* ViewportClient,float DeltaTime)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
if( CurrentModifier )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->Tick( ViewportClient, DeltaTime );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return true if the delta was handled by this editor mode tool.
|
|
|
|
|
*/
|
2014-06-18 10:16:16 -04:00
|
|
|
bool FModeTool_GeometryModify::InputDelta(FEditorViewportClient* InViewportClient,FViewport* InViewport,FVector& InDrag,FRotator& InRot,FVector& InScale)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
bool bResult = false;
|
|
|
|
|
if( InViewportClient->GetCurrentWidgetAxis() != EAxisList::None )
|
|
|
|
|
{
|
|
|
|
|
// Geometry mode passes the input on to the current modifier.
|
|
|
|
|
if( CurrentModifier )
|
|
|
|
|
{
|
|
|
|
|
bResult = CurrentModifier->InputDelta( InViewportClient, InViewport, InDrag, InRot, InScale );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FModeTool_GeometryModify::StartModify()
|
|
|
|
|
{
|
|
|
|
|
// Let the modifier do any set up work that it needs to.
|
|
|
|
|
if( CurrentModifier != NULL )
|
|
|
|
|
{
|
|
|
|
|
//Store the current state of the brush so that we can return to upon faulty operation
|
|
|
|
|
CurrentModifier->CacheBrushState();
|
|
|
|
|
|
|
|
|
|
return CurrentModifier->StartModify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear modified flag, so we can track if something actually changes before EndModify
|
|
|
|
|
bGeomModified = false;
|
|
|
|
|
|
|
|
|
|
// No modifier to start
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FModeTool_GeometryModify::EndModify()
|
|
|
|
|
{
|
|
|
|
|
// Let the modifier finish up.
|
|
|
|
|
if( CurrentModifier != NULL )
|
|
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
FEdModeGeometry* mode = ((FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_Geometry));
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
// Update the source data to match the current geometry data.
|
|
|
|
|
mode->SendToSource();
|
|
|
|
|
|
|
|
|
|
// Make sure the source data has remained viable.
|
|
|
|
|
if( mode->FinalizeSourceData() )
|
|
|
|
|
{
|
|
|
|
|
// If the source data was modified, reconstruct the geometry data to reflect that.
|
|
|
|
|
mode->GetFromSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentModifier->EndModify();
|
|
|
|
|
|
|
|
|
|
// Update internals.
|
|
|
|
|
for( FEdModeGeometry::TGeomObjectIterator Itor( mode->GeomObjectItor() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = *Itor;
|
2014-03-14 14:13:41 -04:00
|
|
|
go->ComputeData();
|
|
|
|
|
FBSPOps::bspUnlinkPolys( go->GetActualBrush()->Brush );
|
|
|
|
|
|
|
|
|
|
// If geometry was actually changed, call PostEditBrush
|
|
|
|
|
if(bGeomModified)
|
|
|
|
|
{
|
|
|
|
|
ABrush* Brush = go->GetActualBrush();
|
|
|
|
|
if(Brush)
|
|
|
|
|
{
|
|
|
|
|
if(!Brush->IsStaticBrush())
|
|
|
|
|
{
|
|
|
|
|
FBSPOps::csgPrepMovingBrush(Brush);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bGeomModified = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::StartTrans()
|
|
|
|
|
{
|
|
|
|
|
if( CurrentModifier != NULL )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->StartTrans();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::EndTrans()
|
|
|
|
|
{
|
|
|
|
|
if( CurrentModifier != NULL )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->EndTrans();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return true if the key was handled by this editor mode tool.
|
|
|
|
|
*/
|
2014-06-18 10:16:16 -04:00
|
|
|
bool FModeTool_GeometryModify::InputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
2014-06-18 10:16:16 -04:00
|
|
|
check( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Geometry ) );
|
2014-03-14 14:13:41 -04:00
|
|
|
// Give the current modifier a chance to handle this first
|
|
|
|
|
if( CurrentModifier && CurrentModifier->InputKey( ViewportClient, Viewport, Key, Event ) )
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Key == EKeys::Escape)
|
|
|
|
|
{
|
|
|
|
|
// Hitting ESC will deselect any subobjects first. If no subobjects are selected, then it will
|
|
|
|
|
// deselect the brushes themselves.
|
|
|
|
|
|
2014-06-18 10:16:16 -04:00
|
|
|
FEdModeGeometry* mode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_Geometry );
|
2014-03-14 14:13:41 -04:00
|
|
|
bool bHadSubObjectSelections = (mode->GetSelectionState() > 0) ? true : false;
|
|
|
|
|
|
|
|
|
|
for( FEdModeGeometry::TGeomObjectIterator Itor( mode->GeomObjectItor() ) ; Itor ; ++Itor )
|
|
|
|
|
{
|
2015-04-02 16:34:30 -04:00
|
|
|
FGeomObjectPtr go = *Itor;
|
2014-03-14 14:13:41 -04:00
|
|
|
|
|
|
|
|
for( int32 p = 0 ; p < go->PolyPool.Num() ; ++p )
|
|
|
|
|
{
|
|
|
|
|
FGeomPoly& gp = go->PolyPool[p];
|
|
|
|
|
if( gp.IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
gp.Select( false );
|
|
|
|
|
bHadSubObjectSelections = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( int32 e = 0 ; e < go->EdgePool.Num() ; ++e )
|
|
|
|
|
{
|
|
|
|
|
FGeomEdge& ge = go->EdgePool[e];
|
|
|
|
|
if( ge.IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
ge.Select( false );
|
|
|
|
|
bHadSubObjectSelections = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( int32 v = 0 ; v < go->VertexPool.Num() ; ++v )
|
|
|
|
|
{
|
|
|
|
|
FGeomVertex& gv = go->VertexPool[v];
|
|
|
|
|
if( gv.IsSelected() )
|
|
|
|
|
{
|
|
|
|
|
gv.Select( false );
|
|
|
|
|
bHadSubObjectSelections = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bHadSubObjectSelections )
|
|
|
|
|
{
|
|
|
|
|
GEditor->RedrawAllViewports();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return FModeTool::InputKey( ViewportClient, Viewport, Key, Event );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 10:16:16 -04:00
|
|
|
void FModeTool_GeometryModify::DrawHUD(FEditorViewportClient* ViewportClient,FViewport* Viewport,const FSceneView* View,FCanvas* Canvas)
|
2014-03-14 14:13:41 -04:00
|
|
|
{
|
|
|
|
|
// Give the current modifier a chance to draw a HUD
|
|
|
|
|
|
|
|
|
|
if( CurrentModifier )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->DrawHUD( ViewportClient, Viewport, View, Canvas );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::Render(const FSceneView* View,FViewport* Viewport,FPrimitiveDrawInterface* PDI)
|
|
|
|
|
{
|
|
|
|
|
// Give the current modifier a chance to render
|
|
|
|
|
|
|
|
|
|
if( CurrentModifier )
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->Render( View, Viewport, PDI );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FModeTool_GeometryModify::StoreAllCurrentGeomSelections()
|
|
|
|
|
{
|
|
|
|
|
if (CurrentModifier)
|
|
|
|
|
{
|
|
|
|
|
CurrentModifier->StoreAllCurrentGeomSelections();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|