void FSingleTileEditorViewportClient::DrawCanvas(FViewport& InViewport, FSceneView& View, FCanvas& Canvas) { const bool bIsHitTesting = Canvas.IsHitTesting(); if (!bIsHitTesting) { Canvas.SetHitProxy(nullptr); } int32 YPos = 42; if (TileBeingEditedIndex != INDEX_NONE) { // Draw the collision geometry stats YPos += 60; //@TODO: Need a better way to determine this from the editor mode if (bShowStats) { bool bHasCollision = false; if (const FPaperTileMetadata* TileData = TileSet->GetTileMetadata(TileBeingEditedIndex)) { if (TileData->HasCollision()) { bHasCollision = true; FSpriteGeometryEditMode::DrawGeometryStats(InViewport, View, Canvas, TileData->CollisionData, false, /*inout*/ YPos); } } if (!bHasCollision) { FCanvasTextItem TextItem(FVector2D(6, YPos), LOCTEXT("NoCollisionDataMainScreen", "No collision data"), GEngine->GetSmallFont(), FLinearColor::White); TextItem.EnableShadow(FLinearColor::Black); TextItem.Draw(&Canvas); } } } FEditorViewportClient::DrawCanvas(InViewport, View, Canvas); }
void FSocketEditingHelper::DrawSocketNames(FSpriteGeometryEditMode* GeometryEditMode, UPrimitiveComponent* PreviewComponent, FViewport& Viewport, FSceneView& View, FCanvas& Canvas) { if (PreviewComponent != nullptr) { const int32 HalfX = Viewport.GetSizeXY().X / 2; const int32 HalfY = Viewport.GetSizeXY().Y / 2; const FColor UnselectedSocketNameColor(255, 196, 196); const FColor SelectedSocketNameColor(FColor::White); TArray<FComponentSocketDescription> SocketList; PreviewComponent->QuerySupportedSockets(/*out*/ SocketList); for (const FComponentSocketDescription& Socket : SocketList) { const FVector SocketWorldPos = PreviewComponent->GetSocketLocation(Socket.Name); const FPlane Proj = View.Project(SocketWorldPos); if (Proj.W > 0.f) { const int32 XPos = HalfX + (HalfX * Proj.X); const int32 YPos = HalfY + (HalfY * (-Proj.Y)); const bool bIsSelected = (GeometryEditMode != nullptr) && GeometryEditMode->IsSocketSelected(Socket.Name); const FColor& SocketColor = bIsSelected ? SelectedSocketNameColor : UnselectedSocketNameColor; FCanvasTextItem Msg(FVector2D(XPos, YPos), FText::FromString(Socket.Name.ToString()), GEngine->GetMediumFont(), SocketColor); Msg.EnableShadow(FLinearColor::Black); Canvas.DrawItem(Msg); // //@TODO: Draws the current value of the rotation (probably want to keep this!) // if (bManipulating && StaticMeshEditorPtr.Pin()->GetSelectedSocket() == Socket) // { // // Figure out the text height // FTextSizingParameters Parameters(GEngine->GetSmallFont(), 1.0f, 1.0f); // UCanvas::CanvasStringSize(Parameters, *Socket->SocketName.ToString()); // int32 YL = FMath::TruncToInt(Parameters.DrawYL); // // DrawAngles(&Canvas, XPos, YPos + YL, // Widget->GetCurrentAxis(), // GetWidgetMode(), // Socket->RelativeRotation, // Socket->RelativeLocation); // } } } } }
void FSpriteGeometryEditMode::DrawMarquee(FViewport& InViewport, const FSceneView& View, FCanvas& Canvas, const FLinearColor& Color) { FVector2D MarqueeDelta = MarqueeEndPos - MarqueeStartPos; FVector2D MarqueeVertices[4]; MarqueeVertices[0] = FVector2D(MarqueeStartPos.X, MarqueeStartPos.Y); MarqueeVertices[1] = MarqueeVertices[0] + FVector2D(MarqueeDelta.X, 0); MarqueeVertices[2] = MarqueeVertices[0] + FVector2D(MarqueeDelta.X, MarqueeDelta.Y); MarqueeVertices[3] = MarqueeVertices[0] + FVector2D(0, MarqueeDelta.Y); for (int32 MarqueeVertexIndex = 0; MarqueeVertexIndex < 4; ++MarqueeVertexIndex) { const int32 NextVertexIndex = (MarqueeVertexIndex + 1) % 4; FCanvasLineItem MarqueeLine(MarqueeVertices[MarqueeVertexIndex], MarqueeVertices[NextVertexIndex]); MarqueeLine.SetColor(Color); Canvas.DrawItem(MarqueeLine); } }
void FSpriteEditorViewportClient::DrawRelatedSprites(FViewport& InViewport, FSceneView& View, FCanvas& Canvas, const FLinearColor& BoundsColor, const FLinearColor& NameColor) { const FLinearColor ShadowColor = FLinearColor::Black; for (int32 SpriteIndex = 0; SpriteIndex < RelatedSprites.Num(); ++SpriteIndex) { FRelatedSprite& RelatedSprite = RelatedSprites[SpriteIndex]; const FVector2D& SourceUV = RelatedSprite.SourceUV; const FVector2D& SourceDimension = RelatedSprite.SourceDimension; if (bShowNamesForSprites) { const FVector2D TextPos = SourceTextureSpaceToScreenSpace(View, SourceUV + SourceDimension*0.5f); const FText AssetNameText = FText::AsCultureInvariant(RelatedSprite.AssetData.AssetName.ToString()); FCanvasTextItem TextItem(TextPos, AssetNameText, GEngine->GetSmallFont(), NameColor); TextItem.EnableShadow(ShadowColor); TextItem.bCentreX = true; TextItem.bCentreY = true; TextItem.Draw(&Canvas); } if (bShowRelatedSprites) { FVector2D BoundsVertices[4]; BoundsVertices[0] = SourceTextureSpaceToScreenSpace(View, SourceUV); BoundsVertices[1] = SourceTextureSpaceToScreenSpace(View, SourceUV + FVector2D(SourceDimension.X, 0)); BoundsVertices[2] = SourceTextureSpaceToScreenSpace(View, SourceUV + FVector2D(SourceDimension.X, SourceDimension.Y)); BoundsVertices[3] = SourceTextureSpaceToScreenSpace(View, SourceUV + FVector2D(0, SourceDimension.Y)); for (int32 VertexIndex = 0; VertexIndex < 4; ++VertexIndex) { const int32 NextVertexIndex = (VertexIndex + 1) % 4; FCanvasLineItem LineItem(BoundsVertices[VertexIndex], BoundsVertices[NextVertexIndex]); LineItem.SetColor(BoundsColor); Canvas.DrawItem(LineItem); } } } }
void FSpriteEditorViewportClient::DrawBoundsAsText(FViewport& InViewport, FSceneView& View, FCanvas& Canvas, int32& YPos) { FNumberFormattingOptions NoDigitGroupingFormat; NoDigitGroupingFormat.UseGrouping = false; UPaperSprite* Sprite = GetSpriteBeingEdited(); FBoxSphereBounds Bounds = Sprite->GetRenderBounds(); const FText DisplaySizeText = FText::Format(LOCTEXT("BoundsSize", "Approx. Size: {0}x{1}x{2}"), FText::AsNumber((int32)(Bounds.BoxExtent.X * 2.0f), &NoDigitGroupingFormat), FText::AsNumber((int32)(Bounds.BoxExtent.Y * 2.0f), &NoDigitGroupingFormat), FText::AsNumber((int32)(Bounds.BoxExtent.Z * 2.0f), &NoDigitGroupingFormat)); Canvas.DrawShadowedString( 6, YPos, *DisplaySizeText.ToString(), GEngine->GetSmallFont(), FLinearColor::White); YPos += 18; }
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 FPhATEdPreviewViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) { if (!PhATPtr.IsValid()) { return; } // Turn on/off the ground box SharedData->EditorFloorComp->SetVisibility(SharedData->bDrawGround); float W, H; PhATFont->GetCharSize(TEXT('L'), W, H); const float XOffset = 5.0f; const float YOffset = 32.0f; FCanvasTextItem TextItem( FVector2D::ZeroVector, FText::GetEmpty(), PhATFont, FLinearColor::White ); // Write body/constraint count at top. FString StatusString = FText::Format( NSLOCTEXT("UnrealEd", "BodiesConstraints_F", "{0} Bodies {1} Considered for bounds {2} Ratio {3} Constraints"), FText::AsNumber(SharedData->PhysicsAsset->SkeletalBodySetups.Num()), FText::AsNumber(SharedData->PhysicsAsset->BoundsBodies.Num()), FText::AsNumber(static_cast<float>(SharedData->PhysicsAsset->BoundsBodies.Num())/static_cast<float>(SharedData->PhysicsAsset->SkeletalBodySetups.Num())), FText::AsNumber(SharedData->PhysicsAsset->ConstraintSetup.Num()) ).ToString(); TextItem.Text = FText::FromString( StatusString ); Canvas.DrawItem( TextItem, XOffset, YOffset); TextItem.Text = FText::GetEmpty(); if (SharedData->bRunningSimulation) { #if PLATFORM_MAC TextItem.Text = NSLOCTEXT("UnrealEd", "Sim_Mac", "SIM: Command+RightMouse to interact with bodies"); #else TextItem.Text = NSLOCTEXT("UnrealEd", "Sim", "SIM: Ctrl+RightMouse to interact with bodies"); #endif } else if (SharedData->bSelectionLock) { TextItem.Text = NSLOCTEXT("UnrealEd", "Lock", "LOCK"); }else if(SharedData->EditingMode == FPhATSharedData::PEM_ConstraintEdit) { if(GetWidgetMode() == FWidget::WM_Translate) { TextItem.Text = NSLOCTEXT("UnrealEd", "SingleMove", "hold ALT to move a single reference frame"); }else if(GetWidgetMode() == FWidget::WM_Rotate) { TextItem.Text = NSLOCTEXT("UnrealEd", "DoubleRotate", "hold ALT to rotate both reference frames"); } } Canvas.DrawItem( TextItem, XOffset, Viewport->GetSizeXY().Y - (3 + H) ); // Draw current physics weight if (SharedData->bRunningSimulation) { FString PhysWeightString = FString::Printf(TEXT("Phys Blend: %3.0f pct"), SharedData->EditorSimOptions->PhysicsBlend * 100.f); int32 PWLW, PWLH; StringSize(PhATFont, PWLW, PWLH, *PhysWeightString); TextItem.Text = FText::FromString(PhysWeightString); Canvas.DrawItem( TextItem, Viewport->GetSizeXY().X - (3 + PWLW + 2*W), Viewport->GetSizeXY().Y - (3 + H) ); } int32 HalfX = (Viewport->GetSizeXY().X-XOffset)/2; int32 HalfY = Viewport->GetSizeXY().Y/2; if ((SharedData->bShowHierarchy && SharedData->EditorSimOptions->bShowNamesInHierarchy)) { // Iterate over each graphics bone. for (int32 i = 0; i < SharedData->EditorSkelComp->GetNumComponentSpaceTransforms(); ++i) { FVector BonePos = SharedData->EditorSkelComp->ComponentToWorld.TransformPosition(SharedData->EditorSkelComp->GetComponentSpaceTransforms()[i].GetLocation()); FPlane proj = View.Project(BonePos); if (proj.W > 0.f) // This avoids drawing bone names that are behind us. { int32 XPos = HalfX + (HalfX * proj.X); int32 YPos = HalfY + (HalfY * (proj.Y * -1)); FName BoneName = SharedData->EditorSkelMesh->RefSkeleton.GetBoneName(i); FColor BoneNameColor = FColor::White; //iterate through selected bones and see if any match for(int32 j=0; j< SharedData->SelectedBodies.Num(); ++j) { int32 SelectedBodyIndex = SharedData->SelectedBodies[j].Index; FName SelectedBoneName = SharedData->PhysicsAsset->SkeletalBodySetups[SelectedBodyIndex]->BoneName; if(SelectedBoneName == BoneName) { BoneNameColor = FColor::Green; break; } } if (Canvas.IsHitTesting()) { Canvas.SetHitProxy(new HPhATEdBoneNameProxy(i)); } TextItem.Text = FText::FromString(BoneName.ToString()); TextItem.SetColor(BoneNameColor); Canvas.DrawItem( TextItem, XPos, YPos ); if (Canvas.IsHitTesting()) { Canvas.SetHitProxy(NULL); } } } } // If showing center-of-mass, and physics is started up.. if (SharedData->bShowCOM) { // iterate over each bone for (int32 i = 0; i <SharedData->EditorSkelComp->Bodies.Num(); ++i) { FBodyInstance* BodyInst = SharedData->EditorSkelComp->Bodies[i]; check(BodyInst); FVector BodyCOMPos = BodyInst->GetCOMPosition(); float BodyMass = BodyInst->GetBodyMass(); FPlane Projection = View.Project(BodyCOMPos); if (Projection.W > 0.f) // This avoids drawing bone names that are behind us. { int32 XPos = HalfX + (HalfX * Projection.X); int32 YPos = HalfY + (HalfY * (Projection.Y * -1)); FString COMString = FString::Printf(TEXT("%3.3f"), BodyMass); TextItem.Text = FText::FromString(COMString); TextItem.SetColor(SharedData->COMRenderColor); Canvas.DrawItem( TextItem, XPos, YPos ); } } } }
void FSpriteEditorViewportClient::DrawCanvas(FViewport& Viewport, FSceneView& View, FCanvas& Canvas) { const bool bIsHitTesting = Canvas.IsHitTesting(); if (!bIsHitTesting) { Canvas.SetHitProxy(nullptr); } if (!SpriteEditorPtr.IsValid()) { return; } UPaperSprite* Sprite = GetSpriteBeingEdited(); int32 YPos = 42; static const FText SourceRegionHelpStr = LOCTEXT("SourceRegionHelp", "Drag handles to adjust source region\nDouble-click on an image region to select all connected pixels (Ctrl creates a new sprite)\nHold down Ctrl and drag a rectangle to create a new sprite at that position\nClick on other sprite rectangles to change the active sprite"); switch (CurrentMode) { case ESpriteEditorMode::ViewMode: default: // Display the pivot { FNumberFormattingOptions NoDigitGroupingFormat; NoDigitGroupingFormat.UseGrouping = false; const FText PivotStr = FText::Format(LOCTEXT("PivotPosition", "Pivot: ({0}, {1})"), FText::AsNumber(Sprite->CustomPivotPoint.X, &NoDigitGroupingFormat), FText::AsNumber(Sprite->CustomPivotPoint.Y, &NoDigitGroupingFormat)); FCanvasTextItem TextItem(FVector2D(6, YPos), PivotStr, GEngine->GetSmallFont(), FLinearColor::White); TextItem.EnableShadow(FLinearColor::Black); TextItem.Draw(&Canvas); YPos += 18; } // Baked collision data if (Sprite->BodySetup != nullptr) { FSpriteGeometryEditMode::DrawCollisionStats(Viewport, View, Canvas, Sprite->BodySetup, /*inout*/ YPos); } // Baked render data DrawRenderStats(Viewport, View, Canvas, Sprite, /*inout*/ YPos); // And bounds DrawBoundsAsText(Viewport, View, Canvas, /*inout*/ YPos); break; case ESpriteEditorMode::EditCollisionMode: { // Draw the collision geometry stats YPos += 60; //@TODO: Need a better way to determine this from the editor mode if (Sprite->BodySetup != nullptr) { FSpriteGeometryEditMode::DrawGeometryStats(Viewport, View, Canvas, Sprite->CollisionGeometry, false, /*inout*/ YPos); FSpriteGeometryEditMode::DrawCollisionStats(Viewport, View, Canvas, Sprite->BodySetup, /*inout*/ YPos); } else { FCanvasTextItem TextItem(FVector2D(6, YPos), LOCTEXT("NoCollisionDataMainScreen", "No collision data"), GEngine->GetSmallFont(), FLinearColor::White); TextItem.EnableShadow(FLinearColor::Black); TextItem.Draw(&Canvas); } } break; case ESpriteEditorMode::EditRenderingGeomMode: { // Draw the render geometry stats YPos += 60; //@TODO: Need a better way to determine this from the editor mode FSpriteGeometryEditMode::DrawGeometryStats(Viewport, View, Canvas, Sprite->RenderGeometry, true, /*inout*/ YPos); DrawRenderStats(Viewport, View, Canvas, Sprite, /*inout*/ YPos); // And bounds DrawBoundsAsText(Viewport, View, Canvas, /*inout*/ YPos); } break; case ESpriteEditorMode::EditSourceRegionMode: { // Display tool help { FCanvasTextItem TextItem(FVector2D(6, YPos), SourceRegionHelpStr, GEngine->GetSmallFont(), FLinearColor::White); TextItem.EnableShadow(FLinearColor::Black); TextItem.Draw(&Canvas); YPos += 18; } if (bShowRelatedSprites) { DrawRelatedSprites(Viewport, View, Canvas, SpriteEditingConstants::SourceRegionRelatedBoundsColor, SpriteEditingConstants::SourceRegionRelatedSpriteNameColor); } DrawSourceRegion(Viewport, View, Canvas, SpriteEditingConstants::SourceRegionBoundsColor); } break; } if (bShowSockets && !IsInSourceRegionEditMode()) { FSpriteGeometryEditMode* GeometryEditMode = ModeTools->GetActiveModeTyped<FSpriteGeometryEditMode>(FSpriteGeometryEditMode::EM_SpriteGeometry); FSocketEditingHelper::DrawSocketNames(GeometryEditMode, RenderSpriteComponent, Viewport, View, Canvas); } FEditorViewportClient::DrawCanvas(Viewport, View, Canvas); }
void FSpriteEditorViewportClient::DrawSourceRegion(FViewport& InViewport, FSceneView& View, FCanvas& Canvas, const FLinearColor& GeometryVertexColor) { const bool bIsHitTesting = Canvas.IsHitTesting(); UPaperSprite* Sprite = GetSpriteBeingEdited(); const float CornerCollisionVertexSize = 8.0f; const float EdgeCollisionVertexSize = 6.0f; const FLinearColor GeometryLineColor(GeometryVertexColor.R, GeometryVertexColor.G, GeometryVertexColor.B, 0.5f * GeometryVertexColor.A); const bool bDrawEdgeHitProxies = true; const bool bDrawCornerHitProxies = true; FVector2D BoundsVertices[4]; BoundsVertices[0] = SourceTextureSpaceToScreenSpace(View, Sprite->SourceUV); BoundsVertices[1] = SourceTextureSpaceToScreenSpace(View, Sprite->SourceUV + FVector2D(Sprite->SourceDimension.X, 0)); BoundsVertices[2] = SourceTextureSpaceToScreenSpace(View, Sprite->SourceUV + FVector2D(Sprite->SourceDimension.X, Sprite->SourceDimension.Y)); BoundsVertices[3] = SourceTextureSpaceToScreenSpace(View, Sprite->SourceUV + FVector2D(0, Sprite->SourceDimension.Y)); if (bShowNamesForSprites) { const FVector2D TextPos = SourceTextureSpaceToScreenSpace(View, Sprite->SourceUV + FVector2D(Sprite->SourceDimension.X*0.5f, Sprite->SourceDimension.Y*0.5f)); const FText AssetNameText = FText::AsCultureInvariant(Sprite->GetName()); FCanvasTextItem TextItem(TextPos, AssetNameText, GEngine->GetSmallFont(), FLinearColor::White); TextItem.EnableShadow(FLinearColor::Black); TextItem.bCentreX = true; TextItem.bCentreY = true; TextItem.Draw(&Canvas); } for (int32 VertexIndex = 0; VertexIndex < 4; ++VertexIndex) { const int32 NextVertexIndex = (VertexIndex + 1) % 4; // Draw the edge if (bIsHitTesting) { TSharedPtr<FSpriteSelectedSourceRegion> Data = MakeShareable(new FSpriteSelectedSourceRegion()); Data->SpritePtr = Sprite; Data->VertexIndex = 4 + VertexIndex; Canvas.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } FCanvasLineItem LineItem(BoundsVertices[VertexIndex], BoundsVertices[NextVertexIndex]); LineItem.SetColor(GeometryVertexColor); Canvas.DrawItem(LineItem); // Add edge hit proxy if (bDrawEdgeHitProxies) { const FVector2D MidPoint = (BoundsVertices[VertexIndex] + BoundsVertices[NextVertexIndex]) * 0.5f; Canvas.DrawTile(MidPoint.X - EdgeCollisionVertexSize*0.5f, MidPoint.Y - EdgeCollisionVertexSize*0.5f, EdgeCollisionVertexSize, EdgeCollisionVertexSize, 0.f, 0.f, 1.f, 1.f, GeometryVertexColor, GWhiteTexture); } if (bIsHitTesting) { Canvas.SetHitProxy(nullptr); } // Add corner hit proxy if (bDrawCornerHitProxies) { const FVector2D CornerPoint = BoundsVertices[VertexIndex]; if (bIsHitTesting) { TSharedPtr<FSpriteSelectedSourceRegion> Data = MakeShareable(new FSpriteSelectedSourceRegion()); Data->SpritePtr = Sprite; Data->VertexIndex = VertexIndex; Canvas.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } Canvas.DrawTile(CornerPoint.X - CornerCollisionVertexSize * 0.5f, CornerPoint.Y - CornerCollisionVertexSize * 0.5f, CornerCollisionVertexSize, CornerCollisionVertexSize, 0.f, 0.f, 1.f, 1.f, GeometryVertexColor, GWhiteTexture); if (bIsHitTesting) { Canvas.SetHitProxy(nullptr); } } } }
void FSpriteGeometryEditingHelper::DrawGeometry_CanvasPass(FViewport& InViewport, const FSceneView& View, FCanvas& Canvas, /*inout*/ int32& YPos, const FLinearColor& GeometryVertexColor, const FLinearColor& NegativeGeometryVertexColor) { if (GeometryBeingEdited == nullptr) { return; } // Calculate the texture-space position of the mouse const FVector MousePositionWorldSpace = View.PixelToWorld(InViewport.GetMouseX(), InViewport.GetMouseY(), 0); const FVector2D MousePositionTextureSpace = EditorContext->WorldSpaceToTextureSpace(MousePositionWorldSpace); //@TODO: Move all of the line drawing to the PDI pass FSpriteGeometryCollection& Geometry = GetGeometryChecked(); // Display tool help { static const FText GeomHelpStr = LOCTEXT("GeomEditHelp", "Shift + click to insert a vertex.\nSelect one or more vertices and press Delete to remove them.\nDouble click a vertex to select a polygon\n"); static const FText GeomClickAddPolygon_NoSubtractive = LOCTEXT("GeomClickAddPolygon_NoSubtractive", "Click to start creating a polygon\n"); static const FText GeomClickAddPolygon_AllowSubtractive = LOCTEXT("GeomClickAddPolygon_AllowSubtractive", "Click to start creating a polygon\nCtrl + Click to start creating a subtractive polygon\n"); static const FText GeomAddVerticesHelpStr = LOCTEXT("GeomClickAddVertices", "Click to add points to the polygon\nDouble-click to add a point and close the shape\nClick again on the first point or press Enter to close the shape\nPress Backspace to remove the last added point or Escape to remove the shape\n"); FLinearColor ToolTextColor = FLinearColor::White; const FText* HelpStr; if (IsAddingPolygon()) { if (AddingPolygonIndex == INDEX_NONE) { HelpStr = bAllowSubtractivePolygons ? &GeomClickAddPolygon_AllowSubtractive : &GeomClickAddPolygon_NoSubtractive; } else { HelpStr = &GeomAddVerticesHelpStr; } ToolTextColor = FLinearColor::Yellow; } else { HelpStr = &GeomHelpStr; } FCanvasTextItem TextItem(FVector2D(6, YPos), *HelpStr, GEngine->GetSmallFont(), ToolTextColor); TextItem.EnableShadow(FLinearColor::Black); TextItem.Draw(&Canvas); YPos += 54; } const bool bIsHitTesting = Canvas.IsHitTesting(); // Run thru the geometry shapes and draw hit proxies for them for (int32 ShapeIndex = 0; ShapeIndex < Geometry.Shapes.Num(); ++ShapeIndex) { const FSpriteGeometryShape& Shape = Geometry.Shapes[ShapeIndex]; const bool bIsShapeSelected = IsGeometrySelected(FShapeVertexPair(ShapeIndex, INDEX_NONE)); const FLinearColor LineColorRaw = Shape.bNegativeWinding ? NegativeGeometryVertexColor : GeometryVertexColor; const FLinearColor VertexColor = Shape.bNegativeWinding ? NegativeGeometryVertexColor : GeometryVertexColor; const FLinearColor LineColor = Shape.IsShapeValid() ? LineColorRaw : FMath::Lerp(LineColorRaw, FLinearColor::Red, 0.8f); // Draw the circle shape if necessary if (Shape.ShapeType == ESpriteShapeType::Circle) { if (bIsHitTesting) { TSharedPtr<FSpriteSelectedShape> Data = MakeShareable(new FSpriteSelectedShape(EditorContext, Geometry, ShapeIndex, /*bIsBackground=*/ false)); Canvas.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } // Draw the circle const float RadiusX = Shape.BoxSize.X * 0.5f; const float RadiusY = Shape.BoxSize.Y * 0.5f; const float AngleDelta = 2.0f * PI / SpriteEditingConstantsEX::CircleShapeNumSides; const float LastX = Shape.BoxPosition.X + RadiusX; const float LastY = Shape.BoxPosition.Y; FVector2D LastVertexPos = TextureSpaceToScreenSpace(View, FVector2D(LastX, LastY)); for (int32 SideIndex = 0; SideIndex < SpriteEditingConstantsEX::CircleShapeNumSides; SideIndex++) { const float X = Shape.BoxPosition.X + RadiusX * FMath::Cos(AngleDelta * (SideIndex + 1)); const float Y = Shape.BoxPosition.Y + RadiusY * FMath::Sin(AngleDelta * (SideIndex + 1)); const FVector2D ScreenPos = TextureSpaceToScreenSpace(View, FVector2D(X, Y)); FCanvasLineItem LineItem(LastVertexPos, ScreenPos); LineItem.SetColor(bIsShapeSelected ? SpriteEditingConstantsEX::GeometrySelectedColor : LineColor); LineItem.LineThickness = SpriteEditingConstantsEX::GeometryBorderLineThickness; Canvas.DrawItem(LineItem); LastVertexPos = ScreenPos; } if (bIsHitTesting) { Canvas.SetHitProxy(nullptr); } } // Draw lines connecting the vertices of the shape for (int32 VertexIndex = 0; VertexIndex < Shape.Vertices.Num(); ++VertexIndex) { const int32 NextVertexIndex = (VertexIndex + 1) % Shape.Vertices.Num(); const FVector2D ScreenPos = TextureSpaceToScreenSpace(View, Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[VertexIndex])); const FVector2D NextScreenPos = TextureSpaceToScreenSpace(View, Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[NextVertexIndex])); const bool bIsThisVertexSelected = IsGeometrySelected(FShapeVertexPair(ShapeIndex, VertexIndex)); const bool bIsNextVertexSelected = IsGeometrySelected(FShapeVertexPair(ShapeIndex, NextVertexIndex)); const bool bIsEdgeSelected = bIsShapeSelected || (bIsThisVertexSelected && bIsNextVertexSelected); // Draw the normal tick if (bShowNormals) { const FVector2D Direction = (NextScreenPos - ScreenPos).GetSafeNormal(); const FVector2D Normal = FVector2D(-Direction.Y, Direction.X); const FVector2D Midpoint = (ScreenPos + NextScreenPos) * 0.5f; const FVector2D NormalPoint = Midpoint - Normal * SpriteEditingConstantsEX::GeometryNormalLength; FCanvasLineItem LineItem(Midpoint, NormalPoint); LineItem.SetColor(SpriteEditingConstantsEX::GeometryNormalColor); Canvas.DrawItem(LineItem); } // Draw the edge { if (bIsHitTesting) { TSharedPtr<FSpriteSelectedEdge> Data = MakeShareable(new FSpriteSelectedEdge(EditorContext, Geometry, ShapeIndex, VertexIndex)); Canvas.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } FCanvasLineItem LineItem(ScreenPos, NextScreenPos); LineItem.SetColor(bIsEdgeSelected ? SpriteEditingConstantsEX::GeometrySelectedColor : LineColor); LineItem.LineThickness = SpriteEditingConstantsEX::GeometryBorderLineThickness; Canvas.DrawItem(LineItem); if (bIsHitTesting) { Canvas.SetHitProxy(nullptr); } } } // Draw the vertices for (int32 VertexIndex = 0; VertexIndex < Shape.Vertices.Num(); ++VertexIndex) { const FVector2D ScreenPos = TextureSpaceToScreenSpace(View, Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[VertexIndex])); const float X = ScreenPos.X; const float Y = ScreenPos.Y; const bool bIsVertexSelected = IsGeometrySelected(FShapeVertexPair(ShapeIndex, VertexIndex)); const bool bIsVertexLastAdded = IsAddingPolygon() && (AddingPolygonIndex == ShapeIndex) && (VertexIndex == Shape.Vertices.Num() - 1); const bool bNeedHighlightVertex = bIsShapeSelected || bIsVertexSelected || bIsVertexLastAdded; if (bIsHitTesting) { TSharedPtr<FSpriteSelectedVertex> Data = MakeShareable(new FSpriteSelectedVertex(EditorContext, Geometry, ShapeIndex, VertexIndex)); Canvas.SetHitProxy(new HSpriteSelectableObjectHitProxy(Data)); } const float VertSize = SpriteEditingConstantsEX::GeometryVertexSize; Canvas.DrawTile(ScreenPos.X - VertSize*0.5f, ScreenPos.Y - VertSize*0.5f, VertSize, VertSize, 0.f, 0.f, 1.f, 1.f, bNeedHighlightVertex ? SpriteEditingConstantsEX::GeometrySelectedColor : VertexColor, GWhiteTexture); if (bIsHitTesting) { Canvas.SetHitProxy(nullptr); } } } // Draw a preview cursor for the add polygon tool if (IsAddingPolygon()) { // Figure out where the mouse is back in screen space const FVector2D PotentialVertexScreenPos = TextureSpaceToScreenSpace(View, MousePositionTextureSpace); bool bWillCloseByClicking = false; if (Geometry.Shapes.IsValidIndex(AddingPolygonIndex)) { const FSpriteGeometryShape& Shape = Geometry.Shapes[AddingPolygonIndex]; const FLinearColor LineColorRaw = Shape.bNegativeWinding ? NegativeGeometryVertexColor : GeometryVertexColor; const FLinearColor LineColorValidity = Shape.IsShapeValid() ? LineColorRaw : FMath::Lerp(LineColorRaw, FLinearColor::Red, 0.8f); const FLinearColor LineColor = FMath::Lerp(LineColorValidity, SpriteEditingConstantsEX::GeometrySelectedColor, 0.2f); if (Shape.Vertices.Num() > 0) { // Draw a line from the last vertex to the potential insertion point for the new one { const FVector2D LastScreenPos = TextureSpaceToScreenSpace(View, Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[Shape.Vertices.Num() - 1])); FCanvasLineItem LineItem(LastScreenPos, PotentialVertexScreenPos); LineItem.SetColor(LineColor); LineItem.LineThickness = SpriteEditingConstantsEX::GeometryBorderLineThickness; Canvas.DrawItem(LineItem); } // And to the first vertex if there were at least 2 if (Shape.Vertices.Num() >= 2) { const FVector2D FirstScreenPos = TextureSpaceToScreenSpace(View, Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[0])); FCanvasLineItem LineItem(PotentialVertexScreenPos, FirstScreenPos); LineItem.SetColor(LineColor); LineItem.LineThickness = SpriteEditingConstantsEX::GeometryBorderLineThickness; Canvas.DrawItem(LineItem); // Determine how close we are to the first vertex (will we close the shape by clicking)? bWillCloseByClicking = (Shape.Vertices.Num() >= 3) && (FVector2D::Distance(FirstScreenPos, PotentialVertexScreenPos) < SpriteEditingConstantsEX::AddPolygonVertexWeldScreenSpaceDistance); } } } // Draw the prospective vert const float VertSize = SpriteEditingConstantsEX::GeometryVertexSize; Canvas.DrawTile(PotentialVertexScreenPos.X - VertSize*0.5f, PotentialVertexScreenPos.Y - VertSize*0.5f, VertSize, VertSize, 0.f, 0.f, 1.f, 1.f, SpriteEditingConstantsEX::GeometrySelectedColor, GWhiteTexture); // Draw a prompt above and to the right of the cursor static const FText CloseButton(LOCTEXT("ClosePolygonPrompt", "Close")); static const FText AddButton(LOCTEXT("AddVertexToPolygonPrompt", "+")); const FText PromptText(bWillCloseByClicking ? CloseButton : AddButton); FCanvasTextItem PromptTextItem(FVector2D(PotentialVertexScreenPos.X + VertSize, PotentialVertexScreenPos.Y - VertSize), PromptText, GEngine->GetSmallFont(), FLinearColor::White); PromptTextItem.EnableShadow(FLinearColor::Black); PromptTextItem.Draw(&Canvas); } }
/** * Helper function to create an unwrapped 2D image of the cube map ( longitude/latitude ) * This version takes explicitly passed properties of the source object, as the sources have different APIs. * @param TextureResource Source FTextureResource object. * @param AxisDimenion axis length of the cube. * @param SourcePixelFormat pixel format of the source. * @param BitsOUT Raw bits of the 2D image bitmap. * @param SizeXOUT Filled with the X dimension of the output bitmap. * @param SizeYOUT Filled with the Y dimension of the output bitmap. * @return true on success. * @param FormatOUT Filled with the pixel format of the output bitmap. */ bool GenerateLongLatUnwrap(const FTextureResource* TextureResource, const uint32 AxisDimenion, const EPixelFormat SourcePixelFormat, TArray<uint8>& BitsOUT, FIntPoint& SizeOUT, EPixelFormat& FormatOUT) { TRefCountPtr<FBatchedElementParameters> BatchedElementParameters; BatchedElementParameters = new FMipLevelBatchedElementParameters((float)0, true); const FIntPoint LongLatDimensions(AxisDimenion * 2, AxisDimenion); // If the source format is 8 bit per channel or less then select a LDR target format. const EPixelFormat TargetPixelFormat = CalculateImageBytes(1, 1, 0, SourcePixelFormat) <= 4 ? PF_B8G8R8A8 : PF_FloatRGBA; UTextureRenderTarget2D* RenderTargetLongLat = NewObject<UTextureRenderTarget2D>(); check(RenderTargetLongLat); RenderTargetLongLat->AddToRoot(); RenderTargetLongLat->ClearColor = FLinearColor(0.0f, 0.0f, 0.0f, 0.0f); RenderTargetLongLat->InitCustomFormat(LongLatDimensions.X, LongLatDimensions.Y, TargetPixelFormat, false); RenderTargetLongLat->TargetGamma = 0; FRenderTarget* RenderTarget = RenderTargetLongLat->GameThread_GetRenderTargetResource(); FCanvas* Canvas = new FCanvas(RenderTarget, NULL, 0, 0, 0, GMaxRHIFeatureLevel); Canvas->SetRenderTarget_GameThread(RenderTarget); // Clear the render target to black Canvas->Clear(FLinearColor(0, 0, 0, 0)); FCanvasTileItem TileItem(FVector2D(0.0f, 0.0f), TextureResource, FVector2D(LongLatDimensions.X, LongLatDimensions.Y), FLinearColor::White); TileItem.BatchedElementParameters = BatchedElementParameters; TileItem.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(TileItem); Canvas->Flush_GameThread(); FlushRenderingCommands(); Canvas->SetRenderTarget_GameThread(NULL); FlushRenderingCommands(); int32 ImageBytes = CalculateImageBytes(LongLatDimensions.X, LongLatDimensions.Y, 0, TargetPixelFormat); BitsOUT.AddUninitialized(ImageBytes); bool bReadSuccess = false; switch (TargetPixelFormat) { case PF_B8G8R8A8: bReadSuccess = RenderTarget->ReadPixelsPtr((FColor*)BitsOUT.GetData()); break; case PF_FloatRGBA: { TArray<FFloat16Color> FloatColors; bReadSuccess = RenderTarget->ReadFloat16Pixels(FloatColors); FMemory::Memcpy(BitsOUT.GetData(), FloatColors.GetData(), ImageBytes); } break; } // Clean up. RenderTargetLongLat->RemoveFromRoot(); RenderTargetLongLat = NULL; delete Canvas; SizeOUT = LongLatDimensions; FormatOUT = TargetPixelFormat; if (bReadSuccess == false) { // Reading has failed clear output buffer. BitsOUT.Empty(); } return bReadSuccess; }
void FStaticMeshEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) { #if TODO_STATICMESH if ( StaticMesh->bHasBeenSimplified && SimplygonLogo && SimplygonLogo->Resource ) { const float LogoSizeX = 64.0f; const float LogoSizeY = 40.65f; const float Padding = 6.0f; const float LogoX = Viewport->GetSizeXY().X - Padding - LogoSizeX; const float LogoY = Viewport->GetSizeXY().Y - Padding - LogoSizeY; Canvas->DrawTile( LogoX, LogoY, LogoSizeX, LogoSizeY, 0.0f, 0.0f, 1.0f, 1.0f, FLinearColor::White, SimplygonLogo->Resource, SE_BLEND_Opaque ); } #endif // #if TODO_STATICMESH auto StaticMeshEditor = StaticMeshEditorPtr.Pin(); auto StaticMeshEditorViewport = StaticMeshEditorViewportPtr.Pin(); if (!StaticMeshEditor.IsValid() || !StaticMeshEditorViewport.IsValid()) { return; } const int32 HalfX = Viewport->GetSizeXY().X/2; const int32 HalfY = Viewport->GetSizeXY().Y/2; // Draw socket names if desired. if( bShowSockets ) { for(int32 i=0; i<StaticMesh->Sockets.Num(); i++) { UStaticMeshSocket* Socket = StaticMesh->Sockets[i]; if(Socket!=NULL) { FMatrix SocketTM; Socket->GetSocketMatrix(SocketTM, StaticMeshComponent); const FVector SocketPos = SocketTM.GetOrigin(); const FPlane proj = View.Project( SocketPos ); if(proj.W > 0.f) { const int32 XPos = HalfX + ( HalfX * proj.X ); const int32 YPos = HalfY + ( HalfY * (proj.Y * -1) ); FCanvasTextItem TextItem( FVector2D( XPos, YPos ), FText::FromString( Socket->SocketName.ToString() ), GEngine->GetSmallFont(), FLinearColor(FColor(255,196,196)) ); Canvas.DrawItem( TextItem ); const UStaticMeshSocket* SelectedSocket = StaticMeshEditor->GetSelectedSocket(); if (bManipulating && SelectedSocket == Socket) { //Figure out the text height FTextSizingParameters Parameters(GEngine->GetSmallFont(), 1.0f, 1.0f); UCanvas::CanvasStringSize(Parameters, *Socket->SocketName.ToString()); int32 YL = FMath::TruncToInt(Parameters.DrawYL); DrawAngles(&Canvas, XPos, YPos + YL, Widget->GetCurrentAxis(), GetWidgetMode(), Socket->RelativeRotation, Socket->RelativeLocation); } } } } } TArray<SStaticMeshEditorViewport::FOverlayTextItem> TextItems; int32 CurrentLODLevel = StaticMeshEditor->GetCurrentLODLevel(); if (CurrentLODLevel == 0) { CurrentLODLevel = ComputeStaticMeshLOD(StaticMesh->RenderData, StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View); } else { CurrentLODLevel -= 1; } TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "LOD_F", "LOD: {0}"), FText::AsNumber(CurrentLODLevel)))); float CurrentScreenSize = ComputeBoundsScreenSize(StaticMeshComponent->Bounds.Origin, StaticMeshComponent->Bounds.SphereRadius, View); FNumberFormattingOptions FormatOptions; FormatOptions.MinimumFractionalDigits = 3; FormatOptions.MaximumFractionalDigits = 6; FormatOptions.MaximumIntegralDigits = 6; TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "ScreenSize_F", "Current Screen Size: {0}"), FText::AsNumber(CurrentScreenSize, &FormatOptions)))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "Triangles_F", "Triangles: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumTriangles(CurrentLODLevel))))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "Vertices_F", "Vertices: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumVertices(CurrentLODLevel))))); TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "UVChannels_F", "UV Channels: {0}"), FText::AsNumber(StaticMeshEditorPtr.Pin()->GetNumUVChannels(CurrentLODLevel))))); if( StaticMesh->RenderData->LODResources.Num() > 0 ) { if (StaticMesh->RenderData->LODResources[0].DistanceFieldData != nullptr ) { const FDistanceFieldVolumeData& VolumeData = *(StaticMesh->RenderData->LODResources[0].DistanceFieldData); if (VolumeData.Size.GetMax() > 0) { float MemoryMb = (VolumeData.Size.X * VolumeData.Size.Y * VolumeData.Size.Z * VolumeData.DistanceFieldVolume.GetTypeSize()) / (1024.0f * 1024.0f); FNumberFormattingOptions NumberOptions; NumberOptions.MinimumFractionalDigits = 2; NumberOptions.MaximumFractionalDigits = 2; if (VolumeData.bMeshWasClosed) { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "DistanceFieldRes_F", "Distance Field: {0}x{1}x{2} = {3}Mb"), FText::AsNumber(VolumeData.Size.X), FText::AsNumber(VolumeData.Size.Y), FText::AsNumber(VolumeData.Size.Z), FText::AsNumber(MemoryMb, &NumberOptions)))); } else { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( NSLOCTEXT("UnrealEd", "DistanceFieldClosed_F", "Distance Field: Mesh was not closed and material was one-sided"))); } } } } TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "ApproxSize_F", "Approx Size: {0}x{1}x{2}"), FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.X * 2.0f)), // x2 as artists wanted length not radius FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Y * 2.0f)), FText::AsNumber(int32(StaticMesh->GetBounds().BoxExtent.Z * 2.0f))))); // Show the number of collision primitives if we are drawing collision. if(bShowCollision && StaticMesh->BodySetup) { TextItems.Add(SStaticMeshEditorViewport::FOverlayTextItem( FText::Format(NSLOCTEXT("UnrealEd", "NumPrimitives_F", "Num Primitives: {0}"), FText::AsNumber(StaticMesh->BodySetup->AggGeom.GetElementCount())))); } StaticMeshEditorViewport->PopulateOverlayText(TextItems); if(bDrawUVs) { const int32 YPos = 160; DrawUVsForMesh(Viewport, &Canvas, YPos); } }