Example #1
0
/* After release of left mouse button, check if this unit is within selection box. */ 
void ARTSUnit::CheckForSelection()
{

	/* Find screen coordinates of the unit. */
	FVector2D MyResult = FVector2D(0, 0);

	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PC->Player);

	if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
	{
		FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
			LocalPlayer->ViewportClient->Viewport,
			GetWorld()->Scene,
			LocalPlayer->ViewportClient->EngineShowFlags)
			.SetRealtimeUpdate(true));

		FVector ViewLocation;
		FRotator ViewRotation;
		FSceneView* SceneView = LocalPlayer->CalcSceneView(&ViewFamily, /*out*/ ViewLocation, /*out*/ ViewRotation, LocalPlayer->ViewportClient->Viewport);

		if (SceneView)
		{
			auto MyWorldPosition = GetActorLocation();
			MyResult;
			SceneView->WorldToPixel(MyWorldPosition, MyResult);
		}
	}

	/* If the selection box contains the screen postion: */
	if (ARTSHUD::SelectionContainsPoint(MyResult)){

		// Select this unit, and leave possibility to select others.
		Select();
	}
}
bool FSpriteGeometryEditMode::InputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event)
{
	bool bHandled = false;
	FInputEventState InputState(Viewport, Key, Event);

	// Handle marquee tracking in source region edit mode
	if (IsEditingGeometry())
	{
		if (SpriteGeometryHelper.IsAddingPolygon())
		{
			if (Key == EKeys::LeftMouseButton)
			{
				const int32 HitX = Viewport->GetMouseX();
				const int32 HitY = Viewport->GetMouseY();

				// Calculate the texture space position of the mouse click
				FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(Viewport, ViewportClient->GetScene(), ViewportClient->EngineShowFlags));
				FSceneView* View = ViewportClient->CalcSceneView(&ViewFamily);
				const FVector WorldPoint = View->PixelToWorld(HitX, HitY, 0);
				const FVector2D TexturePoint = SpriteGeometryHelper.GetEditorContext()->WorldSpaceToTextureSpace(WorldPoint);

				// Add or close the polygon (depending on where the click happened and how)
				const bool bMakeSubtractiveIfAllowed = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
				SpriteGeometryHelper.HandleAddPolygonClick(TexturePoint, bMakeSubtractiveIfAllowed, *View, Event);
			}
			else if ((Key == EKeys::BackSpace) && (Event == IE_Pressed))
			{
				SpriteGeometryHelper.DeleteLastVertexFromAddPolygonMode();
			}			
			else if (Key == EKeys::Enter)
			{
				SpriteGeometryHelper.ResetAddPolygonMode();
			}
			else if (Key == EKeys::Escape)
			{
				SpriteGeometryHelper.AbandonAddPolygonMode();
			}
		}
		else
		{
 			if (ProcessMarquee(Viewport, Key, Event, true))
 			{
 				const bool bAddingToSelection = InputState.IsShiftButtonPressed(); //@TODO: control button moves widget? Hopefully make this more consistent when that is changed
 				SelectVerticesInMarquee(ViewportClient, Viewport, bAddingToSelection);
 			}
		}
	}

	//@TODO: Support select-and-drag in a single operation (may involve InputAxis and StartTracking)

	// Pass keys to standard controls, if we didn't consume input
	return bHandled ? true : FEdMode::InputKey(ViewportClient, Viewport, Key, Event);
}
FSceneView* FJavascriptUMGViewportClient::CalcSceneView(FSceneViewFamily* ViewFamily)
{
	FSceneViewInitOptions ViewInitOptions;

	const FVector& ViewLocation = GetViewLocation();
	const FRotator& ViewRotation = GetViewRotation();

	const FIntPoint ViewportSizeXY = Viewport->GetSizeXY();

	FIntRect ViewRect = FIntRect(0, 0, ViewportSizeXY.X, ViewportSizeXY.Y);
	ViewInitOptions.SetViewRectangle(ViewRect);

	ViewInitOptions.ViewOrigin = ViewLocation;

	ViewInitOptions.ViewRotationMatrix = FInverseRotationMatrix(ViewRotation);
	ViewInitOptions.ViewRotationMatrix = ViewInitOptions.ViewRotationMatrix * FMatrix(
		FPlane(0, 0, 1, 0),
		FPlane(1, 0, 0, 0),
		FPlane(0, 1, 0, 0),
		FPlane(0, 0, 0, 1));

	//@TODO: Should probably be locally configurable (or just made into a FMinimalViewInfo property)
	const EAspectRatioAxisConstraint AspectRatioAxisConstraint = GetDefault<ULocalPlayer>()->AspectRatioAxisConstraint;

	FMinimalViewInfo::CalculateProjectionMatrixGivenView(ViewInfo, AspectRatioAxisConstraint, Viewport, /*inout*/ ViewInitOptions);

	ViewInitOptions.ViewFamily = ViewFamily;
	ViewInitOptions.SceneViewStateInterface = ViewState.GetReference();
	ViewInitOptions.ViewElementDrawer = this;

	ViewInitOptions.BackgroundColor = GetBackgroundColor();

	//ViewInitOptions.EditorViewBitflag = 0, // send the bit for this view - each actor will check it's visibility bits against this

	// for ortho views to steal perspective view origin
	//ViewInitOptions.OverrideLODViewOrigin = FVector::ZeroVector;
	//ViewInitOptions.bUseFauxOrthoViewPos = true;

	//ViewInitOptions.CursorPos = CurrentMousePos;

	FSceneView* View = new FSceneView(ViewInitOptions);

	ViewFamily->Views.Add(View);

	View->StartFinalPostprocessSettings(ViewLocation);

	//OverridePostProcessSettings(*View);

	View->EndFinalPostprocessSettings(ViewInitOptions);

	return View;
}
	virtual void SetMesh(FRHICommandList& RHICmdList, FShader* Shader,const FVertexFactory* VertexFactory,const FSceneView& View,const FMeshBatchElement& BatchElement,uint32 DataFlags) const override
	{
		const bool bInstanced = View.GetFeatureLevel() >= ERHIFeatureLevel::SM4;
		FMeshParticleVertexFactory* MeshParticleVF = (FMeshParticleVertexFactory*)VertexFactory;
		FVertexShaderRHIParamRef VertexShaderRHI = Shader->GetVertexShader();
		SetUniformBufferParameter(RHICmdList, VertexShaderRHI, Shader->GetUniformBufferParameter<FMeshParticleUniformParameters>(), MeshParticleVF->GetUniformBuffer() );

		if (!bInstanced)
		{
			const FMeshParticleVertexFactory::FBatchParametersCPU* BatchParameters = (const FMeshParticleVertexFactory::FBatchParametersCPU*)BatchElement.UserData;
			const FMeshParticleInstanceVertex* Vertex = BatchParameters->InstanceBuffer + BatchElement.UserIndex;
			const FMeshParticleInstanceVertexDynamicParameter* DynamicVertex = BatchParameters->DynamicParameterBuffer + BatchElement.UserIndex;

			SetShaderValue(RHICmdList, VertexShaderRHI, Transform1, Vertex->Transform[0]);
			SetShaderValue(RHICmdList, VertexShaderRHI, Transform2, Vertex->Transform[1]);
			SetShaderValue(RHICmdList, VertexShaderRHI, Transform3, Vertex->Transform[2]);
			SetShaderValue(RHICmdList, VertexShaderRHI, SubUVParams, FVector4((float)Vertex->SubUVParams[0], (float)Vertex->SubUVParams[1], (float)Vertex->SubUVParams[2], (float)Vertex->SubUVParams[3]));
			SetShaderValue(RHICmdList, VertexShaderRHI, SubUVLerp, Vertex->SubUVLerp);
			SetShaderValue(RHICmdList, VertexShaderRHI, ParticleDirection, Vertex->Velocity);
			SetShaderValue(RHICmdList, VertexShaderRHI, RelativeTime, Vertex->RelativeTime);
			if (BatchParameters->DynamicParameterBuffer)
			{
				SetShaderValue(RHICmdList, VertexShaderRHI, DynamicParameter, FVector4(DynamicVertex->DynamicValue[0], DynamicVertex->DynamicValue[1], DynamicVertex->DynamicValue[2], DynamicVertex->DynamicValue[3]));
			}
			SetShaderValue(RHICmdList, VertexShaderRHI, ParticleColor, FVector4(Vertex->Color.Component(0), Vertex->Color.Component(1), Vertex->Color.Component(2), Vertex->Color.Component(3)));
		}
	}
void FSCSEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{
	AActor* PreviewActor = GetPreviewActor();
	if(PreviewActor)
	{
		TGuardValue<bool> AutoRestore(GAllowActorScriptExecutionInEditor, true);

		const int32 HalfX = 0.5f * Viewport->GetSizeXY().X;
		const int32 HalfY = 0.5f * Viewport->GetSizeXY().Y;

		auto SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes();
		if(bIsManipulating && SelectedNodes.Num() > 0)
		{
			USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes[0]->FindComponentInstanceInActor(PreviewActor, true));
			if(SceneComp)
			{
				const FVector WidgetLocation = GetWidgetLocation();
				const FPlane Proj = View.Project(WidgetLocation);
				if(Proj.W > 0.0f)
				{
					const int32 XPos = HalfX + (HalfX * Proj.X);
					const int32 YPos = HalfY + (HalfY * (Proj.Y * -1));
					DrawAngles(&Canvas, XPos, YPos, GetCurrentWidgetAxis(), GetWidgetMode(), GetWidgetCoordSystem().Rotator(), WidgetLocation);
				}
			}
		}
	}
}
FVector2D FSpriteEditorViewportClient::SourceTextureSpaceToScreenSpace(const FSceneView& View, const FVector2D& SourcePoint) const
{
	const FVector WorldSpacePoint = SourceTextureSpaceToWorldSpace(SourcePoint);

	FVector2D PixelLocation;
	View.WorldToPixel(WorldSpacePoint, /*out*/ PixelLocation);
	return PixelLocation;
}
FVector2D FSpriteGeometryEditingHelper::TextureSpaceToScreenSpace(const FSceneView& View, const FVector2D& SourcePoint) const
{
	const FVector WorldSpacePoint = EditorContext->TextureSpaceToWorldSpace(SourcePoint);

	FVector2D PixelLocation;
	View.WorldToPixel(WorldSpacePoint, /*out*/ PixelLocation);
	return PixelLocation;
}
void FSteamVRHMD::PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& View)
{
	check(IsInRenderingThread());

	// The last view location used to set the view will be in BaseHmdOrientation.  We need to calculate the delta from that, so that
	// cameras that rely on game objects (e.g. other components) for their positions don't need to be updated on the render thread.
	const FQuat DeltaOrient = View.BaseHmdOrientation.Inverse() * TrackingFrame.DeviceOrientation[vr::k_unTrackedDeviceIndex_Hmd];
	View.ViewRotation = FRotator(View.ViewRotation.Quaternion() * DeltaOrient);
 	View.UpdateViewMatrix();
}
Example #9
0
void FSimpleElementCollector::DrawBatchedElements(FRHICommandList& RHICmdList, const FSceneView& View, FTexture2DRHIRef DepthTexture, EBlendModeFilter::Type Filter) const
{
	// Mobile HDR does not execute post process, so does not need to render flipped
	const bool bNeedToSwitchVerticalAxis = RHINeedsToSwitchVerticalAxis(View.GetShaderPlatform()) && !bIsMobileHDR;

	// Draw the batched elements.
	BatchedElements.Draw(
		RHICmdList,
		View.GetFeatureLevel(),
		bNeedToSwitchVerticalAxis,
		View.ViewProjectionMatrix,
		View.ViewRect.Width(),
		View.ViewRect.Height(),
		View.Family->EngineShowFlags.HitProxies,
		1.0f,
		&View,
		DepthTexture,
		Filter
		);
}
void AMouseController::GetCameraRay(FVector& WorldOrigin, FVector& WorldDirection)
{
	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
	FVector2D MousePosition;
	if (LocalPlayer)
	{
		if (!LocalPlayer->ViewportClient->GetMousePosition(MousePosition))
		{
			return;
		}
	}

	// Early out if we clicked on a HUD hitbox
	if (GetHUD() != NULL && GetHUD()->GetHitBoxAtCoordinates(MousePosition, true))
	{
		return;
	}

	if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
	{
		// Create a view family for the game viewport
		FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
			LocalPlayer->ViewportClient->Viewport,
			GetWorld()->Scene,
			LocalPlayer->ViewportClient->EngineShowFlags)
			.SetRealtimeUpdate(true));


		// Calculate a view where the player is to update the streaming from the players start location
		FVector ViewLocation;
		FRotator ViewRotation;
		FSceneView* SceneView = LocalPlayer->CalcSceneView(&ViewFamily, /*out*/ ViewLocation, /*out*/ ViewRotation, LocalPlayer->ViewportClient->Viewport);

		if (SceneView)
		{

			SceneView->DeprojectFVector2D(MousePosition, WorldOrigin, WorldDirection);
		}
	}
}
bool TDistortionMeshDrawingPolicyFactory<DistortMeshPolicy>::DrawDynamicMesh(
	FRHICommandList& RHICmdList, 
	const FSceneView& View,
	ContextType bInitializeOffsets,
	const FMeshBatch& Mesh,
	bool bBackFace,
	bool bPreFog,
	const FPrimitiveSceneProxy* PrimitiveSceneProxy,
	FHitProxyId HitProxyId
	)
{
	const auto FeatureLevel = View.GetFeatureLevel();
	bool bDistorted = Mesh.MaterialRenderProxy && Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->IsDistorted();

	if(bDistorted && !bBackFace)
	{
		// draw dynamic mesh element using distortion mesh policy
		TDistortionMeshDrawingPolicy<DistortMeshPolicy> DrawingPolicy(
			Mesh.VertexFactory,
			Mesh.MaterialRenderProxy,
			*Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel),
			bInitializeOffsets,
			View.Family->EngineShowFlags.ShaderComplexity,
			FeatureLevel
			);
		RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
		DrawingPolicy.SetSharedState(RHICmdList, &View, typename TDistortionMeshDrawingPolicy<DistortMeshPolicy>::ContextDataType());
		for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++)
		{
			DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,typename TDistortionMeshDrawingPolicy<DistortMeshPolicy>::ElementDataType(), typename TDistortionMeshDrawingPolicy<DistortMeshPolicy>::ContextDataType());
			DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex);
		}

		return true;
	}
	else
	{
		return false;
	}
}
Example #12
0
void RunBenchmarkShader(FRHICommandList& RHICmdList, const FSceneView& View, TRefCountPtr<IPooledRenderTarget>& Src, float WorkScale)
{
	auto ShaderMap = GetGlobalShaderMap(View.GetFeatureLevel());

	TShaderMapRef<FPostProcessBenchmarkVS> VertexShader(ShaderMap);
	TShaderMapRef<FPostProcessBenchmarkPS<Method> > PixelShader(ShaderMap);

	static FGlobalBoundShaderState BoundShaderState;
	

	SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);

	PixelShader->SetParameters(RHICmdList, View, Src);
	VertexShader->SetParameters(RHICmdList, View);

	// single pass was not fine grained enough so we reduce the pass size based on the fractional part of WorkScale
	float TotalHeight = GBenchmarkResolution * WorkScale;

	// rounds up
	uint32 PassCount = (uint32)FMath::CeilToFloat(TotalHeight / GBenchmarkResolution);

	for(uint32 i = 0; i < PassCount; ++i)
	{
		float Top = i * GBenchmarkResolution;
		float Bottom = FMath::Min(Top + GBenchmarkResolution, TotalHeight);
		float LocalHeight = Bottom - Top;

		DrawRectangle(
			RHICmdList,
			0, 0,
			GBenchmarkResolution, LocalHeight,
			0, 0,
			GBenchmarkResolution, LocalHeight,
			FIntPoint(GBenchmarkResolution, GBenchmarkResolution),
			FIntPoint(GBenchmarkResolution, GBenchmarkResolution),
			*VertexShader,
			EDRF_Default);
	}
}
float ComputeTemporalLODBoundsScreenSize( const FVector& Origin, const float SphereRadius, const FSceneView& View, int32 SampleIndex )
{
	// This is radial LOD, not the view parallel computation used in ComputeBoundsScreenSize
	const float Divisor =  (Origin - View.GetTemporalLODOrigin(SampleIndex)).Size();

	// Get projection multiple accounting for view scaling.
	const float ScreenMultiple = FMath::Max(View.ViewRect.Width() / 2.0f * View.ViewMatrices.ProjMatrix.M[0][0],
		View.ViewRect.Height() / 2.0f * View.ViewMatrices.ProjMatrix.M[1][1]);

	const float ScreenRadius = ScreenMultiple * SphereRadius / FMath::Max(Divisor, 1.0f);
	const float ScreenArea = PI * ScreenRadius * ScreenRadius;
	return FMath::Clamp(ScreenArea / View.ViewRect.Area(), 0.0f, 1.0f);
}
Example #14
0
void FMeshElementCollector::AddMesh(int32 ViewIndex, FMeshBatch& MeshBatch)
{
	checkSlow(MeshBatch.GetNumPrimitives() > 0);
	checkSlow(MeshBatch.VertexFactory && MeshBatch.MaterialRenderProxy);
	checkSlow(PrimitiveSceneProxy);

	if (MeshBatch.bCanApplyViewModeOverrides)
	{
		FSceneView* View = Views[ViewIndex];

		ApplyViewModeOverrides(
			ViewIndex,
			View->Family->EngineShowFlags,
			View->GetFeatureLevel(),
			PrimitiveSceneProxy,
			MeshBatch.bUseWireframeSelectionColoring,
			MeshBatch,
			*this);
	}

	TArray<FMeshBatchAndRelevance,SceneRenderingAllocator>& ViewMeshBatches = *MeshBatches[ViewIndex];
	new (ViewMeshBatches) FMeshBatchAndRelevance(MeshBatch, PrimitiveSceneProxy, FeatureLevel);	
}
void FPhATEdPreviewViewportClient::SimMouseMove(float DeltaX, float DeltaY)
{

	DragX = Viewport->GetMouseX() - SharedData->LastClickPos.X;
	DragY = Viewport->GetMouseY() - SharedData->LastClickPos.Y;

	if (!SharedData->MouseHandle->GrabbedComponent)
	{
		return;
	}

	//We need to convert Pixel Delta into Screen position (deal with different viewport sizes)
	FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( Viewport, GetScene(), EngineShowFlags ));
	FSceneView* View = CalcSceneView(&ViewFamily);
	FVector4 ScreenOldPos = View->PixelToScreen(SharedData->LastClickPos.X, SharedData->LastClickPos.Y, 1.f);
	FVector4 ScreenNewPos = View->PixelToScreen(DragX + SharedData->LastClickPos.X, DragY + SharedData->LastClickPos.Y, 1.f);
	FVector4 ScreenDelta = ScreenNewPos - ScreenOldPos;
	FVector4 ProjectedDelta = View->ScreenToWorld(ScreenDelta);
	FVector4 WorldDelta;

	//Now we project new ScreenPos to xy-plane of SimGrabLocation
	FVector LocalOffset = View->ViewMatrices.ViewMatrix.TransformPosition(SimGrabLocation + SimGrabZ * SimGrabPush);
	float ZDistance = GetViewportType() == ELevelViewportType::LVT_Perspective ? fabs(LocalOffset.Z) : 1.f;	//in the ortho case we don't need to do any fixup because there is no perspective
	WorldDelta = ProjectedDelta * ZDistance;
	
	//Now we convert back into WorldPos
	FVector WorldPos = SimGrabLocation + WorldDelta + SimGrabZ * SimGrabPush;
	FVector NewLocation = WorldPos;
	float QuickRadius = 5 - SimGrabPush / SimHoldDistanceChangeDelta;
	QuickRadius = QuickRadius < 2 ? 2 : QuickRadius;

	DrawDebugPoint(GetWorld(), NewLocation, QuickRadius, FColorList::Red, false, 0.3);

	SharedData->MouseHandle->SetTargetLocation(NewLocation);
	SharedData->MouseHandle->GrabbedComponent->WakeRigidBody(SharedData->MouseHandle->GrabbedBoneName);
}
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 FSCSEditorViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{
	AActor* PreviewActor = GetPreviewActor();
	if(PreviewActor)
	{
		if (GUnrealEd != NULL)
		{
			TArray<FSCSEditorTreeNodePtrType> SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes();
			for (int32 SelectionIndex = 0; SelectionIndex < SelectedNodes.Num(); ++SelectionIndex)
			{
				FSCSEditorTreeNodePtrType SelectedNode = SelectedNodes[SelectionIndex];

				UActorComponent* Comp = Cast<USceneComponent>(SelectedNode->FindComponentInstanceInActor(PreviewActor));
				if (Comp != NULL && Comp->IsRegistered())
				{
					// Try and find a visualizer
					TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(Comp->GetClass());
					if (Visualizer.IsValid())
					{
						Visualizer->DrawVisualizationHUD(Comp, &InViewport, &View, &Canvas);
					}
				}
			}
		}

		TGuardValue<bool> AutoRestore(GAllowActorScriptExecutionInEditor, true);

		const int32 HalfX = 0.5f * Viewport->GetSizeXY().X;
		const int32 HalfY = 0.5f * Viewport->GetSizeXY().Y;

		auto SelectedNodes = BlueprintEditorPtr.Pin()->GetSelectedSCSEditorTreeNodes();
		if(bIsManipulating && SelectedNodes.Num() > 0)
		{
			USceneComponent* SceneComp = Cast<USceneComponent>(SelectedNodes[0]->FindComponentInstanceInActor(PreviewActor));
			if(SceneComp)
			{
				const FVector WidgetLocation = GetWidgetLocation();
				const FPlane Proj = View.Project(WidgetLocation);
				if(Proj.W > 0.0f)
				{
					const int32 XPos = HalfX + (HalfX * Proj.X);
					const int32 YPos = HalfY + (HalfY * (Proj.Y * -1));
					DrawAngles(&Canvas, XPos, YPos, GetCurrentWidgetAxis(), GetWidgetMode(), GetWidgetCoordSystem().Rotator(), WidgetLocation);
				}
			}
		}
	}
}
void AEyeXSimpleInteractorPawn::UpdateRegion()
{
	FVector Origin;
	FVector Extents;
	GetActorBounds(false, Origin, Extents);

	auto playerController = Cast<APlayerController>(Controller);
	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);

	auto ViewFamilyArguments = FSceneViewFamily::ConstructionValues(LocalPlayer->ViewportClient->Viewport, GetWorld()->Scene, LocalPlayer->ViewportClient->EngineShowFlags);
	ViewFamilyArguments.SetRealtimeUpdate(true);
	FSceneViewFamilyContext ViewFamily(ViewFamilyArguments);

	// Calculate a view where the player is to update the streaming from the players start location
	FVector ViewLocation;
	FRotator ViewRotation;
	FSceneView* SceneView = LocalPlayer->CalcSceneView(&ViewFamily, /*out*/ ViewLocation, /*out*/ ViewRotation, LocalPlayer->ViewportClient->Viewport);

	FVector2D ExtentPoints[8];
	SceneView->WorldToPixel(Origin + FVector(Extents.X, Extents.Y, Extents.Z), ExtentPoints[0]); //Right Top Front
	SceneView->WorldToPixel(Origin + FVector(Extents.X, Extents.Y, -Extents.Z), ExtentPoints[1]); //Right Top Back
	SceneView->WorldToPixel(Origin + FVector(Extents.X, -Extents.Y, Extents.Z), ExtentPoints[2]); //Right Bottom Front
	SceneView->WorldToPixel(Origin + FVector(Extents.X, -Extents.Y, -Extents.Z), ExtentPoints[3]); //Right Bottom Back
	SceneView->WorldToPixel(Origin + FVector(-Extents.X, Extents.Y, Extents.Z), ExtentPoints[4]); //Left Top Front
	SceneView->WorldToPixel(Origin + FVector(-Extents.X, Extents.Y, -Extents.Z), ExtentPoints[5]); //Left Top Back
	SceneView->WorldToPixel(Origin + FVector(-Extents.X, -Extents.Y, Extents.Z), ExtentPoints[6]); //Left Bottom Front
	SceneView->WorldToPixel(Origin + FVector(-Extents.X, -Extents.Y, -Extents.Z), ExtentPoints[7]); //Left Bottom Back

	FVector2D TopLeft = FVector2D(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
	FVector2D BottomRight = FVector2D(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());

	for (auto Point : ExtentPoints)
	{
		if (Point.X < TopLeft.X)
			TopLeft.X = Point.X;
		else if (Point.X > BottomRight.X)
			BottomRight.X = Point.X;

		if (Point.Y < TopLeft.Y)
			TopLeft.Y = Point.Y;
		else if (Point.Y > BottomRight.Y)
			BottomRight.Y = Point.Y;
	}

	MyRegion->bounds.left = TopLeft.X;
	MyRegion->bounds.top = TopLeft.Y;
	MyRegion->bounds.right = BottomRight.X;
	MyRegion->bounds.bottom = BottomRight.Y;
}
	void SetParameters(FRHICommandList& RHICmdList, const ShaderRHIParamRef Shader, const FLightSceneInfo* LightSceneInfo, const FSceneView& View, TRefCountPtr<IPooledRenderTarget>& PassSource)
	{
		FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
		const uint32 DownsampleFactor = GetLightShaftDownsampleFactor();
		FIntPoint DownSampledViewSize(FMath::FloorToInt(View.ViewRect.Width() / DownsampleFactor), FMath::FloorToInt(View.ViewRect.Height() / DownsampleFactor));
		const FIntPoint FilterBufferSize = SceneContext.GetBufferSizeXY() / DownsampleFactor;

		const FVector2D ViewRatioOfBuffer((float)DownSampledViewSize.X / FilterBufferSize.X, (float)DownSampledViewSize.Y / FilterBufferSize.Y);
		const FVector4 AspectRatioAndInvAspectRatio(
			ViewRatioOfBuffer.X, 
			(float)FilterBufferSize.X * ViewRatioOfBuffer.Y / FilterBufferSize.Y, 
			1.0f / ViewRatioOfBuffer.X, 
			(float)FilterBufferSize.Y / (FilterBufferSize.X * ViewRatioOfBuffer.Y));

		SetShaderValue(RHICmdList, Shader, AspectRatioAndInvAspectRatioParameter, AspectRatioAndInvAspectRatio);

		const FVector WorldSpaceBlurOrigin = LightSceneInfo->Proxy->GetLightPositionForLightShafts(View.ViewMatrices.ViewOrigin);
		// Transform into texture coordinates
		FVector4 ProjectedBlurOrigin = View.WorldToScreen(WorldSpaceBlurOrigin);

		const FIntPoint BufferSize = SceneContext.GetBufferSizeXY();
		const float InvBufferSizeX = 1.0f / BufferSize.X;
		const float InvBufferSizeY = 1.0f / BufferSize.Y;

		FVector2D ScreenSpaceBlurOrigin;
		{
			verify(ProjectedBlurOrigin.W > 0.0f); 
			float InvW = 1.0f / ProjectedBlurOrigin.W;
			float Y = (GProjectionSignY > 0.0f) ? ProjectedBlurOrigin.Y : 1.0f - ProjectedBlurOrigin.Y;
			ScreenSpaceBlurOrigin = FVector2D(
				View.ViewRect.Min.X + (0.5f + ProjectedBlurOrigin.X * 0.5f * InvW) * View.ViewRect.Width(),
				View.ViewRect.Min.Y + (0.5f - Y * 0.5f * InvW) * View.ViewRect.Height()
				);
		}
		
		ScreenSpaceBlurOrigin.X *= InvBufferSizeX;
		ScreenSpaceBlurOrigin.Y *= InvBufferSizeY;
		FVector2D TextureSpaceBlurOrigin(ScreenSpaceBlurOrigin * FVector2D(AspectRatioAndInvAspectRatio.Z, AspectRatioAndInvAspectRatio.W));

		SetShaderValue(RHICmdList, Shader, TextureSpaceBlurOriginParameter, TextureSpaceBlurOrigin);

		SetShaderValue(RHICmdList, Shader, WorldSpaceBlurOriginAndRadiusParameter, FVector4(WorldSpaceBlurOrigin, LightSceneInfo->Proxy->GetRadius()));
		SetShaderValue(RHICmdList, Shader, LightSourceRadius, LightSceneInfo->Proxy->GetSourceRadius());

		const bool bIsSpotLight = LightSceneInfo->Proxy->GetLightType() == LightType_Spot;
		if (bIsSpotLight)
		{
			SetShaderValue(RHICmdList, Shader, WorldSpaceSpotDirectionParameter, LightSceneInfo->Proxy->GetDirection());
			SetShaderValue(RHICmdList, Shader, SpotAnglesParameter, LightSceneInfo->Proxy->GetLightShaftConeParams());
		}

		const float DistanceFromLight = (View.ViewMatrices.ViewOrigin - WorldSpaceBlurOrigin).Size() + PointLightFadeDistanceIncrease;
		SetShaderValue(RHICmdList, Shader, WorldSpaceCameraPositionParameter, FVector4(View.ViewMatrices.ViewOrigin, DistanceFromLight));

		const FIntPoint DownSampledXY = View.ViewRect.Min / DownsampleFactor;
		const uint32 DownsampledSizeX = View.ViewRect.Width() / DownsampleFactor;
		const uint32 DownsampledSizeY = View.ViewRect.Height() / DownsampleFactor;

		// Limits for where the pixel shader is allowed to sample
		// Prevents reading from outside the valid region of a render target
		// Clamp to 1 less than the actual max, 
		// Since the bottom-right row/column of texels will contain some unwanted values if the size of scene color is not a factor of the downsample factor
		float MinU, MinV, MaxU, MaxV;
		{
			MinU = DownSampledXY.X / (float)FilterBufferSize.X;
			MinV = DownSampledXY.Y / (float)FilterBufferSize.Y;
			MaxU = (float(DownSampledXY.X) + DownsampledSizeX - 1) / (float)FilterBufferSize.X;
			MaxV = (float(DownSampledXY.Y) + DownsampledSizeY - 1) / (float)FilterBufferSize.Y;
		}

		FVector4 UVMinMax( MinU, MinV, MaxU, MaxV );
		SetShaderValue(RHICmdList, Shader, UVMinMaxParameter, UVMinMax);

		const FLinearColor BloomTint = LightSceneInfo->BloomTint;
		SetShaderValue(RHICmdList, Shader, BloomTintAndThresholdParameter, FVector4(BloomTint.R, BloomTint.G, BloomTint.B, LightSceneInfo->BloomThreshold));

		float OcclusionMaskDarkness;
		float OcclusionDepthRange;
		LightSceneInfo->Proxy->GetLightShaftOcclusionParameters(OcclusionMaskDarkness, OcclusionDepthRange);

		const FVector4 LightShaftParameterValues(1.0f / OcclusionDepthRange, LightSceneInfo->BloomScale, 1, OcclusionMaskDarkness);
		SetShaderValue(RHICmdList, Shader, LightShaftParameters, LightShaftParameterValues);

		float DistanceFade = 0.0f;
		if (LightSceneInfo->Proxy->GetLightType() != LightType_Directional)
		{
			DistanceFade = FMath::Clamp(DistanceFromLight / (LightSceneInfo->Proxy->GetRadius() * PointLightRadiusFadeFactor), 0.0f, 1.0f);
		}

		SetShaderValue(RHICmdList, Shader, DistanceFadeParameter, DistanceFade);

		if (IsValidRef(PassSource))
		{
			SetTextureParameter(
				RHICmdList, 
				Shader,
				SourceTextureParameter, SourceTextureSamplerParameter,
				TStaticSamplerState<SF_Bilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
				PassSource->GetRenderTargetItem().ShaderResourceTexture
				);
		}
	}
	void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FMaterialRenderProxy* MaterialProxy, const FDeferredDecalProxy& DecalProxy, const float FadeAlphaValue=1.0f)
	{
		const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();

		FMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialProxy, *MaterialProxy->GetMaterial(View.GetFeatureLevel()), View, View.ViewUniformBuffer, true, ESceneRenderTargetsMode::SetTextures);

		FTransform ComponentTrans = DecalProxy.ComponentTrans;

		FMatrix WorldToComponent = ComponentTrans.ToInverseMatrixWithScale();

		// Set the transform from screen space to light space.
		if(SvPositionToDecal.IsBound())
		{
			FVector2D InvViewSize = FVector2D(1.0f / View.ViewRect.Width(), 1.0f / View.ViewRect.Height());

			// setup a matrix to transform float4(SvPosition.xyz,1) directly to Decal (quality, performance as we don't need to convert or use interpolator)

			//	new_xy = (xy - ViewRectMin.xy) * ViewSizeAndInvSize.zw * float2(2,-2) + float2(-1, 1);

			//  transformed into one MAD:  new_xy = xy * ViewSizeAndInvSize.zw * float2(2,-2)      +       (-ViewRectMin.xy) * ViewSizeAndInvSize.zw * float2(2,-2) + float2(-1, 1);

			float Mx = 2.0f * InvViewSize.X;
			float My = -2.0f * InvViewSize.Y;
			float Ax = -1.0f - 2.0f * View.ViewRect.Min.X * InvViewSize.X;
			float Ay = 1.0f + 2.0f * View.ViewRect.Min.Y * InvViewSize.Y;

			// todo: we could use InvTranslatedViewProjectionMatrix and TranslatedWorldToComponent for better quality
			const FMatrix SvPositionToDecalValue = 
				FMatrix(
					FPlane(Mx,  0,   0,  0),
					FPlane( 0, My,   0,  0),
					FPlane( 0,  0,   1,  0),
					FPlane(Ax, Ay,   0,  1)
				) * View.InvViewProjectionMatrix * WorldToComponent;

			SetShaderValue(RHICmdList, ShaderRHI, SvPositionToDecal, SvPositionToDecalValue);
		}

		// Set the transform from light space to world space
		if(DecalToWorld.IsBound())
		{
			const FMatrix DecalToWorldValue = ComponentTrans.ToMatrixWithScale();
			
			SetShaderValue(RHICmdList, ShaderRHI, DecalToWorld, DecalToWorldValue);
		}

		SetShaderValue(RHICmdList, ShaderRHI, WorldToDecal, WorldToComponent);

		float LifetimeAlpha = FMath::Clamp(View.Family->CurrentWorldTime * -DecalProxy.InvFadeDuration + DecalProxy.FadeStartDelayNormalized, 0.0f, 1.0f);
		SetShaderValue(RHICmdList, ShaderRHI, DecalParams, FVector2D(FadeAlphaValue, LifetimeAlpha));
	}
	virtual void OverridePostProcessSettings(FSceneView& View) override 
	{
		View.OverridePostProcessSettings(PostProcessSettings, PostProcessSettingsWeight);
	}
	void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FMaterialRenderProxy* MaterialProxy, const FDeferredDecalProxy& DecalProxy, const float FadeAlphaValue=1.0f)
	{
		const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();

		FMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialProxy, *MaterialProxy->GetMaterial(View.GetFeatureLevel()), View, true, ESceneRenderTargetsMode::SetTextures);

		FTransform ComponentTrans = DecalProxy.ComponentTrans;

		FMatrix WorldToComponent = ComponentTrans.ToInverseMatrixWithScale();

		// Set the transform from screen space to light space.
		if(ScreenToDecal.IsBound())
		{
			const FMatrix ScreenToDecalValue = 
				FMatrix(
					FPlane(1,0,0,0),
					FPlane(0,1,0,0),
					FPlane(0,0,View.ViewMatrices.ProjMatrix.M[2][2],1),
					FPlane(0,0,View.ViewMatrices.ProjMatrix.M[3][2],0)
				) * View.InvViewProjectionMatrix * WorldToComponent;

			SetShaderValue(RHICmdList, ShaderRHI, ScreenToDecal, ScreenToDecalValue);
		}

		// Set the transform from light space to world space
		if(DecalToWorld.IsBound())
		{
			const FMatrix DecalToWorldValue = ComponentTrans.ToMatrixWithScale();
			
			SetShaderValue(RHICmdList, ShaderRHI, DecalToWorld, DecalToWorldValue);
		}

		SetShaderValue(RHICmdList, ShaderRHI, FadeAlpha, FadeAlphaValue);
		SetShaderValue(RHICmdList, ShaderRHI, WorldToDecal, WorldToComponent);
	}
void FViewExtension::PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& View)
{
	check(IsInRenderingThread());
	FViewExtension& RenderContext = *this;
	FGameFrame* CurrentFrame = static_cast<FGameFrame*>(RenderContext.RenderFrame.Get());

	if (!RenderContext.ShowFlags.Rendering || !CurrentFrame || !CurrentFrame->Settings->IsStereoEnabled())
	{
		return;
	}

	const ovrEyeType eyeIdx = (View.StereoPass == eSSP_LEFT_EYE) ? ovrEye_Left : ovrEye_Right;
	if (RenderContext.ShowFlags.Rendering && CurrentFrame->Settings->Flags.bUpdateOnRT)
	{
		FQuat	CurrentEyeOrientation;
		FVector	CurrentEyePosition;
		CurrentFrame->PoseToOrientationAndPosition(RenderContext.CurEyeRenderPose[eyeIdx], CurrentEyeOrientation, CurrentEyePosition);

		FQuat ViewOrientation = View.ViewRotation.Quaternion();

		// recalculate delta control orientation; it should match the one we used in CalculateStereoViewOffset on a game thread.
		FVector GameEyePosition;
		FQuat GameEyeOrient;

		CurrentFrame->PoseToOrientationAndPosition(CurrentFrame->EyeRenderPose[eyeIdx], GameEyeOrient, GameEyePosition);
		const FQuat DeltaControlOrientation =  ViewOrientation * GameEyeOrient.Inverse();
		// make sure we use the same viewrotation as we had on a game thread
		check(View.ViewRotation == CurrentFrame->CachedViewRotation[eyeIdx]);

		if (CurrentFrame->Flags.bOrientationChanged)
		{
			// Apply updated orientation to corresponding View at recalc matrices.
			// The updated position will be applied from inside of the UpdateViewMatrix() call.
			const FQuat DeltaOrient = View.BaseHmdOrientation.Inverse() * CurrentEyeOrientation;
			View.ViewRotation = FRotator(ViewOrientation * DeltaOrient);
			
			//UE_LOG(LogHMD, Log, TEXT("VIEWDLT: Yaw %.3f Pitch %.3f Roll %.3f"), DeltaOrient.Rotator().Yaw, DeltaOrient.Rotator().Pitch, DeltaOrient.Rotator().Roll);
		}

		if (!CurrentFrame->Flags.bPositionChanged)
		{
			// if no positional change applied then we still need to calculate proper stereo disparity.
			// use the current head pose for this calculation instead of the one that was saved on a game thread.
			FQuat HeadOrientation;
			CurrentFrame->PoseToOrientationAndPosition(RenderContext.CurHeadPose, HeadOrientation, View.BaseHmdLocation);
		}

		// The HMDPosition already has HMD orientation applied.
		// Apply rotational difference between HMD orientation and ViewRotation
		// to HMDPosition vector. 
		const FVector DeltaPosition = CurrentEyePosition - View.BaseHmdLocation;
		const FVector vEyePosition = DeltaControlOrientation.RotateVector(DeltaPosition) + CurrentFrame->Settings->PositionOffset;
		View.ViewLocation += vEyePosition;

		//UE_LOG(LogHMD, Log, TEXT("VDLTPOS: %.3f %.3f %.3f"), vEyePosition.X, vEyePosition.Y, vEyePosition.Z);

		if (CurrentFrame->Flags.bOrientationChanged || CurrentFrame->Flags.bPositionChanged)
		{
			View.UpdateViewMatrix();
		}
	}

	FSettings* FrameSettings = CurrentFrame->GetSettings();
	check(FrameSettings);
	FrameSettings->EyeLayer.EyeFov.RenderPose[eyeIdx] = RenderContext.CurEyeRenderPose[eyeIdx];
}
void FSpriteGeometryEditMode::SelectVerticesInMarquee(FEditorViewportClient* ViewportClient, FViewport* Viewport, bool bAddToSelection)
{
	if (!bAddToSelection)
	{
		SpriteGeometryHelper.ClearSelectionSet();
	}

	{
		// Calculate world space positions
		FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(Viewport, ViewportClient->GetScene(), ViewportClient->EngineShowFlags));
		FSceneView* View = ViewportClient->CalcSceneView(&ViewFamily);
		const FVector StartPos = View->PixelToWorld(MarqueeStartPos.X, MarqueeStartPos.Y, 0);
		const FVector EndPos = View->PixelToWorld(MarqueeEndPos.X, MarqueeEndPos.Y, 0);

		// Convert to source texture space to work out the pixels dragged
		FVector2D TextureSpaceStartPos = SpriteGeometryHelper.GetEditorContext()->WorldSpaceToTextureSpace(StartPos);
		FVector2D TextureSpaceEndPos = SpriteGeometryHelper.GetEditorContext()->WorldSpaceToTextureSpace(EndPos);

		if (TextureSpaceStartPos.X > TextureSpaceEndPos.X)
		{
			Swap(TextureSpaceStartPos.X, TextureSpaceEndPos.X);
		}
		if (TextureSpaceStartPos.Y > TextureSpaceEndPos.Y)
		{
			Swap(TextureSpaceStartPos.Y, TextureSpaceEndPos.Y);
		}

		const FBox2D QueryBounds(TextureSpaceStartPos, TextureSpaceEndPos);

		// Check geometry
		if (FSpriteGeometryCollection* Geometry = SpriteGeometryHelper.GetGeometryBeingEdited())
		{
			for (int32 ShapeIndex = 0; ShapeIndex < Geometry->Shapes.Num(); ++ShapeIndex)
			{
				const FSpriteGeometryShape& Shape = Geometry->Shapes[ShapeIndex];

				bool bSelectWholeShape = false;

				if ((Shape.ShapeType == ESpriteShapeType::Circle) || (Shape.ShapeType == ESpriteShapeType::Box))
				{
					// First see if we are fully contained
					const FBox2D ShapeBoxBounds(Shape.BoxPosition - Shape.BoxSize * 0.5f, Shape.BoxPosition + Shape.BoxSize * 0.5f);
					if (QueryBounds.IsInside(ShapeBoxBounds))
					{
						bSelectWholeShape = true;
					}
				}

				//@TODO: Try intersecting with the circle if it wasn't entirely enclosed

				if (bSelectWholeShape)
				{
					SpriteGeometryHelper.AddShapeToSelection(ShapeIndex);
				}
				else
				{
					// Try to select some subset of the vertices
					for (int32 VertexIndex = 0; VertexIndex < Shape.Vertices.Num(); ++VertexIndex)
					{
						const FVector2D TextureSpaceVertex = Shape.ConvertShapeSpaceToTextureSpace(Shape.Vertices[VertexIndex]);
						if (QueryBounds.IsInside(TextureSpaceVertex))
						{
							SpriteGeometryHelper.AddPolygonVertexToSelection(ShapeIndex, VertexIndex);
						}
					}
				}
			}
		}

		//@TODO: Check other items (sockets/etc...)
	}
}
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);
	}
}
	void SetParameters(
		FRHICommandList& RHICmdList, 
		const FMaterialRenderProxy* MaterialRenderProxy,
		const FSceneView& View
		)
	{
		FMeshMaterialShader::SetParameters(RHICmdList, GetPixelShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, ESceneRenderTargetsMode::SetTextures);

		float Ratio = View.UnscaledViewRect.Width() / (float)View.UnscaledViewRect.Height();
		float Params[4];
		Params[0] = View.ViewMatrices.ProjMatrix.M[0][0];
		Params[1] = Ratio;
		Params[2] = (float)View.UnscaledViewRect.Width();
		Params[3] = (float)View.UnscaledViewRect.Height();

		SetShaderValue(RHICmdList, GetPixelShader(), DistortionParams, Params);

	}
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 );				
			}
		}
	}
}
FSceneRenderer* FScene::CreateSceneRenderer( USceneCaptureComponent* SceneCaptureComponent, UTextureRenderTarget* TextureTarget, const FMatrix& ViewMatrix, const FVector& ViewLocation, float FOV, float MaxViewDistance, bool bCaptureSceneColour, FPostProcessSettings* PostProcessSettings, float PostProcessBlendWeight )
{
	FIntPoint CaptureSize(TextureTarget->GetSurfaceWidth(), TextureTarget->GetSurfaceHeight());

	FTextureRenderTargetResource* Resource = TextureTarget->GameThread_GetRenderTargetResource();
	FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
		Resource,
		this,
		FEngineShowFlags(ESFIM_Game))
		.SetResolveScene(!bCaptureSceneColour));

	// Disable features that are not desired when capturing the scene
	ViewFamily.EngineShowFlags.MotionBlur = 0; // motion blur doesn't work correctly with scene captures.
	ViewFamily.EngineShowFlags.SeparateTranslucency = 0;
	ViewFamily.EngineShowFlags.HMDDistortion = 0;
	FSceneViewInitOptions ViewInitOptions;
	ViewInitOptions.SetViewRectangle(FIntRect(0, 0, CaptureSize.X, CaptureSize.Y));
	ViewInitOptions.ViewFamily = &ViewFamily;
	ViewInitOptions.ViewMatrix = ViewMatrix;
	ViewInitOptions.BackgroundColor = FLinearColor::Black;
	ViewInitOptions.OverrideFarClippingPlaneDistance = MaxViewDistance;

	if (bCaptureSceneColour)
	{
		ViewFamily.EngineShowFlags.PostProcessing = 0;
		ViewInitOptions.OverlayColor = FLinearColor::Black;
	}

	// Build projection matrix
	{
		float XAxisMultiplier;
		float YAxisMultiplier;

		if (CaptureSize.X > CaptureSize.Y)
		{
			// if the viewport is wider than it is tall
			XAxisMultiplier = 1.0f;
			YAxisMultiplier = CaptureSize.X / (float)CaptureSize.Y;
		}
		else
		{
			// if the viewport is taller than it is wide
			XAxisMultiplier = CaptureSize.Y / (float)CaptureSize.X;
			YAxisMultiplier = 1.0f;
		}

		ViewInitOptions.ProjectionMatrix = FReversedZPerspectiveMatrix (
			FOV,
			FOV,
			XAxisMultiplier,
			YAxisMultiplier,
			GNearClippingPlane,
			GNearClippingPlane
			);
	}

	FSceneView* View = new FSceneView(ViewInitOptions);

	View->bIsSceneCapture = true;

	check(SceneCaptureComponent);
	for (auto It = SceneCaptureComponent->HiddenComponents.CreateConstIterator(); It; ++It)
	{
		// If the primitive component was destroyed, the weak pointer will return NULL.
		UPrimitiveComponent* PrimitiveComponent = It->Get();
		if (PrimitiveComponent)
		{
			View->HiddenPrimitives.Add(PrimitiveComponent->ComponentId);
		}
	}

	ViewFamily.Views.Add(View);

	View->StartFinalPostprocessSettings(ViewLocation);
	if (!bCaptureSceneColour)
	{
		View->OverridePostProcessSettings(*PostProcessSettings, PostProcessBlendWeight);
	}
	View->EndFinalPostprocessSettings();

	return FSceneRenderer::CreateSceneRenderer(&ViewFamily, NULL);
}
void FSpriteEditorViewportClient::ProcessClick(FSceneView& View, HHitProxy* HitProxy, FKey Key, EInputEvent Event, uint32 HitX, uint32 HitY)
{
	const FViewportClick Click(&View, this, Key, Event, HitX, HitY);
	const bool bIsCtrlKeyDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
	const bool bIsShiftKeyDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift);
	const bool bIsAltKeyDown = Viewport->KeyState(EKeys::LeftAlt) || Viewport->KeyState(EKeys::RightAlt);
	bool bHandled = false;

	HSpriteSelectableObjectHitProxy* SelectedItemProxy = HitProxyCast<HSpriteSelectableObjectHitProxy>(HitProxy);

	if (IsInSourceRegionEditMode())
	{
		if ((Event == EInputEvent::IE_DoubleClick) && (Key == EKeys::LeftMouseButton))
		{
			FVector4 WorldPoint = View.PixelToWorld(HitX, HitY, 0);
			UPaperSprite* Sprite = GetSpriteBeingEdited();
			FVector2D TexturePoint = SourceTextureViewComponent->GetSprite()->ConvertWorldSpaceToTextureSpace(WorldPoint);
			if (bIsCtrlKeyDown)
			{
				const FVector2D StartingUV = Sprite->GetSourceUV();
				const FVector2D StartingSize = Sprite->GetSourceSize();

				if (UPaperSprite* NewSprite = CreateNewSprite(FIntPoint((int32)StartingUV.X, (int32)StartingUV.Y), FIntPoint((int32)StartingSize.X, (int32)StartingSize.Y)))
				{
					NewSprite->ExtractSourceRegionFromTexturePoint(TexturePoint);
					bHandled = true;
				}
			}
			else
			{
				Sprite->ExtractSourceRegionFromTexturePoint(TexturePoint);
				bHandled = true;
			}
		}
		else if ((Event == EInputEvent::IE_Released) && (Key == EKeys::LeftMouseButton))
		{
			FVector4 WorldPoint = View.PixelToWorld(HitX, HitY, 0);
			FVector2D TexturePoint = SourceTextureViewComponent->GetSprite()->ConvertWorldSpaceToTextureSpace(WorldPoint);
			for (int32 RelatedSpriteIndex = 0; RelatedSpriteIndex < RelatedSprites.Num(); ++RelatedSpriteIndex)
			{
				FRelatedSprite& RelatedSprite = RelatedSprites[RelatedSpriteIndex];
				if ((TexturePoint.X >= RelatedSprite.SourceUV.X) && (TexturePoint.Y >= RelatedSprite.SourceUV.Y) &&
					(TexturePoint.X < (RelatedSprite.SourceUV.X + RelatedSprite.SourceDimension.X)) &&
					(TexturePoint.Y < (RelatedSprite.SourceUV.Y + RelatedSprite.SourceDimension.Y)))
				{
					bHandled = true;

					// Select this sprite
					if (UPaperSprite* LoadedSprite = Cast<UPaperSprite>(RelatedSprite.AssetData.GetAsset()))
					{
						if (SpriteEditorPtr.IsValid())
						{
							SpriteEditorPtr.Pin()->SetSpriteBeingEdited(LoadedSprite);
							break;
						}
					}
				}
			}
		}
	}

	if (!bHandled)
	{
		FPaperEditorViewportClient::ProcessClick(View, HitProxy, Key, Event, HitX, HitY);
	}
}
bool FSpriteEditorViewportClient::ConvertMarqueeToSourceTextureSpace(/*out*/ FIntPoint& OutStartPos, /*out*/ FIntPoint& OutDimension)
{
	FSpriteGeometryEditMode* GeometryEditMode = ModeTools->GetActiveModeTyped<FSpriteGeometryEditMode>(FSpriteGeometryEditMode::EM_SpriteGeometry);
	check(GeometryEditMode);
	const FVector2D MarqueeStartPos = GeometryEditMode->GetMarqueeStartPos();
	const FVector2D MarqueeEndPos = GeometryEditMode->GetMarqueeEndPos();

	bool bSuccessful = false;
	UPaperSprite* Sprite = SourceTextureViewComponent->GetSprite();
	UTexture2D* SpriteSourceTexture = Sprite->GetSourceTexture();
	if (SpriteSourceTexture != nullptr)
	{
		// Calculate world space positions
		FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(Viewport, GetScene(), EngineShowFlags));
		FSceneView* View = CalcSceneView(&ViewFamily);
		const FVector StartPos = View->PixelToWorld(MarqueeStartPos.X, MarqueeStartPos.Y, 0);
		const FVector EndPos = View->PixelToWorld(MarqueeEndPos.X, MarqueeEndPos.Y, 0);

		// Convert to source texture space to work out the pixels dragged
		FVector2D TextureSpaceStartPos = Sprite->ConvertWorldSpaceToTextureSpace(StartPos);
		FVector2D TextureSpaceEndPos = Sprite->ConvertWorldSpaceToTextureSpace(EndPos);

		if (TextureSpaceStartPos.X > TextureSpaceEndPos.X)
		{
			Swap(TextureSpaceStartPos.X, TextureSpaceEndPos.X);
		}
		if (TextureSpaceStartPos.Y > TextureSpaceEndPos.Y)
		{
			Swap(TextureSpaceStartPos.Y, TextureSpaceEndPos.Y);
		}

		const FIntPoint SourceTextureSize(SpriteSourceTexture->GetImportedSize());
		const int32 SourceTextureWidth = SourceTextureSize.X;
		const int32 SourceTextureHeight = SourceTextureSize.Y;
		
		FIntPoint TSStartPos;
		TSStartPos.X = FMath::Clamp<int32>((int32)TextureSpaceStartPos.X, 0, SourceTextureWidth - 1);
		TSStartPos.Y = FMath::Clamp<int32>((int32)TextureSpaceStartPos.Y, 0, SourceTextureHeight - 1);

		FIntPoint TSEndPos;
		TSEndPos.X = FMath::Clamp<int32>((int32)TextureSpaceEndPos.X, 0, SourceTextureWidth - 1);
		TSEndPos.Y = FMath::Clamp<int32>((int32)TextureSpaceEndPos.Y, 0, SourceTextureHeight - 1);

		const FIntPoint TextureSpaceDimensions = TSEndPos - TSStartPos;
		if ((TextureSpaceDimensions.X > 0) || (TextureSpaceDimensions.Y > 0))
		{
			OutStartPos = TSStartPos;
			OutDimension = TextureSpaceDimensions;
			bSuccessful = true;
		}
	}

	return bSuccessful;
}