// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.

#include "OculusXRHMD_SpectatorScreenController.h"

#if OCULUS_HMD_SUPPORTED_PLATFORMS
#include "OculusXRHMD.h"
#include "TextureResource.h"
#include "Engine/TextureRenderTarget2D.h"

namespace OculusXRHMD
{

	//-------------------------------------------------------------------------------------------------
	// FSpectatorScreenController
	//-------------------------------------------------------------------------------------------------

	FSpectatorScreenController::FSpectatorScreenController(FOculusXRHMD* InOculusXRHMD)
		: FDefaultSpectatorScreenController(InOculusXRHMD)
		, OculusXRHMD(InOculusXRHMD)
		, SpectatorMode(EMRSpectatorScreenMode::Default)
		, ForegroundRenderTexture(nullptr)
		, BackgroundRenderTexture(nullptr)
	{
	}

	void FSpectatorScreenController::RenderSpectatorScreen_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* BackBuffer, FTexture2DRHIRef RenderTexture, FVector2D WindowSize)
	{
		CheckInRenderThread();
		if (OculusXRHMD->GetCustomPresent_Internal())
		{
			if (SpectatorMode == EMRSpectatorScreenMode::ExternalComposition)
			{
				auto ForegroundResource = ForegroundRenderTexture->GetRenderTargetResource();
				auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource();
				if (ForegroundResource && BackgroundResource)
				{
					RenderSpectatorModeExternalComposition(
						RHICmdList,
						FTexture2DRHIRef(BackBuffer),
						ForegroundResource->GetRenderTargetTexture(),
						BackgroundResource->GetRenderTargetTexture());
					return;
				}
			}
			else if (SpectatorMode == EMRSpectatorScreenMode::DirectComposition)
			{
				auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource();
				if (BackgroundResource)
				{
					RenderSpectatorModeDirectComposition(
						RHICmdList,
						FTexture2DRHIRef(BackBuffer),
						BackgroundRenderTexture->GetRenderTargetResource()->GetRenderTargetTexture());
					return;
				}
			}
			FDefaultSpectatorScreenController::RenderSpectatorScreen_RenderThread(RHICmdList, BackBuffer, RenderTexture, WindowSize);
		}
	}

	void FSpectatorScreenController::RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize)
	{
		CheckInRenderThread();
		FSettings* Settings = OculusXRHMD->GetSettings_RenderThread();
		FIntRect DestRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY());
		for (int i = 0; i < 2; ++i)
		{
			OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, Settings->EyeRenderViewport[i], TargetTexture, DestRect, false, true);
			DestRect.Min.X += TargetTexture->GetSizeX() / 2;
			DestRect.Max.X += TargetTexture->GetSizeX() / 2;
		}
	}

	void FSpectatorScreenController::RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize)
	{
		CheckInRenderThread();
		FCustomPresent* CustomPresent = OculusXRHMD->GetCustomPresent_Internal();
		FTexture2DRHIRef MirrorTexture = CustomPresent->GetMirrorTexture();
		if (MirrorTexture)
		{
			FIntRect SrcRect(0, 0, MirrorTexture->GetSizeX(), MirrorTexture->GetSizeY());
			FIntRect DestRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());
			OculusXRHMD->CopyTexture_RenderThread(RHICmdList, MirrorTexture, SrcRect, TargetTexture, DestRect, false, true);
		}
	}

	void FSpectatorScreenController::RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize)
	{
		CheckInRenderThread();
		FSettings* Settings = OculusXRHMD->GetSettings_RenderThread();
		const FIntRect SrcRect = Settings->EyeRenderViewport[0];
		const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());

		OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, SrcRect, TargetTexture, DstRect, false, true);
	}

	void FSpectatorScreenController::RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef SrcTexture) const
	{
		CheckInRenderThread();
		const FIntRect SrcRect(0, 0, SrcTexture->GetSizeX(), SrcTexture->GetSizeY());
		const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());

		OculusXRHMD->CopyTexture_RenderThread(RHICmdList, SrcTexture, SrcRect, TargetTexture, DstRect, false, true);
	}

	void FSpectatorScreenController::RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef FrontTexture, const FTexture2DRHIRef BackTexture) const
	{
		CheckInRenderThread();
		const FIntRect FrontSrcRect(0, 0, FrontTexture->GetSizeX(), FrontTexture->GetSizeY());
		const FIntRect FrontDstRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY());
		const FIntRect BackSrcRect(0, 0, BackTexture->GetSizeX(), BackTexture->GetSizeY());
		const FIntRect BackDstRect(TargetTexture->GetSizeX() / 2, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY());

		OculusXRHMD->CopyTexture_RenderThread(RHICmdList, FrontTexture, FrontSrcRect, TargetTexture, FrontDstRect, false, true);
		OculusXRHMD->CopyTexture_RenderThread(RHICmdList, BackTexture, BackSrcRect, TargetTexture, BackDstRect, false, true);
	}

} // namespace OculusXRHMD

#endif // OCULUS_HMD_SUPPORTED_PLATFORMS
