2020-01-08 17:11:23 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
2019-11-07 09:40:07 -05:00
|
|
|
|
|
|
|
|
#include "BaseGizmos/GizmoLineHandleComponent.h"
|
|
|
|
|
#include "BaseGizmos/GizmoRenderingUtil.h"
|
|
|
|
|
#include "BaseGizmos/GizmoMath.h"
|
|
|
|
|
#include "PrimitiveSceneProxy.h"
|
2022-03-17 14:03:58 -04:00
|
|
|
#include "SceneManagement.h" // FMeshElementCollector, FPrimitiveDrawInterface
|
2019-11-07 09:40:07 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FGizmoLineHandleComponentSceneProxy final : public FPrimitiveSceneProxy
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SIZE_T GetTypeHash() const override
|
|
|
|
|
{
|
|
|
|
|
static size_t UniquePointer;
|
|
|
|
|
return reinterpret_cast<size_t>(&UniquePointer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGizmoLineHandleComponentSceneProxy(const UGizmoLineHandleComponent* InComponent)
|
|
|
|
|
: FPrimitiveSceneProxy(InComponent),
|
|
|
|
|
Color(InComponent->Color),
|
|
|
|
|
Normal(InComponent->Normal),
|
|
|
|
|
Direction(InComponent->Direction),
|
|
|
|
|
HandleSize(InComponent->HandleSize),
|
|
|
|
|
Thickness(InComponent->Thickness),
|
|
|
|
|
bBoundaryOnly(false),
|
|
|
|
|
bImageScale(InComponent->bImageScale),
|
|
|
|
|
HoverThicknessMultiplier(InComponent->HoverSizeMultiplier)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
|
|
|
|
|
{
|
|
|
|
|
FVector LocalOffset = Direction;
|
|
|
|
|
if (ExternalDistance != nullptr)
|
|
|
|
|
{
|
|
|
|
|
LocalOffset *= (*ExternalDistance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FMatrix& LocalToWorldMatrix = GetLocalToWorld();
|
2020-06-23 18:40:00 -04:00
|
|
|
FVector WorldOrigin = LocalToWorldMatrix.TransformPosition(FVector::ZeroVector);
|
2019-11-07 09:40:07 -05:00
|
|
|
|
|
|
|
|
float IntervalMarkerSize = HandleSize;
|
|
|
|
|
FVector WorldIntervalEnd = LocalToWorldMatrix.TransformPosition(LocalOffset + IntervalMarkerSize * Normal);
|
|
|
|
|
FVector WorldDiskOrigin = LocalToWorldMatrix.TransformPosition(LocalOffset);
|
|
|
|
|
FVector WorldBaseOrigin = LocalToWorldMatrix.TransformPosition(FVector::ZeroVector);
|
|
|
|
|
|
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
|
|
|
{
|
|
|
|
|
if (VisibilityMap & (1 << ViewIndex))
|
|
|
|
|
{
|
|
|
|
|
const FSceneView* View = Views[ViewIndex];
|
|
|
|
|
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
|
2020-06-23 18:40:00 -04:00
|
|
|
bool bIsOrtho = !View->IsPerspectiveProjection();
|
2019-11-07 09:40:07 -05:00
|
|
|
FVector UpVector = View->GetViewUp();
|
|
|
|
|
FVector ViewVector = View->GetViewDirection();
|
|
|
|
|
|
2021-06-09 16:28:33 -04:00
|
|
|
float LengthScale = 1;
|
|
|
|
|
bool bIsViewDependent = (bExternalIsViewDependent) ? (*bExternalIsViewDependent) : false;
|
|
|
|
|
if (bIsViewDependent)
|
2020-06-23 18:40:00 -04:00
|
|
|
{
|
2021-06-09 16:28:33 -04:00
|
|
|
LengthScale = GizmoRenderingUtil::CalculateLocalPixelToWorldScale(View, WorldDiskOrigin);
|
2020-06-23 18:40:00 -04:00
|
|
|
}
|
|
|
|
|
|
2020-09-24 00:43:27 -04:00
|
|
|
FVector ScaledIntevalStart = -LengthScale * (WorldIntervalEnd - WorldDiskOrigin) + WorldDiskOrigin;
|
|
|
|
|
FVector ScaledIntevalEnd = LengthScale * (WorldIntervalEnd - WorldDiskOrigin) + WorldDiskOrigin;
|
|
|
|
|
FVector ScaledDiskOrigin = 0.5 * (ScaledIntevalStart + ScaledIntevalEnd);
|
2020-06-23 18:40:00 -04:00
|
|
|
|
|
|
|
|
float UseThickness = (bExternalHoverState != nullptr && *bExternalHoverState == true) ?
|
|
|
|
|
(HoverThicknessMultiplier * Thickness) : (Thickness);
|
|
|
|
|
if (!bIsOrtho)
|
|
|
|
|
{
|
|
|
|
|
UseThickness *= (View->FOV / 90.0); // compensate for FOV scaling in Gizmos...
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:40:07 -05:00
|
|
|
// From base origin to disk origin
|
|
|
|
|
PDI->DrawLine(WorldBaseOrigin, ScaledDiskOrigin, Color, SDPG_Foreground, UseThickness, 0.0f, true);
|
|
|
|
|
// Draw the interval marker
|
|
|
|
|
PDI->DrawLine(ScaledIntevalStart, ScaledIntevalEnd, Color, SDPG_Foreground, 2. * UseThickness, 0.0f, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
|
|
|
|
|
{
|
|
|
|
|
FPrimitiveViewRelevance Result;
|
|
|
|
|
Result.bDrawRelevance = IsShown(View);
|
|
|
|
|
Result.bDynamicRelevance = true;
|
|
|
|
|
Result.bShadowRelevance = false;
|
|
|
|
|
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
|
|
|
|
|
Result.bRenderCustomDepth = ShouldRenderCustomDepth();
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool CanBeOccluded() const override
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual uint32 GetMemoryFootprint(void) const override { return sizeof *this + GetAllocatedSize(); }
|
|
|
|
|
uint32 GetAllocatedSize(void) const { return FPrimitiveSceneProxy::GetAllocatedSize(); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SetExternalHoverState(bool* HoverState)
|
|
|
|
|
{
|
|
|
|
|
bExternalHoverState = HoverState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetExternalWorldLocalState(bool* bWorldLocalState)
|
|
|
|
|
{
|
|
|
|
|
bExternalWorldLocalState = bWorldLocalState;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-09 16:28:33 -04:00
|
|
|
void SetExternalIsViewDependent(bool* bExternalIsViewDependentIn)
|
|
|
|
|
{
|
|
|
|
|
bExternalIsViewDependent = bExternalIsViewDependentIn;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:40:07 -05:00
|
|
|
void SetLengthScale(float* Distance)
|
|
|
|
|
{
|
|
|
|
|
ExternalDistance = Distance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
FLinearColor Color;
|
|
|
|
|
FVector Normal;
|
|
|
|
|
FVector Direction;
|
|
|
|
|
float HandleSize;
|
|
|
|
|
float Thickness;
|
|
|
|
|
bool bBoundaryOnly;
|
|
|
|
|
bool bImageScale;
|
|
|
|
|
float HoverThicknessMultiplier;
|
|
|
|
|
|
2020-06-23 18:40:00 -04:00
|
|
|
// set on Component for use in ::GetDynamicMeshElements()
|
2019-11-07 09:40:07 -05:00
|
|
|
bool* bExternalHoverState = nullptr;
|
|
|
|
|
bool* bExternalWorldLocalState = nullptr;
|
2020-06-23 18:40:00 -04:00
|
|
|
float* ExternalDistance = nullptr;
|
2021-06-09 16:28:33 -04:00
|
|
|
bool* bExternalIsViewDependent = nullptr;
|
2019-11-07 09:40:07 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FPrimitiveSceneProxy* UGizmoLineHandleComponent::CreateSceneProxy()
|
|
|
|
|
{
|
|
|
|
|
FGizmoLineHandleComponentSceneProxy* NewProxy = new FGizmoLineHandleComponentSceneProxy(this);
|
|
|
|
|
NewProxy->SetExternalHoverState(&bHovering);
|
|
|
|
|
NewProxy->SetExternalWorldLocalState(&bWorld);
|
|
|
|
|
NewProxy->SetLengthScale(&Length);
|
2021-06-09 16:28:33 -04:00
|
|
|
NewProxy->SetExternalIsViewDependent(&bIsViewDependent);
|
2019-11-07 09:40:07 -05:00
|
|
|
return NewProxy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBoxSphereBounds UGizmoLineHandleComponent::CalcBounds(const FTransform& LocalToWorld) const
|
|
|
|
|
{
|
|
|
|
|
// the handle looks like
|
|
|
|
|
// ------|
|
|
|
|
|
// where '------' has length "Length" and '|' is of length 2*Handlesize
|
|
|
|
|
//
|
|
|
|
|
float Radius = FMath::Sqrt(Length * Length + HandleSize * HandleSize);
|
|
|
|
|
return FBoxSphereBounds(FSphere(FVector::ZeroVector, Radius).TransformBy(LocalToWorld));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UGizmoLineHandleComponent::LineTraceComponent(FHitResult& OutHit, const FVector Start, const FVector End, const FCollisionQueryParams& Params)
|
|
|
|
|
{
|
2021-06-09 16:28:33 -04:00
|
|
|
const FTransform& Transform = this->GetComponentToWorld();
|
|
|
|
|
FVector WorldBaseOrigin = Transform.TransformPosition(FVector::ZeroVector);
|
|
|
|
|
float PixelToWorldScale = 1;
|
|
|
|
|
if (bIsViewDependent)
|
|
|
|
|
{
|
|
|
|
|
PixelToWorldScale = GizmoRenderingUtil::CalculateLocalPixelToWorldScale(GizmoViewContext, WorldBaseOrigin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float LengthScale = (bImageScale) ? PixelToWorldScale : 1.f;
|
2019-11-07 09:40:07 -05:00
|
|
|
double UseHandleSize = LengthScale * HandleSize;
|
|
|
|
|
FVector LocalOffset = Length * Direction;
|
|
|
|
|
|
|
|
|
|
FVector HandleDir = (bWorld) ? Normal : Transform.TransformVector(Normal);
|
|
|
|
|
FVector WorldHandleOrigin = Transform.TransformPosition(LocalOffset);
|
|
|
|
|
|
|
|
|
|
FVector BaseToHandle = WorldHandleOrigin - WorldBaseOrigin;
|
|
|
|
|
|
|
|
|
|
// where the handle crosses the connecting line
|
|
|
|
|
FVector ScaledHandleOrigin = LengthScale * BaseToHandle + WorldBaseOrigin;
|
|
|
|
|
|
|
|
|
|
// start and end point of the handle.
|
|
|
|
|
FVector HandleStart = ScaledHandleOrigin + LengthScale * HandleDir;
|
|
|
|
|
FVector HandleEnd = ScaledHandleOrigin - LengthScale * HandleDir;
|
|
|
|
|
|
|
|
|
|
FVector NearestOnHandle, NearestOnLine;
|
|
|
|
|
FMath::SegmentDistToSegmentSafe(HandleStart, HandleEnd, Start, End, NearestOnHandle, NearestOnLine);
|
|
|
|
|
double Distance = FVector::Distance(NearestOnHandle, NearestOnLine);
|
2021-06-09 16:28:33 -04:00
|
|
|
if (Distance > PixelHitDistanceThreshold * PixelToWorldScale)
|
2019-11-07 09:40:07 -05:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OutHit.Component = this;
|
|
|
|
|
OutHit.Distance = FVector::Distance(Start, NearestOnLine);
|
|
|
|
|
OutHit.ImpactPoint = NearestOnLine;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|