void FEditorLiveStreaming::BroadcastStatusCallback( const FLiveStreamingStatus& Status ) { TSharedPtr< SNotificationItem > Notification( NotificationWeakPtr.Pin() ); if( Notification.IsValid() ) { // Don't bother clobbering existing message with text about web cam starting/stopping, unless we're already broadcasting. // We want to make sure people see the persistent text about login state. if( SubmittedVideoFrameCount > 0 || ( Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamStarted && Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamStopped && Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamTextureNotReady && Status.StatusType != FLiveStreamingStatus::EStatusType::WebCamTextureReady && Status.StatusType != FLiveStreamingStatus::EStatusType::ChatConnected && Status.StatusType != FLiveStreamingStatus::EStatusType::ChatDisconnected ) ) { Notification->SetText( Status.CustomStatusDescription ); } } else { // Only spawn a notification if we're actually still trying to broadcast, not if we're stopping broadcasting. We don't want // to revive our notification that we intentionally expired. if( bIsBroadcasting ) { FNotificationInfo Info( Status.CustomStatusDescription ); Info.FadeInDuration = 0.1f; Info.FadeOutDuration = 0.5f; Info.ExpireDuration = 1.5f; Info.bUseThrobber = false; Info.bUseSuccessFailIcons = true; Info.bUseLargeFont = true; Info.bFireAndForget = false; Info.bAllowThrottleWhenFrameRateIsLow = false; NotificationWeakPtr = FSlateNotificationManager::Get().AddNotification( Info ); } } Notification = NotificationWeakPtr.Pin(); if( Notification.IsValid() ) { SNotificationItem::ECompletionState State = SNotificationItem::CS_Pending; if( Status.StatusType == FLiveStreamingStatus::EStatusType::Failure ) { State = SNotificationItem::CS_Fail; } else if( Status.StatusType == FLiveStreamingStatus::EStatusType::BroadcastStarted || Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamStarted || Status.StatusType == FLiveStreamingStatus::EStatusType::ChatConnected ) { State = SNotificationItem::CS_Success; } Notification->SetCompletionState( State ); } // If the web cam just turned on, then we'll go ahead and show it if( Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamTextureReady ) { bool bIsImageFlippedHorizontally = false; bool bIsImageFlippedVertically = false; UTexture2D* WebCamTexture = LiveStreamer->GetWebCamTexture( bIsImageFlippedHorizontally, bIsImageFlippedVertically ); if( ensure( WebCamTexture != nullptr ) ) { IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( TEXT( "MainFrame" ) ); check( MainFrameModule.IsWindowInitialized() ); auto RootWindow = MainFrameModule.GetParentWindow(); check( RootWindow.IsValid() ); // Allow the user to customize the image mirroring, too! const auto& Settings = *GetDefault< UEditorLiveStreamingSettings >(); if( Settings.bMirrorWebCamImage ) { bIsImageFlippedHorizontally = !bIsImageFlippedHorizontally; } // How many pixels from the edge of the main frame window to where the broadcast status window appears const int WindowBorderPadding = 50; // @todo livestream: Currently this window is not created as "topmost". We don't really want it to be OS-topmost, but we do want it to be the most // topmost "regular" window in our application (not on top of tooltips, etc.) // Create a window that will show the web cam video feed BroadcastStatusWindow = SNew( SWindow ) .Title( LOCTEXT( "StreamingWindowTitle", "Web Camera" ) ) .ClientSize( FVector2D( WebCamTexture->GetSizeX(), WebCamTexture->GetSizeY() ) ) .ScreenPosition( FVector2D( RootWindow->GetRectInScreen().Right - WebCamTexture->GetSizeX() - WindowBorderPadding, RootWindow->GetRectInScreen().Top + WindowBorderPadding ) ) // @todo livestream: Ideally the user could freely resize the window, but it gets a bit tricky to preserve the web cam aspect. Plus, we don't really like how letterboxing/columnboxing looks with this. .SizingRule( ESizingRule::FixedSize ) .AutoCenter( EAutoCenter::None ) .bDragAnywhere( true ) .SupportsMaximize( true ) .SupportsMinimize( true ) .FocusWhenFirstShown( false ) .ActivateWhenFirstShown( false ) .SaneWindowPlacement( false ); WebCamDynamicImageBrush = MakeShareable( new FSlateDynamicImageBrush( WebCamTexture, FVector2D( WebCamTexture->GetSizeX(), WebCamTexture->GetSizeY() ), WebCamTexture->GetFName() ) ); // If the web cam image is coming in flipped, we'll apply mirroring to the Slate brush if( bIsImageFlippedHorizontally && bIsImageFlippedVertically ) { WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Both; } else if( bIsImageFlippedHorizontally ) { WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Horizontal; } else if( bIsImageFlippedVertically ) { WebCamDynamicImageBrush->Mirroring = ESlateBrushMirrorType::Vertical; } // @todo livestream: Currently if the user closes the window, the camera is deactivated and it doesn't turn back on unless the broadcast is restarted. We could allow the camera to be reactivated though. BroadcastStatusWindow->SetOnWindowClosed( FOnWindowClosed::CreateStatic( []( const TSharedRef<SWindow>& Window, FEditorLiveStreaming* This ) { // User closed the broadcast status window, so go ahead and shut down the web cam This->LiveStreamer->StopWebCam(); This->BroadcastStatusWindow.Reset(); This->WebCamDynamicImageBrush.Reset(); }, this ) ); BroadcastStatusWindow->SetContent( SNew( SImage ) .Image( WebCamDynamicImageBrush.Get() ) ); FSlateApplication::Get().AddWindowAsNativeChild( BroadcastStatusWindow.ToSharedRef(), RootWindow.ToSharedRef() ); } } else if( Status.StatusType == FLiveStreamingStatus::EStatusType::WebCamTextureNotReady ) { CloseBroadcastStatusWindow(); } }
void FEdMode::DrawHUD(FEditorViewportClient* ViewportClient,FViewport* Viewport,const FSceneView* View,FCanvas* Canvas) { // Render the drag tool. ViewportClient->RenderDragTool( View, Canvas ); // Let the current mode tool draw a HUD if it wants to FModeTool* tool = GetCurrentTool(); if( tool ) { tool->DrawHUD( ViewportClient, Viewport, View, Canvas ); } if (ViewportClient->IsPerspective() && GetDefault<ULevelEditorViewportSettings>()->bHighlightWithBrackets) { DrawBrackets( ViewportClient, Viewport, View, Canvas ); } // If this viewport doesn't show mode widgets or the mode itself doesn't want them, leave. if( !(ViewportClient->EngineShowFlags.ModeWidgets) || !ShowModeWidgets() ) { return; } // Clear Hit proxies const bool bIsHitTesting = Canvas->IsHitTesting(); if ( !bIsHitTesting ) { Canvas->SetHitProxy(NULL); } // Draw vertices for selected BSP brushes and static meshes if the large vertices show flag is set. if ( !ViewportClient->bDrawVertices ) { return; } const bool bLargeVertices = View->Family->EngineShowFlags.LargeVertices; const bool bShowBrushes = View->Family->EngineShowFlags.Brushes; const bool bShowBSP = View->Family->EngineShowFlags.BSP; const bool bShowBuilderBrush = View->Family->EngineShowFlags.BuilderBrush != 0; UTexture2D* VertexTexture = GetVertexTexture(); const float TextureSizeX = VertexTexture->GetSizeX() * ( bLargeVertices ? 1.0f : 0.5f ); const float TextureSizeY = VertexTexture->GetSizeY() * ( bLargeVertices ? 1.0f : 0.5f ); // Temporaries. TArray<FVector> Vertices; for ( FSelectionIterator It( *Owner->GetSelectedActors() ) ; It ; ++It ) { AActor* SelectedActor = static_cast<AActor*>( *It ); checkSlow( SelectedActor->IsA(AActor::StaticClass()) ); if( bLargeVertices ) { FCanvasItemTestbed::bTestState = !FCanvasItemTestbed::bTestState; // Static mesh vertices AStaticMeshActor* Actor = Cast<AStaticMeshActor>( SelectedActor ); if( Actor && Actor->GetStaticMeshComponent() && Actor->GetStaticMeshComponent()->StaticMesh && Actor->GetStaticMeshComponent()->StaticMesh->RenderData ) { FTransform ActorToWorld = Actor->ActorToWorld(); Vertices.Empty(); const FPositionVertexBuffer& VertexBuffer = Actor->GetStaticMeshComponent()->StaticMesh->RenderData->LODResources[0].PositionVertexBuffer; for( uint32 i = 0 ; i < VertexBuffer.GetNumVertices() ; i++ ) { Vertices.AddUnique( ActorToWorld.TransformPosition( VertexBuffer.VertexPosition(i) ) ); } FCanvasTileItem TileItem( FVector2D( 0.0f, 0.0f ), FVector2D( 0.0f, 0.0f ), FLinearColor::White ); TileItem.BlendMode = SE_BLEND_Translucent; for( int32 VertexIndex = 0 ; VertexIndex < Vertices.Num() ; ++VertexIndex ) { const FVector& Vertex = Vertices[VertexIndex]; FVector2D PixelLocation; if(View->ScreenToPixel(View->WorldToScreen(Vertex),PixelLocation)) { const bool bOutside = PixelLocation.X < 0.0f || PixelLocation.X > View->ViewRect.Width() || PixelLocation.Y < 0.0f || PixelLocation.Y > View->ViewRect.Height(); if( !bOutside ) { const float X = PixelLocation.X - (TextureSizeX/2); const float Y = PixelLocation.Y - (TextureSizeY/2); if( bIsHitTesting ) { Canvas->SetHitProxy( new HStaticMeshVert(Actor,Vertex) ); } TileItem.Texture = VertexTexture->Resource; TileItem.Size = FVector2D( TextureSizeX, TextureSizeY ); Canvas->DrawItem( TileItem, FVector2D( X, Y ) ); if( bIsHitTesting ) { Canvas->SetHitProxy( NULL ); } } } } } } } if(UsesPropertyWidgets()) { AActor* SelectedActor = GetFirstSelectedActorInstance(); if (SelectedActor != NULL) { FEditorScriptExecutionGuard ScriptGuard; const int32 HalfX = 0.5f * Viewport->GetSizeXY().X; const int32 HalfY = 0.5f * Viewport->GetSizeXY().Y; UClass* Class = SelectedActor->GetClass(); TArray<FPropertyWidgetInfo> WidgetInfos; GetPropertyWidgetInfos(Class, SelectedActor, WidgetInfos); for(int32 i=0; i<WidgetInfos.Num(); i++) { FString WidgetName = WidgetInfos[i].PropertyName; FName WidgetValidator = WidgetInfos[i].PropertyValidationName; int32 WidgetIndex = WidgetInfos[i].PropertyIndex; bool bIsTransform = WidgetInfos[i].bIsTransform; FVector LocalPos = FVector::ZeroVector; if(bIsTransform) { FTransform LocalTM = GetPropertyValueByName<FTransform>(SelectedActor, WidgetName, WidgetIndex); LocalPos = LocalTM.GetLocation(); } else { LocalPos = GetPropertyValueByName<FVector>(SelectedActor, WidgetName, WidgetIndex); } FTransform ActorToWorld = SelectedActor->ActorToWorld(); FVector WorldPos = ActorToWorld.TransformPosition(LocalPos); UFunction* ValidateFunc = NULL; FString FinalString; if(WidgetValidator != NAME_None && (ValidateFunc = SelectedActor->FindFunction(WidgetValidator)) != NULL) { SelectedActor->ProcessEvent(ValidateFunc, &FinalString); } const FPlane Proj = View->Project( WorldPos ); //do some string fixing const uint32 VectorIndex = WidgetInfos[i].PropertyIndex; const FString WidgetDisplayName = WidgetInfos[i].DisplayName + ((VectorIndex != INDEX_NONE) ? FString::Printf(TEXT("[%d]"), VectorIndex) : TEXT("")); FinalString = FinalString.IsEmpty() ? WidgetDisplayName : FinalString; if(Proj.W > 0.f) { const int32 XPos = HalfX + ( HalfX * Proj.X ); const int32 YPos = HalfY + ( HalfY * (Proj.Y * -1.f) ); FCanvasTextItem TextItem( FVector2D( XPos + 5, YPos), FText::FromString( FinalString ), GEngine->GetSmallFont(), FLinearColor::White ); Canvas->DrawItem( TextItem ); } } } } }
void UPaperTileMapComponent::RebuildRenderData(FPaperTileMapRenderSceneProxy* Proxy) { TArray<FSpriteDrawCallRecord> BatchedSprites; if (TileMap == nullptr) { return; } FVector CornerOffset; FVector OffsetYFactor; FVector StepPerTileX; FVector StepPerTileY; TileMap->GetTileToLocalParameters(/*out*/ CornerOffset, /*out*/ StepPerTileX, /*out*/ StepPerTileY, /*out*/ OffsetYFactor); UTexture2D* LastSourceTexture = nullptr; FVector TileSetOffset = FVector::ZeroVector; FVector2D InverseTextureSize(1.0f, 1.0f); FVector2D SourceDimensionsUV(1.0f, 1.0f); FVector2D TileSizeXY(0.0f, 0.0f); for (int32 Z = 0; Z < TileMap->TileLayers.Num(); ++Z) { UPaperTileLayer* Layer = TileMap->TileLayers[Z]; if (Layer == nullptr) { continue; } FLinearColor DrawColor = FLinearColor::White; #if WITH_EDITORONLY_DATA if (Layer->bHiddenInEditor) { continue; } DrawColor.A = Layer->LayerOpacity; #endif FSpriteDrawCallRecord* CurrentBatch = nullptr; for (int32 Y = 0; Y < TileMap->MapHeight; ++Y) { // In pixels FVector EffectiveTopLeftCorner; switch (TileMap->ProjectionMode) { case ETileMapProjectionMode::Orthogonal: default: EffectiveTopLeftCorner = CornerOffset; break; case ETileMapProjectionMode::IsometricDiamond: EffectiveTopLeftCorner = CornerOffset - StepPerTileX; break; case ETileMapProjectionMode::IsometricStaggered: case ETileMapProjectionMode::HexagonalStaggered: EffectiveTopLeftCorner = CornerOffset + (Y & 1) * OffsetYFactor; break; } for (int32 X = 0; X < TileMap->MapWidth; ++X) { const FPaperTileInfo TileInfo = Layer->GetCell(X, Y); // do stuff const float TotalSeparation = (TileMap->SeparationPerLayer * Z) + (TileMap->SeparationPerTileX * X) + (TileMap->SeparationPerTileY * Y); FVector TopLeftCornerOfTile = (StepPerTileX * X) + (StepPerTileY * Y) + EffectiveTopLeftCorner; TopLeftCornerOfTile += TotalSeparation * PaperAxisZ; const int32 TileWidth = TileMap->TileWidth; const int32 TileHeight = TileMap->TileHeight; { UTexture2D* SourceTexture = nullptr; FVector2D SourceUV = FVector2D::ZeroVector; if (Layer->bCollisionLayer) { if (TileInfo.PackedTileIndex == 0) { continue; } SourceTexture = UCanvas::StaticClass()->GetDefaultObject<UCanvas>()->DefaultTexture; } else { if (TileInfo.TileSet == nullptr) { continue; } if (!TileInfo.TileSet->GetTileUV(TileInfo.PackedTileIndex, /*out*/ SourceUV)) { continue; } SourceTexture = TileInfo.TileSet->TileSheet; if (SourceTexture == nullptr) { continue; } } if ((SourceTexture != LastSourceTexture) || (CurrentBatch == nullptr)) { CurrentBatch = (new (BatchedSprites) FSpriteDrawCallRecord()); CurrentBatch->Texture = SourceTexture; CurrentBatch->Color = DrawColor; CurrentBatch->Destination = TopLeftCornerOfTile.ProjectOnTo(PaperAxisZ); } if (SourceTexture != LastSourceTexture) { InverseTextureSize = FVector2D(1.0f / SourceTexture->GetSizeX(), 1.0f / SourceTexture->GetSizeY()); if (TileInfo.TileSet != nullptr) { SourceDimensionsUV = FVector2D(TileInfo.TileSet->TileWidth * InverseTextureSize.X, TileInfo.TileSet->TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileInfo.TileSet->TileWidth, TileInfo.TileSet->TileHeight); TileSetOffset = (TileInfo.TileSet->DrawingOffset.X * PaperAxisX) + (TileInfo.TileSet->DrawingOffset.Y * PaperAxisY); } else { SourceDimensionsUV = FVector2D(TileWidth * InverseTextureSize.X, TileHeight * InverseTextureSize.Y); TileSizeXY = FVector2D(TileWidth, TileHeight); TileSetOffset = FVector::ZeroVector; } LastSourceTexture = SourceTexture; } TopLeftCornerOfTile += TileSetOffset; SourceUV.X *= InverseTextureSize.X; SourceUV.Y *= InverseTextureSize.Y; FSpriteDrawCallRecord& NewTile = *CurrentBatch; const float WX0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisX); const float WY0 = FVector::DotProduct(TopLeftCornerOfTile, PaperAxisY); const FVector4 BottomLeft(WX0, WY0 - TileSizeXY.Y, SourceUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 BottomRight(WX0 + TileSizeXY.X, WY0 - TileSizeXY.Y, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y + SourceDimensionsUV.Y); const FVector4 TopRight(WX0 + TileSizeXY.X, WY0, SourceUV.X + SourceDimensionsUV.X, SourceUV.Y); const FVector4 TopLeft(WX0, WY0, SourceUV.X, SourceUV.Y); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopRight); new (NewTile.RenderVerts) FVector4(BottomRight); new (NewTile.RenderVerts) FVector4(BottomLeft); new (NewTile.RenderVerts) FVector4(TopLeft); new (NewTile.RenderVerts) FVector4(TopRight); } } } } Proxy->SetBatchesHack(BatchedSprites); }
static bool UpdateSelectedTexel( UPrimitiveComponent* Component, int32 NodeIndex, FLightMapRef& Lightmap, const FVector& Position, FVector2D InterpolatedUV, int32 LocalX, int32 LocalY, int32 LightmapSizeX, int32 LightmapSizeY) { if (Component == GCurrentSelectedLightmapSample.Component && NodeIndex == GCurrentSelectedLightmapSample.NodeIndex && LocalX == GCurrentSelectedLightmapSample.LocalX && LocalY == GCurrentSelectedLightmapSample.LocalY) { return false; } else { // Store information about the selected texel FSelectedLightmapSample NewSelectedTexel(Component, NodeIndex, Lightmap, Position, LocalX, LocalY, LightmapSizeX, LightmapSizeY); if (IsValidRef(Lightmap)) { FLightMap2D* Lightmap2D = Lightmap->GetLightMap2D(); check(Lightmap2D); const FVector2D CoordinateScale = Lightmap2D->GetCoordinateScale(); const FVector2D CoordinateBias = Lightmap2D->GetCoordinateBias(); // Calculate lightmap atlas UV's for the selected point FVector2D LightmapUV = InterpolatedUV * CoordinateScale + CoordinateBias; int32 LightmapIndex = Lightmap2D->AllowsHighQualityLightmaps() ? 0 : 1; UTexture2D* CurrentLightmap = Lightmap2D->GetTexture( LightmapIndex ); // UV's in the lightmap atlas NewSelectedTexel.LightmapX = FMath::TruncToInt(LightmapUV.X * CurrentLightmap->GetSizeX()); NewSelectedTexel.LightmapY = FMath::TruncToInt(LightmapUV.Y * CurrentLightmap->GetSizeY()); // Write the selection color to the selected lightmap texel WriteTexel(CurrentLightmap, NewSelectedTexel.LightmapX, NewSelectedTexel.LightmapY, GTexelSelectionColor, NewSelectedTexel.OriginalColor); GCurrentSelectedLightmapSample = NewSelectedTexel; return true; } else { UE_LOG(LogStaticLightingSystem, Log, TEXT("Texel selection failed because the lightmap is an invalid reference!")); return false; } } }