void FRCPassPostProcessLensFlares::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, LensFlares); const FPooledRenderTargetDesc* InputDesc1 = GetInputDesc(ePId_Input0); const FPooledRenderTargetDesc* InputDesc2 = GetInputDesc(ePId_Input1); if(!InputDesc1 || !InputDesc2) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); FIntPoint TexSize1 = InputDesc1->Extent; FIntPoint TexSize2 = InputDesc2->Extent; uint32 ScaleToFullRes1 = GSceneRenderTargets.GetBufferSizeXY().X / TexSize1.X; uint32 ScaleToFullRes2 = GSceneRenderTargets.GetBufferSizeXY().X / TexSize2.X; FIntRect ViewRect1 = FIntRect::DivideAndRoundUp(View.ViewRect, ScaleToFullRes1); FIntRect ViewRect2 = FIntRect::DivideAndRoundUp(View.ViewRect, ScaleToFullRes2); FIntPoint ViewSize1 = ViewRect1.Size(); FIntPoint ViewSize2 = ViewRect2.Size(); const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); // is optimized away if possible (RT size=view size, ) Context.RHICmdList.Clear(true, FLinearColor::Black, false, 1.0f, false, 0, ViewRect1); Context.SetViewportAndCallRHI(ViewRect1); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI()); TShaderMapRef<FPostProcessVS> VertexShader(Context.GetShaderMap()); // setup background (bloom), can be implemented to use additive blending to avoid the read here { TShaderMapRef<FPostProcessLensFlareBasePS> PixelShader(Context.GetShaderMap()); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); VertexShader->SetParameters(Context); PixelShader->SetParameters(Context); // Draw a quad mapping scene color to the view's render target DrawRectangle( Context.RHICmdList, 0, 0, ViewSize1.X, ViewSize1.Y, ViewRect1.Min.X, ViewRect1.Min.Y, ViewSize1.X, ViewSize1.Y, ViewSize1, TexSize1, *VertexShader, EDRF_UseTriangleOptimization); } // additive blend Context.RHICmdList.SetBlendState(TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_One>::GetRHI()); // add lens flares on top of that { TShaderMapRef<FPostProcessLensFlaresPS> PixelShader(Context.GetShaderMap()); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); FVector2D TexScaleValue = FVector2D(TexSize2) / ViewSize2; VertexShader->SetParameters(Context); PixelShader->SetParameters(Context, TexScaleValue); // todo: expose const uint32 Count = 8; // we assume the center of the view is the center of the lens (would not be correct for tiled rendering) FVector2D Center = FVector2D(ViewSize1) * 0.5f; FLinearColor LensFlareHDRColor = Context.View.FinalPostProcessSettings.LensFlareTint * Context.View.FinalPostProcessSettings.LensFlareIntensity; // to get the same brightness with 4x more quads (TileSize=1 in LensBlur) LensFlareHDRColor.R *= 0.25f; LensFlareHDRColor.G *= 0.25f; LensFlareHDRColor.B *= 0.25f; for(uint32 i = 0; i < Count; ++i) { FLinearColor FlareColor = Context.View.FinalPostProcessSettings.LensFlareTints[i % 8]; float NormalizedAlpha = FlareColor.A; float Alpha = NormalizedAlpha * 7.0f - 3.5f; // scale to blur outside of the view (only if we use LensBlur) Alpha *= SizeScale; // set the individual flare color SetShaderValue(Context.RHICmdList, PixelShader->GetPixelShader(), PixelShader->FlareColor, FlareColor * LensFlareHDRColor); // Draw a quad mapping scene color to the view's render target DrawRectangle( Context.RHICmdList, Center.X - 0.5f * ViewSize1.X * Alpha, Center.Y - 0.5f * ViewSize1.Y * Alpha, ViewSize1.X * Alpha, ViewSize1.Y * Alpha, ViewRect2.Min.X, ViewRect2.Min.Y, ViewSize2.X, ViewSize2.Y, ViewSize1, TexSize2, *VertexShader, EDRF_Default); } } Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); }
void SProfilerThreadView::DrawUIStackNodes() const { // SCOPE_LOG_TIME_FUNC(); check( PaintState ); const double ThreadViewOffsetPx = PositionXMS*NumPixelsPerMillisecond; PaintState->LayerId++; static const FSlateBrush* BorderBrush = FEditorStyle::GetBrush( "Profiler.ThreadView.SampleBorder" ); const FColor GameThreadColor = FColorList::Red; const FColor RenderThreadColor = FColorList::Blue; const FColor ThreadColors[2] = {GameThreadColor, RenderThreadColor}; // Draw nodes. for( const auto& RowOfNodes : ProfilerUIStream.LinearRowsOfNodes ) { int32 NodeIndex = 0; for( const auto& UIStackNode : RowOfNodes ) { NodeIndex++; // Check if the node is visible. //if( UIStackNode->IsVisible() ) { const FVector2D PositionPx = UIStackNode->GetLocalPosition( ThreadViewOffsetPx, PositionY ) * FVector2D( 1.0f, NUM_PIXELS_PER_ROW ); const FVector2D SizePx = FVector2D( FMath::Max( UIStackNode->WidthPx - 1.0, 0.0 ), NUM_PIXELS_PER_ROW ); const FSlateRect ClippedNodeRect = PaintState->LocalClippingRect.IntersectionWith( FSlateRect( PositionPx, PositionPx + SizePx ) ); // Check if this node is inside the visible area. if( ClippedNodeRect.IsEmpty() ) { continue; } FColor NodeColor = UIStackNode->bIsCombined ? ThreadColors[UIStackNode->ThreadIndex].WithAlpha( 64 ) : ThreadColors[UIStackNode->ThreadIndex].WithAlpha( 192 ); NodeColor.G += NodeIndex % 2 ? 0 : 64; // Draw a cycle counter for this profiler UI stack node. FSlateDrawElement::MakeBox ( PaintState->OutDrawElements, PaintState->LayerId, PaintState->AllottedGeometry.ToPaintGeometry( ClippedNodeRect.GetTopLeft(), ClippedNodeRect.GetSize() ), BorderBrush, PaintState->AbsoluteClippingRect, PaintState->DrawEffects, NodeColor ); } } } // @TODO yrx 2014-04-29 Separate layer for makebox, makeshadowtext, maketext. PaintState->LayerId++; const float MarkerPosYOffsetPx = ((float)NUM_PIXELS_PER_ROW - PaintState->SummaryFont8Height)*0.5f; // Draw nodes' descriptions. for( const auto& RowOfNodes : ProfilerUIStream.LinearRowsOfNodes ) { for( const auto& UIStackNode : RowOfNodes ) { const FVector2D PositionPx = UIStackNode->GetLocalPosition( ThreadViewOffsetPx, PositionY ) * FVector2D( 1.0f, NUM_PIXELS_PER_ROW ); const FVector2D SizePx = FVector2D( UIStackNode->WidthPx, NUM_PIXELS_PER_ROW ); const FSlateRect ClippedNodeRect = PaintState->LocalClippingRect.IntersectionWith( FSlateRect( PositionPx, PositionPx + SizePx ) ); // Check if this node is inside the visible area. if( ClippedNodeRect.IsEmpty() ) { continue; } FString StringStatName = UIStackNode->StatName.GetPlainNameString(); FString StringStatNameWithTime = StringStatName + FString::Printf( TEXT( " (%.4f MS)" ), UIStackNode->GetDurationMS() ); if( UIStackNode->bIsCulled ) { StringStatName += TEXT( " [C]" ); StringStatNameWithTime += TEXT( " [C]" ); } // Update position of the text to be always visible and try to center it. const float StatNameWidthPx = PaintState->FontMeasureService->Measure( StringStatName, PaintState->SummaryFont8 ).X; const float StatNameWithTimeWidthPx = PaintState->FontMeasureService->Measure( StringStatNameWithTime, PaintState->SummaryFont8 ).X; const float TextAreaWidthPx = ClippedNodeRect.GetSize().X; bool bUseShortVersion = true; FVector2D AdjustedPositionPx; // Center the stat name with timing if we can. if( TextAreaWidthPx > StatNameWithTimeWidthPx ) { AdjustedPositionPx = FVector2D( ClippedNodeRect.Left + (TextAreaWidthPx - StatNameWithTimeWidthPx)*0.5f, PositionPx.Y + MarkerPosYOffsetPx ); bUseShortVersion = false; } // Center the stat name. else if( TextAreaWidthPx > StatNameWidthPx ) { AdjustedPositionPx = FVector2D( ClippedNodeRect.Left + (TextAreaWidthPx - StatNameWidthPx)*0.5f, PositionPx.Y + MarkerPosYOffsetPx ); } // Move to the edge. else { AdjustedPositionPx = FVector2D( ClippedNodeRect.Left, PositionPx.Y + MarkerPosYOffsetPx ); } const FVector2D AbsolutePositionPx = PaintState->AllottedGeometry.LocalToAbsolute( ClippedNodeRect.GetTopLeft() ); const FSlateRect AbsoluteClippingRect = FSlateRect( AbsolutePositionPx, AbsolutePositionPx + ClippedNodeRect.GetSize() ); DrawText( bUseShortVersion ? StringStatName : StringStatNameWithTime, PaintState->SummaryFont8, AdjustedPositionPx, FColorList::White, FColorList::Black, FVector2D( 1.0f, 1.0f ), &AbsoluteClippingRect ); } } }
int32 SProfilerThreadView::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // SCOPE_LOG_TIME_FUNC(); // Rendering info. const bool bEnabled = ShouldBeEnabled( bParentEnabled ); const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; const FSlateBrush* BackgroundBrush = FEditorStyle::GetBrush( "Profiler.LineGraphArea" ); const FSlateBrush* WhiteBrush = FEditorStyle::GetBrush( "WhiteTexture" ); // Paint state for this call to OnPaint, valid only in this scope. PaintState = new((void*)PaintStateMemory) FSlateOnPaintState( AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, DrawEffects ); // Draw background. FSlateDrawElement::MakeBox ( PaintState->OutDrawElements, PaintState->LayerId, PaintState->AllottedGeometry.ToPaintGeometry( FVector2D( 0, 0 ), PaintState->Size2D() ), BackgroundBrush, PaintState->AbsoluteClippingRect, PaintState->DrawEffects, BackgroundBrush->GetTint( InWidgetStyle ) * InWidgetStyle.GetColorAndOpacityTint() ); LayerId++; // Draw all cycle counters for each thread nodes. if( IsReady() ) { DrawFramesBackgroundAndTimelines(); DrawUIStackNodes(); DrawFrameMarkers(); } #if 0/*DEBUG_PROFILER_PERFORMANCE*/ LayerId++; // Draw debug information. float GraphDescPosY = PaintState->Size2D().Y - 4.0f * PaintState->SummaryFont8Height; // Debug text. FSlateDrawElement::MakeText ( OutDrawElements, LayerId, AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ), FString::Printf( TEXT( "Pos X=%f,Y=%f R X=%f,Y=%f TR X=%f,Y=%f ZF X=%f" ), PositionXMS, PositionY, RangeXMS, RangeY, TotalRangeXMS, TotalRangeY, ZoomFactorX ), PaintState->SummaryFont8, MyClippingRect, DrawEffects, FLinearColor::White ); GraphDescPosY -= PaintState->SummaryFont8Height + 1.0f; FSlateDrawElement::MakeText ( OutDrawElements, LayerId, AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ), FString::Printf( TEXT( "NumMSPerWin=%f H Fr=%i,TID=%i,PX=%f,PY=%f" ), NumMillisecondsPerWindow, HoveredFrameIndex, HoveredThreadID, HoveredPositionX, HoveredPositionY ), PaintState->SummaryFont8, MyClippingRect, DrawEffects, FLinearColor::White ); GraphDescPosY -= PaintState->SummaryFont8Height + 1.0f; FSlateDrawElement::MakeText ( OutDrawElements, LayerId, AllottedGeometry.ToOffsetPaintGeometry( FVector2D( 16.0f, GraphDescPosY ) ), FString::Printf( TEXT( "DistD=%.2f FI=%3i,%3i" ), DistanceDragged, FramesIndices.X, FramesIndices.Y ), PaintState->SummaryFont8, MyClippingRect, DrawEffects, FLinearColor::White ); GraphDescPosY -= PaintState->SummaryFont8Height + 1.0f; #endif // DEBUG_PROFILER_PERFORMANCE // Reset paint state. PaintState = nullptr; return SCompoundWidget::OnPaint( Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled && IsEnabled() ); }
/** * For the given text, constructs a mesh to be used by the vertex factory for rendering. */ bool FTextRenderSceneProxy::BuildStringMesh( TArray<FDynamicMeshVertex>& OutVertices, TArray<uint16>& OutIndices ) { if(!Font || Text.IsEmpty()) { return false; } float FirstLineHeight = -1; // Only kept around for legacy positioning support float StartY = 0; const float CharIncrement = ( (float)Font->Kerning + HorizSpacingAdjust ) * XScale; float LineX = 0; const int32 PageIndex = 0; FTextIterator It(*Text.ToString()); while (It.NextLine()) { FVector2D LineSize = ComputeTextSize(It, Font, XScale, YScale, HorizSpacingAdjust); float StartX = ComputeHorizontalAlignmentOffset(LineSize, HorizontalAlignment); if (FirstLineHeight < 0) { FirstLineHeight = LineSize.Y; } LineX = 0; int32 Ch; while (It.NextCharacterInLine(Ch)) { Ch = (int32)Font->RemapChar(Ch); if(!Font->Characters.IsValidIndex(Ch + PageIndex)) { continue; } FFontCharacter& Char = Font->Characters[Ch + PageIndex]; if(!Font->Textures.IsValidIndex(Char.TextureIndex)) { continue; } UTexture2D* Tex = Font->Textures[Char.TextureIndex]; if(Tex) { FIntPoint ImportedTextureSize = Tex->GetImportedSize(); FVector2D InvTextureSize(1.0f / (float)ImportedTextureSize.X, 1.0f / (float)ImportedTextureSize.Y); const float X = LineX + StartX; const float Y = StartY + Char.VerticalOffset * YScale; float SizeX = Char.USize * XScale; const float SizeY = Char.VSize * YScale; const float U = Char.StartU * InvTextureSize.X; const float V = Char.StartV * InvTextureSize.Y; const float SizeU = Char.USize * InvTextureSize.X; const float SizeV = Char.VSize * InvTextureSize.Y; float Left = X; float Top = Y; float Right = X + SizeX; float Bottom = Y + SizeY; // axis choice and sign to get good alignment when placed on surface FVector4 V0 = FVector4(0, -Left, -Top, 0); FVector4 V1 = FVector4(0, -Right, -Top, 0); FVector4 V2 = FVector4(0, -Left, -Bottom, 0); FVector4 V3 = FVector4(0, -Right, -Bottom, 0); FVector TangentX(0, -1, 0); FVector TangentY(0, 0, -1); FVector TangentZ(1, 0, 0); int32 V00 = OutVertices.Add(FDynamicMeshVertex(V0, TangentX, TangentZ, FVector2D(U, V), TextRenderColor)); int32 V10 = OutVertices.Add(FDynamicMeshVertex(V1, TangentX, TangentZ, FVector2D(U + SizeU, V), TextRenderColor)); int32 V01 = OutVertices.Add(FDynamicMeshVertex(V2, TangentX, TangentZ, FVector2D(U, V + SizeV), TextRenderColor)); int32 V11 = OutVertices.Add(FDynamicMeshVertex(V3, TangentX, TangentZ, FVector2D(U + SizeU, V + SizeV), TextRenderColor)); check(V00 < 65536); check(V10 < 65536); check(V01 < 65536); check(V11 < 65536); OutIndices.Add(V00); OutIndices.Add(V11); OutIndices.Add(V10); OutIndices.Add(V00); OutIndices.Add(V01); OutIndices.Add(V11); // if we have another non-whitespace character to render, add the font's kerning. int32 NextChar; if( It.Peek(NextChar) && !FChar::IsWhitespace(NextChar) ) { SizeX += CharIncrement; } LineX += SizeX; } } // Move Y position down to next line. If the current line is empty, move by max char height in font StartY += LineSize.Y > 0 ? LineSize.Y : Font->GetMaxCharHeight(); } // Avoid initializing RHI resources when no vertices are generated. return (OutVertices.Num() > 0); }
TSharedPtr<SWidget> SHierarchyView::WidgetHierarchy_OnContextMenuOpening() { FMenuBuilder MenuBuilder(true, nullptr); FWidgetBlueprintEditorUtils::CreateWidgetContextMenu(MenuBuilder, BlueprintEditor.Pin().ToSharedRef(), FVector2D(0, 0)); MenuBuilder.AddMenuEntry(FGenericCommands::Get().Rename); return MenuBuilder.MakeWidget(); }
void USlateBrushThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* RenderTarget, FCanvas* Canvas) { USlateBrushAsset* SlateBrushAsset = Cast<USlateBrushAsset>(Object); if (SlateBrushAsset) { FSlateBrush Brush = SlateBrushAsset->Brush; UTexture2D* Texture = Cast<UTexture2D>( Brush.GetResourceObject() ); // Draw the background checkboard pattern const int32 CheckerDensity = 8; auto* Checker = UThumbnailManager::Get().CheckerboardTexture; Canvas->DrawTile( 0.0f, 0.0f, Width, Height, // Dimensions 0.0f, 0.0f, CheckerDensity, CheckerDensity, // UVs FLinearColor::White, Checker->Resource); // Tint & Texture if (Texture) { switch(Brush.DrawAs) { case ESlateBrushDrawType::Image: { FCanvasTileItem CanvasTile( FVector2D( X, Y ), Texture->Resource, FVector2D( Width,Height ), Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } break; case ESlateBrushDrawType::Border: { FCanvasTileItem CanvasTile( FVector2D( X, Y ), Texture->Resource, FVector2D( Width,Height ), Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } break; case ESlateBrushDrawType::Box: { float NaturalWidth = Texture->GetSurfaceWidth(); float NaturalHeight = Texture->GetSurfaceHeight(); float TopPx = FMath::Clamp<float>(NaturalHeight * Brush.Margin.Top, 0, Height); float BottomPx = FMath::Clamp<float>(NaturalHeight * Brush.Margin.Bottom, 0, Height); float VerticalCenterPx = FMath::Clamp<float>(Height - TopPx - BottomPx, 0, Height); float LeftPx = FMath::Clamp<float>(NaturalWidth * Brush.Margin.Left, 0, Width); float RightPx = FMath::Clamp<float>(NaturalWidth * Brush.Margin.Right, 0, Width); float HorizontalCenterPx = FMath::Clamp<float>(Width - LeftPx - RightPx, 0, Width); // Top-Left FVector2D TopLeftSize( LeftPx, TopPx ); { FVector2D UV0( 0, 0 ); FVector2D UV1( Brush.Margin.Left, Brush.Margin.Top ); FCanvasTileItem CanvasTile( FVector2D( X, Y ), Texture->Resource, TopLeftSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } // Bottom-Left FVector2D BottomLeftSize( LeftPx, BottomPx ); { FVector2D UV0( 0, 1 - Brush.Margin.Bottom ); FVector2D UV1( Brush.Margin.Left, 1 ); FCanvasTileItem CanvasTile( FVector2D( X, Y + Height - BottomPx ), Texture->Resource, BottomLeftSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } // Top-Right FVector2D TopRightSize( RightPx, TopPx ); { FVector2D UV0( 1 - Brush.Margin.Right, 0 ); FVector2D UV1( 1, Brush.Margin.Top ); FCanvasTileItem CanvasTile( FVector2D( X + Width - RightPx, Y ), Texture->Resource, TopRightSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } // Bottom-Right FVector2D BottomRightSize( RightPx, BottomPx ); { FVector2D UV0( 1 - Brush.Margin.Right, 1 - Brush.Margin.Bottom ); FVector2D UV1( 1, 1 ); FCanvasTileItem CanvasTile( FVector2D( X + Width - RightPx, Y + Height - BottomPx ), Texture->Resource, BottomRightSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } //----------------------------------------------------------------------- // Center-Vertical-Left FVector2D CenterVerticalLeftSize( LeftPx, VerticalCenterPx ); { FVector2D UV0( 0, Brush.Margin.Top ); FVector2D UV1( Brush.Margin.Left, 1 - Brush.Margin.Bottom ); FCanvasTileItem CanvasTile( FVector2D( X, Y + TopPx), Texture->Resource, CenterVerticalLeftSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } // Center-Vertical-Right FVector2D CenterVerticalRightSize( RightPx, VerticalCenterPx ); { FVector2D UV0( 1 - Brush.Margin.Right, Brush.Margin.Top ); FVector2D UV1( 1, 1 - Brush.Margin.Bottom ); FCanvasTileItem CanvasTile( FVector2D( X + Width - RightPx, Y + TopPx), Texture->Resource, CenterVerticalRightSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } //----------------------------------------------------------------------- // Center-Horizontal-Top FVector2D CenterHorizontalTopSize( HorizontalCenterPx, TopPx ); { FVector2D UV0( Brush.Margin.Left, 0 ); FVector2D UV1( 1 - Brush.Margin.Right, Brush.Margin.Top ); FCanvasTileItem CanvasTile( FVector2D( X + LeftPx, Y), Texture->Resource, CenterHorizontalTopSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } // Center-Horizontal-Bottom FVector2D CenterHorizontalBottomSize( HorizontalCenterPx, BottomPx ); { FVector2D UV0( Brush.Margin.Left, 1 - Brush.Margin.Bottom ); FVector2D UV1( 1 - Brush.Margin.Right, 1 ); FCanvasTileItem CanvasTile( FVector2D( X + LeftPx, Y + Height - BottomPx ), Texture->Resource, CenterHorizontalBottomSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } //----------------------------------------------------------------------- // Center FVector2D CenterSize( HorizontalCenterPx, VerticalCenterPx ); { FVector2D UV0( Brush.Margin.Left, Brush.Margin.Top ); FVector2D UV1( 1 - Brush.Margin.Right, 1 - Brush.Margin.Bottom ); FCanvasTileItem CanvasTile( FVector2D( X + LeftPx, Y + TopPx), Texture->Resource, CenterSize, UV0, UV1, Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } } break; case ESlateBrushDrawType::NoDrawType: { FCanvasTileItem CanvasTile( FVector2D( X, Y ), Texture->Resource, FVector2D( Width,Height ), Brush.TintColor.GetSpecifiedColor() ); CanvasTile.BlendMode = SE_BLEND_Translucent; CanvasTile.Draw( Canvas ); } break; default: check(false); } } } }
void AStrategyHUD::DrawMiniMap() { const AStrategyPlayerController* const PC = Cast<AStrategyPlayerController>(PlayerOwner); AStrategyGameState const* const MyGameState = GetWorld()->GetGameState<AStrategyGameState>(); // @todo, clean this up if (PC && MyGameState && MyGameState->MiniMapCamera.IsValid()) { const float BaseRotation = 270; UTexture* MiniMapTexture = Cast<UTexture>(MyGameState->MiniMapCamera->GetCaptureComponent2D()->TextureTarget); const float MapWidth = (MyGameState->MiniMapCamera->MiniMapWidth - MiniMapMargin) * UIScale; const float MapHeight = (MyGameState->MiniMapCamera->MiniMapHeight - MiniMapMargin) * UIScale; const FVector WorldCenter = MyGameState->WorldBounds.GetCenter(); const FVector WorldExtent = MyGameState->WorldBounds.GetExtent(); const FRotator RotOrg = MyGameState->MiniMapCamera->GetCaptureComponent2D()->GetComponentRotation(); const FRotationMatrix RotationMatrix(FRotator(0,BaseRotation-RotOrg.Roll,0)); const FVector2D Offset(MiniMapMargin * UIScale + (MapWidth/2.0f), Canvas->ClipY - (MapHeight/2.0f) - MiniMapMargin * UIScale ); if (MiniMapTexture) { FCanvasTileItem MapTileItem( FVector2D( 0.0f, 0.0f), FVector2D( 0.0f, 0.0f ), FLinearColor::White ); MapTileItem.Texture = MiniMapTexture->Resource; MapTileItem.Size = FVector2D( MapWidth, MapHeight ); MapTileItem.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem( MapTileItem, FVector2D( MiniMapMargin * UIScale, Canvas->ClipY - MapHeight - MiniMapMargin * UIScale ) ); } FCanvasTileItem TileItem( FVector2D( 0.0f, 0.0f), FVector2D( 0.0f, 0.0f ), FLinearColor::White ); TileItem.Size = FVector2D( 6 * UIScale, 6 * UIScale ); for (FConstPawnIterator Iterator = GetWorld()->GetPawnIterator(); Iterator; ++Iterator) { AStrategyChar* TestChar = Cast<AStrategyChar>(*Iterator); if (TestChar != NULL && TestChar->GetHealth() > 0 ) { AStrategyAIController* AIController = Cast<AStrategyAIController>(TestChar->Controller); if (AIController != NULL && AIController->IsLogicEnabled()) { FLinearColor DrawColor; if (PC != NULL && TestChar->GetTeamNum() == PC->GetTeamNum()) { DrawColor = FColor( 49, 137, 253, 255); } else { DrawColor = FColor( 242, 114, 16, 255); } const FVector CenterRelativeLocation = RotationMatrix.TransformPosition(TestChar->GetActorLocation() - WorldCenter); const FVector2D MiniMapPoint = FVector2D(CenterRelativeLocation.X / WorldExtent.X, CenterRelativeLocation.Y / WorldExtent.Y); TileItem.SetColor( DrawColor ); Canvas->DrawItem( TileItem, FVector2D( Offset.X + MiniMapPoint.X * (MapWidth/2.0f), Offset.Y + MiniMapPoint.Y * (MapHeight/2.0f) ) ); } } } ULocalPlayer* MyPlayer = Cast<ULocalPlayer>(PC->Player); FVector2D ScreenCorners[4] = { FVector2D(0, 0), FVector2D(Canvas->ClipX, 0), FVector2D(Canvas->ClipX, Canvas->ClipY), FVector2D(0, Canvas->ClipY) }; const FPlane GroundPlane = FPlane(FVector(0, 0, MyGameState->WorldBounds.Max.Z), FVector::UpVector); for (int32 i = 0; i < 4; i++) { FVector RayOrigin, RayDirection; FStrategyHelpers::DeprojectScreenToWorld(ScreenCorners[i], MyPlayer, RayOrigin, RayDirection); const FVector GroundPoint = FStrategyHelpers::IntersectRayWithPlane(RayOrigin, RayDirection, GroundPlane); const FVector CenterRelativeLocation = RotationMatrix.TransformPosition(GroundPoint - WorldCenter); MiniMapPoints[i] = FVector2D(CenterRelativeLocation.X / WorldExtent.X, CenterRelativeLocation.Y / WorldExtent.Y); } } }
void RunCrashReportClient(const TCHAR* CommandLine) { // Override the stack size for the thread pool. FQueuedThreadPool::OverrideStackSize = 256 * 1024; // Set up the main loop GEngineLoop.PreInit(CommandLine); // Initialize config. FCrashReportClientConfig::Get(); const bool bUnattended = #if CRASH_REPORT_UNATTENDED_ONLY true; #else FApp::IsUnattended(); #endif // CRASH_REPORT_UNATTENDED_ONLY // Set up the main ticker FMainLoopTiming MainLoop(IdealTickRate, bUnattended ? EMainLoopOptions::CoreTickerOnly : EMainLoopOptions::UsingSlate); // Find the report to upload in the command line arguments ParseCommandLine(CommandLine); // Increase the HttpSendTimeout to 5 minutes GConfig->SetFloat(TEXT("HTTP"), TEXT("HttpSendTimeout"), 5*60.0f, GEngineIni); FPlatformErrorReport::Init(); auto ErrorReport = LoadErrorReport(); if( ErrorReport.HasFilesToUpload() ) { // Send analytics. extern FCrashDescription& GetCrashDescription(); GetCrashDescription().SendAnalytics(); } if (bUnattended) { ErrorReport.SetUserComment( NSLOCTEXT( "CrashReportClient", "UnattendedMode", "Sent in the unattended mode" ), false ); FCrashReportClientUnattended CrashReportClient( ErrorReport ); // loop until the app is ready to quit while (!GIsRequestingExit) { MainLoop.Tick(); } } else { #if !CRASH_REPORT_UNATTENDED_ONLY // crank up a normal Slate application using the platform's standalone renderer FSlateApplication::InitializeAsStandaloneApplication(GetStandardStandaloneRenderer()); // Prepare the custom Slate styles FCrashReportClientStyle::Initialize(); // Create the main implementation object TSharedRef<FCrashReportClient> CrashReportClient = MakeShareable(new FCrashReportClient(ErrorReport)); // open up the app window TSharedRef<SCrashReportClient> ClientControl = SNew(SCrashReportClient, CrashReportClient); auto Window = FSlateApplication::Get().AddWindow( SNew(SWindow) .Title(NSLOCTEXT("CrashReportClient", "CrashReportClientAppName", "Unreal Engine 4 Crash Reporter")) .ClientSize(InitialWindowDimensions) [ ClientControl ]); Window->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride::CreateSP(CrashReportClient, &FCrashReportClient::RequestCloseWindow)); // Setting focus seems to have to happen after the Window has been added FSlateApplication::Get().ClearKeyboardFocus(EFocusCause::Cleared); // Debugging code if (RunWidgetReflector) { FSlateApplication::Get().AddWindow( SNew(SWindow) .ClientSize(FVector2D(800, 600)) [ FModuleManager::LoadModuleChecked<ISlateReflectorModule>("SlateReflector").GetWidgetReflector() ]); } // loop until the app is ready to quit while (!GIsRequestingExit) { MainLoop.Tick(); if (CrashReportClient->ShouldWindowBeHidden()) { Window->HideWindow(); } } // Clean up the custom styles FCrashReportClientStyle::Shutdown(); // Close down the Slate application FSlateApplication::Shutdown(); #endif // !CRASH_REPORT_UNATTENDED_ONLY } FPlatformErrorReport::ShutDown(); FEngineLoop::AppPreExit(); FTaskGraphInterface::Shutdown(); FEngineLoop::AppExit(); }
void AFogOfWarWorker::UpdateFowTexture() { Manager->LastFrameTextureData = TArray<FColor>(Manager->TextureData); uint32 halfTextureSize = Manager->TextureSize / 2; int signedSize = (int)Manager->TextureSize; //For convenience.... TSet<FVector2D> texelsToBlur; int sightTexels = Manager->SightRange * Manager->SamplesPerMeter; float dividend = 100.0f / Manager->SamplesPerMeter; Manager->CurrentlyInSight.Reset(); for (auto Itr(Manager->FowActors.CreateIterator()); Itr; Itr++) { if (StopTaskCounter.GetValue() != 0) { return; } //Find actor position if (!*Itr) continue; FVector position = (*Itr)->GetActorLocation(); //We divide by 100.0 because 1 texel equals 1 meter of visibility-data. int posX = (int)(position.X / dividend) + halfTextureSize; int posY = (int)(position.Y / dividend) + halfTextureSize; float integerX, integerY; FVector2D fractions = FVector2D(modf(position.X / 50.0f, &integerX), modf(position.Y / 50.0f, &integerY)); FVector2D textureSpacePos = FVector2D(posX, posY); int size = (int)Manager->TextureSize; FCollisionQueryParams queryParams(FName(TEXT("FOW trace")), false, (*Itr)); int halfKernelSize = (Manager->blurKernelSize - 1) / 2; //Store the positions we want to blur for (int y = posY - sightTexels - halfKernelSize; y <= posY + sightTexels + halfKernelSize; y++) { for (int x = posX - sightTexels - halfKernelSize; x <= posX + sightTexels + halfKernelSize; x++) { if (x > 0 && x < size && y > 0 && y < size) { texelsToBlur.Add(FIntPoint(x, y)); } } } //Unveil the positions our actors are currently looking at for (int y = posY - sightTexels; y <= posY + sightTexels; y++) { for (int x = posX - sightTexels; x <= posX + sightTexels; x++) { //Kernel for radial sight if (x > 0 && x < size && y > 0 && y < size) { FVector2D currentTextureSpacePos = FVector2D(x, y); int length = (int)(textureSpacePos - currentTextureSpacePos).Size(); if (length <= sightTexels) { FVector currentWorldSpacePos = FVector( ((x - (int)halfTextureSize)) * dividend, ((y - (int)halfTextureSize)) * dividend, position.Z); //CONSIDER: This is NOT the most efficient way to do conditional unfogging. With long view distances and/or a lot of actors affecting the FOW-data //it would be preferrable to not trace against all the boundary points and internal texels/positions of the circle, but create and cache "rasterizations" of //viewing circles (using Bresenham's midpoint circle algorithm) for the needed sightranges, shift the circles to the actor's location //and just trace against the boundaries. //We would then use Manager->GetWorld()->LineTraceSingle() and find the first collision texel. Having found the nearest collision //for every ray we would unveil all the points between the collision and origo using Bresenham's Line-drawing algorithm. //However, the tracing doesn't seem like it takes much time at all (~0.02ms with four actors tracing circles of 18 texels each), //it's the blurring that chews CPU.. if (!Manager->GetWorld()->LineTraceTestByObjectType(position, currentWorldSpacePos, ECC_WorldStatic, queryParams)) //if (!Manager->GetWorld()->LineTraceTestByChannel(position, currentWorldSpacePos, ECC_WorldStatic, queryParams)) { //Unveil the positions we are currently seeing Manager->UnfoggedData[x + y * Manager->TextureSize] = true; //Store the positions we are currently seeing. Manager->CurrentlyInSight.Add(FVector2D(x, y)); } } } } } } if (Manager->GetIsBlurEnabled()) { //Horizontal blur pass int offset = floorf(Manager->blurKernelSize / 2.0f); for (auto Itr(texelsToBlur.CreateIterator()); Itr; ++Itr) { int x = (Itr)->IntPoint().X; int y = (Itr)->IntPoint().Y; float sum = 0; for (int i = 0; i < Manager->blurKernelSize; i++) { int shiftedIndex = i - offset; if (x + shiftedIndex >= 0 && x + shiftedIndex <= signedSize - 1) { if (Manager->UnfoggedData[x + shiftedIndex + (y * signedSize)]) { //If we are currently looking at a position, unveil it completely if (Manager->CurrentlyInSight.Contains(FVector2D(x + shiftedIndex, y))) { sum += (Manager->blurKernel[i] * 255); } //If this is a previously discovered position that we're not currently looking at, put it into a "shroud of darkness". else { sum += (Manager->blurKernel[i] * 100); } } } } Manager->HorizontalBlurData[x + y * signedSize] = (uint8)sum; } //Vertical blur pass for (auto Itr(texelsToBlur.CreateIterator()); Itr; ++Itr) { int x = (Itr)->IntPoint().X; int y = (Itr)->IntPoint().Y; float sum = 0; for (int i = 0; i < Manager->blurKernelSize; i++) { int shiftedIndex = i - offset; if (y + shiftedIndex >= 0 && y + shiftedIndex <= signedSize - 1) { sum += (Manager->blurKernel[i] * Manager->HorizontalBlurData[x + (y + shiftedIndex) * signedSize]); } } Manager->TextureData[x + y * signedSize] = FColor((uint8)FMath::Max(sum, 100.0f), (uint8)FMath::Max(sum, 100.0f), (uint8)FMath::Max(sum, 100.0f), 255); } } else { for (int y = 0; y < signedSize; y++) { for (int x = 0; x < signedSize; x++) { if (Manager->UnfoggedData[x + (y * signedSize)]) { if (Manager->CurrentlyInSight.Contains(FVector2D(x, y))) { Manager->TextureData[x + y * signedSize] = FColor((uint8)255, (uint8)255, (uint8)255, 255); } else { Manager->TextureData[x + y * signedSize] = FColor((uint8)100, (uint8)100, (uint8)100, 255); } } } } } Manager->bHasFOWTextureUpdate = true; }
FVector2D SAutoFolding::ComputeDesiredSize(float) const { return FVector2D(100, 50); }
void SScrubControlPanel::Construct( const SScrubControlPanel::FArguments& InArgs ) { ScrubWidget = NULL; IsRealtimeStreamingMode = InArgs._IsRealtimeStreamingMode; FEditorWidgetsModule& EditorWidgetsModule = FModuleManager::Get().LoadModuleChecked<FEditorWidgetsModule>( "EditorWidgets" ); FTransportControlArgs TransportControlArgs; TransportControlArgs.OnForwardPlay = InArgs._OnClickedForwardPlay; TransportControlArgs.OnRecord = InArgs._OnClickedRecord; TransportControlArgs.OnBackwardPlay = InArgs._OnClickedBackwardPlay; TransportControlArgs.OnForwardStep = InArgs._OnClickedForwardStep; TransportControlArgs.OnBackwardStep = InArgs._OnClickedBackwardStep; TransportControlArgs.OnForwardEnd = InArgs._OnClickedForwardEnd; TransportControlArgs.OnBackwardEnd = InArgs._OnClickedBackwardEnd; TransportControlArgs.OnToggleLooping = InArgs._OnClickedToggleLoop; TransportControlArgs.OnGetLooping = InArgs._OnGetLooping; TransportControlArgs.OnGetPlaybackMode = InArgs._OnGetPlaybackMode; TransportControlArgs.OnTickPlayback = InArgs._OnTickPlayback; FTransportControlArgs TransportControlArgsForRealtimeStreamingMode; TransportControlArgsForRealtimeStreamingMode.OnForwardPlay = TransportControlArgs.OnForwardPlay; TransportControlArgsForRealtimeStreamingMode.OnForwardStep = TransportControlArgs.OnForwardStep; TransportControlArgsForRealtimeStreamingMode.OnGetPlaybackMode = TransportControlArgs.OnGetPlaybackMode; this->ChildSlot .Padding( FMargin( 0.0f, 1.0f) ) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .HAlign(HAlign_Fill) .VAlign(VAlign_Center) .FillWidth(1) .Padding( FMargin( 0.0f, 0.0f) ) [ SNew( SBorder ) [ SAssignNew(ScrubWidget, SScrubWidget) .Value(InArgs._Value) .NumOfKeys(InArgs._NumOfKeys) .SequenceLength(InArgs._SequenceLength) .OnValueChanged(InArgs._OnValueChanged) .OnBeginSliderMovement(InArgs._OnBeginSliderMovement) .OnEndSliderMovement(InArgs._OnEndSliderMovement) .ViewInputMin(InArgs._ViewInputMin) .ViewInputMax(InArgs._ViewInputMax) .OnSetInputViewRange(InArgs._OnSetInputViewRange) .OnCropAnimSequence(InArgs._OnCropAnimSequence) .OnAddAnimSequence(InArgs._OnAddAnimSequence) .OnReZeroAnimSequence(InArgs._OnReZeroAnimSequence) .bAllowZoom(InArgs._bAllowZoom) .DraggableBars(InArgs._DraggableBars) .OnBarDrag(InArgs._OnBarDrag) ] ] // Padding +SHorizontalBox::Slot() .AutoWidth() [ // Padding to make controls line up with the track label widths. // note: a more robust way to accomplish this would be nice. SNew(SSpacer) .Size(FVector2D(16.0f, 16.0f)) ] +SHorizontalBox::Slot() .AutoWidth() [ SNew(SBorder) .Padding(0) .BorderImage(FEditorStyle::GetBrush("NoBorder")) .Visibility(this, &SScrubControlPanel::GetRealtimeControlVisibility, false) [ EditorWidgetsModule.CreateTransportControl(TransportControlArgs) ] ] +SHorizontalBox::Slot() .AutoWidth() [ SNew(SBorder) .Padding(0) .BorderImage(FEditorStyle::GetBrush("NoBorder")) .Visibility(this, &SScrubControlPanel::GetRealtimeControlVisibility, true) [ EditorWidgetsModule.CreateTransportControl(TransportControlArgsForRealtimeStreamingMode) ] ] ]; }
void SAutoFolding::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { //这里处理添加到content里面的逻辑,对齐方式,显示方式 areaSize = AllottedGeometry.GetLocalSize(); float startX = contentMargin.Left; float startY = contentMargin.Top; for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex) { const SBoxPanel::FSlot& CurChild = Children[ChildIndex]; const EVisibility ChildVisibility = CurChild.GetWidget()->GetVisibility(); FVector2D size = CurChild.GetWidget()->GetDesiredSize(); ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild(CurChild.GetWidget(), FVector2D(startX, startY), FVector2D(size.X, size.Y))); } }
void SLogVisualizerTimeline::Construct(const FArguments& InArgs, TSharedPtr<FVisualLoggerTimeSliderController> TimeSliderController, TSharedPtr<SVisualLoggerTimelinesContainer> InContainer, FName InName, FName InOwnerClassName) { OnGetMenuContent = InArgs._OnGetMenuContent; Owner = InContainer; OwnerName = InName; OwnerClassName = InOwnerClassName; ChildSlot [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .Padding(FMargin(0, 4, 0, 0)) .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) .FillWidth(TAttribute<float>::Create(TAttribute<float>::FGetter::CreateLambda([=] { return FLogVisualizer::Get().GetAnimationOutlinerFillPercentage(); }))) [ SAssignNew(PopupAnchor, STimelineLabelAnchor, SharedThis(this)) .OnGetMenuContent(OnGetMenuContent) [ SNew(SBorder) .HAlign(HAlign_Fill) .Padding(FMargin(0, 0, 4, 0)) .BorderImage(FCoreStyle::Get().GetBrush("NoBorder")) [ SNew(SBorder) .VAlign(VAlign_Center) .BorderImage(this, &SLogVisualizerTimeline::GetBorder) .Padding(FMargin(4, 0, 2, 0)) [ // Search box for searching through the outliner SNew(SVerticalBox) + SVerticalBox::Slot() .Padding(FMargin(0, 0, 0, 0)) .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [ SNew(STextBlock) .Text(FText::FromName(OwnerName)) .ShadowOffset(FVector2D(1.f, 1.f)) ] + SVerticalBox::Slot() .Padding(FMargin(0, 0, 0, 0)) .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [ SNew(STextBlock) .Text(FText::FromName(OwnerClassName)) .TextStyle(FLogVisualizerStyle::Get(), TEXT("Sequencer.ClassNAme")) ] ] ] ] ] + SHorizontalBox::Slot() .Padding(FMargin(0, 4, 0, 0)) .HAlign(HAlign_Left) [ SNew(SBox) .Padding(FMargin(0, 0, 0, 0)) .HAlign(HAlign_Left) [ // Search box for searching through the outliner SAssignNew(TimelineBar, SVisualLoggerTimelineBar, TimeSliderController, SharedThis(this)) ] ] ]; ULogVisualizerSettings::StaticClass()->GetDefaultObject<ULogVisualizerSettings>()->OnSettingChanged().AddRaw(this, &SLogVisualizerTimeline::HandleLogVisualizerSettingChanged); FVisualLoggerDatabase::Get().GetEvents().OnNewItem.AddRaw(this, &SLogVisualizerTimeline::OnNewItemHandler); FVisualLoggerDatabase::Get().GetEvents().OnRowSelectionChanged.AddRaw(this, &SLogVisualizerTimeline::OnRowSelectionChanged); }
FVector2D UKismetMathLibrary::MakeVector2D(float X, float Y) { return FVector2D(X, Y); }
/** * Construct the widget * * @param InDeclaration A declaration from which to construct the widget */ void Construct( const STableColumnHeader::FArguments& InArgs, const SHeaderRow::FColumn& Column, const FMargin DefaultHeaderContentPadding ) { check(InArgs._Style); SWidget::Construct( InArgs._ToolTipText, InArgs._ToolTip, InArgs._Cursor, InArgs._IsEnabled, InArgs._Visibility, InArgs._RenderTransform, InArgs._RenderTransformPivot, InArgs._Tag, InArgs._ForceVolatile, InArgs.MetaData ); Style = InArgs._Style; ColumnId = Column.ColumnId; SortMode = Column.SortMode; SortPriority = Column.SortPriority; OnSortModeChanged = Column.OnSortModeChanged; ContextMenuContent = Column.HeaderMenuContent.Widget; ComboVisibility = Column.HeaderComboVisibility; FMargin AdjustedDefaultHeaderContentPadding = DefaultHeaderContentPadding; TAttribute< FText > LabelText = Column.DefaultText; TAttribute< FText > TooltipText = Column.DefaultTooltip; if (Column.HeaderContent.Widget == SNullWidget::NullWidget) { if (!Column.DefaultText.IsSet()) { LabelText = FText::FromString( Column.ColumnId.ToString() + TEXT("[LabelMissing]") ); } if (!Column.DefaultTooltip.IsSet()) { TooltipText = LabelText; } } TSharedPtr< SHorizontalBox > Box; TSharedRef< SOverlay > Overlay = SNew( SOverlay ); Overlay->AddSlot( 0 ) [ SAssignNew( Box, SHorizontalBox ) ]; TSharedRef< SWidget > PrimaryContent = Column.HeaderContent.Widget; if ( PrimaryContent == SNullWidget::NullWidget ) { PrimaryContent = SNew( SBox ) .Padding( OnSortModeChanged.IsBound() ? FMargin( 0, 2, 0, 2 ) : FMargin( 0, 4, 0, 4 ) ) .VAlign( VAlign_Center ) [ SNew(STextBlock) .Text( LabelText ) .ToolTipText( TooltipText ) ]; } if ( OnSortModeChanged.IsBound() ) { //optional main button with the column's title. Used to toggle sorting modes. PrimaryContent = SNew(SButton) .ButtonStyle( FCoreStyle::Get(), "NoBorder" ) .ForegroundColor( FSlateColor::UseForeground() ) .ContentPadding( FMargin( 0, 2, 0, 2 ) ) .OnClicked(this, &STableColumnHeader::OnTitleClicked) [ PrimaryContent ]; } Box->AddSlot() .FillWidth(1.0f) [ PrimaryContent ]; if( Column.HeaderMenuContent.Widget != SNullWidget::NullWidget ) { // Add Drop down menu button (only if menu content has been specified) Box->AddSlot() .AutoWidth() [ SAssignNew( MenuOverlay, SOverlay ) .Visibility( this, &STableColumnHeader::GetMenuOverlayVisibility ) +SOverlay::Slot() [ SNew( SSpacer ) .Size( FVector2D( 12.0f, 0 ) ) ] +SOverlay::Slot() .Padding(FMargin(0,1,0,1)) [ SNew( SBorder ) .Padding( FMargin( 0, 0, AdjustedDefaultHeaderContentPadding.Right, 0 ) ) .BorderImage( this, &STableColumnHeader::GetComboButtonBorderBrush ) [ SAssignNew( ComboButton, SComboButton) .HasDownArrow(false) .ButtonStyle( FCoreStyle::Get(), "NoBorder" ) .ContentPadding( FMargin(0) ) .ButtonContent() [ SNew( SSpacer ) .Size( FVector2D( 14.0f, 0 ) ) ] .MenuContent() [ ContextMenuContent ] ] ] +SOverlay::Slot() .Padding(FMargin(0,0,0,2)) .HAlign( HAlign_Center ) .VAlign( VAlign_Bottom ) [ SNew(SImage) .Image( &Style->MenuDropdownImage ) .ColorAndOpacity( this, &STableColumnHeader::GetComboButtonTint ) .Visibility( EVisibility::HitTestInvisible ) ] ]; AdjustedDefaultHeaderContentPadding.Right = 0; } Overlay->AddSlot( 1 ) .HAlign(HAlign_Center) .VAlign( VAlign_Top ) .Padding( FMargin( 0, 2, 0, 0 ) ) [ SNew(SImage) .Image( this, &STableColumnHeader::GetSortingBrush ) .Visibility( this, &STableColumnHeader::GetSortModeVisibility ) ]; this->ChildSlot [ SNew( SBorder ) .BorderImage( this, &STableColumnHeader::GetHeaderBackgroundBrush ) .HAlign( Column.HeaderHAlignment ) .VAlign( Column.HeaderVAlignment ) .Padding( Column.HeaderContentPadding.Get( AdjustedDefaultHeaderContentPadding ) ) [ Overlay ] ]; }
FVector2D SErrorText::GetDesiredSizeScale() const { const float AnimAmount = ExpandAnimation.GetLerp(); return FVector2D( 1.0f, AnimAmount ); }
/** * Generates a pseudo-random position within a unit disk, * Whose PDF == 1 / PI, which is a uniform distribution over the area of the disk. */ FVector2D GetUniformUnitDiskPosition(FLMRandomStream& RandomStream) { const float Theta = 2.0f * (float)PI * RandomStream.GetFraction(); const float Radius = FMath::Sqrt(RandomStream.GetFraction()); return FVector2D(Radius * FMath::Cos(Theta), Radius * FMath::Sin(Theta)); }
FSlateRect FGeometry::GetClippingRect() const { return TransformRect(GetAccumulatedLayoutTransform(), FSlateRect(FVector2D(0.0f,0.0f), Size)); }
void FMainFrameHandler::ShutDownEditor() { FEditorDelegates::OnShutdownPostPackagesSaved.Broadcast(); // Any pending autosaves should not happen. A tick will go by before the editor shuts down and we want to avoid auto-saving during this time. GUnrealEd->GetPackageAutoSaver().ResetAutoSaveTimer(); GEditor->RequestEndPlayMap(); // End any play on console/PC games still happening GEditor->EndPlayOnLocalPc(); // Cancel any current Launch On in progress GEditor->CancelPlayingViaLauncher(); TSharedPtr<SWindow> RootWindow = RootWindowPtr.Pin(); // Save root window placement so we can restore it. if (RootWindow.IsValid()) { FSlateRect WindowRect = RootWindow->GetNonMaximizedRectInScreen(); FRootWindowLocation RootWindowLocation(FVector2D(WindowRect.Left, WindowRect.Top), WindowRect.GetSize(), RootWindow->IsWindowMaximized()); RootWindowLocation.SaveToIni(); } // Save the visual state of the editor before we even // ask whether we can shut down. TSharedRef<FGlobalTabmanager> GlobalTabManager = FGlobalTabmanager::Get(); if (FUnrealEdMisc::Get().IsSavingLayoutOnClosedAllowed()) { GlobalTabManager->SaveAllVisualState(); } else { GConfig->EmptySection(TEXT("EditorLayouts"), *GEditorLayoutIni); } // Clear the callback for destructionfrom the main tab; otherwise it will re-enter this shutdown function. if (MainTabPtr.IsValid()) { MainTabPtr.Pin()->SetOnTabClosed(SDockTab::FOnTabClosedCallback()); } // Inform the AssetEditorManager that the editor is exiting so that it may save open assets // and report usage stats FAssetEditorManager::Get().OnExit(); if (RootWindow.IsValid()) { RootWindow->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride()); RootWindow->RequestDestroyWindow(); } // Save out any config settings for the editor so they don't get lost GEditor->SaveConfig(); GLevelEditorModeTools().SaveConfig(); // Delete user settings, if requested if (FUnrealEdMisc::Get().IsDeletePreferences()) { IFileManager::Get().Delete(*GEditorPerProjectIni); } // Take a screenshot of this project for the project browser if (FApp::HasGameName()) { const FString ExistingBaseFilename = FString(FApp::GetGameName()) + TEXT(".png"); const FString ExistingScreenshotFilename = FPaths::Combine(*FPaths::GameDir(), *ExistingBaseFilename); // If there is already a screenshot, no need to take an auto screenshot if (!FPaths::FileExists(ExistingScreenshotFilename)) { const FString ScreenShotFilename = FPaths::Combine(*FPaths::GameSavedDir(), TEXT("AutoScreenshot.png")); FViewport* Viewport = GEditor->GetActiveViewport(); if (Viewport) { UThumbnailManager::CaptureProjectThumbnail(Viewport, ScreenShotFilename, false); } } } // Shut down the editor // NOTE: We can't close the editor from within this stack frame as it will cause various DLLs // (such as MainFrame) to become unloaded out from underneath the code pointer. We'll shut down // as soon as it's safe to do so. // Note this is the only place in slate that should be calling QUIT_EDITOR GEngine->DeferredCommands.Add(TEXT("QUIT_EDITOR")); }
bool FGeometry::IsUnderLocation(const FVector2D& AbsoluteCoordinate) const { // this render transform invert is a little expensive. We might consider caching it. return FSlateRect(FVector2D(0.0f, 0.0f), Size).ContainsPoint(TransformPoint(Inverse(GetAccumulatedRenderTransform()), AbsoluteCoordinate)); }
void UPaperTerrainComponent::OnSplineEdited() { // Ensure we have the data structure for the desired collision method if (SpriteCollisionDomain == ESpriteCollisionMode::Use3DPhysics) { CachedBodySetup = NewObject<UBodySetup>(this); } else { CachedBodySetup = nullptr; } const float SlopeAnalysisTimeRate = 10.0f; const float FillRasterizationTimeRate = 100.0f; GeneratedSpriteGeometry.Empty(); if ((AssociatedSpline != nullptr) && (TerrainMaterial != nullptr)) { if (AssociatedSpline->ReparamStepsPerSegment != ReparamStepsPerSegment) { AssociatedSpline->ReparamStepsPerSegment = ReparamStepsPerSegment; AssociatedSpline->UpdateSpline(); } FRandomStream RandomStream(RandomSeed); const FInterpCurveVector& SplineInfo = AssociatedSpline->SplineInfo; float SplineLength = AssociatedSpline->GetSplineLength(); struct FTerrainRuleHelper { public: FTerrainRuleHelper(const FPaperTerrainMaterialRule* Rule) : StartWidth(0.0f) , EndWidth(0.0f) { for (const UPaperSprite* Sprite : Rule->Body) { if (Sprite != nullptr) { const float Width = GetSpriteRenderDataBounds2D(Sprite->BakedRenderData).GetSize().X; if (Width > 0.0f) { ValidBodies.Add(Sprite); ValidBodyWidths.Add(Width); } } } if (Rule->StartCap != nullptr) { const float Width = GetSpriteRenderDataBounds2D(Rule->StartCap->BakedRenderData).GetSize().X; if (Width > 0.0f) { StartWidth = Width; } } if (Rule->EndCap != nullptr) { const float Width = GetSpriteRenderDataBounds2D(Rule->EndCap->BakedRenderData).GetSize().X; if (Width > 0.0f) { EndWidth = Width; } } } float StartWidth; float EndWidth; TArray<const UPaperSprite*> ValidBodies; TArray<float> ValidBodyWidths; int32 GenerateBodyIndex(FRandomStream& InRandomStream) const { check(ValidBodies.Num() > 0); return InRandomStream.GetUnsignedInt() % ValidBodies.Num(); } }; // Split the spline into segments based on the slope rules in the material TArray<FTerrainSegment> Segments; FTerrainSegment* ActiveSegment = new (Segments) FTerrainSegment(); ActiveSegment->StartTime = 0.0f; ActiveSegment->EndTime = SplineLength; { float CurrentTime = 0.0f; while (CurrentTime < SplineLength) { const FTransform Frame(GetTransformAtDistance(CurrentTime)); const FVector UnitTangent = Frame.GetUnitAxis(EAxis::X); const float RawSlopeAngleRadians = FMath::Atan2(FVector::DotProduct(UnitTangent, PaperAxisY), FVector::DotProduct(UnitTangent, PaperAxisX)); const float RawSlopeAngle = FMath::RadiansToDegrees(RawSlopeAngleRadians); const float SlopeAngle = FMath::Fmod(FMath::UnwindDegrees(RawSlopeAngle) + 360.0f, 360.0f); const FPaperTerrainMaterialRule* DesiredRule = (TerrainMaterial->Rules.Num() > 0) ? &(TerrainMaterial->Rules[0]) : nullptr; for (const FPaperTerrainMaterialRule& TestRule : TerrainMaterial->Rules) { if ((SlopeAngle >= TestRule.MinimumAngle) && (SlopeAngle < TestRule.MaximumAngle)) { DesiredRule = &TestRule; } } if (ActiveSegment->Rule != DesiredRule) { if (ActiveSegment->Rule == nullptr) { ActiveSegment->Rule = DesiredRule; } else { ActiveSegment->EndTime = CurrentTime; // Segment is too small, delete it if (ActiveSegment->EndTime < ActiveSegment->StartTime + 2.0f * SegmentOverlapAmount) { Segments.Pop(false); } ActiveSegment = new (Segments)FTerrainSegment(); ActiveSegment->StartTime = CurrentTime; ActiveSegment->EndTime = SplineLength; ActiveSegment->Rule = DesiredRule; } } CurrentTime += SlopeAnalysisTimeRate; } } // Account for overlap for (FTerrainSegment& Segment : Segments) { Segment.StartTime -= SegmentOverlapAmount; Segment.EndTime += SegmentOverlapAmount; } // Convert those segments to actual geometry for (FTerrainSegment& Segment : Segments) { check(Segment.Rule); FTerrainRuleHelper RuleHelper(Segment.Rule); float RemainingSegStart = Segment.StartTime + RuleHelper.StartWidth; float RemainingSegEnd = Segment.EndTime - RuleHelper.EndWidth; const float BodyDistance = RemainingSegEnd - RemainingSegStart; float DistanceBudget = BodyDistance; bool bUseBodySegments = (DistanceBudget > 0.0f) && (RuleHelper.ValidBodies.Num() > 0); // Add the start cap if (RuleHelper.StartWidth > 0.0f) { new (Segment.Stamps) FTerrainSpriteStamp(Segment.Rule->StartCap, Segment.StartTime + RuleHelper.StartWidth * 0.5f, /*bIsEndCap=*/ bUseBodySegments); } // Add body segments if (bUseBodySegments) { int32 NumSegments = 0; float Position = RemainingSegStart; while (DistanceBudget > 0.0f) { const int32 BodyIndex = RuleHelper.GenerateBodyIndex(RandomStream); const UPaperSprite* Sprite = RuleHelper.ValidBodies[BodyIndex]; const float Width = RuleHelper.ValidBodyWidths[BodyIndex]; if ((NumSegments > 0) && ((Width * 0.5f) > DistanceBudget)) { break; } new (Segment.Stamps) FTerrainSpriteStamp(Sprite, Position + (Width * 0.5f), /*bIsEndCap=*/ false); DistanceBudget -= Width; Position += Width; ++NumSegments; } const float UsedSpace = (BodyDistance - DistanceBudget); const float OverallScaleFactor = BodyDistance / UsedSpace; // Stretch body segments float PositionCorrectionSum = 0.0f; for (int32 Index = 0; Index < NumSegments; ++Index) { FTerrainSpriteStamp& Stamp = Segment.Stamps[Index + (Segment.Stamps.Num() - NumSegments)]; const float WidthChange = (OverallScaleFactor - 1.0f) * Stamp.NominalWidth; const float FirstGapIsSmallerFactor = (Index == 0) ? 0.5f : 1.0f; PositionCorrectionSum += WidthChange * FirstGapIsSmallerFactor; Stamp.Scale = OverallScaleFactor; Stamp.Time += PositionCorrectionSum; } } else { // Stretch endcaps } // Add the end cap if (RuleHelper.EndWidth > 0.0f) { new (Segment.Stamps) FTerrainSpriteStamp(Segment.Rule->EndCap, Segment.EndTime - RuleHelper.EndWidth * 0.5f, /*bIsEndCap=*/ bUseBodySegments); } } // Convert stamps into geometry SpawnSegments(Segments, !bClosedSpline || (bClosedSpline && !bFilledSpline)); // Generate the background if the spline is closed if (bClosedSpline && bFilledSpline) { // Create a polygon from the spline FBox2D SplineBounds(ForceInit); TArray<FVector2D> SplinePolyVertices2D; TArray<float> SplineEdgeOffsetAmounts; { float CurrentTime = 0.0f; while (CurrentTime < SplineLength) { const float Param = AssociatedSpline->SplineReparamTable.Eval(CurrentTime, 0.0f); const FVector Position3D = AssociatedSpline->SplineInfo.Eval(Param, FVector::ZeroVector); const FVector2D Position2D = FVector2D(FVector::DotProduct(Position3D, PaperAxisX), FVector::DotProduct(Position3D, PaperAxisY)); SplineBounds += Position2D; SplinePolyVertices2D.Add(Position2D); // Find the collision offset for this sample point float CollisionOffset = 0; for (int SegmentIndex = 0; SegmentIndex < Segments.Num(); ++SegmentIndex) { FTerrainSegment& Segment = Segments[SegmentIndex]; if (CurrentTime >= Segment.StartTime && CurrentTime <= Segment.EndTime) { CollisionOffset = (Segment.Rule != nullptr) ? (Segment.Rule->CollisionOffset * 0.25f) : 0; break; } } SplineEdgeOffsetAmounts.Add(CollisionOffset); CurrentTime += FillRasterizationTimeRate; } } SimplifyPolygon(SplinePolyVertices2D, SplineEdgeOffsetAmounts); // Always CCW and facing forward regardless of spline winding TArray<FVector2D> CorrectedSplineVertices; PaperGeomTools::CorrectPolygonWinding(CorrectedSplineVertices, SplinePolyVertices2D, false); TArray<FVector2D> TriangulatedPolygonVertices; PaperGeomTools::TriangulatePoly(/*out*/TriangulatedPolygonVertices, CorrectedSplineVertices, false); GenerateCollisionDataFromPolygon(SplinePolyVertices2D, SplineEdgeOffsetAmounts, TriangulatedPolygonVertices); if (TerrainMaterial->InteriorFill != nullptr) { const UPaperSprite* FillSprite = TerrainMaterial->InteriorFill; FPaperTerrainSpriteGeometry& MaterialBatch = *new (GeneratedSpriteGeometry)FPaperTerrainSpriteGeometry(); //@TODO: Look up the existing one instead MaterialBatch.Material = FillSprite->GetDefaultMaterial(); FSpriteDrawCallRecord& FillDrawCall = *new (MaterialBatch.Records) FSpriteDrawCallRecord(); FillDrawCall.BuildFromSprite(FillSprite); FillDrawCall.RenderVerts.Empty(); FillDrawCall.Color = TerrainColor; FillDrawCall.Destination = PaperAxisZ * 0.1f; const FVector2D TextureSize = GetSpriteRenderDataBounds2D(FillSprite->BakedRenderData).GetSize(); const FVector2D SplineSize = SplineBounds.GetSize(); GenerateFillRenderDataFromPolygon(FillSprite, FillDrawCall, TextureSize, TriangulatedPolygonVertices); //@TODO: Add support for the fill sprite being smaller than the entire texture #if NOT_WORKING const float StartingDivisionPointX = FMath::CeilToFloat(SplineBounds.Min.X / TextureSize.X); const float StartingDivisionPointY = FMath::CeilToFloat(SplineBounds.Min.Y / TextureSize.Y); FPoly VerticalRemainder = SplineAsPolygon; for (float Y = StartingDivisionPointY; VerticalRemainder.Vertices.Num() > 0; Y += TextureSize.Y) { FPoly Top; FPoly Bottom; const FVector SplitBaseOuter = (Y * PaperAxisY); VerticalRemainder.SplitWithPlane(SplitBaseOuter, -PaperAxisY, &Top, &Bottom, 1); VerticalRemainder = Bottom; FPoly HorizontalRemainder = Top; for (float X = StartingDivisionPointX; HorizontalRemainder.Vertices.Num() > 0; X += TextureSize.X) { FPoly Left; FPoly Right; const FVector SplitBaseInner = (X * PaperAxisX) + (Y * PaperAxisY); HorizontalRemainder.SplitWithPlane(SplitBaseInner, -PaperAxisX, &Left, &Right, 1); HorizontalRemainder = Right; //BROKEN, function no longer exists (split into 2 parts) SpawnFromPoly(Segments, SplineEdgeOffsetAmounts, FillSprite, FillDrawCall, TextureSize, Left); } } #endif } } // Draw debug frames at the start and end of the spline #if PAPER_TERRAIN_DRAW_DEBUG { const float Time = 5.0f; { FTransform WorldTransform = GetTransformAtDistance(0.0f) * ComponentToWorld; DrawDebugCoordinateSystem(GetWorld(), WorldTransform.GetLocation(), FRotator(WorldTransform.GetRotation()), 30.0f, true, Time, SDPG_Foreground); } { FTransform WorldTransform = GetTransformAtDistance(SplineLength) * ComponentToWorld; DrawDebugCoordinateSystem(GetWorld(), WorldTransform.GetLocation(), FRotator(WorldTransform.GetRotation()), 30.0f, true, Time, SDPG_Foreground); } } #endif } RecreateRenderState_Concurrent(); }
TEXT("r.AOUseJitter"), GAOUseJitter, TEXT("Whether to use 4x temporal supersampling with Screen Grid DFAO. When jitter is disabled, a shorter history can be used but there will be more spatial aliasing."), ECVF_Cheat | ECVF_RenderThreadSafe ); int32 GConeTraceDownsampleFactor = 4; FIntPoint GetBufferSizeForConeTracing() { return FIntPoint::DivideAndRoundDown(GetBufferSizeForAO(), GConeTraceDownsampleFactor); } FVector2D JitterOffsets[4] = { FVector2D(1, 0), FVector2D(3, 1), FVector2D(2, 3), FVector2D(0, 2) }; extern int32 GAOUseHistory; FVector2D GetJitterOffset(int32 SampleIndex) { if (GAOUseJitter && GAOUseHistory) { return JitterOffsets[SampleIndex]; } return FVector2D(0, 0);
void UBuoyancyForceComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // If disabled or we are not attached to a parent component, return. if (!bIsActive || !GetAttachParent()) return; if (!OceanManager) return; UPrimitiveComponent* BasePrimComp = Cast<UPrimitiveComponent>(GetAttachParent()); if (!BasePrimComp) return; if (!BasePrimComp->IsSimulatingPhysics()) { if (!SnapToSurfaceIfNoPhysics) return; UE_LOG(LogTemp, Warning, TEXT("Running in no physics mode..")); float waveHeight = OceanManager->GetWaveHeightValue(BasePrimComp->GetComponentLocation(), World, true, TwoGerstnerIterations).Z; BasePrimComp->SetWorldLocation(FVector(BasePrimComp->GetComponentLocation().X, BasePrimComp->GetComponentLocation().Y, waveHeight)); return; } //Get gravity float Gravity = BasePrimComp->GetPhysicsVolume()->GetGravityZ(); //--------------- If Skeletal --------------- USkeletalMeshComponent* SkeletalComp = Cast<USkeletalMeshComponent>(GetAttachParent()); if (SkeletalComp && ApplyForceToBones) { TArray<FName> BoneNames; SkeletalComp->GetBoneNames(BoneNames); for (int32 Itr = 0; Itr < BoneNames.Num(); Itr++) { FBodyInstance* BI = SkeletalComp->GetBodyInstance(BoneNames[Itr], false); if (BI && BI->IsValidBodyInstance() && BI->bEnableGravity) //Buoyancy doesn't exist without gravity { bool isUnderwater = false; //FVector worldBoneLoc = SkeletalComp->GetBoneLocation(BoneNames[Itr]); FVector worldBoneLoc = BI->GetCOMPosition(); //Use center of mass of the bone's physics body instead of bone's location FVector waveHeight = OceanManager->GetWaveHeightValue(worldBoneLoc, World, true, TwoGerstnerIterations); float BoneDensity = MeshDensity; float BoneTestRadius = FMath::Abs(TestPointRadius); float SignedBoneRadius = FMath::Sign(Gravity) * TestPointRadius; //Direction of radius (test radius is actually a Z offset, should probably rename it!). Just in case we need an upside down world. //Get density & radius from the override array, if available. for (int pointIndex = 0; pointIndex < BoneOverride.Num(); pointIndex++) { FStructBoneOverride Override = BoneOverride[pointIndex]; if (Override.BoneName.IsEqual(BoneNames[Itr])) { BoneDensity = Override.Density; BoneTestRadius = FMath::Abs(Override.TestRadius); SignedBoneRadius = FMath::Sign(Gravity) * BoneTestRadius; } } //If test point radius is below water surface, add buoyancy force. if (waveHeight.Z > (worldBoneLoc.Z + SignedBoneRadius)) { isUnderwater = true; float DepthMultiplier = (waveHeight.Z - (worldBoneLoc.Z + SignedBoneRadius)) / (BoneTestRadius * 2); DepthMultiplier = FMath::Clamp(DepthMultiplier, 0.f, 1.f); float Mass = SkeletalComp->CalculateMass(BoneNames[Itr]); //Mass of this specific bone's physics body /** * -------- * Buoyancy force formula: (Volume(Mass / Density) * Fluid Density * -Gravity) / Total Points * Depth Multiplier * -------- */ float BuoyancyForceZ = Mass / BoneDensity * FluidDensity * -Gravity * DepthMultiplier; //Velocity damping. FVector DampingForce = -BI->GetUnrealWorldVelocity() * VelocityDamper * Mass * DepthMultiplier; //Experimental xy wave force if (EnableWaveForces) { float waveVelocity = FMath::Clamp(BI->GetUnrealWorldVelocity().Z, -20.f, 150.f) * (1 - DepthMultiplier); DampingForce += FVector(OceanManager->GlobalWaveDirection.X, OceanManager->GlobalWaveDirection.Y, 0) * Mass * waveVelocity * WaveForceMultiplier; } //Add force to this bone BI->AddForce(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ)); //BasePrimComp->AddForceAtLocation(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ), worldBoneLoc, BoneNames[Itr]); } //Apply fluid damping & clamp velocity if (isUnderwater) { BI->SetLinearVelocity(-BI->GetUnrealWorldVelocity() * (FluidLinearDamping / 10), true); BI->SetAngularVelocity(-BI->GetUnrealWorldAngularVelocity() * (FluidAngularDamping / 10), true); //Clamp the velocity to MaxUnderwaterVelocity if (ClampMaxVelocity && BI->GetUnrealWorldVelocity().Size() > MaxUnderwaterVelocity) { FVector Velocity = BI->GetUnrealWorldVelocity().GetSafeNormal() * MaxUnderwaterVelocity; BI->SetLinearVelocity(Velocity, false); } } if (DrawDebugPoints) { FColor DebugColor = FLinearColor(0.8, 0.7, 0.2, 0.8).ToRGBE(); if (isUnderwater) { DebugColor = FLinearColor(0, 0.2, 0.7, 0.8).ToRGBE(); } //Blue color underwater, yellow out of watter DrawDebugSphere(World, worldBoneLoc, BoneTestRadius, 8, DebugColor); } } } return; } //-------------------------------------------------------- float TotalPoints = TestPoints.Num(); if (TotalPoints < 1) return; int PointsUnderWater = 0; for (int pointIndex = 0; pointIndex < TotalPoints; pointIndex++) { if (!TestPoints.IsValidIndex(pointIndex)) return; //Array size changed during runtime bool isUnderwater = false; FVector testPoint = TestPoints[pointIndex]; FVector worldTestPoint = BasePrimComp->GetComponentTransform().TransformPosition(testPoint); FVector waveHeight = OceanManager->GetWaveHeightValue(worldTestPoint, World, !EnableWaveForces, TwoGerstnerIterations); //Direction of radius (test radius is actually a Z offset, should probably rename it!). Just in case we need an upside down world. float SignedRadius = FMath::Sign(BasePrimComp->GetPhysicsVolume()->GetGravityZ()) * TestPointRadius; //If test point radius is below water surface, add buoyancy force. if (waveHeight.Z > (worldTestPoint.Z + SignedRadius) && BasePrimComp->IsGravityEnabled()) //Buoyancy doesn't exist without gravity { PointsUnderWater++; isUnderwater = true; float DepthMultiplier = (waveHeight.Z - (worldTestPoint.Z + SignedRadius)) / (TestPointRadius * 2); DepthMultiplier = FMath::Clamp(DepthMultiplier, 0.f, 1.f); //If we have a point density override, use the overridden value instead of MeshDensity float PointDensity = PointDensityOverride.IsValidIndex(pointIndex) ? PointDensityOverride[pointIndex] : MeshDensity; /** * -------- * Buoyancy force formula: (Volume(Mass / Density) * Fluid Density * -Gravity) / Total Points * Depth Multiplier * -------- */ float BuoyancyForceZ = BasePrimComp->GetMass() / PointDensity * FluidDensity * -Gravity / TotalPoints * DepthMultiplier; //Experimental velocity damping using VelocityAtPoint. FVector DampingForce = -GetUnrealVelocityAtPoint(BasePrimComp, worldTestPoint) * VelocityDamper * BasePrimComp->GetMass() * DepthMultiplier; //Experimental xy wave force if (EnableWaveForces) { DampingForce += BasePrimComp->GetMass() * FVector2D(waveHeight.X, waveHeight.Y).Size() * FVector(OceanManager->GlobalWaveDirection.X, OceanManager->GlobalWaveDirection.Y, 0) * WaveForceMultiplier / TotalPoints; //float waveVelocity = FMath::Clamp(GetUnrealVelocityAtPoint(BasePrimComp, worldTestPoint).Z, -20.f, 150.f) * (1 - DepthMultiplier); //DampingForce += OceanManager->GlobalWaveDirection * BasePrimComp->GetMass() * waveVelocity * WaveForceMultiplier / TotalPoints; } //Add force for this test point BasePrimComp->AddForceAtLocation(FVector(DampingForce.X, DampingForce.Y, DampingForce.Z + BuoyancyForceZ), worldTestPoint); } if (DrawDebugPoints) { FColor DebugColor = FLinearColor(0.8, 0.7, 0.2, 0.8).ToRGBE(); if (isUnderwater) { DebugColor = FLinearColor(0, 0.2, 0.7, 0.8).ToRGBE(); } //Blue color underwater, yellow out of watter DrawDebugSphere(World, worldTestPoint, TestPointRadius, 8, DebugColor); } } //Clamp the velocity to MaxUnderwaterVelocity if there is any point underwater if (ClampMaxVelocity && PointsUnderWater > 0 && BasePrimComp->GetPhysicsLinearVelocity().Size() > MaxUnderwaterVelocity) { FVector Velocity = BasePrimComp->GetPhysicsLinearVelocity().GetSafeNormal() * MaxUnderwaterVelocity; BasePrimComp->SetPhysicsLinearVelocity(Velocity); } //Update damping based on number of underwater test points BasePrimComp->SetLinearDamping(_baseLinearDamping + FluidLinearDamping / TotalPoints * PointsUnderWater); BasePrimComp->SetAngularDamping(_baseAngularDamping + FluidAngularDamping / TotalPoints * PointsUnderWater); }
void UWorldThumbnailRenderer::GetView(UWorld* World, FSceneViewFamily* ViewFamily, int32 X, int32 Y, uint32 SizeX, uint32 SizeY) const { check(ViewFamily); check(World); check(World->PersistentLevel); FIntRect ViewRect( FMath::Max<int32>(X, 0), FMath::Max<int32>(Y, 0), FMath::Max<int32>(X + SizeX, 0), FMath::Max<int32>(Y + SizeY, 0)); if (ViewRect.Width() > 0 && ViewRect.Height() > 0) { FBox WorldBox(0); TArray<ULevel*> LevelsToRender = World->GetLevels(); for ( auto* Level : LevelsToRender ) { if (Level && Level->bIsVisible) { ALevelBounds* LevelBounds = Level->LevelBoundsActor.Get(); if (!LevelBounds) { // Ensure a Level Bounds Actor exists for future renders FActorSpawnParameters SpawnParameters; SpawnParameters.OverrideLevel = Level; LevelBounds = World->SpawnActor<ALevelBounds>(SpawnParameters); LevelBounds->UpdateLevelBoundsImmediately(); Level->LevelBoundsActor = LevelBounds; } if (!LevelBounds->IsUsingDefaultBounds()) { WorldBox += LevelBounds->GetComponentsBoundingBox(); } } } UWorldThumbnailInfo* ThumbnailInfo = Cast<UWorldThumbnailInfo>(World->ThumbnailInfo); if (!ThumbnailInfo) { ThumbnailInfo = UWorldThumbnailInfo::StaticClass()->GetDefaultObject<UWorldThumbnailInfo>(); } const FVector Origin = WorldBox.GetCenter(); FMatrix ViewMatrix = FTranslationMatrix(-Origin); FMatrix ProjectionMatrix; float FOVScreenSize = 0; // Screen size taking FOV into account if (ThumbnailInfo->CameraMode == ECameraProjectionMode::Perspective) { const float FOVDegrees = 30.f; const float HalfFOVRadians = FMath::DegreesToRadians<float>(FOVDegrees) * 0.5f; const float WorldRadius = WorldBox.GetSize().Size() / 2.f; float TargetDistance = WorldRadius / FMath::Tan(HalfFOVRadians); if (ensure(ThumbnailInfo)) { if (TargetDistance + ThumbnailInfo->OrbitZoom < 0) { ThumbnailInfo->OrbitZoom = -TargetDistance; } } float OrbitPitch = GlobalOrbitPitchOffset + ThumbnailInfo->OrbitPitch; float OrbitYaw = GlobalOrbitYawOffset + ThumbnailInfo->OrbitYaw; float OrbitZoom = TargetDistance + ThumbnailInfo->OrbitZoom; // Ensure a minimum camera distance to prevent problems with really small objects const float MinCameraDistance = 48; OrbitZoom = FMath::Max<float>(MinCameraDistance, OrbitZoom); const FRotator RotationOffsetToViewCenter(0.f, 90.f, 0.f); ViewMatrix = ViewMatrix * FRotationMatrix(FRotator(0, OrbitYaw, 0)) * FRotationMatrix(FRotator(0, 0, OrbitPitch)) * FTranslationMatrix(FVector(0, OrbitZoom, 0)) * FInverseRotationMatrix(RotationOffsetToViewCenter); ViewMatrix = ViewMatrix * FMatrix( FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, 0, 1)); const float NearPlane = 1.0f; ProjectionMatrix = FReversedZPerspectiveMatrix( HalfFOVRadians, 1.0f, 1.0f, NearPlane ); FOVScreenSize = SizeX / FMath::Tan(FOVDegrees); } else if (ThumbnailInfo->CameraMode == ECameraProjectionMode::Orthographic) { FVector2D WorldSizeMin2D; FVector2D WorldSizeMax2D; switch (ThumbnailInfo->OrthoDirection) { case EOrthoThumbnailDirection::Top: ViewMatrix = ViewMatrix * FMatrix( FPlane(1, 0, 0, 0), FPlane(0, -1, 0, 0), FPlane(0, 0, -1, 0), FPlane(0, 0, Origin.Z, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.X,WorldBox.Min.Y); WorldSizeMax2D = FVector2D(WorldBox.Max.X,WorldBox.Max.Y); break; case EOrthoThumbnailDirection::Bottom: ViewMatrix = ViewMatrix * FMatrix( FPlane(1, 0, 0, 0), FPlane(0, -1, 0, 0), FPlane(0, 0, 1, 0), FPlane(0, 0, Origin.Z, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.X, WorldBox.Min.Y); WorldSizeMax2D = FVector2D(WorldBox.Max.X, WorldBox.Max.Y); break; case EOrthoThumbnailDirection::Front: ViewMatrix = ViewMatrix * FMatrix( FPlane(1, 0, 0, 0), FPlane(0, 0, -1, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, Origin.Y, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.X, WorldBox.Min.Z); WorldSizeMax2D = FVector2D(WorldBox.Max.X, WorldBox.Max.Z); break; case EOrthoThumbnailDirection::Back: ViewMatrix = ViewMatrix * FMatrix( FPlane(-1, 0, 0, 0), FPlane(0, 0, 1, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, Origin.Y, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.X, WorldBox.Min.Z); WorldSizeMax2D = FVector2D(WorldBox.Max.X, WorldBox.Max.Z); break; case EOrthoThumbnailDirection::Left: ViewMatrix = ViewMatrix * FMatrix( FPlane(0, 0, -1, 0), FPlane(-1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, Origin.X, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.Y, WorldBox.Min.Z); WorldSizeMax2D = FVector2D(WorldBox.Max.Y, WorldBox.Max.Z); break; case EOrthoThumbnailDirection::Right: ViewMatrix = ViewMatrix * FMatrix( FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, Origin.X, 1)); WorldSizeMin2D = FVector2D(WorldBox.Min.Y, WorldBox.Min.Z); WorldSizeMax2D = FVector2D(WorldBox.Max.Y, WorldBox.Max.Z); break; default: // Unknown OrthoDirection ensureMsgf(false, TEXT("Unknown thumbnail OrthoDirection")); break; } FVector2D WorldSize2D = (WorldSizeMax2D - WorldSizeMin2D); WorldSize2D.X = FMath::Abs(WorldSize2D.X); WorldSize2D.Y = FMath::Abs(WorldSize2D.Y); const bool bUseXAxis = (WorldSize2D.X / WorldSize2D.Y) > 1.f; const float WorldAxisSize = bUseXAxis ? WorldSize2D.X : WorldSize2D.Y; const uint32 ViewportAxisSize = bUseXAxis ? SizeX : SizeY; const float OrthoZoom = WorldAxisSize / ViewportAxisSize / 2.f; const float OrthoWidth = FMath::Max(1.f, SizeX * OrthoZoom); const float OrthoHeight = FMath::Max(1.f, SizeY * OrthoZoom); const float ZOffset = HALF_WORLD_MAX; ProjectionMatrix = FReversedZOrthoMatrix( OrthoWidth, OrthoHeight, 0.5f / ZOffset, ZOffset ); FOVScreenSize = SizeX; } else { // Unknown CameraMode ensureMsgf(false, TEXT("Unknown thumbnail CameraMode")); } FSceneViewInitOptions ViewInitOptions; ViewInitOptions.ViewFamily = ViewFamily; ViewInitOptions.SetViewRectangle(ViewRect); ViewInitOptions.BackgroundColor = FLinearColor::Black; ViewInitOptions.ViewMatrix = ViewMatrix; ViewInitOptions.ProjectionMatrix = ProjectionMatrix; FSceneView* NewView = new FSceneView(ViewInitOptions); ViewFamily->Views.Add(NewView); // Tell the texture streaming system about this thumbnail view, so the textures will stream in as needed // NOTE: Sizes may not actually be in screen space depending on how the thumbnail ends up stretched by the UI. Not a big deal though. // NOTE: Textures still take a little time to stream if the view has not been re-rendered recently, so they may briefly appear blurry while mips are prepared // NOTE: Content Browser only renders thumbnails for loaded assets, and only when the mouse is over the panel. They'll be frozen in their last state while the mouse cursor is not over the panel. This is for performance reasons IStreamingManager::Get().AddViewInformation(Origin, SizeX, FOVScreenSize); } }
void SProfilerThreadView::DrawFramesBackgroundAndTimelines() const { static const FSlateColorBrush SolidWhiteBrush = FSlateColorBrush( FColorList::White ); check( PaintState ); const double ThreadViewOffsetPx = PositionXMS*NumPixelsPerMillisecond; PaintState->LayerId++; TArray<FVector2D> LinePoints; // Draw frames background for easier reading. for( const auto& ThreadNode : ProfilerUIStream.ThreadNodes ) { if( ThreadNode.StatName == NAME_GameThread ) { const FVector2D PositionPx = ThreadNode.GetLocalPosition( ThreadViewOffsetPx, -1.0f ); const FVector2D SizePx = FVector2D( ThreadNode.WidthPx, PaintState->Size2D().Y ); const FSlateRect ClippedFrameBackgroundRect = PaintState->LocalClippingRect.IntersectionWith( FSlateRect( PositionPx, PositionPx + SizePx ) ); FSlateDrawElement::MakeBox ( PaintState->OutDrawElements, PaintState->LayerId, PaintState->AllottedGeometry.ToPaintGeometry( ClippedFrameBackgroundRect.GetTopLeft(), ClippedFrameBackgroundRect.GetSize() ), &SolidWhiteBrush, PaintState->AbsoluteClippingRect, PaintState->DrawEffects, ThreadNode.FrameIndex % 2 ? FColorList::White.WithAlpha( 64 ) : FColorList::White.WithAlpha( 128 ) ); // Check if this frame time marker is inside the visible area. const float LocalPositionXPx = PositionPx.X + SizePx.X; if( LocalPositionXPx < 0.0f || LocalPositionXPx > PaintState->Size2D().X ) { continue; } LinePoints.Reset( 2 ); LinePoints.Add( FVector2D( LocalPositionXPx, 0.0f ) ); LinePoints.Add( FVector2D( LocalPositionXPx, PaintState->Size2D().Y ) ); // Draw frame time marker. FSlateDrawElement::MakeLines ( PaintState->OutDrawElements, PaintState->LayerId, PaintState->AllottedGeometry.ToPaintGeometry(), LinePoints, PaintState->AbsoluteClippingRect, PaintState->DrawEffects, PaintState->WidgetStyle.GetColorAndOpacityTint() * FColorList::SkyBlue, false ); } } PaintState->LayerId++; const double PositionXStartPx = FMath::TruncToFloat( PositionXMS*NumPixelsPerMillisecond / (double)NUM_PIXELS_BETWEEN_TIMELINE )*(double)NUM_PIXELS_BETWEEN_TIMELINE; const double PositionXEndPx = PositionXStartPx + RangeXMS*NumPixelsPerMillisecond; for( double TimelinePosXPx = PositionXStartPx; TimelinePosXPx < PositionXEndPx; TimelinePosXPx += (double)NUM_PIXELS_BETWEEN_TIMELINE ) { LinePoints.Reset( 2 ); LinePoints.Add( FVector2D( TimelinePosXPx - ThreadViewOffsetPx, 0.0f ) ); LinePoints.Add( FVector2D( TimelinePosXPx - ThreadViewOffsetPx, PaintState->Size2D().Y ) ); // Draw time line. FSlateDrawElement::MakeLines ( PaintState->OutDrawElements, PaintState->LayerId, PaintState->AllottedGeometry.ToPaintGeometry(), LinePoints, PaintState->AbsoluteClippingRect, PaintState->DrawEffects, PaintState->WidgetStyle.GetColorAndOpacityTint() * FColorList::LimeGreen, false ); } }
void UOffAxisGameViewportClient::Draw(FViewport* InViewport, FCanvas* SceneCanvas) { //Valid SceneCanvas is required. Make this explicit. check(SceneCanvas); FCanvas* DebugCanvas = InViewport->GetDebugCanvas(); // Create a temporary canvas if there isn't already one. static FName CanvasObjectName(TEXT("CanvasObject")); UCanvas* CanvasObject = GetCanvasByName(CanvasObjectName); CanvasObject->Canvas = SceneCanvas; // Create temp debug canvas object static FName DebugCanvasObjectName(TEXT("DebugCanvasObject")); UCanvas* DebugCanvasObject = GetCanvasByName(DebugCanvasObjectName); DebugCanvasObject->Canvas = DebugCanvas; DebugCanvasObject->Init(InViewport->GetSizeXY().X, InViewport->GetSizeXY().Y, NULL); const bool bScaledToRenderTarget = GEngine->HMDDevice.IsValid() && GEngine->IsStereoscopic3D(InViewport); if (bScaledToRenderTarget) { // Allow HMD to modify screen settings GEngine->HMDDevice->UpdateScreenSettings(Viewport); } if (DebugCanvas) { DebugCanvas->SetScaledToRenderTarget(bScaledToRenderTarget); } if (SceneCanvas) { SceneCanvas->SetScaledToRenderTarget(bScaledToRenderTarget); } bool bUIDisableWorldRendering = false; FViewElementDrawer GameViewDrawer; // create the view family for rendering the world scene to the viewport's render target FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( InViewport, GetWorld()->Scene, EngineShowFlags) .SetRealtimeUpdate(true)); // Allow HMD to modify the view later, just before rendering if (GEngine->HMDDevice.IsValid() && GEngine->IsStereoscopic3D(InViewport)) { ISceneViewExtension* HmdViewExt = GEngine->HMDDevice->GetViewExtension(); if (HmdViewExt) { ViewFamily.ViewExtensions.Add(HmdViewExt); HmdViewExt->ModifyShowFlags(ViewFamily.EngineShowFlags); } } ESplitScreenType::Type SplitScreenConfig = GetCurrentSplitscreenConfiguration(); EngineShowFlagOverride(ESFIM_Game, (EViewModeIndex)ViewModeIndex, ViewFamily.EngineShowFlags, NAME_None, SplitScreenConfig != ESplitScreenType::None); TMap<ULocalPlayer*, FSceneView*> PlayerViewMap; FAudioDevice* AudioDevice = GEngine->GetAudioDevice(); bool bReverbSettingsFound = false; FReverbSettings ReverbSettings; class AAudioVolume* AudioVolume = nullptr; for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; if (PlayerController) { ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player); if (LocalPlayer) { const bool bEnableStereo = GEngine->IsStereoscopic3D(InViewport); int32 NumViews = bEnableStereo ? 2 : 1; for (int i = 0; i < NumViews; ++i) { // Calculate the player's view information. FVector ViewLocation; FRotator ViewRotation; EStereoscopicPass PassType = !bEnableStereo ? eSSP_FULL : ((i == 0) ? eSSP_LEFT_EYE : eSSP_RIGHT_EYE); FSceneView* View = LocalPlayer->CalcSceneView(&ViewFamily, ViewLocation, ViewRotation, InViewport, &GameViewDrawer, PassType); if (mOffAxisMatrixSetted) UpdateProjectionMatrix(View, mOffAxisMatrix); if (View) { if (View->Family->EngineShowFlags.Wireframe) { // Wireframe color is emissive-only, and mesh-modifying materials do not use material substitution, hence... View->DiffuseOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); View->SpecularOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); } else if (View->Family->EngineShowFlags.OverrideDiffuseAndSpecular) { View->DiffuseOverrideParameter = FVector4(GEngine->LightingOnlyBrightness.R, GEngine->LightingOnlyBrightness.G, GEngine->LightingOnlyBrightness.B, 0.0f); View->SpecularOverrideParameter = FVector4(.1f, .1f, .1f, 0.0f); } else if (View->Family->EngineShowFlags.ReflectionOverride) { View->DiffuseOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); View->SpecularOverrideParameter = FVector4(1, 1, 1, 0.0f); View->NormalOverrideParameter = FVector4(0, 0, 1, 0.0f); View->RoughnessOverrideParameter = FVector2D(0.0f, 0.0f); } if (!View->Family->EngineShowFlags.Diffuse) { View->DiffuseOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); } if (!View->Family->EngineShowFlags.Specular) { View->SpecularOverrideParameter = FVector4(0.f, 0.f, 0.f, 0.f); } View->CameraConstrainedViewRect = View->UnscaledViewRect; // If this is the primary drawing pass, update things that depend on the view location if (i == 0) { // Save the location of the view. LocalPlayer->LastViewLocation = ViewLocation; PlayerViewMap.Add(LocalPlayer, View); // Update the listener. if (AudioDevice != NULL) { FVector Location; FVector ProjFront; FVector ProjRight; PlayerController->GetAudioListenerPosition(/*out*/ Location, /*out*/ ProjFront, /*out*/ ProjRight); FTransform ListenerTransform(FRotationMatrix::MakeFromXY(ProjFront, ProjRight)); ListenerTransform.SetTranslation(Location); ListenerTransform.NormalizeRotation(); bReverbSettingsFound = true; FReverbSettings PlayerReverbSettings; FInteriorSettings PlayerInteriorSettings; class AAudioVolume* PlayerAudioVolume = GetWorld()->GetAudioSettings(Location, &PlayerReverbSettings, &PlayerInteriorSettings); if (AudioVolume == nullptr || (PlayerAudioVolume != nullptr && PlayerAudioVolume->Priority > AudioVolume->Priority)) { AudioVolume = PlayerAudioVolume; ReverbSettings = PlayerReverbSettings; } uint32 ViewportIndex = PlayerViewMap.Num() - 1; AudioDevice->SetListener(ViewportIndex, ListenerTransform, (View->bCameraCut ? 0.f : GetWorld()->GetDeltaSeconds()), PlayerAudioVolume, PlayerInteriorSettings); } } // Add view information for resource streaming. IStreamingManager::Get().AddViewInformation(View->ViewMatrices.ViewOrigin, View->ViewRect.Width(), View->ViewRect.Width() * View->ViewMatrices.ProjMatrix.M[0][0]); GetWorld()->ViewLocationsRenderedLastFrame.Add(View->ViewMatrices.ViewOrigin); } } } } } if (bReverbSettingsFound) { AudioDevice->SetReverbSettings(AudioVolume, ReverbSettings); } // Update level streaming. GetWorld()->UpdateLevelStreaming(); // Draw the player views. if (!bDisableWorldRendering && !bUIDisableWorldRendering && PlayerViewMap.Num() > 0) { GetRendererModule().BeginRenderingViewFamily(SceneCanvas, &ViewFamily); } // Clear areas of the rendertarget (backbuffer) that aren't drawn over by the views. { // Find largest rectangle bounded by all rendered views. uint32 MinX = InViewport->GetSizeXY().X, MinY = InViewport->GetSizeXY().Y, MaxX = 0, MaxY = 0; uint32 TotalArea = 0; for (int32 ViewIndex = 0; ViewIndex < ViewFamily.Views.Num(); ++ViewIndex) { const FSceneView* View = ViewFamily.Views[ViewIndex]; FIntRect UpscaledViewRect = View->UnscaledViewRect; MinX = FMath::Min<uint32>(UpscaledViewRect.Min.X, MinX); MinY = FMath::Min<uint32>(UpscaledViewRect.Min.Y, MinY); MaxX = FMath::Max<uint32>(UpscaledViewRect.Max.X, MaxX); MaxY = FMath::Max<uint32>(UpscaledViewRect.Max.Y, MaxY); TotalArea += FMath::TruncToInt(UpscaledViewRect.Width()) * FMath::TruncToInt(UpscaledViewRect.Height()); } // To draw black borders around the rendered image (prevents artifacts from post processing passes that read outside of the image e.g. PostProcessAA) { int32 BlackBorders = 0; // FMath::Clamp(CVarSetBlackBordersEnabled.GetValueOnGameThread(), 0, 10); if (ViewFamily.Views.Num() == 1 && BlackBorders) { MinX += BlackBorders; MinY += BlackBorders; MaxX -= BlackBorders; MaxY -= BlackBorders; TotalArea = (MaxX - MinX) * (MaxY - MinY); } } // If the views don't cover the entire bounding rectangle, clear the entire buffer. if (ViewFamily.Views.Num() == 0 || TotalArea != (MaxX - MinX)*(MaxY - MinY) || bDisableWorldRendering) { SceneCanvas->DrawTile(0, 0, InViewport->GetSizeXY().X, InViewport->GetSizeXY().Y, 0.0f, 0.0f, 1.0f, 1.f, FLinearColor::Black, NULL, false); } else { // clear left if (MinX > 0) { SceneCanvas->DrawTile(0, 0, MinX, InViewport->GetSizeXY().Y, 0.0f, 0.0f, 1.0f, 1.f, FLinearColor::Black, NULL, false); } // clear right if (MaxX < (uint32)InViewport->GetSizeXY().X) { SceneCanvas->DrawTile(MaxX, 0, InViewport->GetSizeXY().X, InViewport->GetSizeXY().Y, 0.0f, 0.0f, 1.0f, 1.f, FLinearColor::Black, NULL, false); } // clear top if (MinY > 0) { SceneCanvas->DrawTile(MinX, 0, MaxX, MinY, 0.0f, 0.0f, 1.0f, 1.f, FLinearColor::Black, NULL, false); } // clear bottom if (MaxY < (uint32)InViewport->GetSizeXY().Y) { SceneCanvas->DrawTile(MinX, MaxY, MaxX, InViewport->GetSizeXY().Y, 0.0f, 0.0f, 1.0f, 1.f, FLinearColor::Black, NULL, false); } } } // Remove temporary debug lines. if (GetWorld()->LineBatcher != NULL) { GetWorld()->LineBatcher->Flush(); } if (GetWorld()->ForegroundLineBatcher != NULL) { GetWorld()->ForegroundLineBatcher->Flush(); } // Draw FX debug information. if (GetWorld()->FXSystem) { GetWorld()->FXSystem->DrawDebug(SceneCanvas); } // Render the UI. { //SCOPE_CYCLE_COUNTER(STAT_UIDrawingTime); // render HUD bool bDisplayedSubtitles = false; for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; if (PlayerController) { ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player); if (LocalPlayer) { FSceneView* View = PlayerViewMap.FindRef(LocalPlayer); if (View != NULL) { // rendering to directly to viewport target FVector CanvasOrigin(FMath::TruncToFloat(View->UnscaledViewRect.Min.X), FMath::TruncToInt(View->UnscaledViewRect.Min.Y), 0.f); CanvasObject->Init(View->UnscaledViewRect.Width(), View->UnscaledViewRect.Height(), View); // Set the canvas transform for the player's view rectangle. SceneCanvas->PushAbsoluteTransform(FTranslationMatrix(CanvasOrigin)); CanvasObject->ApplySafeZoneTransform(); // Render the player's HUD. if (PlayerController->MyHUD) { //SCOPE_CYCLE_COUNTER(STAT_HudTime); DebugCanvasObject->SceneView = View; PlayerController->MyHUD->SetCanvas(CanvasObject, DebugCanvasObject); if (GEngine->IsStereoscopic3D(InViewport)) { check(GEngine->StereoRenderingDevice.IsValid()); GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_LEFT_EYE, SceneCanvas, CanvasObject, Viewport); PlayerController->MyHUD->PostRender(); SceneCanvas->PopTransform(); GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_RIGHT_EYE, SceneCanvas, CanvasObject, Viewport); PlayerController->MyHUD->PostRender(); SceneCanvas->PopTransform(); // Reset the canvas for rendering to the full viewport. CanvasObject->Reset(); CanvasObject->SizeX = View->UnscaledViewRect.Width(); CanvasObject->SizeY = View->UnscaledViewRect.Height(); CanvasObject->SetView(NULL); CanvasObject->Update(); } else { PlayerController->MyHUD->PostRender(); } // Put these pointers back as if a blueprint breakpoint hits during HUD PostRender they can // have been changed CanvasObject->Canvas = SceneCanvas; DebugCanvasObject->Canvas = DebugCanvas; // A side effect of PostRender is that the playercontroller could be destroyed if (!PlayerController->IsPendingKill()) { PlayerController->MyHUD->SetCanvas(NULL, NULL); } } if (DebugCanvas != NULL) { DebugCanvas->PushAbsoluteTransform(FTranslationMatrix(CanvasOrigin)); UDebugDrawService::Draw(ViewFamily.EngineShowFlags, InViewport, View, DebugCanvas); DebugCanvas->PopTransform(); } CanvasObject->PopSafeZoneTransform(); SceneCanvas->PopTransform(); // draw subtitles if (!bDisplayedSubtitles) { FVector2D MinPos(0.f, 0.f); FVector2D MaxPos(1.f, 1.f); GetSubtitleRegion(MinPos, MaxPos); uint32 SizeX = SceneCanvas->GetRenderTarget()->GetSizeXY().X; uint32 SizeY = SceneCanvas->GetRenderTarget()->GetSizeXY().Y; FIntRect SubtitleRegion(FMath::TruncToInt(SizeX * MinPos.X), FMath::TruncToInt(SizeY * MinPos.Y), FMath::TruncToInt(SizeX * MaxPos.X), FMath::TruncToInt(SizeY * MaxPos.Y)); // We need a world to do this FSubtitleManager::GetSubtitleManager()->DisplaySubtitles(SceneCanvas, SubtitleRegion, GetWorld()->GetAudioTimeSeconds()); } } } } } //ensure canvas has been flushed before rendering UI SceneCanvas->Flush_GameThread(); if (DebugCanvas != NULL) { DebugCanvas->Flush_GameThread(); } // Allow the viewport to render additional stuff PostRender(DebugCanvasObject); // Render the console. if (ViewportConsole) { if (GEngine->IsStereoscopic3D(InViewport)) { GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_LEFT_EYE, DebugCanvas, DebugCanvasObject, Viewport); ViewportConsole->PostRender_Console(DebugCanvasObject); #if !UE_BUILD_SHIPPING if (DebugCanvas != NULL && GEngine->HMDDevice.IsValid()) { GEngine->HMDDevice->DrawDebug(DebugCanvasObject, eSSP_LEFT_EYE); } #endif DebugCanvas->PopTransform(); GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_RIGHT_EYE, DebugCanvas, DebugCanvasObject, Viewport); ViewportConsole->PostRender_Console(DebugCanvasObject); #if !UE_BUILD_SHIPPING if (DebugCanvas != NULL && GEngine->HMDDevice.IsValid()) { GEngine->HMDDevice->DrawDebug(DebugCanvasObject, eSSP_RIGHT_EYE); } #endif DebugCanvas->PopTransform(); // Reset the canvas for rendering to the full viewport. DebugCanvasObject->Reset(); DebugCanvasObject->SizeX = Viewport->GetSizeXY().X; DebugCanvasObject->SizeY = Viewport->GetSizeXY().Y; DebugCanvasObject->SetView(NULL); DebugCanvasObject->Update(); } else { ViewportConsole->PostRender_Console(DebugCanvasObject); } } } // Grab the player camera location and orientation so we can pass that along to the stats drawing code. FVector PlayerCameraLocation = FVector::ZeroVector; FRotator PlayerCameraRotation = FRotator::ZeroRotator; { for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) { (*Iterator)->GetPlayerViewPoint(PlayerCameraLocation, PlayerCameraRotation); } } if (GEngine->IsStereoscopic3D(InViewport)) { GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_LEFT_EYE, DebugCanvas, DebugCanvasObject, InViewport); DrawStatsHUD(GetWorld(), InViewport, DebugCanvas, DebugCanvasObject, DebugProperties, PlayerCameraLocation, PlayerCameraRotation); DebugCanvas->PopTransform(); GEngine->StereoRenderingDevice->PushViewportCanvas(eSSP_RIGHT_EYE, DebugCanvas, DebugCanvasObject, InViewport); DrawStatsHUD(GetWorld(), InViewport, DebugCanvas, DebugCanvasObject, DebugProperties, PlayerCameraLocation, PlayerCameraRotation); DebugCanvas->PopTransform(); // Reset the canvas for rendering to the full viewport. DebugCanvasObject->Reset(); DebugCanvasObject->SizeX = Viewport->GetSizeXY().X; DebugCanvasObject->SizeY = Viewport->GetSizeXY().Y; DebugCanvasObject->SetView(NULL); DebugCanvasObject->Update(); #if !UE_BUILD_SHIPPING if (GEngine->HMDDevice.IsValid()) { GEngine->HMDDevice->DrawDebug(DebugCanvasObject, eSSP_FULL); } #endif } else { DrawStatsHUD(GetWorld(), InViewport, DebugCanvas, DebugCanvasObject, DebugProperties, PlayerCameraLocation, PlayerCameraRotation); } }
void SProfilerThreadView::DrawFrameMarkers() const { check( PaintState ); const double ThreadViewOffsetPx = PositionXMS*NumPixelsPerMillisecond; PaintState->LayerId++; for( const auto& ThreadNode : ProfilerUIStream.ThreadNodes ) { if( ThreadNode.StatName == NAME_GameThread ) { const float MarkerPosXPx = ThreadNode.GetLocalPosition( ThreadViewOffsetPx, 0.0f ).X + ThreadNode.WidthPx; // Check if this frame time marker is inside the visible area. if( MarkerPosXPx < 0.0f || MarkerPosXPx > PaintState->Size2D().X ) { continue; } // Draw text. const FString FrameIndexStr = FString::Printf( TEXT( "%i" ), ThreadNode.FrameIndex ); const FString FrameTimesStr = FString::Printf( TEXT( "%.4f [%.4f] MS" ), ThreadNode.CycleCountersEndTimeMS, ThreadNode.GetDurationMS() ); float MarkerPosYPx = PaintState->Size2D().Y - 2 * PaintState->SummaryFont8Height; DrawText( FrameIndexStr, PaintState->SummaryFont8, FVector2D( MarkerPosXPx, MarkerPosYPx ), FColorList::SkyBlue, FColorList::Black, FVector2D( 1.0f, 1.0f ) ); MarkerPosYPx += PaintState->SummaryFont8Height; DrawText( FrameTimesStr, PaintState->SummaryFont8, FVector2D( MarkerPosXPx, MarkerPosYPx ), FColorList::SkyBlue, FColorList::Black, FVector2D( 1.0f, 1.0f ) ); } } PaintState->LayerId++; const double PositionXStartPx = FMath::TruncToFloat( PositionXMS*NumPixelsPerMillisecond / (double)NUM_PIXELS_BETWEEN_TIMELINE )*(double)NUM_PIXELS_BETWEEN_TIMELINE; const double PositionXEndPx = PositionXStartPx + RangeXMS*NumPixelsPerMillisecond; for( double TimelinePosXPx = PositionXStartPx; TimelinePosXPx < PositionXEndPx; TimelinePosXPx += (double)NUM_PIXELS_BETWEEN_TIMELINE ) { const FString TimelineStr = FString::Printf( TEXT( "%.4f MS" ), TimelinePosXPx / NumPixelsPerMillisecond ); // Draw time line text. float MarkerPosYPx = PaintState->Size2D().Y - 3 * PaintState->SummaryFont8Height; DrawText( TimelineStr, PaintState->SummaryFont8, FVector2D( TimelinePosXPx - ThreadViewOffsetPx, MarkerPosYPx ), FColorList::LimeGreen, FColorList::Black, FVector2D( 1.0f, 1.0f ) ); } #if 0 for( int32 FrameIndex = FramesIndices.X; FrameIndex < FramesIndices.Y; ++FrameIndex ) { const double FrameTimeMS = ProfilerStream->GetFrameTimeMS( FrameIndex ); const double ElapsedTimeMS = ProfilerStream->GetElapsedFrameTimeMS( FrameIndex ); const double FrameEndMarkerLocalPosX = ElapsedTimeMS * NumPixelsPerMillisecond - ThreadViewOffsetPx; // Draw text. const FVector2D TextLocalPosTop = FVector2D( FrameEndMarkerLocalPosX, PaintState->SummaryFont8Height ); const FString FrameTimeStr = FString::Printf( TEXT( "%.4f [%.4f] MS" ), ElapsedTimeMS, FrameTimeMS ); DrawText( FrameTimeStr, PaintState->SummaryFont8, TextLocalPosTop, FColorList::SkyBlue, FColorList::Black, FVector2D( 1.0f, 1.0f ) ); const FVector2D TextLocalPosBottom = FVector2D( FrameEndMarkerLocalPosX, PaintState->Size2D().Y - 2 * PaintState->SummaryFont8Height ); DrawText( FrameTimeStr, PaintState->SummaryFont8, TextLocalPosBottom, FColorList::SkyBlue, FColorList::Black, FVector2D( 1.0f, 1.0f ) ); } #endif // 0 }
void FShadowMap2D::EncodeSingleTexture(FShadowMapPendingTexture& PendingTexture, UShadowMapTexture2D* Texture, TArray< TArray<FFourDistanceFieldSamples> >& MipData) { TArray<FFourDistanceFieldSamples>* TopMipData = new(MipData) TArray<FFourDistanceFieldSamples>(); TopMipData->Empty(PendingTexture.GetSizeX() * PendingTexture.GetSizeY()); TopMipData->AddZeroed(PendingTexture.GetSizeX() * PendingTexture.GetSizeY()); int32 TextureSizeX = Texture->Source.GetSizeX(); int32 TextureSizeY = Texture->Source.GetSizeY(); for (int32 AllocationIndex = 0;AllocationIndex < PendingTexture.Allocations.Num();AllocationIndex++) { FShadowMapAllocation& Allocation = *PendingTexture.Allocations[AllocationIndex]; bool bChannelUsed[4] = {0}; for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { for (TMap<ULightComponent*, TArray<FQuantizedSignedDistanceFieldShadowSample>>::TIterator It(Allocation.ShadowMapData); It; ++It) { if (It.Key()->ShadowMapChannel == ChannelIndex) { bChannelUsed[ChannelIndex] = true; const TArray<FQuantizedSignedDistanceFieldShadowSample>& SourceSamples = It.Value(); // Copy the raw data for this light-map into the raw texture data array. for (int32 Y = Allocation.MappedRect.Min.Y; Y < Allocation.MappedRect.Max.Y; ++Y) { for (int32 X = Allocation.MappedRect.Min.X; X < Allocation.MappedRect.Max.X; ++X) { int32 DestY = Y - Allocation.MappedRect.Min.Y + Allocation.OffsetY; int32 DestX = X - Allocation.MappedRect.Min.X + Allocation.OffsetX; FFourDistanceFieldSamples& DestSample = (*TopMipData)[DestY * TextureSizeX + DestX]; const FQuantizedSignedDistanceFieldShadowSample& SourceSample = SourceSamples[Y * Allocation.TotalSizeX + X]; if ( SourceSample.Coverage > 0 ) { DestSample.Samples[ChannelIndex] = SourceSample; } #if WITH_EDITOR if ( SourceSample.Coverage > 0 ) { GNumShadowmapMappedTexels++; } else { GNumShadowmapUnmappedTexels++; } #endif } } } } } // Link the shadow-map to the texture. Allocation.ShadowMap->Texture = Texture; // Free the shadow-map's raw data. for (TMap<ULightComponent*, TArray<FQuantizedSignedDistanceFieldShadowSample> >::TIterator It(Allocation.ShadowMapData); It; ++It) { It.Value().Empty(); } int32 PaddedSizeX = Allocation.TotalSizeX; int32 PaddedSizeY = Allocation.TotalSizeY; int32 BaseX = Allocation.OffsetX - Allocation.MappedRect.Min.X; int32 BaseY = Allocation.OffsetY - Allocation.MappedRect.Min.Y; #if WITH_EDITOR if (GLightmassDebugOptions.bPadMappings && (Allocation.PaddingType == LMPT_NormalPadding)) { if ((PaddedSizeX - 2 > 0) && ((PaddedSizeY - 2) > 0)) { PaddedSizeX -= 2; PaddedSizeY -= 2; BaseX += 1; BaseY += 1; } } #endif // Calculate the coordinate scale/biases for each shadow-map stored in the texture. Allocation.ShadowMap->CoordinateScale = FVector2D( (float)PaddedSizeX / (float)PendingTexture.GetSizeX(), (float)PaddedSizeY / (float)PendingTexture.GetSizeY() ); Allocation.ShadowMap->CoordinateBias = FVector2D( (float)BaseX / (float)PendingTexture.GetSizeX(), (float)BaseY / (float)PendingTexture.GetSizeY() ); for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { Allocation.ShadowMap->bChannelValid[ChannelIndex] = bChannelUsed[ChannelIndex]; } } const uint32 NumMips = FMath::Max(FMath::CeilLogTwo(TextureSizeX),FMath::CeilLogTwo(TextureSizeY)) + 1; for (uint32 MipIndex = 1;MipIndex < NumMips;MipIndex++) { const uint32 SourceMipSizeX = FMath::Max(1, TextureSizeX >> (MipIndex - 1)); const uint32 SourceMipSizeY = FMath::Max(1, TextureSizeY >> (MipIndex - 1)); const uint32 DestMipSizeX = FMath::Max(1, TextureSizeX >> MipIndex); const uint32 DestMipSizeY = FMath::Max(1, TextureSizeY >> MipIndex); // Downsample the previous mip-level, taking into account which texels are mapped. TArray<FFourDistanceFieldSamples>* NextMipData = new(MipData) TArray<FFourDistanceFieldSamples>(); NextMipData->Empty(DestMipSizeX * DestMipSizeY); NextMipData->AddZeroed(DestMipSizeX * DestMipSizeY); const uint32 MipFactorX = SourceMipSizeX / DestMipSizeX; const uint32 MipFactorY = SourceMipSizeY / DestMipSizeY; for (uint32 Y = 0;Y < DestMipSizeY;Y++) { for (uint32 X = 0;X < DestMipSizeX;X++) { float AccumulatedFilterableComponents[4][FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents]; for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { AccumulatedFilterableComponents[ChannelIndex][i] = 0; } } uint32 Coverage[4] = {0}; for (uint32 SourceY = Y * MipFactorY;SourceY < (Y + 1) * MipFactorY;SourceY++) { for (uint32 SourceX = X * MipFactorX;SourceX < (X + 1) * MipFactorX;SourceX++) { for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { const FFourDistanceFieldSamples& FourSourceSamples = MipData[MipIndex - 1][SourceY * SourceMipSizeX + SourceX]; const FQuantizedSignedDistanceFieldShadowSample& SourceSample = FourSourceSamples.Samples[ChannelIndex]; if (SourceSample.Coverage) { for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { AccumulatedFilterableComponents[ChannelIndex][i] += SourceSample.GetFilterableComponent(i) * SourceSample.Coverage; } Coverage[ChannelIndex] += SourceSample.Coverage; } } } } FFourDistanceFieldSamples& FourDestSamples = (*NextMipData)[Y * DestMipSizeX + X]; for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { FQuantizedSignedDistanceFieldShadowSample& DestSample = FourDestSamples.Samples[ChannelIndex]; if (Coverage[ChannelIndex]) { for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { DestSample.SetFilterableComponent(AccumulatedFilterableComponents[ChannelIndex][i] / (float)Coverage[ChannelIndex], i); } DestSample.Coverage = (uint8)(Coverage[ChannelIndex] / (MipFactorX * MipFactorY)); } else { for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { AccumulatedFilterableComponents[ChannelIndex][i] = 0; } DestSample.Coverage = 0; } } } } } const FIntPoint Neighbors[] = { // Check immediate neighbors first FIntPoint(1,0), FIntPoint(0,1), FIntPoint(-1,0), FIntPoint(0,-1), // Check diagonal neighbors if no immediate neighbors are found FIntPoint(1,1), FIntPoint(-1,1), FIntPoint(-1,-1), FIntPoint(1,-1) }; // Extrapolate texels which are mapped onto adjacent texels which are not mapped to avoid artifacts when using texture filtering. for (int32 MipIndex = 0;MipIndex < MipData.Num();MipIndex++) { uint32 MipSizeX = FMath::Max(1,TextureSizeX >> MipIndex); uint32 MipSizeY = FMath::Max(1,TextureSizeY >> MipIndex); for (uint32 DestY = 0;DestY < MipSizeY;DestY++) { for (uint32 DestX = 0;DestX < MipSizeX;DestX++) { FFourDistanceFieldSamples& FourDestSamples = MipData[MipIndex][DestY * MipSizeX + DestX]; for (int32 ChannelIndex = 0; ChannelIndex < 4; ChannelIndex++) { FQuantizedSignedDistanceFieldShadowSample& DestSample = FourDestSamples.Samples[ChannelIndex]; if (DestSample.Coverage == 0) { float ExtrapolatedFilterableComponents[FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents]; for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { ExtrapolatedFilterableComponents[i] = 0; } for (int32 NeighborIndex = 0; NeighborIndex < ARRAY_COUNT(Neighbors); NeighborIndex++) { if (DestY + Neighbors[NeighborIndex].Y >= 0 && DestY + Neighbors[NeighborIndex].Y < MipSizeY && DestX + Neighbors[NeighborIndex].X >= 0 && DestX + Neighbors[NeighborIndex].X < MipSizeX) { const FFourDistanceFieldSamples& FourNeighborSamples = MipData[MipIndex][(DestY + Neighbors[NeighborIndex].Y) * MipSizeX + DestX + Neighbors[NeighborIndex].X]; const FQuantizedSignedDistanceFieldShadowSample& NeighborSample = FourNeighborSamples.Samples[ChannelIndex]; if (NeighborSample.Coverage > 0) { if (DestY + Neighbors[NeighborIndex].Y * 2 >= 0 && DestY + Neighbors[NeighborIndex].Y * 2 < MipSizeY && DestX + Neighbors[NeighborIndex].X * 2 >= 0 && DestX + Neighbors[NeighborIndex].X * 2 < MipSizeX) { // Lookup the second neighbor in the first neighbor's direction //@todo - check the second neighbor's coverage? const FFourDistanceFieldSamples& SecondFourNeighborSamples = MipData[MipIndex][(DestY + Neighbors[NeighborIndex].Y * 2) * MipSizeX + DestX + Neighbors[NeighborIndex].X * 2]; const FQuantizedSignedDistanceFieldShadowSample& SecondNeighborSample = FourNeighborSamples.Samples[ChannelIndex]; for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { // Extrapolate while maintaining the first derivative, which is especially important for signed distance fields ExtrapolatedFilterableComponents[i] = NeighborSample.GetFilterableComponent(i) * 2.0f - SecondNeighborSample.GetFilterableComponent(i); } } else { // Couldn't find a second neighbor to use for extrapolating, just copy the neighbor's values for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { ExtrapolatedFilterableComponents[i] = NeighborSample.GetFilterableComponent(i); } } break; } } } for (int32 i = 0; i < FQuantizedSignedDistanceFieldShadowSample::NumFilterableComponents; i++) { DestSample.SetFilterableComponent(ExtrapolatedFilterableComponents[i], i); } } } } } } }
virtual FVector2D GetLightShaftConeParams() const override { return FVector2D(CosLightShaftConeAngle, InvCosLightShaftConeDifference); }
/** Generate a widget for the specified column name */ TSharedRef<SWidget> FPListNodeBoolean::GenerateWidgetForColumn(const FName& ColumnName, int32 Depth, ITableRow* RowPtr) { if(ColumnName == "PListKeyColumn") { return SNew(SBorder) .BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared()) [ SNew(SHorizontalBox) // Space before item representing expansion + SHorizontalBox::Slot() [ SNew(SSpacer) .Size(FVector2D(20 * Depth, 0)) ] // Editable key value + SHorizontalBox::Slot() .FillWidth(1.0f) [ SAssignNew(KeyStringTextBox, SEditableTextBox) .BackgroundColor(this, &FPListNodeBoolean::GetKeyBackgroundColor) .ForegroundColor(this, &FPListNodeBoolean::GetKeyForegroundColor) .Text(bArrayMember ? FText::FromString(FString::FromInt(ArrayIndex)) : FText::FromString(KeyString)) .OnTextChanged(this, &FPListNodeBoolean::OnKeyStringChanged) .IsReadOnly(bArrayMember) ] // Space before type column + SHorizontalBox::Slot() [ SNew(SSpacer) .Size(FVector2D(30, 0)) ] ]; } else if(ColumnName == "PListValueTypeColumn") { return SNew(SBorder) .BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared()) [ SNew(STextBlock) .Text(NSLOCTEXT("PListEditor", "booleanValueTypeLabel", "boolean")) ]; } else if(ColumnName == "PListValueColumn") { return SNew(SBorder) .BorderImage_Static(&IPListNode::GetOverlayBrushDelegate, AsShared()) [ SNew(SHorizontalBox) // Editable "value" value + SHorizontalBox::Slot() .FillWidth(1.0f) [ SAssignNew(ValueCheckBox, SCheckBox) .IsChecked(bValue) .OnCheckStateChanged(this, &FPListNodeBoolean::OnValueChanged) ] ]; } // Invalid column name else { return SNew(STextBlock) .Text(NSLOCTEXT("PListEditor", "UnknownColumn", "Unknown Column")); } }