void DrawRectangle(
	float X,
	float Y,
	float SizeX,
	float SizeY,
	float U,
	float V,
	float SizeU,
	float SizeV,
	FIntPoint TargetSize,
	FIntPoint TextureSize,
	EDrawRectangleFlags Flags
	)
{
	float ClipSpaceQuadZ = 0.0f;

	DoDrawRectangleFlagOverride(Flags);

	// triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts
	if(X > 0.0f || Y > 0.0f)
	{
		// don't use triangle optimization
		Flags = EDRF_Default;
	}

	if (Flags == EDRF_UseTriangleOptimization)
	{
		// A single triangle spans the entire viewport this results in a quad that fill the viewport. This can increase rasterization efficiency
		// as we do not have a diagonal edge (through the center) for the rasterizer/span-dispatch. Although the actual benefit of this technique is dependent upon hardware.
		FFilterVertex Vertices[3];

		Vertices[0].Position = FVector4(X + SizeX,	Y - SizeY, ClipSpaceQuadZ,	1);
		Vertices[1].Position = FVector4(X + SizeX,  Y + SizeY,	ClipSpaceQuadZ,	1);
		Vertices[2].Position = FVector4(X - SizeX,  Y + SizeY ,	ClipSpaceQuadZ,	1);

		Vertices[0].UV = FVector2D(U + SizeU, V - SizeV);
		Vertices[1].UV = FVector2D(U + SizeU, V + SizeV);
		Vertices[2].UV = FVector2D(U - SizeU, V + SizeV);

		for (int32 VertexIndex = 0; VertexIndex < 3; VertexIndex++)
		{
			Vertices[VertexIndex].Position.X = -1.0f + 2.0f * (Vertices[VertexIndex].Position.X - GPixelCenterOffset) / (float)TargetSize.X;
			Vertices[VertexIndex].Position.Y = (+1.0f - 2.0f * (Vertices[VertexIndex].Position.Y - GPixelCenterOffset) / (float)TargetSize.Y) * GProjectionSignY;

			Vertices[VertexIndex].UV.X = Vertices[VertexIndex].UV.X / (float)TextureSize.X;
			Vertices[VertexIndex].UV.Y = Vertices[VertexIndex].UV.Y / (float)TextureSize.Y;
		}
		
		static const uint16 Indices[] = { 0, 1, 2 };

		RHIDrawIndexedPrimitiveUP(PT_TriangleList, 0, 3, 1, Indices, sizeof(Indices[0]), Vertices, sizeof(Vertices[0]));
	}
	else
	{
		FFilterVertex Vertices[4];

		Vertices[0].Position = FVector4(X,			Y,			ClipSpaceQuadZ,	1);
		Vertices[1].Position = FVector4(X + SizeX,	Y,			ClipSpaceQuadZ,	1);
		Vertices[2].Position = FVector4(X,			Y + SizeY,	ClipSpaceQuadZ,	1);
		Vertices[3].Position = FVector4(X + SizeX,	Y + SizeY,	ClipSpaceQuadZ,	1);

		Vertices[0].UV = FVector2D(U,			V);
		Vertices[1].UV = FVector2D(U + SizeU,	V);
		Vertices[2].UV = FVector2D(U,			V + SizeV);
		Vertices[3].UV = FVector2D(U + SizeU,	V + SizeV);

		for (int32 VertexIndex = 0; VertexIndex < 4; VertexIndex++)
		{
			Vertices[VertexIndex].Position.X = -1.0f + 2.0f * (Vertices[VertexIndex].Position.X - GPixelCenterOffset) / (float)TargetSize.X;
			Vertices[VertexIndex].Position.Y = (+1.0f - 2.0f * (Vertices[VertexIndex].Position.Y - GPixelCenterOffset) / (float)TargetSize.Y) * GProjectionSignY;

			Vertices[VertexIndex].UV.X = Vertices[VertexIndex].UV.X / (float)TextureSize.X;
			Vertices[VertexIndex].UV.Y = Vertices[VertexIndex].UV.Y / (float)TextureSize.Y;
		}

		static const uint16 Indices[] = { 0, 1, 3, 0, 3, 2 };

		RHIDrawIndexedPrimitiveUP(PT_TriangleList, 0, 4, 2, Indices, sizeof(Indices[0]), Vertices, sizeof(Vertices[0]));
	}
}
void DrawRectangle(
	FRHICommandList& RHICmdList,
	float X,
	float Y,
	float SizeX,
	float SizeY,
	float U,
	float V,
	float SizeU,
	float SizeV,
	FIntPoint TargetSize,
	FIntPoint TextureSize,
	FShader* VertexShader,
	EDrawRectangleFlags Flags
	)
{
	float ClipSpaceQuadZ = 0.0f;

	DoDrawRectangleFlagOverride(Flags);

	// triangle if extending to left and top of the given rectangle, if it's not left top of the viewport it can cause artifacts
	if(X > 0.0f || Y > 0.0f)
	{
		// don't use triangle optimization
		Flags = EDRF_Default;
	}

	// Set up vertex uniform parameters for scaling and biasing the rectangle.
	// Note: Use DrawRectangle in the vertex shader to calculate the correct vertex position and uv.

	FDrawRectangleParameters Parameters;
	Parameters.PosScaleBias = FVector4(SizeX, SizeY, X, Y);
	Parameters.UVScaleBias = FVector4(SizeU, SizeV, U, V);

	Parameters.InvTargetSizeAndTextureSize = FVector4( 
		1.0f / TargetSize.X, 1.0f / TargetSize.Y, 
		1.0f / TextureSize.X, 1.0f / TextureSize.Y);

	SetUniformBufferParameterImmediate(RHICmdList, VertexShader->GetVertexShader(), VertexShader->GetUniformBufferParameter<FDrawRectangleParameters>(), Parameters);

	if(Flags == EDRF_UseTesselatedIndexBuffer)
	{
		// no vertex buffer needed as we compute it in VS
		RHICmdList.SetStreamSource(0, NULL, 0, 0);

		RHICmdList.DrawIndexedPrimitive(
			GTesselatedScreenRectangleIndexBuffer.IndexBufferRHI,
			PT_TriangleList,
			/*BaseVertexIndex=*/ 0,
			/*MinIndex=*/ 0,
			/*NumVertices=*/ GTesselatedScreenRectangleIndexBuffer.NumVertices(),
			/*StartIndex=*/ 0,
			/*NumPrimitives=*/ GTesselatedScreenRectangleIndexBuffer.NumPrimitives(),
			/*NumInstances=*/ 1
			);
	}
	else
	{
		RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, sizeof(FFilterVertex), 0);

		if (Flags == EDRF_UseTriangleOptimization)
		{
			// A single triangle spans the entire viewport this results in a quad that fill the viewport. This can increase rasterization efficiency
			// as we do not have a diagonal edge (through the center) for the rasterizer/span-dispatch. Although the actual benefit of this technique is dependent upon hardware.

			// We offset into the index buffer when using the triangle optimization to access the correct vertices.
			RHICmdList.DrawIndexedPrimitive(
				GScreenRectangleIndexBuffer.IndexBufferRHI,
				PT_TriangleList,
				/*BaseVertexIndex=*/ 0,
				/*MinIndex=*/ 0,
				/*NumVertices=*/ 3,
				/*StartIndex=*/ 6,
				/*NumPrimitives=*/ 1,
				/*NumInstances=*/ 1
				);
		}
		else
		{
			RHICmdList.SetStreamSource(0, GScreenRectangleVertexBuffer.VertexBufferRHI, sizeof(FFilterVertex), 0);

			RHICmdList.DrawIndexedPrimitive(
				GScreenRectangleIndexBuffer.IndexBufferRHI,
				PT_TriangleList,
				/*BaseVertexIndex=*/ 0,
				/*MinIndex=*/ 0,
				/*NumVertices=*/ 4,
				/*StartIndex=*/ 0,
				/*NumPrimitives=*/ 2,
				/*NumInstances=*/ 1
				);
		}
	}
}