Files
UnrealEngine/Engine/Plugins/Runtime/MeshModelingToolset/Source/MeshModelingTools/Public/AddPrimitiveTool.h
2025-05-18 13:04:45 +08:00

695 lines
24 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "BaseTools/SingleClickTool.h"
#include "CoreMinimal.h"
#include "InteractiveToolBuilder.h"
#include "PreviewMesh.h"
#include "Properties/MeshMaterialProperties.h"
#include "PropertySets/CreateMeshObjectTypeProperties.h"
#include "UObject/NoExportTypes.h"
#include "InteractiveToolQueryInterfaces.h"
#include "AddPrimitiveTool.generated.h"
#define UE_API MESHMODELINGTOOLS_API
PREDECLARE_USE_GEOMETRY_CLASS(FDynamicMesh3);
class UCombinedTransformGizmo;
class UDragAlignmentMechanic;
/**
* Builder
*/
UCLASS(MinimalAPI)
class UAddPrimitiveToolBuilder : public UInteractiveToolBuilder
{
GENERATED_BODY()
public:
enum class EMakeMeshShapeType : uint32
{
Box,
Cylinder,
Cone,
Arrow,
Rectangle,
Disc,
Torus,
Sphere,
Stairs,
Capsule
};
UE_API virtual bool CanBuildTool(const FToolBuilderState& SceneState) const override;
UE_API virtual UInteractiveTool* BuildTool(const FToolBuilderState& SceneState) const override;
EMakeMeshShapeType ShapeType{EMakeMeshShapeType::Box};
};
/** Placement Target Types */
UENUM()
enum class EMakeMeshPlacementType : uint8
{
GroundPlane = 0,
OnScene = 1,
AtOrigin = 2
};
/** Placement Pivot Location */
UENUM()
enum class EMakeMeshPivotLocation : uint8
{
Base,
Centered,
Top
};
/** PolyGroup mode for shape */
UENUM()
enum class EMakeMeshPolygroupMode : uint8
{
/** One PolyGroup for the entire shape */
PerShape,
/** One PolyGroup for each geometric face */
PerFace,
/** One PolyGroup for each quad/triangle */
PerQuad
};
UCLASS(MinimalAPI)
class UProceduralShapeToolProperties : public UInteractiveToolPropertySet
{
GENERATED_BODY()
public:
/** How PolyGroups are assigned to shape primitives. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (ProceduralShapeSetting, DisplayName = "PolyGroup Mode"))
EMakeMeshPolygroupMode PolygroupMode = EMakeMeshPolygroupMode::PerFace;
/** How the shape is placed in the scene. */
UPROPERTY(EditAnywhere, Category = Positioning, meta = (DisplayName = "Target Position"))
EMakeMeshPlacementType TargetSurface = EMakeMeshPlacementType::OnScene;
/** Location of pivot within the shape */
UPROPERTY(EditAnywhere, Category = Positioning, meta = (ProceduralShapeSetting))
EMakeMeshPivotLocation PivotLocation = EMakeMeshPivotLocation::Base;
/** Initial rotation of the shape around its up axis, before placement. After placement, use the gizmo to control rotation. */
UPROPERTY(EditAnywhere, Category = Positioning, DisplayName = "Initial Rotation", meta = (UIMin = "0.0", UIMax = "360.0", EditCondition = "!bShowGizmoOptions", HideEditConditionToggle))
float Rotation = 0.0;
/** If true, aligns the shape along the normal of the surface it is placed on. */
UPROPERTY(EditAnywhere, Category = Positioning, meta = (EditCondition = "TargetSurface == EMakeMeshPlacementType::OnScene"))
bool bAlignToNormal = true;
/** Show a gizmo to allow the mesh to be repositioned after the initial placement click. */
UPROPERTY(EditAnywhere, Category = Positioning, meta = (EditCondition = "bShowGizmoOptions", EditConditionHides, HideEditConditionToggle))
bool bShowGizmo = true;
//~ Not user visible- used to hide the bShowGizmo option when not yet placed mesh.
UPROPERTY(meta = (TransientToolProperty))
bool bShowGizmoOptions = false;
};
UCLASS(MinimalAPI)
class UProceduralBoxToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Width of the box */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Width = 100.f;
/** Depth of the box */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Depth = 100.f;
/** Height of the box */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Height = 100.f;
/** Number of subdivisions along the width */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int WidthSubdivisions = 1;
/** Number of subdivisions along the depth */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int DepthSubdivisions = 1;
/** Number of subdivisions along the height */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int HeightSubdivisions = 1;
};
UENUM()
enum class EProceduralRectType
{
/** Create a rectangle */
Rectangle,
/** Create a rounded rectangle */
RoundedRectangle
};
UCLASS(MinimalAPI)
class UProceduralRectangleToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Type of rectangle */
UPROPERTY(EditAnywhere, Category = Shape)
EProceduralRectType RectangleType = EProceduralRectType::Rectangle;
/** Width of the rectangle */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Width = 100.f;
/** Depth of the rectangle */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Depth = 100.f;
/** Number of subdivisions along the width */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int WidthSubdivisions = 1;
/** Number of subdivisions along the depth */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int DepthSubdivisions = 1;
/** Whether to preserve the overall Width and Depth for a Rounded Rectangle, or to allow the rounded corners to extend outside those dimensions. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (EditCondition = "RectangleType == EProceduralRectType::RoundedRectangle"))
bool bMaintainDimension = true;
/** Radius of rounded corners. This is only available for Rounded Rectangles. */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting,
EditCondition = "RectangleType == EProceduralRectType::RoundedRectangle"))
float CornerRadius = 25.f;
/** Number of radial slices for each rounded corner. This is only available for Rounded Rectangles. */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting,
EditCondition = "RectangleType == EProceduralRectType::RoundedRectangle"))
int CornerSlices = 16;
};
UENUM()
enum class EProceduralDiscType
{
/** Create a disc */
Disc,
/** Create a disc with a hole */
PuncturedDisc
};
UCLASS(MinimalAPI)
class UProceduralDiscToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Type of disc */
UPROPERTY(EditAnywhere, Category = Shape)
EProceduralDiscType DiscType = EProceduralDiscType::Disc;
/** Radius of the disc */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Radius = 50.f;
/** Number of radial slices for the disc */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int RadialSlices = 16;
/** Number of radial subdivisions for each radial slice of the disc */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int RadialSubdivisions = 1;
/** Radius of the hole in the disc. This is only available for Punctured Discs. */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting,
EditCondition = "DiscType == EProceduralDiscType::PuncturedDisc"))
float HoleRadius = 25.f;
};
UCLASS(MinimalAPI)
class UProceduralTorusToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Major radius of the torus, measured from the torus center to the center of the torus tube */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float MajorRadius = 50.f;
/** Minor radius of the torus, measured from the center ot the torus tube to the tube surface */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float MinorRadius = 25.f;
/** Number of radial slices along the torus tube */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int MajorSlices = 16;
/** Number of radial slices around the torus tube */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int MinorSlices = 16;
};
UCLASS(MinimalAPI)
class UProceduralCylinderToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Radius of the cylinder */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Radius = 50.f;
/** Height of the cylinder */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Height = 200.f;
/** Number of radial slices for the cylinder */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int RadialSlices = 16;
/** Number of subdivisions along the height of the cylinder */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int HeightSubdivisions = 1;
};
UCLASS(MinimalAPI)
class UProceduralConeToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Radius of the cone */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Radius = 50.f;
/** Height of the cone */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Height = 200.f;
/** Number of radial slices for the cone */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "128", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int RadialSlices = 16;
/** Number of subdivisions along the height of the cone */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int HeightSubdivisions = 1;
};
UCLASS(MinimalAPI)
class UProceduralArrowToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Radius of the arrow shaft */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float ShaftRadius = 20.f;
/** Height of arrow shaft */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float ShaftHeight = 200.f;
/** Radius of the arrow head base */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float HeadRadius = 60.f;
/** Height of arrow head */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float HeadHeight = 120.f;
/** Number of radial slices for the arrow */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "100", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int RadialSlices = 16;
/** Number of subdivisions along each part of the arrow, i.e. shaft, head base, head cone */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting))
int HeightSubdivisions = 1;
};
UENUM()
enum class EProceduralSphereType
{
/** Create a Sphere with Lat Long parameterization */
LatLong,
/** Create a Sphere with Box parameterization */
Box
};
UCLASS(MinimalAPI)
class UProceduralSphereToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Radius of the sphere */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Radius = 50.f;
/** Type of subdivision for the sphere */
UPROPERTY(EditAnywhere, Category = Shape)
EProceduralSphereType SubdivisionType = EProceduralSphereType::Box;
/** Number of subdivisions for each side of the sphere. This is only available for spheres with Box subdivision. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1", UIMax = "100", ClampMin = "1", ClampMax = "500", ProceduralShapeSetting,
EditCondition = "SubdivisionType == EProceduralSphereType::Box"))
int Subdivisions = 16;
/** Number of horizontal slices of the sphere. This is only available for spheres with Lat Long subdivision. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "100", ClampMin = "4", ClampMax = "500", ProceduralShapeSetting,
EditCondition = "SubdivisionType == EProceduralSphereType::LatLong"))
int HorizontalSlices = 16;
/** Number of vertical slices of the sphere. This is only available for spheres with Lat Long subdivision. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "100", ClampMin = "4", ClampMax = "500", ProceduralShapeSetting,
EditCondition = "SubdivisionType == EProceduralSphereType::LatLong"))
int VerticalSlices = 16;
};
UCLASS(MinimalAPI)
class UProceduralCapsuleToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Radius of the capsule */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float Radius = 25.f;
/** Length of cylindrical section of the capsule */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float CylinderLength = 50.f;
/** Number of slices of the hemispherical end caps. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "2", UIMax = "100", ClampMin = "2", ClampMax = "500", ProceduralShapeSetting))
int HemisphereSlices = 8;
/** Number of radial slices of the cylindrical section. */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "3", UIMax = "100", ClampMin = "3", ClampMax = "500", ProceduralShapeSetting))
int CylinderSlices = 16;
/** Number of lengthwise subdivisions along cylindrical section */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "0", UIMax = "100", ClampMin = "0", ClampMax = "500", ProceduralShapeSetting))
int CylinderSubdivisions = 1;
};
UENUM()
enum class EProceduralStairsType
{
/** Create a linear staircase */
Linear,
/** Create a floating staircase */
Floating,
/** Create a curved staircase */
Curved,
/** Create a spiral staircase */
Spiral
};
UCLASS(MinimalAPI)
class UProceduralStairsToolProperties : public UProceduralShapeToolProperties
{
GENERATED_BODY()
public:
/** Type of staircase */
UPROPERTY(EditAnywhere, Category = Shape)
EProceduralStairsType StairsType = EProceduralStairsType::Linear;
/** Number of steps */
UPROPERTY(EditAnywhere, Category = Shape, meta = (DisplayName = "Number of Steps", UIMin = "2", UIMax = "100", ClampMin = "2", ClampMax = "1000000", ProceduralShapeSetting))
int NumSteps = 8;
/** Width of each step */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float StepWidth = 150.0f;
/** Height of each step */
UPROPERTY(EditAnywhere, Category = Shape, meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting))
float StepHeight = 20.0f;
/** Depth of each step of linear stairs */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting,
EditCondition = "StairsType == EProceduralStairsType::Linear || StairsType == EProceduralStairsType::Floating"))
float StepDepth = 30.0f;
/** Angular length of curved stairs. Positive values are for clockwise and negative values are for counterclockwise. */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "-360.0", UIMax = "360.0", ClampMin = "-360.0", ClampMax = "360.0", ProceduralShapeSetting,
EditCondition = "StairsType == EProceduralStairsType::Curved"))
float CurveAngle = 90.0f;
/** Angular length of spiral stairs. Positive values are for clockwise and negative values are for counterclockwise. */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "-720.0", UIMax = "720.0", ClampMin = "-360000.0", ClampMax = "360000.0", ProceduralShapeSetting,
EditCondition = "StairsType == EProceduralStairsType::Spiral"))
float SpiralAngle = 90.0f;
/** Inner radius of curved and spiral stairs */
UPROPERTY(EditAnywhere, Category = Shape,
meta = (UIMin = "1.0", UIMax = "1000.0", ClampMin = "0.0001", ClampMax = "1000000.0", ProceduralShapeSetting,
EditCondition = "StairsType == EProceduralStairsType::Curved || StairsType == EProceduralStairsType::Spiral"))
float InnerRadius = 150.0f;
};
/**
* Base tool to create primitives
*/
UCLASS(MinimalAPI)
class UAddPrimitiveTool : public USingleClickTool, public IHoverBehaviorTarget, public IInteractiveToolCameraFocusAPI
{
GENERATED_BODY()
public:
UE_API explicit UAddPrimitiveTool(const FObjectInitializer&);
UE_API virtual void SetWorld(UWorld* World);
UE_API virtual void Setup() override;
UE_API virtual void Shutdown(EToolShutdownType ShutdownType) override;
UE_API virtual void Render(IToolsContextRenderAPI* RenderAPI) override;
virtual bool HasCancel() const override { return true; }
virtual bool HasAccept() const override { return true; }
UE_API virtual bool CanAccept() const override;
UE_API virtual void OnPropertyModified(UObject* PropertySet, FProperty* Property) override;
// USingleClickTool
UE_API virtual void OnClicked(const FInputDeviceRay& ClickPos) override;
UE_API virtual FInputRayHit IsHitByClick(const FInputDeviceRay& ClickPos) override;
// IHoverBehaviorTarget interface
UE_API virtual FInputRayHit BeginHoverSequenceHitTest(const FInputDeviceRay& PressPos) override;
UE_API virtual void OnBeginHover(const FInputDeviceRay& DevicePos) override;
UE_API virtual bool OnUpdateHover(const FInputDeviceRay& DevicePos) override;
UE_API virtual void OnEndHover() override;
// IInteractiveToolCameraFocusAPI implementation
UE_API virtual bool SupportsWorldSpaceFocusBox() override;
UE_API virtual FBox GetWorldSpaceFocusBox() override;
UE_API virtual bool SupportsWorldSpaceFocusPoint() override;
UE_API virtual bool GetWorldSpaceFocusPoint(const FRay& WorldRay, FVector& PointOut) override;
protected:
virtual EMakeMeshPolygroupMode GetDefaultPolygroupMode() const { return EMakeMeshPolygroupMode::PerQuad; }
enum class EState
{
PlacingPrimitive,
AdjustingSettings
};
EState CurrentState = EState::PlacingPrimitive;
UE_API void SetState(EState NewState);
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const {}
virtual UProceduralShapeToolProperties* CreateShapeSettings(){return nullptr;}
UE_API virtual void GenerateAsset();
/** Property set for type of output object (StaticMesh, Volume, etc) */
UPROPERTY()
TObjectPtr<UCreateMeshObjectTypeProperties> OutputTypeProperties;
UPROPERTY()
TObjectPtr<UProceduralShapeToolProperties> ShapeSettings;
UPROPERTY()
TObjectPtr<UNewMeshMaterialProperties> MaterialProperties;
UPROPERTY()
TObjectPtr<UPreviewMesh> PreviewMesh;
UPROPERTY()
TObjectPtr<UCombinedTransformGizmo> Gizmo = nullptr;
UPROPERTY()
TObjectPtr<UDragAlignmentMechanic> DragAlignmentMechanic = nullptr;
UPROPERTY()
FString AssetName = TEXT("GeneratedAsset");
UWorld* TargetWorld;
UE_API void UpdatePreviewPosition(const FInputDeviceRay& ClickPos);
UE::Geometry::FFrame3d ShapeFrame;
UE_API void UpdatePreviewMesh() const;
UE_API void UpdateTargetSurface();
// @return true if the primitive needs to be centered in the XY plane when placed.
virtual bool ShouldCenterXY() const
{
// Most primitives are already XY centered, and re-centering them only introduces issues at very low samplings where the bounds center is offset from the intended center.
return false;
}
// Used to make the initial placement of the mesh undoable
class FStateChange : public FToolCommandChange
{
public:
FStateChange(const FTransform& MeshTransformIn)
: MeshTransform(MeshTransformIn)
{
}
virtual void Apply(UObject* Object) override;
virtual void Revert(UObject* Object) override;
virtual FString ToString() const override
{
return TEXT("UAddPrimitiveTool::FStateChange");
}
protected:
FTransform MeshTransform;
};
};
UCLASS()
class UAddBoxPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddBoxPrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddCylinderPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddCylinderPrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddCapsulePrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddCapsulePrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddConePrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddConePrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddRectanglePrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddRectanglePrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddDiscPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddDiscPrimitiveTool(const FObjectInitializer& ObjectInitializer);
virtual void Setup() override;
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddTorusPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddTorusPrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddArrowPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddArrowPrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddSpherePrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddSpherePrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual EMakeMeshPolygroupMode GetDefaultPolygroupMode() const override
{
return EMakeMeshPolygroupMode::PerFace;
}
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
};
UCLASS()
class UAddStairsPrimitiveTool : public UAddPrimitiveTool
{
GENERATED_BODY()
public:
explicit UAddStairsPrimitiveTool(const FObjectInitializer& ObjectInitializer);
protected:
virtual void GenerateMesh(FDynamicMesh3* OutMesh) const override;
virtual bool ShouldCenterXY() const override
{
return true;
}
};
#undef UE_API