495 lines
20 KiB
C++
495 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "HitProxies.h"
|
|
#include "UObject/GCObject.h"
|
|
#include "UnrealWidgetFwd.h"
|
|
|
|
class FCanvas;
|
|
class FEditorModeTools;
|
|
class FEditorViewportClient;
|
|
class FPrimitiveDrawInterface;
|
|
class FSceneView;
|
|
class UMaterialInstanceDynamic;
|
|
class UMaterialInterface;
|
|
class FMaterialRenderProxy;
|
|
|
|
class FWidget : public FGCObject
|
|
{
|
|
public:
|
|
constexpr static float AXIS_LENGTH = 35.0f;
|
|
constexpr static float TRANSLATE_ROTATE_AXIS_CIRCLE_RADIUS = 20.0f;
|
|
constexpr static float TWOD_AXIS_CIRCLE_RADIUS = 10.0f;
|
|
constexpr static float INNER_AXIS_CIRCLE_RADIUS = 48.0f;
|
|
constexpr static float OUTER_AXIS_CIRCLE_RADIUS = 56.0f;
|
|
constexpr static float ROTATION_TEXT_RADIUS = 75.0f;
|
|
constexpr static int32 AXIS_CIRCLE_SIDES = 24;
|
|
constexpr static float AXIS_LENGTH_SCALE_OFFSET = 5.0f;
|
|
|
|
FWidget();
|
|
|
|
/**
|
|
* Sets editor mode tools to use in this widget
|
|
*/
|
|
UNREALED_API void SetUsesEditorModeTools(FEditorModeTools* InEditorModeTools);
|
|
|
|
/**
|
|
* Renders any widget specific HUD text
|
|
* @param Canvas - Canvas to use for 2d rendering
|
|
*/
|
|
void DrawHUD(FCanvas* Canvas);
|
|
|
|
// @param ViewportClient must not be 0
|
|
void Render(const FSceneView* View, FPrimitiveDrawInterface* PDI, FEditorViewportClient* ViewportClient);
|
|
|
|
public:
|
|
/**
|
|
* Converts mouse movement on the screen to widget axis movement/rotation.
|
|
*/
|
|
void ConvertMouseMovementToAxisMovement(FSceneView* InView, FEditorViewportClient* InViewportClient,
|
|
bool bInUsedDragModifier, FVector& InDiff, FVector& OutDrag,
|
|
FRotator& OutRotation, FVector& OutScale);
|
|
|
|
/**
|
|
* Absolute Translation conversion from mouse movement on the screen to widget axis movement/rotation.
|
|
*/
|
|
void AbsoluteTranslationConvertMouseMovementToAxisMovement(FSceneView* InView,
|
|
FEditorViewportClient* InViewportClient,
|
|
const FVector& InLocation,
|
|
const FVector2D& InMousePosition, FVector& OutDrag,
|
|
FRotator& OutRotation, FVector& OutScale);
|
|
|
|
/**
|
|
* Grab the initial offset again first time input is captured
|
|
*/
|
|
void ResetInitialTranslationOffset(void)
|
|
{
|
|
bAbsoluteTranslationInitialOffsetCached = false;
|
|
}
|
|
|
|
/** Only some modes support Absolute Translation Movement. Check current mode */
|
|
static bool AllowsAbsoluteTranslationMovement(UE::Widget::EWidgetMode WidgetMode);
|
|
|
|
/** Only some modes support Absolute Rotation Movement. Check current mode */
|
|
static bool AllowsAbsoluteRotationMovement(UE::Widget::EWidgetMode WidgetMode, EAxisList::Type InAxisType);
|
|
/**
|
|
* Sets the default visibility of the widget, if it is not overridden by an active editor mode tool.
|
|
*
|
|
* @param bInVisibility true for visible
|
|
*/
|
|
void SetDefaultVisibility(bool bInDefaultVisibility)
|
|
{
|
|
bDefaultVisibility = bInDefaultVisibility;
|
|
}
|
|
|
|
/**
|
|
* Sets the axis currently being moused over. Typically called by FMouseDeltaTracker or FLevelEditorViewportClient.
|
|
*
|
|
* @param InCurrentAxis The new axis value.
|
|
*/
|
|
void SetCurrentAxis(EAxisList::Type InCurrentAxis)
|
|
{
|
|
CurrentAxis = InCurrentAxis;
|
|
}
|
|
|
|
/**
|
|
* @return The axis currently being moused over.
|
|
*/
|
|
EAxisList::Type GetCurrentAxis() const
|
|
{
|
|
return CurrentAxis;
|
|
}
|
|
|
|
/**
|
|
* @return The widget origin in viewport space.
|
|
*/
|
|
FVector2D GetOrigin() const
|
|
{
|
|
return Origin;
|
|
}
|
|
|
|
/**
|
|
* @return The mouse drag start position in viewport space.
|
|
*/
|
|
void SetDragStartPosition(const FVector2D& Position)
|
|
{
|
|
DragStartPos = Position;
|
|
LastDragPos = DragStartPos;
|
|
}
|
|
|
|
/**
|
|
* Returns whether we are actively dragging
|
|
*/
|
|
bool IsDragging(void) const
|
|
{
|
|
return bDragging;
|
|
}
|
|
|
|
/**
|
|
* Sets if we are currently engaging the widget in dragging
|
|
*/
|
|
void SetDragging(const bool InDragging)
|
|
{
|
|
bDragging = InDragging;
|
|
}
|
|
|
|
/**
|
|
* Sets if we are currently engaging the widget in dragging
|
|
*/
|
|
void SetSnapEnabled(const bool InSnapEnabled)
|
|
{
|
|
bSnapEnabled = InSnapEnabled;
|
|
}
|
|
|
|
/**
|
|
* FGCObject interface: Serializes the widget reference so they dont get garbage collected.
|
|
*
|
|
* @param Ar FArchive to serialize with
|
|
*/
|
|
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
|
|
virtual FString GetReferencerName() const override
|
|
{
|
|
return "FWidget";
|
|
}
|
|
|
|
/**
|
|
* Gets the axis to draw based on the current widget mode
|
|
*/
|
|
EAxisList::Type GetAxisToDraw(UE::Widget::EWidgetMode WidgetMode) const;
|
|
|
|
/** @return true if the widget is disabled */
|
|
bool IsWidgetDisabled() const;
|
|
|
|
/** Updates the delta rotation on the widget */
|
|
UNREALED_API void UpdateDeltaRotation();
|
|
|
|
/** Resets the total delta rotation back to zero */
|
|
void ResetDeltaRotation()
|
|
{
|
|
TotalDeltaRotation = 0;
|
|
}
|
|
|
|
/** @return the rotation speed of the widget */
|
|
static float GetRotationSpeed()
|
|
{
|
|
return (2.f * (float)PI) / 360.f;
|
|
}
|
|
|
|
private:
|
|
void ConvertMouseToAxis_Translate(FVector2D DragDir, FVector& InOutDelta, FVector& OutDrag) const;
|
|
void ConvertMouseToAxis_Rotate(FVector2D TangentDir, FVector2D DragDir, FSceneView* InView,
|
|
FEditorViewportClient* InViewportClient, FVector& InOutDelta, FRotator& OutRotation);
|
|
void ConvertMouseToAxis_Scale(FVector2D DragDir, FVector& InOutDelta, FVector& OutScale);
|
|
void ConvertMouseToAxis_TranslateRotateZ(FVector2D TangentDir, FVector2D DragDir, FVector& InOutDelta,
|
|
FVector& OutDrag, FRotator& OutRotation);
|
|
void ConvertMouseToAxis_WM_2D(FVector2D TangentDir, FVector2D DragDir, FVector& InOutDelta, FVector& OutDrag,
|
|
FRotator& OutRotation);
|
|
|
|
struct FAbsoluteMovementParams
|
|
{
|
|
/** The normal of the plane to project onto */
|
|
FVector PlaneNormal;
|
|
/** A vector that represent any displacement we want to mute (remove an axis if we're doing axis movement)*/
|
|
FVector NormalToRemove;
|
|
/** The current position of the widget */
|
|
FVector Position;
|
|
|
|
//Coordinate System Axes
|
|
FVector XAxis;
|
|
FVector YAxis;
|
|
FVector ZAxis;
|
|
|
|
//true if camera movement is locked to the object
|
|
bool bMovementLockedToCamera;
|
|
|
|
//Direction in world space to the current mouse location
|
|
FVector PixelDir;
|
|
//Direction in world space of the middle of the camera
|
|
FVector CameraDir;
|
|
FVector EyePos;
|
|
|
|
//whether to snap the requested positionto the grid
|
|
bool bPositionSnapping;
|
|
};
|
|
|
|
void AbsoluteConvertMouseToAxis_Translate(FSceneView* InView, const FMatrix& InputCoordSystem,
|
|
FAbsoluteMovementParams& InOutParams, FVector& OutDrag);
|
|
void AbsoluteConvertMouseToAxis_WM_2D(const FMatrix& InputCoordSystem, FAbsoluteMovementParams& InOutParams,
|
|
FVector& OutDrag, FRotator& OutRotation);
|
|
void AbsoluteConvertMouseToAxis_TranslateRotateZ(const FMatrix& InputCoordSystem,
|
|
FAbsoluteMovementParams& InOutParams, FVector& OutDrag,
|
|
FRotator& OutRotation);
|
|
|
|
/**
|
|
* Render helper functions
|
|
*/
|
|
void RenderGrid(const FSceneView* View, FPrimitiveDrawInterface* PDI, FEditorViewportClient* ViewportClient);
|
|
void Render_Axis(const FSceneView* View, FPrimitiveDrawInterface* PDI, EAxisList::Type InAxis, FMatrix& InMatrix,
|
|
UMaterialInterface* InMaterial, const FLinearColor& InColor, FVector2D& OutAxisDir,
|
|
const FVector& InScale, bool bDrawWidget, bool bCubeHead = false, float AxisLengthOffset = 0);
|
|
void Render_Cube(FPrimitiveDrawInterface* PDI, const FMatrix& InMatrix, const UMaterialInterface* InMaterial,
|
|
const FVector& InScale);
|
|
UNREALED_API void Render_Translate(const FSceneView* View, FPrimitiveDrawInterface* PDI,
|
|
FEditorViewportClient* ViewportClient, const FVector& InLocation,
|
|
bool bDrawWidget);
|
|
UNREALED_API void Render_Rotate(const FSceneView* View, FPrimitiveDrawInterface* PDI,
|
|
FEditorViewportClient* ViewportClient, const FVector& InLocation, bool bDrawWidget);
|
|
void Render_Scale(const FSceneView* View, FPrimitiveDrawInterface* PDI, FEditorViewportClient* ViewportClient,
|
|
const FVector& InLocation, bool bDrawWidget);
|
|
void Render_TranslateRotateZ(const FSceneView* View, FPrimitiveDrawInterface* PDI,
|
|
FEditorViewportClient* ViewportClient, const FVector& InLocation, bool bDrawWidget);
|
|
void Render_2D(const FSceneView* View, FPrimitiveDrawInterface* PDI, FEditorViewportClient* ViewportClient,
|
|
const FVector& InLocation, bool bDrawWidget);
|
|
|
|
|
|
struct FThickArcParams
|
|
{
|
|
FThickArcParams(FPrimitiveDrawInterface* InPDI, const FVector& InPosition, UMaterialInterface* InMaterial,
|
|
const float InInnerRadius, const float InOuterRadius)
|
|
: Position(InPosition)
|
|
, PDI(InPDI)
|
|
, Material(InMaterial)
|
|
, InnerRadius(InInnerRadius)
|
|
, OuterRadius(InOuterRadius)
|
|
{}
|
|
|
|
/** The current position of the widget */
|
|
FVector Position;
|
|
|
|
//interface for Drawing
|
|
FPrimitiveDrawInterface* PDI;
|
|
|
|
//Material to use to render
|
|
UMaterialInterface* Material;
|
|
|
|
//Radii
|
|
float InnerRadius;
|
|
float OuterRadius;
|
|
};
|
|
|
|
/**
|
|
* Returns the Delta from the current position that the absolute movement system wants the object to be at
|
|
* @param InParams - Structure containing all the information needed for absolute movement
|
|
* @return - The requested delta from the current position
|
|
*/
|
|
FVector GetAbsoluteTranslationDelta(const FAbsoluteMovementParams& InParams);
|
|
/**
|
|
* Returns the offset from the initial selection point
|
|
*/
|
|
FVector GetAbsoluteTranslationInitialOffset(const FVector& InNewPosition, const FVector& InCurrentPosition);
|
|
|
|
/**
|
|
* Returns true if we're in Local Space editing mode or editing BSP (which uses the World axes anyway
|
|
*/
|
|
bool IsRotationLocalSpace() const;
|
|
|
|
/**
|
|
* Returns how far we have just rotated
|
|
*/
|
|
float GetDeltaRotation() const;
|
|
|
|
/**
|
|
* If actively dragging, draws a ring representing the potential rotation of the selected objects, snap ticks, and "delta" markers
|
|
* If not actively dragging, draws a quarter ring representing the closest quadrant to the camera
|
|
* @param View - Information about the scene/camera/etc
|
|
* @param PDI - Drawing interface
|
|
* @param InAxis - Enumeration of axis to rotate about
|
|
* @param InLocation - The Origin of the widget
|
|
* @param Axis0 - The Axis that describes a 0 degree rotation
|
|
* @param Axis1 - The Axis that describes a 90 degree rotation
|
|
* @param InDirectionToWidget - Direction from camera to the widget
|
|
* @param InColor - The color associated with the axis of rotation
|
|
* @param InScale - Multiplier to maintain a constant screen size for rendering the widget
|
|
* @param OutAxisDir - Viewport-space direction of rotation arc chord is placed here
|
|
*/
|
|
void DrawRotationArc(const FSceneView* View, FPrimitiveDrawInterface* PDI, EAxisList::Type InAxis,
|
|
const FVector& InLocation, const FVector& Axis0, const FVector& Axis1,
|
|
const FVector& InDirectionToWidget, const FColor& InColor, const float InScale,
|
|
FVector2D& OutAxisEnd);
|
|
|
|
/**
|
|
* If actively dragging, draws a ring representing the potential rotation of the selected objects, snap ticks, and "delta" markers
|
|
* If not actively dragging, draws a quarter ring representing the closest quadrant to the camera
|
|
* @param View - Information about the scene/camera/etc
|
|
* @param PDI - Drawing interface
|
|
* @param InAxis - Enumeration of axis to rotate about
|
|
* @param InLocation - The Origin of the widget
|
|
* @param Axis0 - The Axis that describes a 0 degree rotation
|
|
* @param Axis1 - The Axis that describes a 90 degree rotation
|
|
* @param InStartAngle - The starting angle about (Axis0^Axis1) to render the arc
|
|
* @param InEndAngle - The ending angle about (Axis0^Axis1) to render the arc
|
|
* @param InColor - The color associated with the axis of rotation
|
|
* @param InScale - Multiplier to maintain a constant screen size for rendering the widget
|
|
*/
|
|
void DrawPartialRotationArc(const FSceneView* View, FPrimitiveDrawInterface* PDI, EAxisList::Type InAxis,
|
|
const FVector& InLocation, const FVector& Axis0, const FVector& Axis1,
|
|
const float InStartAngle, const float InEndAngle, const FColor& InColor,
|
|
const float InScale, const FVector& InDirectionToWidget);
|
|
|
|
/**
|
|
* Renders a portion of an arc for the rotation widget
|
|
* @param InParams - Material, Radii, etc
|
|
* @param InStartAxis - Start of the arc
|
|
* @param InEndAxis - End of the arc
|
|
* @param InColor - Color to use for the arc
|
|
*/
|
|
void DrawThickArc(const FThickArcParams& InParams, const FVector& Axis0, const FVector& Axis1,
|
|
const float InStartAngle, const float InEndAngle, const FColor& InColor,
|
|
const FVector& InDirectionToWidget, bool bIsOrtho);
|
|
|
|
/**
|
|
* Draws protractor like ticks where the rotation widget would snap too.
|
|
* Also, used to draw the wider axis tick marks
|
|
* @param PDI - Drawing interface
|
|
* @param InLocation - The Origin of the widget
|
|
* @param Axis0 - The Axis that describes a 0 degree rotation
|
|
* @param Axis1 - The Axis that describes a 90 degree rotation
|
|
* @param InAngle - The Angle to rotate about the axis of rotation, the vector (Axis0 ^ Axis1)
|
|
* @param InColor - The color to use for line/poly drawing
|
|
* @param InScale - Multiplier to maintain a constant screen size for rendering the widget
|
|
* @param InWidthPercent - The percent of the distance between the outer ring and inner ring to use for tangential thickness
|
|
* @param InPercentSize - The percent of the distance between the outer ring and inner ring to use for radial distance
|
|
*/
|
|
void DrawSnapMarker(FPrimitiveDrawInterface* PDI, const FVector& InLocation, const FVector& Axis0,
|
|
const FVector& Axis1, const FColor& InColor, const float InScale,
|
|
const float InWidthPercent = 0.0f, const float InPercentSize = 1.0f);
|
|
|
|
/**
|
|
* Draw Start/Stop Marker to show delta rotations along the arc of rotation
|
|
* @param PDI - Drawing interface
|
|
* @param InLocation - The Origin of the widget
|
|
* @param Axis0 - The Axis that describes a 0 degree rotation
|
|
* @param Axis1 - The Axis that describes a 90 degree rotation
|
|
* @param InAngle - The Angle to rotate about the axis of rotation, the vector (Axis0 ^ Axis1)
|
|
* @param InColor - The color to use for line/poly drawing
|
|
* @param InScale - Multiplier to maintain a constant screen size for rendering the widget
|
|
*/
|
|
void DrawStartStopMarker(FPrimitiveDrawInterface* PDI, const FVector& InLocation, const FVector& Axis0,
|
|
const FVector& Axis1, const float InAngle, const FColor& InColor, const float InScale);
|
|
|
|
/**
|
|
* Caches off HUD text to display after 3d rendering is complete
|
|
* @param View - Information about the scene/camera/etc
|
|
* @param PDI - Drawing interface
|
|
* @param InLocation - The Origin of the widget
|
|
* @param Axis0 - The Axis that describes a 0 degree rotation
|
|
* @param Axis1 - The Axis that describes a 90 degree rotation
|
|
* @param AngleOfAngle - angle we've rotated so far (in degrees)
|
|
* @param InScale - Multiplier to maintain a constant screen size for rendering the widget
|
|
*/
|
|
void CacheRotationHUDText(const FSceneView* View, FPrimitiveDrawInterface* PDI, const FVector& InLocation,
|
|
const FVector& Axis0, const FVector& Axis1, const float AngleOfChange,
|
|
const float InScale);
|
|
|
|
/**
|
|
* Gets the axis to use when converting mouse movement, accounting for Ortho views.
|
|
*
|
|
* @param InDiff Difference vector to determine dominant axis.
|
|
* @param ViewportType Type of viewport for ortho checks.
|
|
*
|
|
* @return Index of the dominant axis.
|
|
*/
|
|
uint32 GetDominantAxisIndex(const FVector& InDiff, FEditorViewportClient* ViewportClient) const;
|
|
|
|
|
|
void DrawColoredSphere(FPrimitiveDrawInterface* PDI, const FVector& Center, const FRotator& Orientation,
|
|
FColor Color, const FVector& Radii, int32 NumSides, int32 NumRings,
|
|
const FMaterialRenderProxy* MaterialRenderProxy, uint8 DepthPriority,
|
|
bool bDisableBackfaceCulling);
|
|
|
|
/** The axis currently being moused over */
|
|
EAxisList::Type CurrentAxis;
|
|
|
|
/** Viewport space origin location of the widget */
|
|
FVector2D Origin;
|
|
/** Viewport space direction vectors of the axes on the widget */
|
|
FVector2D XAxisDir, YAxisDir, ZAxisDir;
|
|
/** Drag start position in viewport space */
|
|
FVector2D DragStartPos;
|
|
/** Last mouse position in viewport space */
|
|
FVector2D LastDragPos;
|
|
enum
|
|
{
|
|
AXIS_ARROW_SEGMENTS = 16
|
|
};
|
|
|
|
/** Materials and colors to be used when drawing the items for each axis */
|
|
TObjectPtr<UMaterialInterface> TransparentPlaneMaterialXY;
|
|
TObjectPtr<UMaterialInterface> GridMaterial;
|
|
|
|
TObjectPtr<UMaterialInstanceDynamic> AxisMaterialX;
|
|
TObjectPtr<UMaterialInstanceDynamic> AxisMaterialY;
|
|
TObjectPtr<UMaterialInstanceDynamic> AxisMaterialZ;
|
|
TObjectPtr<UMaterialInstanceDynamic> CurrentAxisMaterial;
|
|
TObjectPtr<UMaterialInstanceDynamic> OpaquePlaneMaterialXY;
|
|
|
|
FLinearColor AxisColorX, AxisColorY, AxisColorZ;
|
|
FLinearColor ScreenAxisColor;
|
|
FColor PlaneColorXY, ScreenSpaceColor, CurrentColor;
|
|
FColor ArcBallColor;
|
|
|
|
/** Any mode tools being used */
|
|
FEditorModeTools* EditorModeTools;
|
|
|
|
/**
|
|
* An extra matrix to apply to the widget before drawing it (allows for local/custom coordinate systems).
|
|
*/
|
|
FMatrix CustomCoordSystem;
|
|
|
|
/** The space of the custom coord system */
|
|
ECoordSystem CustomCoordSystemSpace;
|
|
|
|
//location in the viewport to render the hud string
|
|
FVector2D HUDInfoPos;
|
|
//string to be displayed on top of the viewport
|
|
FString HUDString;
|
|
|
|
/** Whether Absolute Translation cache position has been captured */
|
|
bool bAbsoluteTranslationInitialOffsetCached;
|
|
/** The initial offset where the widget was first clicked */
|
|
FVector InitialTranslationOffset;
|
|
/** The initial position of the widget before it was clicked */
|
|
FVector InitialTranslationPosition;
|
|
/** Whether or not the widget is actively dragging */
|
|
bool bDragging;
|
|
/** Whether or not snapping is enabled for all actors */
|
|
bool bSnapEnabled;
|
|
/** Default visibility for the widget if an Editor Mode Tool doesn't override it */
|
|
bool bDefaultVisibility;
|
|
/** Whether we are drawing the full ring in rotation mode (ortho viewports only) */
|
|
bool bIsOrthoDrawingFullRing;
|
|
|
|
/** Total delta rotation applied since the widget was dragged */
|
|
float TotalDeltaRotation;
|
|
|
|
/** Current delta rotation applied to the rotation widget */
|
|
float CurrentDeltaRotation;
|
|
};
|
|
|
|
/**
|
|
* Widget hit proxy.
|
|
*/
|
|
struct HWidgetAxis : public HHitProxy
|
|
{
|
|
DECLARE_HIT_PROXY(UNREALED_API);
|
|
|
|
EAxisList::Type Axis;
|
|
uint32 bDisabled : 1;
|
|
|
|
UNREALED_API HWidgetAxis(EAxisList::Type InAxis, bool InbDisabled = false, EHitProxyPriority InHitProxy = HPP_UI);
|
|
|
|
virtual EMouseCursor::Type GetMouseCursor() override;
|
|
|
|
/**
|
|
* Method that specifies whether the hit proxy *always* allows translucent primitives to be associated with it or not,
|
|
* regardless of any other engine/editor setting. For example, if translucent selection was disabled, any hit proxies
|
|
* returning true would still allow translucent selection. In this specific case, true is always returned because geometry
|
|
* mode hit proxies always need to be selectable or geometry mode will not function correctly.
|
|
*
|
|
* @return true if translucent primitives are always allowed with this hit proxy; false otherwise
|
|
*/
|
|
virtual bool AlwaysAllowsTranslucentPrimitives() const override;
|
|
};
|