295 lines
13 KiB
C++
295 lines
13 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "ToolContextInterfaces.h" // for FViewCameraState
|
|
|
|
class FPrimitiveDrawInterface;
|
|
class IToolsContextRenderAPI;
|
|
class FMaterialRenderProxy;
|
|
|
|
/**
|
|
* FToolDataVisualizer is a utility class for Tool and Gizmo implementations
|
|
* to use to draw 3D lines, points, etc.
|
|
*
|
|
* Currently uses PDI drawing but may use different back-ends in the future
|
|
*/
|
|
class FToolDataVisualizer
|
|
{
|
|
public:
|
|
/** Default color used for drawing lines */
|
|
FLinearColor LineColor; // = Red
|
|
/** Default thickness used for drawing lines */
|
|
float LineThickness = 1.0f;
|
|
|
|
/** Default color used for drawing points */
|
|
FLinearColor PointColor; // = Red
|
|
/** Default size used for drawing points */
|
|
float PointSize = 1.0f;
|
|
|
|
/** Depth bias applied to lines */
|
|
float DepthBias = 0.0f;
|
|
/** Should lines be clipped by 3D geometry, or should they be drawn with quasi-transparency */
|
|
bool bDepthTested = true;
|
|
|
|
public:
|
|
INTERACTIVETOOLSFRAMEWORK_API FToolDataVisualizer();
|
|
INTERACTIVETOOLSFRAMEWORK_API FToolDataVisualizer(const FToolDataVisualizer&);
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual ~FToolDataVisualizer();
|
|
|
|
|
|
//
|
|
// Frame initialization/cleanup
|
|
//
|
|
|
|
|
|
/** This must be called every frame to allow Visualizer to extract necessary rendering data/objects */
|
|
INTERACTIVETOOLSFRAMEWORK_API void BeginFrame(IToolsContextRenderAPI* RenderAPI, const FViewCameraState& CameraState);
|
|
|
|
/** This must be called every frame to allow Visualizer to extract necessary rendering data/objects */
|
|
INTERACTIVETOOLSFRAMEWORK_API void BeginFrame(IToolsContextRenderAPI* RenderAPI);
|
|
|
|
/** this should be called at the end of every frame to allow for necessary cleanup */
|
|
INTERACTIVETOOLSFRAMEWORK_API void EndFrame();
|
|
|
|
|
|
//
|
|
// Transform support
|
|
//
|
|
|
|
/** Clear transform stack and push the given Transform */
|
|
INTERACTIVETOOLSFRAMEWORK_API void SetTransform(const FTransform& Transform);
|
|
/** Push a Transform onto the transform stack */
|
|
INTERACTIVETOOLSFRAMEWORK_API void PushTransform(const FTransform& Transform);
|
|
/** Pop a transform from the transform stack */
|
|
INTERACTIVETOOLSFRAMEWORK_API void PopTransform();
|
|
/** Clear the transform stack to identity */
|
|
INTERACTIVETOOLSFRAMEWORK_API void PopAllTransforms();
|
|
|
|
/** @return input Point transformed by transform stack */
|
|
FVector TransformP(const FVector& Point)
|
|
{
|
|
return TotalTransform.TransformPosition(Point);
|
|
}
|
|
|
|
/** @return input Vector transformed by transform stack */
|
|
FVector TransformV(const FVector& Vector)
|
|
{
|
|
return TotalTransform.TransformVector(Vector);
|
|
}
|
|
|
|
/** @return input Normal transformed by transform stack */
|
|
FVector TransformN(const FVector& Normal)
|
|
{
|
|
// transform normal by a safe inverse scale + normalize, and a standard rotation (TODO: move implementation into FTransform)
|
|
const FVector& S = TotalTransform.GetScale3D();
|
|
double DetSign = FMath::Sign(S.X*S.Y*S.Z); // we only need to multiply by the sign of the determinant, rather than divide by it, since we normalize later anyway
|
|
FVector SafeInvS(S.Y*S.Z*DetSign, S.X*S.Z*DetSign, S.X*S.Y*DetSign);
|
|
return TotalTransform.TransformVectorNoScale((SafeInvS*Normal).GetSafeNormal());
|
|
}
|
|
|
|
|
|
//
|
|
// Parameters
|
|
//
|
|
|
|
|
|
/** Update the default line color and thickness */
|
|
void SetLineParameters(const FLinearColor& Color, float Thickness)
|
|
{
|
|
LineColor = Color;
|
|
LineThickness = Thickness;
|
|
}
|
|
|
|
/** Update the default point color and size */
|
|
void SetPointParameters(const FLinearColor& Color, float Size)
|
|
{
|
|
PointColor = Color;
|
|
PointSize = Size;
|
|
}
|
|
|
|
|
|
//
|
|
// Drawing functions
|
|
//
|
|
|
|
|
|
/** Draw a line with default parameters */
|
|
template<typename PointType>
|
|
void DrawLine(const PointType& A, const PointType& B)
|
|
{
|
|
InternalDrawTransformedLine(TransformP((FVector)A), TransformP((FVector)B), LineColor, LineThickness, bDepthTested);
|
|
}
|
|
|
|
/** Draw a line with the given Color, otherwise use default parameters */
|
|
template<typename PointType>
|
|
void DrawLine(const PointType& A, const PointType& B, const FLinearColor& Color)
|
|
{
|
|
InternalDrawTransformedLine(TransformP((FVector)A), TransformP((FVector)B), Color, LineThickness, bDepthTested);
|
|
}
|
|
|
|
/** Draw a line with the given Color and Thickness, otherwise use default parameters */
|
|
template<typename PointType>
|
|
void DrawLine(const PointType& A, const PointType& B, const FLinearColor& Color, float LineThicknessIn)
|
|
{
|
|
InternalDrawTransformedLine(TransformP((FVector)A), TransformP((FVector)B), Color, LineThicknessIn, bDepthTested);
|
|
}
|
|
|
|
/** Draw a line with the given parameters */
|
|
template<typename PointType>
|
|
void DrawLine(const PointType& A, const PointType& B, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawTransformedLine(TransformP((FVector)A), TransformP((FVector)B), Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
|
|
/** Draw a point with default parameters */
|
|
template<typename PointType>
|
|
void DrawPoint(const PointType& Position)
|
|
{
|
|
InternalDrawTransformedPoint(TransformP((FVector)Position), PointColor, PointSize, bDepthTested);
|
|
}
|
|
|
|
/** Draw a point with the given Color, otherwise use default parameters */
|
|
template<typename PointType>
|
|
void DrawPoint(const PointType& Position, const FLinearColor& Color)
|
|
{
|
|
InternalDrawTransformedPoint(TransformP((FVector)Position), Color, PointSize, bDepthTested);
|
|
}
|
|
|
|
/** Draw a point with the given parameters */
|
|
template<typename PointType>
|
|
void DrawPoint(const PointType& Position, const FLinearColor& Color, float PointSizeIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawTransformedPoint(TransformP((FVector)Position), Color, PointSizeIn, bDepthTestedIn);
|
|
}
|
|
|
|
|
|
/** Draw a 3D circle at given position/normal with the given parameters. Tangent axes are defined internally */
|
|
template<typename PointType>
|
|
void DrawCircle(const PointType& Position, const PointType& Normal, float Radius, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawCircle((FVector)Position, (FVector)Normal, Radius, Steps, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a 3D circle at given position/normal with the given parameters. Tangent axes are defined internally */
|
|
template<typename PointType>
|
|
void DrawViewFacingCircle(const PointType& Position, float Radius, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawViewFacingCircle((FVector)Position, Radius, Steps, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a 3D arc at given position/normal with the given parameters. Tangent axes are defined internally */
|
|
template<typename PointType>
|
|
void DrawArc(const PointType& Position, const PointType& Normal, float Radius, int Steps, float MinAngle, float MaxAngle, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawArc((FVector)Position, (FVector)Normal, Radius, Steps, MinAngle, MaxAngle, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a 3D arc at given position/normal with the given parameters. Tangent axes are defined internally */
|
|
template<typename PointType>
|
|
void DrawViewFacingArc(const PointType& Position, float Radius, int Steps, float MinAngle, float MaxAngle, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawViewFacingArc((FVector)Position, Radius, Steps, MinAngle, MaxAngle, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a world-space X facing the viewer at the given position. */
|
|
template<typename PointType>
|
|
void DrawViewFacingX(const PointType& Position, float Width)
|
|
{
|
|
InternalDrawViewFacingX((FVector)Position, Width, LineColor, LineThickness, bDepthTested);
|
|
}
|
|
|
|
/** Draw a world-space X facing the viewer at the given position. */
|
|
template<typename PointType>
|
|
void DrawViewFacingX(const PointType& Position, float Width, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawViewFacingX((FVector)Position, Width, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a 3D cylinder, parameterized the same as the 3D circle but extruded by Height */
|
|
template<typename PointType>
|
|
void DrawWireCylinder(const PointType& Position, const PointType& Normal, float Radius, float Height, int Steps, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawWireCylinder((FVector)Position, (FVector)Normal, Radius, Height, Steps, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
/** Draw a 3D cylinder, parameterized the same as the 3D circle but extruded by Height */
|
|
template<typename PointType>
|
|
void DrawWireCylinder(const PointType& Position, const PointType& Normal, float Radius, float Height, int Steps)
|
|
{
|
|
InternalDrawWireCylinder((FVector)Position, (FVector)Normal, Radius, Height, Steps, LineColor, LineThickness, bDepthTested);
|
|
}
|
|
|
|
/** Draw a 3D box, parameterized the same as the 3D circle but extruded by Height */
|
|
void DrawWireBox(const FBox& Box)
|
|
{
|
|
InternalDrawWireBox(Box, LineColor, LineThickness, bDepthTested);
|
|
}
|
|
|
|
void DrawWireBox(const FBox& Box, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawWireBox(Box, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
template<typename PointType>
|
|
void DrawSquare(const PointType& Center, const PointType& SideA, const PointType& SideB, const FLinearColor& Color, float LineThicknessIn, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawSquare(Center, SideA, SideB, Color, LineThicknessIn, bDepthTestedIn);
|
|
}
|
|
|
|
template<typename PointType>
|
|
void DrawSquare(const PointType& Center, const PointType& SideA, const PointType& SideB)
|
|
{
|
|
InternalDrawSquare(Center, SideA, SideB, LineColor, LineThickness, bDepthTested);
|
|
}
|
|
|
|
/** Draw a 3D disc at given position/normal with the given parameters. Tangent axes are defined internally */
|
|
template<typename PointType>
|
|
void DrawDisc(const PointType& Position, const PointType& Normal, float Radius, int Steps, const FColor& Color, FMaterialRenderProxy* RenderProxy, bool bDepthTestedIn)
|
|
{
|
|
InternalDrawDisc(Position, Normal, Radius, Steps, Color, RenderProxy, bDepthTestedIn);
|
|
}
|
|
|
|
protected:
|
|
/** We use this for drawing, extracted in InitializeFrame */
|
|
FPrimitiveDrawInterface* CurrentPDI = nullptr;
|
|
|
|
FViewCameraState CameraState;
|
|
bool bHaveCameraState;
|
|
|
|
// screen-space line thicknesses and point sizes are multiplied by this value to try to normalize for variable thickness
|
|
// that occurs at different FOVs.
|
|
float PDISizeScale = 1.0;
|
|
|
|
|
|
TArray<FTransform> TransformStack;
|
|
FTransform TotalTransform;
|
|
|
|
// actually does the line drawing; assumes A and B are already transformed
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawTransformedLine(const FVector& A, const FVector& B, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the point drawing; assumes Position is already transformed
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawTransformedPoint(const FVector& Position, const FLinearColor& Color, float PointSize, bool bDepthTested);
|
|
|
|
|
|
// actually does the circle drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawCircle(const FVector& Position, const FVector& Normal, float Radius, int Steps, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the circle drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawViewFacingCircle(const FVector& Position, float Radius, int Steps, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the arc drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawArc(const FVector& InPosition, const FVector& InNormal, const float InRadius, int32 InSteps, const float InMinAngle, const float InMaxAngle, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the arc drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawViewFacingArc(const FVector& InPosition, float InRadius, int32 InSteps, const float InMinAngle, const float InMaxAngle, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the cylinder drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawWireCylinder(const FVector& Position, const FVector& Normal, float Radius, float Height, int Steps, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the box drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawWireBox(const FBox& Box, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the square drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawSquare(const FVector& Center, const FVector& SideA, const FVector& SideB, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the X drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawViewFacingX(const FVector& Position, float Width, const FLinearColor& Color, float LineThickness, bool bDepthTested);
|
|
// actually does the disc drawing
|
|
INTERACTIVETOOLSFRAMEWORK_API virtual void InternalDrawDisc(const FVector& Position, const FVector& Normal, float Radius, int Steps, const FColor& Color, FMaterialRenderProxy* RenderProxy, bool bDepthTested);
|
|
};
|