bool ULeapMotionFunctionLibrary::GetPinchStrength(int32 HandId, float& PinchStrength)
{
	FLeapMotionDevice* LeapDevice = FLeapMotionControllerPlugin::GetLeapDeviceSafe();
	if (LeapDevice)
	{
		LeapDevice->SetReferenceFrameOncePerTick();
		return LeapDevice->GetPinchStrength(HandId, PinchStrength);
	}
	return false;
}
bool ULeapMotionFunctionLibrary::GetOldestLeftOrRightHandId(ELeapSide LeapSide, int32& OutHandId)
{
	FLeapMotionDevice* LeapDevice = FLeapMotionControllerPlugin::GetLeapDeviceSafe();
	if (LeapDevice)
	{
		LeapDevice->SetReferenceFrameOncePerTick();
		return LeapDevice->GetOldestLeftOrRightHandId(LeapSide, OutHandId);
	}
	return false;
}
bool ULeapMotionFunctionLibrary::GetAllHandsIds(TArray<int32>& OutAllHandIds)
{
	FLeapMotionDevice* LeapDevice = FLeapMotionControllerPlugin::GetLeapDeviceSafe();
	if (LeapDevice)
	{
		LeapDevice->SetReferenceFrameOncePerTick();
		return LeapDevice->GetAllHandsIds(OutAllHandIds);
	}
	return false;
}
bool ULeapMotionFunctionLibrary::GetBoneWidthAndLength(int32 HandId, ELeapBone LeapBone, float& OutWidth, float& OutLength)
{
	OutWidth = 0.0f;
	OutLength = 0.0f;

	FLeapMotionDevice* LeapDevice = FLeapMotionControllerPlugin::GetLeapDeviceSafe();
	if (LeapDevice)
	{
		LeapDevice->SetReferenceFrameOncePerTick();
		return LeapDevice->GetBoneWidthAndLength(HandId, LeapBone, OutWidth, OutLength);
	}

	return false;
}
bool ULeapMotionFunctionLibrary::GetBonePostionAndOrientation(int32 HandId, ELeapBone LeapBone, FVector& OutPosition, FRotator& OutOrientation)
{
	OutPosition = FVector::ZeroVector;
	OutOrientation = FRotator::ZeroRotator;

	FLeapMotionDevice* LeapDevice = FLeapMotionControllerPlugin::GetLeapDeviceSafe();
	if (LeapDevice)
	{
		LeapDevice->SetReferenceFrameOncePerTick();
		return LeapDevice->GetBonePostionAndOrientation(HandId, LeapBone, OutPosition, OutOrientation);
	}

	return false;
}
void ULeapMotionImageComponent::UpdateImageTexture()
{
	FLeapMotionDevice* Device = FLeapMotionControllerPlugin::GetLeapDeviceSafe();

	if (Device && Device->IsConnected())
	{
		Device->SetReferenceFrameOncePerTick();
	}
	
	if (Device && Device->IsConnected() && Device->Frame().images().count() > 1)
	{
		Leap::ImageList ImageList = Device->Frame().images();
		
		for (int eye = 0; eye < 2; eye++)
		{
			Leap::Image Image = ImageList[eye];
			bool isRGB = Image.format() != Leap::Image::INFRARED;
			UTexture2D*& Texture = eye ? ImagePassthroughRight : ImagePassthroughLeft;
			UTexture2D*& Distortion = eye ? DistortionTextureRight : DistortionTextureLeft;
			
			// Recreate the image & distortion textures.
			if (!Texture || Image.width() != Texture->PlatformData->SizeX || Image.height() != Texture->PlatformData->SizeY)
			{
				EPixelFormat PixelFormat = !isRGB ? PF_G8 : PF_R8G8B8A8;
				Texture = UTexture2D::CreateTransient(Image.width(), Image.height(), PixelFormat);
				Texture->SRGB = 0;
				Texture->UpdateResource();

				Distortion = BuildDistortionTextures(Image);

				if (isRGB)
				{
					DynamicPassthroughMaterial->SetTextureParameterValue(eye ? TEXT("BaseTextureRGB_Right") : TEXT("BaseTextureRGB"), Texture);
					DynamicPassthroughMaterial->SetScalarParameterValue(TEXT("ImageFormat"), 1.0);
				}
				else
				{
					DynamicPassthroughMaterial->SetTextureParameterValue(eye ? TEXT("BaseTextureIR_Right") : TEXT("BaseTextureIR"), Texture);
					DynamicPassthroughMaterial->SetScalarParameterValue(TEXT("ImageFormat"), -1.0);
				}

				DynamicPassthroughMaterial->SetTextureParameterValue(eye ? TEXT("DistortionTextureRight") : TEXT("DistortionTexture"), Distortion);

				if (GEngine && GEngine->GameViewport && GEngine->GameViewport->Viewport)
				{
					FIntPoint Resolution = GEngine->GameViewport->Viewport->GetSizeXY();
					FLinearColor ScreenRes = FLinearColor(Resolution.X, Resolution.Y, 0.f, 0.f);
					DynamicPassthroughMaterial->SetVectorParameterValue(TEXT("ScreenResolution"), ScreenRes);
				}
				
				AttachDisplaySurface();
			}

			// Extract the image 
			{
				UTexture2D*& Texture = eye ? ImagePassthroughRight : ImagePassthroughLeft;

				const uint8* LeapData = Image.data();
				const int LeapDataSize = Image.width() * Image.height() * Image.bytesPerPixel();

				//Check for dragonfly
				if (!isRGB)
				{
					uint8* Dest = (uint8*)Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
					FMemory::Memcpy(Dest, LeapData, LeapDataSize);
				}
				else
				{
					uint32* Dest = (uint32*)Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
					FMemory::Memcpy(Dest, LeapData, LeapDataSize);
				}

				Texture->PlatformData->Mips[0].BulkData.Unlock();
				Texture->UpdateResource();
			}

			// Hack: need to update distortion texture every frame to handle device flipping.
			UpdateDistortionTextures(Image, Distortion);
		}

		const bool bUsingHmd = GEngine->HMDDevice.IsValid() && GEngine->HMDDevice->IsHeadTrackingAllowed();
		DynamicPassthroughMaterial->SetScalarParameterValue("HorizontalTanHalfFOV", bUsingHmd ? 1.4f : 1.0f);

	}
	else
	{
		// We can't find two images, that might be due to device being detached & maybe exchanged later -- trigger reset.
		ImagePassthroughLeft = nullptr;
		ImagePassthroughRight = nullptr;
		DistortionTextureLeft = nullptr;
		DistortionTextureRight = nullptr;
	}
}