// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "BaseBehaviors/BehaviorTargetInterfaces.h" #include "RectangleMarqueeMechanic.h" #include "InteractiveToolChange.h" #include "Spatial/GeometrySet3.h" #include "ToolContextInterfaces.h" //FViewCameraState #include "IntVectorTypes.h" #include "TransactionUtil.h" #include "LatticeControlPointsMechanic.generated.h" #define UE_API MODELINGCOMPONENTS_API class APreviewGeometryActor; class ULineSetComponent; class UMouseHoverBehavior; class UPointSetComponent; class USingleClickInputBehavior; class UCombinedTransformGizmo; class UTransformProxy; UCLASS(MinimalAPI) class ULatticeControlPointsMechanic : public UInteractionMechanic, public IClickBehaviorTarget, public IHoverBehaviorTarget { GENERATED_BODY() using FVector2i = UE::Geometry::FVector2i; public: // TODO: Snapping // This delegate is called every time the control points are moved. DECLARE_MULTICAST_DELEGATE(OnPointsChangedEvent); OnPointsChangedEvent OnPointsChanged; // This delegate is called every time the control point selection changes. DECLARE_MULTICAST_DELEGATE(OnSelectionChangedEvent); OnSelectionChangedEvent OnSelectionChanged; UE_API virtual void Initialize(const TArray& Points, const TArray& Edges, const FTransform3d& LocalToWorldTransform ); UE_API void SetWorld(UWorld* World); UE_API const TArray& GetControlPoints() const; UE_API void UpdateControlPointPositions(const TArray& NewPoints); UE_API void SetCoordinateSystem(EToolContextCoordinateSystem InCoordinateSystem); UE_API EToolContextCoordinateSystem GetCoordinateSystem() const; UE_API void UpdateSetPivotMode(bool bInSetPivotMode); UE_API virtual void DrawHUD(FCanvas* Canvas, IToolsContextRenderAPI* RenderAPI); // UInteractionMechanic UE_API virtual void Setup(UInteractiveTool* ParentTool) override; UE_API virtual void Shutdown() override; UE_API virtual void Render(IToolsContextRenderAPI* RenderAPI) override; // IClickBehaviorTarget implementation UE_API virtual FInputRayHit IsHitByClick(const FInputDeviceRay& ClickPos) override; UE_API virtual void OnClicked(const FInputDeviceRay& ClickPos) override; // IHoverBehaviorTarget implementation 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; UE_API virtual void OnUpdateModifierState(int ModifierID, bool bIsOn) override; bool bHasChanged = false; bool ControlPointIsSelected(int32 Index) { return SelectedPointIDs.Contains(Index); } const TSet& GetSelectedPointIDs() const { return SelectedPointIDs; } void SetPointColorOverride(int32 Index, const FColor& NewColor) { ColorOverrides.FindOrAdd(Index) = NewColor; } void ClearPointColorOverride(int32 Index) { ColorOverrides.Remove(Index); } void ClearAllPointColorOverrides() { ColorOverrides.Reset(); } UE_API void UpdateDrawables(); UE_API void UpdatePointLocations(const TMap& NewLocations); /// Set all lattice control points UE_API void UpdatePointLocations(const TArray& NewLocations); bool IsGizmoBeingDragged() const { return bGizmoBeingDragged; } DECLARE_DELEGATE_RetVal(bool, FShouldHideGizmo); FShouldHideGizmo ShouldHideGizmo; protected: TArray ControlPoints; TArray LatticeEdges; FTransform3d LocalToWorldTransform; // Used for spatial queries UE::Geometry::FGeometrySet3 GeometrySet; FViewCameraState CachedCameraState; /** Used for displaying points/segments */ UPROPERTY() TObjectPtr PreviewGeometryActor; UPROPERTY() TObjectPtr DrawnControlPoints; UPROPERTY() TObjectPtr DrawnLatticeEdges; // Variables for drawing FColor NormalSegmentColor; FColor NormalPointColor; float SegmentsThickness; float PointsSize; FColor HoverColor; FColor SelectedColor; // Cache previous color while temporarily changing the color of a hovered-over point FColor PreHoverPointColor; // Support for Shift and Ctrl toggle bool bShiftToggle = false; bool bCtrlToggle = false; static const int32 ShiftModifierID = 1; static const int32 CtrlModifierID = 2; // Default modifier key behavior is consistent with PolygonSelectionMechanic TFunction ShouldAddToSelectionFunc = [this]() {return bShiftToggle; }; TFunction ShouldRemoveFromSelectionFunc = [this]() {return bCtrlToggle; }; // Support for gizmo. Since the points aren't individual components, we don't actually use UTransformProxy // for the transform forwarding- we just use it for the callbacks. UPROPERTY() TObjectPtr PointTransformProxy; UPROPERTY() TObjectPtr PointTransformGizmo; // Used to make it easy to tell whether the gizmo was moved by the user or by undo/redo or // some other change that we shouldn't respond to. Basing our movement undo/redo on the // gizmo turns out to be quite a pain, though may someday be easier if the transform proxy // is able to manage arbitrary objects. bool bGizmoBeingDragged = false; // Callbacks we'll receive from the gizmo proxy UE_API void GizmoTransformChanged(UTransformProxy* Proxy, FTransform Transform); UE_API void GizmoTransformStarted(UTransformProxy* Proxy); UE_API void GizmoTransformEnded(UTransformProxy* Proxy); // Support for hovering TFunction GeometrySetToleranceTest; int32 HoveredPointID = -1; UE_API void ClearHover(); // Support for selection UPROPERTY() TObjectPtr MarqueeMechanic; bool bIsDraggingRectangle = false; TSet SelectedPointIDs; TSet PreDragSelection; TArray CurrentDragSelection; UE_API void OnDragRectangleStarted(); UE_API void OnDragRectangleChanged(const FCameraRectangle& Rectangle); UE_API void OnDragRectangleFinished(const FCameraRectangle& Rectangle, bool bCancelled); // We need the selected point start positions so we can move multiple points appropriately. TMap SelectedPointStartPositions; // The starting point of the gizmo is needed to determine the offset by which to move the points. // TODO: Replace with single FTransform? FVector GizmoStartPosition; FQuat GizmoStartRotation; FVector GizmoStartScale; // All of the following do not issue undo/redo change objects. UE_API bool HitTest(const FInputDeviceRay& ClickPos, FInputRayHit& ResultOut); UE_API void SelectPoint(int32 PointID); UE_API bool DeselectPoint(int32 PointID); UE_API void UpdateGizmoLocation(); UE_API void UpdateGizmoVisibility(); UE_API void RebuildDrawables(); // Used for expiring undo/redo changes, which compare this to their stored value and expire themselves if they do not match. int32 CurrentChangeStamp = 0; TMap ColorOverrides; friend class FLatticeControlPointsMechanicSelectionChange; friend class FLatticeControlPointsMechanicMovementChange; private: UE::TransactionUtil::FLongTransactionTracker LongTransactions; }; // Undo/redo support: // Control point selection has changed class FLatticeControlPointsMechanicSelectionChange : public FToolCommandChange { public: UE_API FLatticeControlPointsMechanicSelectionChange(int32 PointIDIn, bool bAddedIn, const FTransform& PreviousTransformIn, const FTransform& NewTransformIn, int32 ChangeStampIn); UE_API FLatticeControlPointsMechanicSelectionChange(const TSet& PointIDsIn, bool bAddedIn, const FTransform& PreviousTransformIn, const FTransform& NewTransformIn, int32 ChangeStampIn); UE_API virtual void Apply(UObject* Object) override; UE_API virtual void Revert(UObject* Object) override; virtual bool HasExpired(UObject* Object) const override { return Cast(Object)->CurrentChangeStamp != ChangeStamp; } UE_API virtual FString ToString() const override; protected: TSet PointIDs; bool bAdded; const FTransform PreviousTransform; const FTransform NewTransform; int32 ChangeStamp; }; // Control points have moved class FLatticeControlPointsMechanicMovementChange : public FToolCommandChange { public: UE_API FLatticeControlPointsMechanicMovementChange( const TMap& OriginalPositionsIn, const TMap& NewPositionsIn, int32 ChangeStampIn, bool bFirstMovementIn); UE_API virtual void Apply(UObject* Object) override; UE_API virtual void Revert(UObject* Object) override; virtual bool HasExpired(UObject* Object) const override { return Cast(Object)->CurrentChangeStamp != ChangeStamp; } UE_API virtual FString ToString() const override; protected: TMap OriginalPositions; TMap NewPositions; int32 ChangeStamp; bool bFirstMovement; }; #undef UE_API