742 lines
29 KiB
C++
742 lines
29 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Containers/Array.h"
|
|
#include "Containers/Map.h"
|
|
#include "Delegates/Delegate.h"
|
|
#include "EdMode.h"
|
|
#include "Engine/EngineBaseTypes.h"
|
|
#include "HAL/PlatformCrt.h"
|
|
#include "InputCoreTypes.h"
|
|
#include "InstancedFoliage.h"
|
|
#include "Internationalization/Text.h"
|
|
#include "Math/Axis.h"
|
|
#include "Math/Box.h"
|
|
#include "Math/Color.h"
|
|
#include "Math/Rotator.h"
|
|
#include "Math/Sphere.h"
|
|
#include "Math/UnrealMathSSE.h"
|
|
#include "Math/Vector.h"
|
|
#include "Templates/SharedPointer.h"
|
|
#include "Templates/UniquePtr.h"
|
|
#include "UnrealWidgetFwd.h"
|
|
#include "Widgets/Views/SHeaderRow.h"
|
|
|
|
class AActor;
|
|
class AInstancedFoliageActor;
|
|
class FCanvas;
|
|
class FEditorViewportClient;
|
|
class FName;
|
|
class FPrimitiveDrawInterface;
|
|
class FReferenceCollector;
|
|
class FSceneView;
|
|
class FUICommandList;
|
|
class FViewport;
|
|
class HHitProxy;
|
|
class UClass;
|
|
class UFoliageType;
|
|
class ULandscapeComponent;
|
|
class ULevel;
|
|
class UObject;
|
|
class UPrimitiveComponent;
|
|
class UStaticMeshComponent;
|
|
class UWorld;
|
|
struct FAssetData;
|
|
struct FHitResult;
|
|
struct FViewportClick;
|
|
template <typename FuncType> class TFunctionRef;
|
|
|
|
/** View modes supported by the foliage palette */
|
|
namespace EFoliagePaletteViewMode
|
|
{
|
|
enum Type
|
|
{
|
|
Thumbnail,
|
|
Tree
|
|
};
|
|
}
|
|
|
|
/** Single instance mode */
|
|
namespace EFoliageSingleInstantiationPlacementMode
|
|
{
|
|
enum class Type
|
|
{
|
|
All,
|
|
CycleThrough,
|
|
ModeCount
|
|
};
|
|
};
|
|
|
|
const float SingleInstanceModeBrushSize = 20.0f;
|
|
|
|
// Current user settings in Foliage UI
|
|
struct FFoliageUISettings
|
|
{
|
|
void Load();
|
|
void Save();
|
|
|
|
// Window
|
|
void SetWindowSizePos(int32 NewX, int32 NewY, int32 NewWidth, int32 NewHeight) { WindowX = NewX; WindowY = NewY; WindowWidth = NewWidth; WindowHeight = NewHeight; }
|
|
void GetWindowSizePos(int32& OutX, int32& OutY, int32& OutWidth, int32& OutHeight) { OutX = WindowX; OutY = WindowY; OutWidth = WindowWidth; OutHeight = WindowHeight; }
|
|
|
|
// tool
|
|
bool GetPaintToolSelected() const { return bPaintToolSelected ? true : false; }
|
|
void SetPaintToolSelected(bool InbPaintToolSelected) { bPaintToolSelected = InbPaintToolSelected; }
|
|
bool GetReapplyToolSelected() const { return bReapplyToolSelected ? true : false; }
|
|
void SetReapplyToolSelected(bool InbReapplyToolSelected) { bReapplyToolSelected = InbReapplyToolSelected; }
|
|
bool GetSelectToolSelected() const { return bSelectToolSelected ? true : false; }
|
|
void SetSelectToolSelected(bool InbSelectToolSelected) { bSelectToolSelected = InbSelectToolSelected; }
|
|
bool GetLassoSelectToolSelected() const { return bLassoSelectToolSelected ? true : false; }
|
|
void SetLassoSelectToolSelected(bool InbLassoSelectToolSelected) { bLassoSelectToolSelected = InbLassoSelectToolSelected; }
|
|
bool GetPaintBucketToolSelected() const { return bPaintBucketToolSelected ? true : false; }
|
|
void SetPaintBucketToolSelected(bool InbPaintBucketToolSelected) { bPaintBucketToolSelected = InbPaintBucketToolSelected; }
|
|
bool GetReapplyPaintBucketToolSelected() const { return bReapplyPaintBucketToolSelected ? true : false; }
|
|
void SetReapplyPaintBucketToolSelected(bool InbReapplyPaintBucketToolSelected) { bReapplyPaintBucketToolSelected = InbReapplyPaintBucketToolSelected; }
|
|
bool GetEraseToolSelected() const { return bEraseToolSelected ? true : false; }
|
|
void SetEraseToolSelected(bool InbEraseToolSelected) { bEraseToolSelected = InbEraseToolSelected; }
|
|
|
|
float GetRadius() const { return (IsInAnySingleInstantiationMode()) ? SingleInstanceModeBrushSize : Radius; }
|
|
void SetRadius(float InRadius) { if (!IsInAnySingleInstantiationMode()) Radius = InRadius; }
|
|
float GetPaintDensity() const { return PaintDensity; }
|
|
void SetPaintDensity(float InPaintDensity) { PaintDensity = InPaintDensity; }
|
|
float GetUnpaintDensity() const { return UnpaintDensity; }
|
|
void SetUnpaintDensity(float InUnpaintDensity) { UnpaintDensity = InUnpaintDensity; }
|
|
bool GetFilterLandscape() const { return bFilterLandscape ? true : false; }
|
|
void SetFilterLandscape(bool InbFilterLandscape) { bFilterLandscape = InbFilterLandscape; }
|
|
bool GetFilterStaticMesh() const { return bFilterStaticMesh ? true : false; }
|
|
void SetFilterStaticMesh(bool InbFilterStaticMesh) { bFilterStaticMesh = InbFilterStaticMesh; }
|
|
bool GetFilterBSP() const { return bFilterBSP ? true : false; }
|
|
void SetFilterBSP(bool InbFilterBSP) { bFilterBSP = InbFilterBSP; }
|
|
bool GetFilterFoliage() const { return bFilterFoliage; }
|
|
void SetFilterFoliage(bool InbFilterFoliage) { bFilterFoliage = InbFilterFoliage; }
|
|
bool GetFilterTranslucent() const { return bFilterTranslucent; }
|
|
void SetFilterTranslucent(bool InbFilterTranslucent) { bFilterTranslucent = InbFilterTranslucent; }
|
|
|
|
bool IsInAnySingleInstantiationMode() const { return GetIsInSingleInstantiationMode() || GetIsInQuickSingleInstantiationMode(); }
|
|
|
|
bool GetIsInSingleInstantiationMode() const { return IsInSingleInstantiationMode; }
|
|
void SetIsInSingleInstantiationMode(bool InIsInSingleInstantiationMode) { IsInSingleInstantiationMode = InIsInSingleInstantiationMode; }
|
|
|
|
bool GetIsInQuickSingleInstantiationMode() const { return IsInQuickSingleInstantiationMode; }
|
|
void SetIsInQuickSingleInstantiationMode(bool InIsInQuickSingleInstantiationMode) { IsInQuickSingleInstantiationMode = InIsInQuickSingleInstantiationMode; }
|
|
|
|
bool IsInAnyEraseMode() const { return GetEraseToolSelected() || GetIsInQuickEraseMode(); }
|
|
bool GetIsInQuickEraseMode() const { return IsInQuickEraseMode; }
|
|
void SetIsInQuickEraseMode(bool InIsInQuickEraseMode) { IsInQuickEraseMode = InIsInQuickEraseMode; }
|
|
|
|
EFoliageSingleInstantiationPlacementMode::Type GetSingleInstantiationPlacementMode() const { return SingleInstantiationPlacementMode; }
|
|
void SetSingleInstantiationPlacementMode(EFoliageSingleInstantiationPlacementMode::Type InSingleInstantiationPlacementMode) { SingleInstantiationPlacementMode = InSingleInstantiationPlacementMode; }
|
|
|
|
int32 GetSingleInstantiationCycleThroughIndex() const { return SingleInstantiationCycleThroughIndex; }
|
|
void IncrementSingleInstantiationCycleThroughIndex() { SingleInstantiationCycleThroughIndex++; }
|
|
|
|
bool GetIsInSpawnInCurrentLevelMode() const { return IsInSpawnInCurrentLevelMode; }
|
|
void SetSpawnInCurrentLevelMode(bool InSpawnInCurrentLevelMode) { IsInSpawnInCurrentLevelMode = InSpawnInCurrentLevelMode; }
|
|
|
|
bool GetShowPaletteItemDetails() const { return bShowPaletteItemDetails; }
|
|
void SetShowPaletteItemDetails(bool InbShowPaletteItemDetails) { bShowPaletteItemDetails = InbShowPaletteItemDetails; }
|
|
bool GetShowPaletteItemTooltips() const { return bShowPaletteItemTooltips; }
|
|
void SetShowPaletteItemTooltips(bool InbShowPaletteItemTooltips) { bShowPaletteItemTooltips = InbShowPaletteItemTooltips; }
|
|
EFoliagePaletteViewMode::Type GetActivePaletteViewMode() const { return ActivePaletteViewMode; }
|
|
void SetActivePaletteViewMode(EFoliagePaletteViewMode::Type InActivePaletteViewMode) { ActivePaletteViewMode = InActivePaletteViewMode; }
|
|
float GetPaletteThumbnailScale() const { return PaletteThumbnailScale; }
|
|
void SetPaletteThumbnailScale(float InThumbnailScale) { PaletteThumbnailScale = InThumbnailScale; }
|
|
|
|
FFoliageUISettings()
|
|
: WindowX(-1)
|
|
, WindowY(-1)
|
|
, WindowWidth(284)
|
|
, WindowHeight(400)
|
|
, bPaintToolSelected(true)
|
|
, bReapplyToolSelected(false)
|
|
, bSelectToolSelected(false)
|
|
, bLassoSelectToolSelected(false)
|
|
, bPaintBucketToolSelected(false)
|
|
, bReapplyPaintBucketToolSelected(false)
|
|
, bEraseToolSelected(false)
|
|
, bShowPaletteItemDetails(true)
|
|
, bShowPaletteItemTooltips(true)
|
|
, ActivePaletteViewMode(EFoliagePaletteViewMode::Thumbnail)
|
|
, PaletteThumbnailScale(0.3f)
|
|
, Radius(250.f)
|
|
, PaintDensity(0.5f)
|
|
, UnpaintDensity(0.f)
|
|
, IsInSingleInstantiationMode(false)
|
|
, IsInQuickSingleInstantiationMode(false)
|
|
, IsInQuickEraseMode(false)
|
|
, SingleInstantiationPlacementMode(EFoliageSingleInstantiationPlacementMode::Type::All)
|
|
, SingleInstantiationCycleThroughIndex(0)
|
|
, IsInSpawnInCurrentLevelMode(false)
|
|
, bFilterLandscape(true)
|
|
, bFilterStaticMesh(true)
|
|
, bFilterBSP(true)
|
|
, bFilterFoliage(false)
|
|
, bFilterTranslucent(false)
|
|
{
|
|
}
|
|
|
|
~FFoliageUISettings()
|
|
{
|
|
}
|
|
|
|
private:
|
|
int32 WindowX;
|
|
int32 WindowY;
|
|
int32 WindowWidth;
|
|
int32 WindowHeight;
|
|
|
|
bool bPaintToolSelected;
|
|
bool bReapplyToolSelected;
|
|
bool bSelectToolSelected;
|
|
bool bLassoSelectToolSelected;
|
|
bool bPaintBucketToolSelected;
|
|
bool bReapplyPaintBucketToolSelected;
|
|
bool bEraseToolSelected;
|
|
|
|
bool bShowPaletteItemDetails;
|
|
bool bShowPaletteItemTooltips;
|
|
EFoliagePaletteViewMode::Type ActivePaletteViewMode;
|
|
float PaletteThumbnailScale;
|
|
|
|
float Radius;
|
|
float PaintDensity;
|
|
float UnpaintDensity;
|
|
|
|
bool IsInSingleInstantiationMode;
|
|
bool IsInQuickSingleInstantiationMode;
|
|
bool IsInQuickEraseMode;
|
|
EFoliageSingleInstantiationPlacementMode::Type SingleInstantiationPlacementMode;
|
|
int32 SingleInstantiationCycleThroughIndex;
|
|
bool IsInSpawnInCurrentLevelMode;
|
|
|
|
public:
|
|
bool bFilterLandscape;
|
|
bool bFilterStaticMesh;
|
|
bool bFilterBSP;
|
|
bool bFilterFoliage;
|
|
bool bFilterTranslucent;
|
|
};
|
|
|
|
|
|
struct FFoliageMeshUIInfo
|
|
{
|
|
TObjectPtr<UFoliageType> Settings;
|
|
int32 InstanceCountCurrentLevel;
|
|
int32 InstanceCountTotal;
|
|
|
|
FFoliageMeshUIInfo(UFoliageType* InSettings);
|
|
|
|
bool operator == (const FFoliageMeshUIInfo& Other) const
|
|
{
|
|
return Settings == Other.Settings;
|
|
}
|
|
|
|
FText GetNameText() const;
|
|
};
|
|
|
|
typedef TSharedPtr<FFoliageMeshUIInfo> FFoliageMeshUIInfoPtr;
|
|
|
|
// Snapshot of current MeshInfo state. Created at start of a brush stroke to store the existing instance info.
|
|
class FMeshInfoSnapshot
|
|
{
|
|
FFoliageInstanceHash Hash;
|
|
TArray<FVector> Locations;
|
|
public:
|
|
FMeshInfoSnapshot(FFoliageInfo* MeshInfo)
|
|
: Hash(*MeshInfo->InstanceHash)
|
|
{
|
|
int32 NumInstances = MeshInfo->Instances.Num();
|
|
Locations.Reserve(NumInstances);
|
|
Locations.AddUninitialized(NumInstances);
|
|
for (int32 Idx = 0; Idx < NumInstances; Idx++)
|
|
{
|
|
Locations[Idx] = MeshInfo->Instances[Idx].Location;
|
|
}
|
|
}
|
|
|
|
int32 CountInstancesInsideSphere(const FSphere& Sphere) const
|
|
{
|
|
int32 Count = 0;
|
|
|
|
auto TempInstances = Hash.GetInstancesOverlappingBox(FBox::BuildAABB(Sphere.Center, FVector(Sphere.W)));
|
|
for (int32 Idx : TempInstances)
|
|
{
|
|
if (FSphere(Locations[Idx], 0.f).IsInside(Sphere))
|
|
{
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Painting filtering options
|
|
//
|
|
struct FFoliagePaintingGeometryFilter
|
|
{
|
|
bool bAllowLandscape;
|
|
bool bAllowStaticMesh;
|
|
bool bAllowBSP;
|
|
bool bAllowFoliage;
|
|
bool bAllowTranslucent;
|
|
|
|
FFoliagePaintingGeometryFilter(const FFoliageUISettings& InUISettings)
|
|
: bAllowLandscape(InUISettings.bFilterLandscape)
|
|
, bAllowStaticMesh(InUISettings.bFilterStaticMesh)
|
|
, bAllowBSP(InUISettings.bFilterBSP)
|
|
, bAllowFoliage(InUISettings.bFilterFoliage)
|
|
, bAllowTranslucent(InUISettings.bFilterTranslucent)
|
|
{
|
|
}
|
|
|
|
FFoliagePaintingGeometryFilter()
|
|
: bAllowLandscape(false)
|
|
, bAllowStaticMesh(false)
|
|
, bAllowBSP(false)
|
|
, bAllowFoliage(false)
|
|
, bAllowTranslucent(false)
|
|
{
|
|
}
|
|
|
|
bool operator() (const UPrimitiveComponent* Component) const;
|
|
};
|
|
|
|
|
|
// Number of buckets for layer weight histogram distribution.
|
|
#define NUM_INSTANCE_BUCKETS 10
|
|
|
|
enum class EFoliageEditingState : uint8
|
|
{
|
|
Unknown,
|
|
Enabled,
|
|
PIEWorld,
|
|
SIEWorld,
|
|
};
|
|
/**
|
|
* Foliage editor mode
|
|
*/
|
|
class FEdModeFoliage : public FEdMode
|
|
{
|
|
public:
|
|
FFoliageUISettings UISettings;
|
|
|
|
/** Command list lives here so that the key bindings on the commands can be processed in the viewport. */
|
|
TSharedPtr<FUICommandList> UICommandList;
|
|
|
|
/** Constructor */
|
|
FEdModeFoliage();
|
|
|
|
/** Destructor */
|
|
virtual ~FEdModeFoliage();
|
|
|
|
/** FGCObject interface */
|
|
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
|
|
|
|
/** FEdMode: Called when the mode is entered */
|
|
virtual void Enter() override;
|
|
|
|
/** FEdMode: Called when the mode is exited */
|
|
virtual void Exit() override;
|
|
|
|
/** FEdMode: Called after an Undo operation */
|
|
virtual void PostUndo() override;
|
|
|
|
virtual bool UsesToolkits() const override { return true; }
|
|
|
|
/** Called when the current level changes */
|
|
void NotifyNewCurrentLevel();
|
|
void NotifyLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld);
|
|
void NotifyLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld);
|
|
|
|
/** Called when asset is removed */
|
|
void NotifyAssetRemoved(const FAssetData& AssetInfo);
|
|
|
|
/** Called when actor foliage selection changes */
|
|
void NotifyActorSelectionChanged(bool bSelect, const TArray<AActor*>& Selection);
|
|
|
|
/**
|
|
* Called when the mouse is moved over the viewport
|
|
*
|
|
* @param InViewportClient Level editor viewport client that captured the mouse input
|
|
* @param InViewport Viewport that captured the mouse input
|
|
* @param InMouseX New mouse cursor X coordinate
|
|
* @param InMouseY New mouse cursor Y coordinate
|
|
*
|
|
* @return true if input was handled
|
|
*/
|
|
virtual bool MouseMove(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y) override;
|
|
|
|
/**
|
|
* FEdMode: Called when the mouse is moved while a window input capture is in effect
|
|
*
|
|
* @param InViewportClient Level editor viewport client that captured the mouse input
|
|
* @param InViewport Viewport that captured the mouse input
|
|
* @param InMouseX New mouse cursor X coordinate
|
|
* @param InMouseY New mouse cursor Y coordinate
|
|
*
|
|
* @return true if input was handled
|
|
*/
|
|
virtual bool CapturedMouseMove(FEditorViewportClient* InViewportClient, FViewport* InViewport, int32 InMouseX, int32 InMouseY) override;
|
|
|
|
/** FEdMode: Called when a mouse button is pressed */
|
|
virtual bool StartTracking(FEditorViewportClient* InViewportClient, FViewport* InViewport) override;
|
|
|
|
/** FEdMode: Called when a mouse button is released */
|
|
virtual bool EndTracking(FEditorViewportClient* InViewportClient, FViewport* InViewport) override;
|
|
|
|
/** FEdMode: Called once per frame */
|
|
virtual void Tick(FEditorViewportClient* ViewportClient, float DeltaTime) override;
|
|
|
|
/** FEdMode: Called when a key is pressed */
|
|
virtual bool InputKey(FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey, EInputEvent InEvent) override;
|
|
|
|
/** FEdMode: Called when mouse drag input it applied */
|
|
virtual bool InputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDrag, FRotator& InRot, FVector& InScale) override;
|
|
|
|
/** FEdMode: Render elements for the Foliage tool */
|
|
virtual void Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) override;
|
|
|
|
/** FEdMode: Render HUD elements for this tool */
|
|
virtual void DrawHUD(FEditorViewportClient* ViewportClient, FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) override;
|
|
|
|
/** FEdMode: Handling SelectActor */
|
|
virtual bool Select(AActor* InActor, bool bInSelected) override;
|
|
|
|
/** FEdMode: Check to see if an actor can be selected in this mode - no side effects */
|
|
virtual bool IsSelectionAllowed(AActor* InActor, bool bInSelection) const override;
|
|
|
|
/** FEdMode: Called when the currently selected actor has changed */
|
|
virtual void ActorSelectionChangeNotify() override;
|
|
|
|
/** Notifies all active modes of mouse click messages. */
|
|
bool HandleClick(FEditorViewportClient* InViewportClient, HHitProxy *HitProxy, const FViewportClick &Click) override;
|
|
|
|
/** Moves selected foliage instances to the target level. */
|
|
void MoveSelectedFoliageToLevel(ULevel* InTargetLevel);
|
|
|
|
/** Tell us if we can moves selected foliage instances to the target level. */
|
|
bool CanMoveSelectedFoliageToLevel(ULevel* InTargetLevel) const;
|
|
|
|
/** Moves selected foliage instances to the current actor editor context */
|
|
void MoveSelectedFoliageToActorEditorContext();
|
|
|
|
/** Ends tracking and end potential transaction */
|
|
bool EndTracking();
|
|
|
|
/** FEdMode: widget handling */
|
|
virtual FVector GetWidgetLocation() const override;
|
|
virtual bool AllowWidgetMove() override;
|
|
virtual bool ShouldDrawWidget() const override;
|
|
virtual bool UsesTransformWidget() const override;
|
|
virtual EAxisList::Type GetWidgetAxisToDraw(UE::Widget::EWidgetMode InWidgetMode) const override;
|
|
|
|
virtual bool DisallowMouseDeltaTracking() const override;
|
|
|
|
/** Called when objects are replaced (after a BP compile for instance) */
|
|
void OnObjectsReplaced(const TMap<UObject*, UObject*>& ReplacementMap);
|
|
|
|
/** Forces real-time perspective viewports */
|
|
void ForceRealTimeViewports(const bool bEnable);
|
|
|
|
/** Start foliage tracing */
|
|
void StartFoliageBrushTrace(FEditorViewportClient* ViewportClient, class UViewportInteractor* Interactor = nullptr);
|
|
|
|
/* End foliage tracing*/
|
|
void EndFoliageBrushTrace();
|
|
|
|
/** Trace under the mouse cursor and update brush position */
|
|
void FoliageBrushTrace(FEditorViewportClient* ViewportClient, const FVector& InRayOrigin, const FVector& InRayDirection);
|
|
|
|
/** Generate start/end points for a random trace inside the sphere brush.
|
|
returns a line segment inside the sphere parallel to the view direction */
|
|
void GetRandomVectorInBrush(FVector& OutStart, FVector& OutEnd);
|
|
|
|
/** Setup before call to ApplyBrush */
|
|
void PreApplyBrush();
|
|
|
|
/** Apply brush */
|
|
void ApplyBrush(FEditorViewportClient* ViewportClient);
|
|
|
|
/** Get list of meshes for current level */
|
|
TArray<FFoliageMeshUIInfoPtr>& GetFoliageMeshList();
|
|
|
|
/** Populate mesh with foliage mesh settings found across world */
|
|
void PopulateFoliageMeshList();
|
|
|
|
/** Handler for mesh list sort mode changes */
|
|
void OnFoliageMeshListSortModeChanged(EColumnSortMode::Type InSortMode);
|
|
|
|
/** Returns foliage mesh list sort mode */
|
|
EColumnSortMode::Type GetFoliageMeshListSortMode() const;
|
|
|
|
/** Handler for foliage mesh instance count changes */
|
|
void OnInstanceCountUpdated(const UFoliageType* FoliageType);
|
|
|
|
/** Counts total number of instances in current level and across whole world */
|
|
void CalcTotalInstanceCount(int32& OutInstanceCountTotal, int32& OutInstanceCountCurrentLevel);
|
|
|
|
/** Whether any of the selected foliage types can be painted into level */
|
|
bool CanPaint(const ULevel* InLevel);
|
|
|
|
/** Whether specified FoliageType can be painted into level */
|
|
static bool CanPaint(const UFoliageType* FoliageType, const ULevel* InLevel);
|
|
|
|
/** Shift or modifier button pressed */
|
|
bool IsModifierButtonPressed(const FEditorViewportClient* ViewportClient) const;
|
|
|
|
/** Add a new asset (FoliageType or StaticMesh) */
|
|
UFoliageType* AddFoliageAsset(UObject* InAsset, bool bInPlaceholderAsset = false);
|
|
|
|
/** Remove a list of Foliage types */
|
|
bool RemoveFoliageType(UFoliageType** FoliageTypes, int32 Num);
|
|
|
|
/** Reapply cluster settings to all the instances */
|
|
void ReallocateClusters(UFoliageType* Settings);
|
|
|
|
/** Bake meshes to StaticMeshActors */
|
|
void BakeFoliage(UFoliageType* Settings, bool bSelectedOnly);
|
|
|
|
/**
|
|
* Copy the settings object for this static mesh
|
|
*
|
|
* @param StaticMesh The static mesh to copy the settings of.
|
|
*
|
|
* @return The duplicated settings now assigned to the static mesh.
|
|
*/
|
|
UFoliageType* CopySettingsObject(UFoliageType* Settings);
|
|
|
|
/** Replace the settings object for this static mesh with the one specified */
|
|
void ReplaceSettingsObject(UFoliageType* OldSettings, UFoliageType* NewSettings);
|
|
|
|
/** Save the foliage type object. If it isn't an asset, will prompt the user for a location to save the new asset. */
|
|
UFoliageType* SaveFoliageTypeObject(UFoliageType* Settings, bool bPlaceholderAsset = false);
|
|
|
|
void IncludeNonFoliageActors(const TArray<const UFoliageType*>& FoliageTypes, bool bOnlyCurrentLevel);
|
|
|
|
void ExcludeFoliageActors(const TArray<const UFoliageType*>& FoliageTypes, bool bOnlyCurrentLevel);
|
|
|
|
/** Set/Clear selection for foliage instances of a specific types */
|
|
void SelectInstances(const TArray<const UFoliageType*>& FoliageTypes, bool bSelect);
|
|
|
|
/** Set/Clear selection for foliage instances of specific type */
|
|
void SelectInstances(const UFoliageType* Settings, bool bSelect);
|
|
|
|
/*Focus on selected instances*/
|
|
void FocusSelectedInstances() const;
|
|
|
|
/** Find and select instances that don't have valid base or 'off-ground' */
|
|
void SelectInvalidInstances(const TArray<const UFoliageType*>& FoliageTypes);
|
|
|
|
/** Find and select instances that don't have valid base or 'off-ground' */
|
|
void SelectInvalidInstances(const UFoliageType* Settings);
|
|
|
|
/** Returns selected foliage types based on selected foliage instances */
|
|
void GetSelectedInstanceFoliageTypes(TArray<const UFoliageType*>& OutFoliageTypes) const;
|
|
|
|
/** Adjusts the radius of the foliage brush, using the given multiplier to adjust speed */
|
|
void AdjustBrushRadius(float Multiplier);
|
|
|
|
/** Adjusts the painting density of the foliage brush, using the given multiplier to adjust speed */
|
|
void AdjustPaintDensity(float Multiplier);
|
|
|
|
/** Adjusts the unpainting (erasing) density of the foliage brush, using the given multiplier to adjust speed */
|
|
void AdjustUnpaintDensity(float Multiplier);
|
|
|
|
/** Add desired instances. Uses foliage settings to determine location/scale/rotation and whether instances should be ignored */
|
|
static void AddInstances(UWorld* InWorld, const TArray<FDesiredFoliageInstance>& DesiredInstances, const FFoliagePaintingGeometryFilter& OverrideGeometryFilter, bool InRebuildFoliageTree = true);
|
|
|
|
/** Called as PIE ends */
|
|
void OnEndPIE(const bool bIsSimulating);
|
|
|
|
/** Return the current foliage editing state */
|
|
EFoliageEditingState GetEditingState() const;
|
|
|
|
/** Simgple wrapper to know if we can edit foliage based on edit state */
|
|
bool IsEditingEnabled() const
|
|
{
|
|
return GetEditingState() == EFoliageEditingState::Enabled;
|
|
}
|
|
|
|
typedef TMap<FName, TMap<ULandscapeComponent*, TArray<uint8> > > LandscapeLayerCacheData;
|
|
|
|
FSimpleMulticastDelegate OnToolChanged;
|
|
|
|
/** Sets the tool mode to Paint. */
|
|
void OnSetPaint();
|
|
|
|
/** Sets the tool mode to Reapply Settings. */
|
|
void OnSetReapplySettings();
|
|
|
|
/** Sets the tool mode to Select. */
|
|
void OnSetSelectInstance();
|
|
|
|
/** Sets the tool mode to Lasso Select. */
|
|
void OnSetLasso();
|
|
|
|
/** Sets the tool mode to Paint Bucket. */
|
|
void OnSetPaintFill();
|
|
|
|
/** Sets the tool mode to Erase */
|
|
void OnSetErase();
|
|
|
|
/** Sets the tool mode to Place Single Instance*/
|
|
void OnSetPlace();
|
|
|
|
/** Handle reflecting selected foliage types in the FoliagePalette */
|
|
void OnReflectSelectionInPalette();
|
|
|
|
/** Remove currently selected instances*/
|
|
void RemoveSelectedInstances(UWorld* InWorld);
|
|
|
|
/** Returns the list of valid FoliageType class filters */
|
|
void GetFoliageTypeFilters(TArray<const UClass*>& OutFilters) const;
|
|
|
|
/*Find the relevant foliage actor with the foliage type and run the operation*/
|
|
static void ForEachFoliageInfo(UWorld* InWorld, const UFoliageType* FoliageType, const FSphere& BrushSphere, TFunctionRef<bool(AInstancedFoliageActor* IFA, FFoliageInfo* FoliageInfo, const UFoliageType* FoliageType)> InOperation);
|
|
|
|
private:
|
|
|
|
void BindCommands();
|
|
bool CurrentToolUsesBrush() const;
|
|
|
|
/** Called when the user changes the current tool in the UI */
|
|
void HandleToolChanged();
|
|
|
|
/** Deselects all tools */
|
|
void ClearAllToolSelection();
|
|
|
|
/** Add instances inside the brush to match DesiredInstanceCount */
|
|
void AddInstancesForBrush(UWorld* InWorld, const UFoliageType* Settings, const FSphere& BrushSphere, int32 DesiredInstanceCount, float Pressure);
|
|
|
|
/** Add single instance inside the brush
|
|
* @return true if instance was added successfully
|
|
*/
|
|
bool AddSingleInstanceForBrush(UWorld* InWorld, const UFoliageType* Settings, float Pressure);
|
|
|
|
/** Remove instances inside the brush to match DesiredInstanceCount. */
|
|
void RemoveInstancesForBrush(UWorld* InWorld, const UFoliageType* Settings, const FSphere& BrushSphere, int32 DesiredInstanceCount, float Pressure);
|
|
|
|
/** Apply paint bucket to actor */
|
|
void ApplyPaintBucket_Add(AActor* Actor);
|
|
void ApplyPaintBucket_Remove(AActor* Actor);
|
|
|
|
/** Reapply instance settings to exiting instances */
|
|
void ReapplyInstancesDensityForBrush(UWorld* InWorld, const UFoliageType* Settings, const FSphere& BrushSphere, float Pressure);
|
|
void ReapplyInstancesForBrush(UWorld* InWorld, const UFoliageType* Settings, const FSphere& BrushSphere, float Pressure, bool bSingleInstanceMode);
|
|
void ReapplyInstancesForBrush(UWorld* InWorld, AInstancedFoliageActor* IFA, const UFoliageType* Settings, FFoliageInfo* MeshInfo, const FSphere& BrushSphere, float Pressure, bool bSingleInstanceMode);
|
|
|
|
/** Select instances inside the brush. */
|
|
void SelectInstancesForBrush(UWorld* InWorld, const UFoliageType* Settings, const FSphere& BrushSphere, bool bSelect);
|
|
|
|
/** Select instance closest to the brush. */
|
|
void SelectInstanceAtLocation(UWorld* InWorld, const UFoliageType* Settings, const FVector& BrushLocation, bool bSelect);
|
|
|
|
/** Set/Clear selection for all foliage instances */
|
|
void SelectInstances(UWorld* InWorld, bool bSelect);
|
|
|
|
/** Set/Clear selection for foliage instances of specific type */
|
|
void SelectInstances(UWorld* InWorld, const UFoliageType* Settings, bool bSelect);
|
|
|
|
/** Propagate the selected foliage instances to the actual render foliage */
|
|
void ApplySelection(UWorld* InWorld, bool bApply);
|
|
|
|
/** Update Instances so that they are in the right partitioning level */
|
|
void UpdateInstancePartitioning(UWorld* InWorld);
|
|
|
|
/** Called when transform transaction is done */
|
|
void PostTransformSelectedInstances(UWorld* InWorld);
|
|
|
|
/** Applies relative transformation to selected instances */
|
|
void TransformSelectedInstances(UWorld* InWorld, const FVector& InDrag, const FRotator& InRot, const FVector& InScale, bool bDuplicate);
|
|
|
|
/** Return true if OutLocation is valid */
|
|
bool GetSelectionLocation(UWorld* InWorld, FVector& OutLocation) const;
|
|
|
|
/** Updates ed mode widget location to currently selected instance */
|
|
void UpdateWidgetLocationToInstanceSelection();
|
|
|
|
/** Snap instance to the ground */
|
|
bool SnapInstanceToGround(AInstancedFoliageActor* InIFA, const UFoliageType* Settings, FFoliageInfo& Mesh, int32 InstanceIdx);
|
|
void SnapSelectedInstancesToGround(UWorld* InWorld);
|
|
|
|
/** Callback for when an actor is spawned (to check if it's a new IFA) */
|
|
void HandleOnActorSpawned(AActor* Actor);
|
|
|
|
/** Callback for when the mesh assigned to a foliage type referenced by an IFA is changed */
|
|
void HandleOnFoliageTypeMeshChanged(UFoliageType* FoliageType);
|
|
|
|
/** Common code for adding instances to world based on settings */
|
|
static bool AddInstancesImp(UWorld* InWorld, const UFoliageType* Settings, const TArray<FDesiredFoliageInstance>& DesiredInstances, const TArray<int32>& ExistingInstances = TArray<int32>(), const float Pressure = 1.f, LandscapeLayerCacheData* LandscapeLayerCaches = nullptr, const FFoliageUISettings* UISettings = nullptr, const FFoliagePaintingGeometryFilter* OverrideGeometryFilter = nullptr, bool InRebuildFoliageTree = true);
|
|
|
|
/** Logic for determining which instances can be placed in the world*/
|
|
static void CalculatePotentialInstances(UWorld* InWorld, const UFoliageType* Settings, const TArray<FDesiredFoliageInstance>& DesiredInstances, TArray<FPotentialInstance> OutPotentialInstances[NUM_INSTANCE_BUCKETS], LandscapeLayerCacheData* LandscaleLayerCachesPtr, const FFoliageUISettings* UISettings, const FFoliagePaintingGeometryFilter* OverrideGeometryFilter = nullptr);
|
|
|
|
/** Similar to CalculatePotentialInstances, but it doesn't do any overlap checks which are much harder to thread. Meant to be run in parallel for placing lots of instances */
|
|
static void CalculatePotentialInstances_ThreadSafe(UWorld* InWorld, const UFoliageType* Settings, const TArray<FDesiredFoliageInstance>* DesiredInstances, TArray<FPotentialInstance> OutPotentialInstances[NUM_INSTANCE_BUCKETS], const FFoliageUISettings* UISettings, const int32 StartIdx, const int32 LastIdx, const FFoliagePaintingGeometryFilter* OverrideGeometryFilter = nullptr);
|
|
|
|
/** Lookup the vertex color corresponding to a location traced on a static mesh */
|
|
static bool GetStaticMeshVertexColorForHit(const UStaticMeshComponent* InStaticMeshComponent, int32 InTriangleIndex, const FVector& InHitLocation, FColor& OutVertexColor);
|
|
|
|
/** Returns true when at least one color channel is used by the vertex color mask */
|
|
static bool IsUsingVertexColorMask(const UFoliageType* Settings);
|
|
|
|
/** Does a filter based on the vertex color of a static mesh */
|
|
static bool VertexMaskCheck(const FHitResult& Hit, const UFoliageType* Settings);
|
|
|
|
/** Set the brush mesh opacity */
|
|
void SetBrushOpacity(const float InOpacity);
|
|
|
|
float GetPaintingBrushRadius() const;
|
|
|
|
/** Called if the foliage tree is outdated */
|
|
void RebuildFoliageTree(const UFoliageType* Settings);
|
|
|
|
/** Increments a counter that prevents sending out notifications until end selection is called and counter reaches 0 */
|
|
void BeginSelectionUpdate();
|
|
|
|
/** Decrements counter and will notify editor of selection change if counter reaches 0 */
|
|
void EndSelectionUpdate();
|
|
|
|
bool bBrushTraceValid;
|
|
FVector BrushLocation;
|
|
FVector BrushNormal;
|
|
FVector BrushTraceDirection;
|
|
TObjectPtr<UStaticMeshComponent> SphereBrushComponent;
|
|
|
|
/** The dynamic material of the sphere brush. */
|
|
class UMaterialInstanceDynamic* BrushMID;
|
|
FColor BrushDefaultHighlightColor;
|
|
FColor BrushCurrentHighlightColor;
|
|
|
|
/** Default opacity received from the brush material to reset it when closing. */
|
|
float DefaultBrushOpacity;
|
|
|
|
// Landscape layer cache data
|
|
LandscapeLayerCacheData LandscapeLayerCaches;
|
|
|
|
// Cache of instance positions at the start of the transaction
|
|
TMultiMap<UFoliageType*, FMeshInfoSnapshot> InstanceSnapshot;
|
|
|
|
bool bToolActive;
|
|
bool bCanAltDrag;
|
|
|
|
TArray<FFoliageMeshUIInfoPtr> FoliageMeshList;
|
|
EColumnSortMode::Type FoliageMeshListSortMode;
|
|
|
|
FDelegateHandle OnActorSpawnedHandle;
|
|
|
|
int32 UpdateSelectionCounter;
|
|
bool bHasDeferredSelectionNotification;
|
|
friend class FEdModeFoliageSelectionUpdate;
|
|
|
|
/** When transforming instances */
|
|
bool bMoving;
|
|
|
|
/** Flag to know when we are tracking a transaction in mouse delta */
|
|
bool bTracking;
|
|
};
|
|
|