void FBehaviorTreeConnectionDrawingPolicy::Internal_DrawLineWithArrow(const FVector2D& StartAnchorPoint, const FVector2D& EndAnchorPoint, const FLinearColor& WireColor, float WireThickness, bool bDrawBubbles) { //@TODO: Should this be scaled by zoom factor? const float LineSeparationAmount = 4.5f; const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint; const FVector2D UnitDelta = DeltaPos.SafeNormal(); const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).SafeNormal(); // Come up with the final start/end points const FVector2D DirectionBias = Normal * LineSeparationAmount; const FVector2D LengthBias = ArrowRadius.X * UnitDelta; const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias; const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias; // Draw a line/spline DrawConnection(WireLayerID, StartPoint, EndPoint, WireColor, WireThickness, bDrawBubbles); // Draw the arrow const FVector2D ArrowDrawPos = EndPoint - ArrowRadius; const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X); FSlateDrawElement::MakeRotatedBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ClippingRect, ESlateDrawEffect::None, AngleInRadians, TOptional<FVector2D>(), FSlateDrawElement::RelativeToElement, WireColor ); }
void FBlueprintProfilerConnectionDrawingPolicy::DrawInterpColorSpline(const FGeometry& StartGeom, const FGeometry& EndGeom, const FScriptPerfConnectionParams& Params) { //@TODO: These values should be pushed into the Slate style, they are compensating for a bit of // empty space inside of the pin brush images. const float StartFudgeX = 4.0f; const float EndFudgeX = 4.0f; const FVector2D StartPoint = FGeometryHelper::VerticalMiddleRightOf(StartGeom) - FVector2D(StartFudgeX, 0.0f); const FVector2D EndPoint = FGeometryHelper::VerticalMiddleLeftOf(EndGeom) - FVector2D(ArrowRadius.X - EndFudgeX, 0); // Draw the spline DrawPerfConnection(WireLayerID, StartPoint, EndPoint, Params); // Draw the arrow if (ArrowImage) { FVector2D ArrowPoint = EndPoint - ArrowRadius; FSlateDrawElement::MakeBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowPoint, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ClippingRect, ESlateDrawEffect::None, Params.WireColor ); } }
void FConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, const FLinearColor& WireColor, float WireThickness, bool bDrawBubbles, bool Bidirectional) { // Draw the spline DrawConnection( WireLayerID, StartPoint, EndPoint, WireColor, WireThickness, bDrawBubbles); // Draw the arrow if (ArrowImage != nullptr) { FVector2D ArrowPoint = EndPoint - ArrowRadius; FSlateDrawElement::MakeBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowPoint, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ClippingRect, ESlateDrawEffect::None, WireColor ); } }
void FConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint, const FConnectionParams& Params) { // Draw the spline DrawConnection( WireLayerID, StartPoint, EndPoint, Params); // Draw the arrow if (ArrowImage != nullptr) { FVector2D ArrowPoint = EndPoint - ArrowRadius; FSlateDrawElement::MakeBox( DrawElementsList, ArrowLayerID, FPaintGeometry(ArrowPoint, ArrowImage->ImageSize * ZoomFactor, ZoomFactor), ArrowImage, ClippingRect, ESlateDrawEffect::None, Params.WireColor ); } }
void FBehaviorTreeConnectionDrawingPolicy::DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, const FLinearColor& InColor, float Thickness, bool bDrawBubbles) { const FVector2D& P0 = Start; const FVector2D& P1 = End; const FVector2D Delta = End-Start; const FVector2D NormDelta = Delta.SafeNormal(); const FVector2D P0Tangent = NormDelta; const FVector2D P1Tangent = NormDelta; // Draw the spline itself FSlateDrawElement::MakeDrawSpaceSpline( DrawElementsList, LayerId, P0, P0Tangent, P1, P1Tangent, ClippingRect, Thickness, ESlateDrawEffect::None, InColor ); if (bDrawBubbles) { // This table maps distance along curve to alpha FInterpCurve<float> SplineReparamTable; float SplineLength = MakeSplineReparamTable(P0, P0Tangent, P1, P1Tangent, SplineReparamTable); // Draw bubbles on the spline const float BubbleSpacing = 64.f * ZoomFactor; const float BubbleSpeed = 192.f * ZoomFactor; const FVector2D BubbleSize = BubbleImage->ImageSize * ZoomFactor * 0.1f * Thickness; float Time = (FPlatformTime::Seconds() - GStartTime); const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing); const int32 NumBubbles = FMath::CeilToInt(SplineLength/BubbleSpacing); for (int32 i = 0; i < NumBubbles; ++i) { const float Distance = ((float)i * BubbleSpacing) + BubbleOffset; if (Distance < SplineLength) { const float Alpha = SplineReparamTable.Eval(Distance, 0.f); FVector2D BubblePos = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, Alpha); BubblePos -= (BubbleSize * 0.5f); FSlateDrawElement::MakeBox( DrawElementsList, LayerId, FPaintGeometry( BubblePos, BubbleSize, ZoomFactor ), BubbleImage, ClippingRect, ESlateDrawEffect::None, InColor ); } } } }
void FSlateDrawElement::MakeCustom( FSlateWindowElementList& ElementList, uint32 InLayer, TSharedPtr<ICustomSlateElement, ESPMode::ThreadSafe> CustomDrawer ) { FSlateDrawElement& DrawElt = ElementList.AddUninitialized(); DrawElt.Init(InLayer, FPaintGeometry(), FSlateRect(1,1,1,1), ESlateDrawEffect::None); DrawElt.RenderTransform = FSlateRenderTransform(); DrawElt.ElementType = ET_Custom; DrawElt.DataPayload.SetCustomDrawerPayloadProperties( CustomDrawer ); }
FPaintGeometry FGeometry::CenteredPaintGeometryOnRight( const FVector2D& SizeBeingAligned, float InScale ) const { const float CombinedScale = this->Scale*InScale; return FPaintGeometry( this->AbsolutePosition + FVector2D(this->Size.X, this->Size.Y/2 - SizeBeingAligned.Y/2) * InScale, SizeBeingAligned * CombinedScale, CombinedScale ); }
int32 FSlateSimpleRunHighlighter::OnPaint( const FTextLayout::FLineView& Line, const TSharedRef< ISlateRun >& Run, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { FVector2D Location( Block->GetLocationOffset() ); Location.Y = Line.Offset.Y; // Draw the actual highlight rectangle FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, FPaintGeometry( AllottedGeometry.AbsolutePosition + Location, FVector2D( Block->GetSize().X, Line.Size.Y ), AllottedGeometry.Scale ), &DefaultStyle.HighlightShape, MyClippingRect, bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, InWidgetStyle.GetColorAndOpacityTint() * DefaultStyle.HighlightColor ); FLinearColor InvertedForeground = FLinearColor::White - InWidgetStyle.GetForegroundColor(); InvertedForeground.A = InWidgetStyle.GetForegroundColor().A; FWidgetStyle WidgetStyle( InWidgetStyle ); WidgetStyle.SetForegroundColor( InvertedForeground ); return Run->OnPaint( Line, Block, DefaultStyle, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, WidgetStyle, bParentEnabled ); }
void FSlateDrawElement::MakeDrawSpaceSpline( FSlateWindowElementList& ElementList, uint32 InLayer, const FVector2D& InStart, const FVector2D& InStartDir, const FVector2D& InEnd, const FVector2D& InEndDir, const FSlateRect InClippingRect, float InThickness, ESlateDrawEffect::Type InDrawEffects, const FColor& InTint ) { MakeSpline( ElementList, InLayer, FPaintGeometry(), InStart, InStartDir, InEnd, InEndDir, InClippingRect, InThickness, InDrawEffects, InTint ); }
FPaintGeometry FGeometry::ToPaintGeometry(const FVector2D& LocalSize, const FSlateLayoutTransform& LayoutTransform) const { FSlateLayoutTransform NewAccumulatedLayoutTransform = Concatenate(LayoutTransform, GetAccumulatedLayoutTransform()); return FPaintGeometry(NewAccumulatedLayoutTransform, Concatenate(LayoutTransform, GetAccumulatedRenderTransform()), LocalSize); }
FPaintGeometry FGeometry::ToPaintGeometry() const { return FPaintGeometry(GetAccumulatedLayoutTransform(), GetAccumulatedRenderTransform(), Size); }
FPaintGeometry FGeometry::ToInflatedPaintGeometry( const FVector2D& InflateAmount ) const { return FPaintGeometry( this->AbsolutePosition - InflateAmount*this->Scale, (this->Size+InflateAmount*2)*this->Scale, this->Scale ); }
FPaintGeometry FGeometry::ToPaintGeometry( FVector2D InOffset, FVector2D InSize, float InScale ) const { const float CombinedScale = this->Scale*InScale; return FPaintGeometry( this->AbsolutePosition + InOffset*CombinedScale, InSize * CombinedScale, CombinedScale ); }
void FBlueprintProfilerConnectionDrawingPolicy::DrawPerfConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End, const FScriptPerfConnectionParams& Params) { const FVector2D& P0 = Start; const FVector2D& P1 = End; const FVector2D SplineTangent = ComputeSplineTangent(P0, P1); const FVector2D P0Tangent = (Params.StartDirection == EGPD_Output) ? SplineTangent : -SplineTangent; const FVector2D P1Tangent = (Params.EndDirection == EGPD_Input) ? SplineTangent : -SplineTangent; if (Settings->bTreatSplinesLikePins) { // Distance to consider as an overlap const float QueryDistanceTriggerThresholdSquared = FMath::Square(Settings->SplineHoverTolerance + Params.WireThickness * 0.5f); // Distance to pass the bounding box cull test (may want to expand this later on if we want to do 'closest pin' actions that don't require an exact hit) const float QueryDistanceToBoundingBoxSquared = QueryDistanceTriggerThresholdSquared; bool bCloseToSpline = false; { // The curve will include the endpoints but can extend out of a tight bounds because of the tangents // P0Tangent coefficient maximizes to 4/27 at a=1/3, and P1Tangent minimizes to -4/27 at a=2/3. const float MaximumTangentContribution = 4.0f / 27.0f; FBox2D Bounds(ForceInit); Bounds += FVector2D(P0); Bounds += FVector2D(P0 + MaximumTangentContribution * P0Tangent); Bounds += FVector2D(P1); Bounds += FVector2D(P1 - MaximumTangentContribution * P1Tangent); bCloseToSpline = Bounds.ComputeSquaredDistanceToPoint(LocalMousePosition) < QueryDistanceToBoundingBoxSquared; } if (bCloseToSpline) { // Find the closest approach to the spline FVector2D ClosestPoint(ForceInit); float ClosestDistanceSquared = FLT_MAX; const int32 NumStepsToTest = 16; const float StepInterval = 1.0f / (float)NumStepsToTest; FVector2D Point1 = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, 0.0f); for (float TestAlpha = 0.0f; TestAlpha < 1.0f; TestAlpha += StepInterval) { const FVector2D Point2 = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, TestAlpha + StepInterval); const FVector2D ClosestPointToSegment = FMath::ClosestPointOnSegment2D(LocalMousePosition, Point1, Point2); const float DistanceSquared = (LocalMousePosition - ClosestPointToSegment).SizeSquared(); if (DistanceSquared < ClosestDistanceSquared) { ClosestDistanceSquared = DistanceSquared; ClosestPoint = ClosestPointToSegment; } Point1 = Point2; } // Record the overlap if (ClosestDistanceSquared < QueryDistanceTriggerThresholdSquared) { if (ClosestDistanceSquared < SplineOverlapResult.GetDistanceSquared()) { const float SquaredDistToPin1 = (Params.AssociatedPin1 != nullptr) ? (P0 - ClosestPoint).SizeSquared() : FLT_MAX; const float SquaredDistToPin2 = (Params.AssociatedPin2 != nullptr) ? (P1 - ClosestPoint).SizeSquared() : FLT_MAX; SplineOverlapResult = FGraphSplineOverlapResult(Params.AssociatedPin1, Params.AssociatedPin2, ClosestDistanceSquared, SquaredDistToPin1, SquaredDistToPin2); } } } } // Draw the spline itself const float WireThickness = Params.WireThickness * ZoomFactor; TArray<FSlateGradientStop> Gradients; Gradients.Add(FSlateGradientStop(FVector2D::ZeroVector, Params.WireColor)); Gradients.Add(FSlateGradientStop(FVector2D::ZeroVector, Params.WireColor2)); FSlateDrawElement::MakeDrawSpaceGradientSpline( DrawElementsList, LayerId, P0, P0Tangent, P1, P1Tangent, ClippingRect, Gradients, WireThickness, ESlateDrawEffect::None); if (Params.bDrawBubbles || (MidpointImage != nullptr)) { // This table maps distance along curve to alpha FInterpCurve<float> SplineReparamTable; const float SplineLength = MakeSplineReparamTable(P0, P0Tangent, P1, P1Tangent, SplineReparamTable); // Draw bubbles on the spline if (Params.bDrawBubbles) { const float BubbleSpacing = 64.f * ZoomFactor; const float BubbleSpeed = 192.f * ZoomFactor; float Time = (FPlatformTime::Seconds() - GStartTime); const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing); const int32 NumBubbles = FMath::CeilToInt(SplineLength/BubbleSpacing); const float SizeMin = WireThickness * 0.05f; const float SizeScale = WireThickness * 0.10f; const float SizeA = SizeMin + (Params.PerformanceData1 * SizeScale); const float SizeB = SizeMin + (Params.PerformanceData2 * SizeScale); for (int32 i = 0; i < NumBubbles; ++i) { const float Distance = ((float)i * BubbleSpacing) + BubbleOffset; if (Distance < SplineLength) { const float Alpha = SplineReparamTable.Eval(Distance, 0.f); FVector2D BubblePos = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, Alpha); const FVector2D BubbleSize = BubbleImage->ImageSize * FMath::Lerp(SizeA, SizeB, Alpha); const FLinearColor ElementColor = FLinearColor::LerpUsingHSV(Params.WireColor, Params.WireColor2, Alpha); BubblePos -= (BubbleSize * 0.5f); FSlateDrawElement::MakeBox( DrawElementsList, LayerId, FPaintGeometry( BubblePos, BubbleSize, ZoomFactor ), BubbleImage, ClippingRect, ESlateDrawEffect::None, ElementColor ); } } } // Draw the midpoint image if (MidpointImage != nullptr) { // Determine the spline position for the midpoint const float MidpointAlpha = SplineReparamTable.Eval(SplineLength * 0.5f, 0.f); const FVector2D Midpoint = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha); // Approximate the slope at the midpoint (to orient the midpoint image to the spline) const FVector2D MidpointPlusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha + KINDA_SMALL_NUMBER); const FVector2D MidpointMinusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha - KINDA_SMALL_NUMBER); const FVector2D SlopeUnnormalized = MidpointPlusE - MidpointMinusE; // Draw the arrow const FVector2D MidpointDrawPos = Midpoint - MidpointRadius; const float AngleInRadians = SlopeUnnormalized.IsNearlyZero() ? 0.0f : FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X); FLinearColor ElementColor = FLinearColor::LerpUsingHSV(Params.WireColor, Params.WireColor2, 0.5f); FSlateDrawElement::MakeRotatedBox( DrawElementsList, LayerId, FPaintGeometry(MidpointDrawPos, MidpointImage->ImageSize * ZoomFactor, ZoomFactor), MidpointImage, ClippingRect, ESlateDrawEffect::None, AngleInRadians, TOptional<FVector2D>(), FSlateDrawElement::RelativeToElement, ElementColor ); } } }
void FConnectionDrawingPolicy::DrawConnection( int32 LayerId, const FVector2D& Start, const FVector2D& End, const FLinearColor& InColor, float Thickness, bool bDrawBubbles ) { const FVector2D& P0 = Start; const FVector2D& P1 = End; const int32 Tension = FMath::Abs<int32>(Start.X - End.X); const FVector2D P0Tangent = Tension * FVector2D(1.0f, 0); const FVector2D P1Tangent = P0Tangent; // Draw the spline itself FSlateDrawElement::MakeDrawSpaceSpline( DrawElementsList, LayerId, P0, P0Tangent, P1, P1Tangent, ClippingRect, Thickness, ESlateDrawEffect::None, InColor ); if (bDrawBubbles || (MidpointImage != NULL)) { // This table maps distance along curve to alpha FInterpCurve<float> SplineReparamTable; float SplineLength = MakeSplineReparamTable(P0, P0Tangent, P1, P1Tangent, SplineReparamTable); // Draw bubbles on the spline if (bDrawBubbles) { const float BubbleSpacing = 64.f * ZoomFactor; const float BubbleSpeed = 192.f * ZoomFactor; const FVector2D BubbleSize = BubbleImage->ImageSize * ZoomFactor * 0.1f * Thickness; float Time = (FPlatformTime::Seconds() - GStartTime); const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing); const int32 NumBubbles = FMath::Ceil(SplineLength/BubbleSpacing); for (int32 i = 0; i < NumBubbles; ++i) { const float Distance = ((float)i * BubbleSpacing) + BubbleOffset; if (Distance < SplineLength) { const float Alpha = SplineReparamTable.Eval(Distance, 0.f); FVector2D BubblePos = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, Alpha); BubblePos -= (BubbleSize * 0.5f); FSlateDrawElement::MakeBox( DrawElementsList, LayerId, FPaintGeometry( BubblePos, BubbleSize, ZoomFactor ), BubbleImage, ClippingRect, ESlateDrawEffect::None, InColor ); } } } // Draw the midpoint image if (MidpointImage != NULL) { // Determine the spline position for the midpoint const float MidpointAlpha = SplineReparamTable.Eval(SplineLength * 0.5f, 0.f); const FVector2D Midpoint = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha); // Approximate the slope at the midpoint (to orient the midpoint image to the spline) const FVector2D MidpointPlusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha + KINDA_SMALL_NUMBER); const FVector2D MidpointMinusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha - KINDA_SMALL_NUMBER); const FVector2D SlopeUnnormalized = MidpointPlusE - MidpointMinusE; // Draw the arrow const FVector2D MidpointDrawPos = Midpoint - MidpointRadius; const float AngleInRadians = SlopeUnnormalized.IsNearlyZero() ? 0.0f : FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X); FSlateDrawElement::MakeRotatedBox( DrawElementsList, LayerId, FPaintGeometry(MidpointDrawPos, MidpointImage->ImageSize * ZoomFactor, ZoomFactor), MidpointImage, ClippingRect, ESlateDrawEffect::None, AngleInRadians, TOptional<FVector2D>(), FSlateDrawElement::RelativeToElement, InColor ); } } }