//=============================================================================
// KFPlayerCamera
//=============================================================================
// Camera class for KF players
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// John "Ramm-Jaeger" Gibson
//=============================================================================

class KFPlayerCamera extends GamePlayerCamera
	config(Camera);

`include(KFProfileSettings.uci);

/** Implements typical third person camera. */
var(Camera) editinline transient KFCustomizationCamera			CustomizationCam;
/** Class to use for third person camera. */
var(Camera) protected const  class<KFCustomizationCamera>      	CustomizationCameraClass;


/** Implements the boss camera. */
var(Camera) editinline transient KFBossCamera					BossCam;
/** Class to use for viewing the boss camera. */
var(Camera) protected const  class<KFBossCamera>      			BossCameraClass;

/** Implements typical first person camera. */
var(Camera) editinline transient KFFirstPersonCamera			FirstPersonCam;
/** Class to use for first person camera. */
var(Camera) protected const  class<GameCameraBase>      		FirstPersonCameraClass;

/** Implements the Emote camera. */
var(Camera) editinline transient KFEmoteCamera					EmoteCam;
/** Class to use for viewing the Emote camera. */
var(Camera) protected const  class<KFEmoteCamera>      			EmoteCameraClass;

/*********************************************************************************************
 FOV Blending
********************************************************************************************* */

/** The FOV that the Camera is trying to acheive */
var()	float		TargetFOV;
/** The FOV that was being used at the start of the FOV Transition */
var		float		TransitionStartFOV;
/** How long (in seconds) the camera has been transitioning to TargetFOV */
var		float		TransitionTimeElapsed;
/** How long it should take to transition to the target FOV */
var		float		TransitionTimeTotal;

function PostBeginPlay()
{
	super.PostBeginPlay();

	// Setup camera modes
	if ( (CustomizationCam == None) && (CustomizationCameraClass != None) )
	{
		CustomizationCam = KFCustomizationCamera( CreateCamera(CustomizationCameraClass) );
	}

	// Setup camera modes
	if ( (BossCam == None) && (BossCameraClass != None) )
	{
		BossCam = KFBossCamera( CreateCamera(BossCameraClass) );
	}

	// Setup camera modes
	if ( (FirstPersonCam == None) && (FirstPersonCameraClass != None) )
	{
		FirstPersonCam = KFFirstPersonCamera( CreateCamera(FirstPersonCameraClass) );
	}

	if ( EmoteCam == None && EmoteCameraClass != None )
	{
		EmoteCam = KFEmoteCamera( CreateCamera(EmoteCameraClass) );
	}
}

/** Performs camera update. */
simulated function DoUpdateCamera(float DeltaTime)
{
	// __TW_ZEDTIME_ : Adjust by Pawn's TimeDilation (partial zed time) for camera anims
	Super.DoUpdateCamera(DeltaTime * ViewTarget.Target.CustomTimeDilation);
}

/**
 * UpdateViewTarget
 * Overridden to support FOV Blending
 */
simulated function UpdateViewTarget(out TViewTarget OutVT, float DeltaSeconds)
{
	local float CurrentFOVAngle;
	local float TransitionDelta;

	super.UpdateViewTarget(OutVT,DeltaSeconds);

	if ( CameraActor(OutVT.Target) != None )
	{
		SetFOV(0);	// Give CameraActor control over FOV
	}
	else
	{
		CurrentFOVAngle = GetFOVAngle();
		// Updating the FOV
		if( TransitionTimeTotal > 0.0f && CurrentFOVAngle != TargetFOV )
		{
			TransitionTimeElapsed += DeltaSeconds;
			if( TransitionTimeElapsed > TransitionTimeTotal )
			{
				TransitionTimeElapsed = TransitionTimeTotal;
				TransitionDelta = 1.0;
			}
			else
			{
                TransitionDelta = TransitionTimeElapsed/TransitionTimeTotal;
			}

            //`log("CurrentFOVAngle = "$CurrentFOVAngle$" TransitionDelta = "$TransitionDelta$" TransitionTimeTotal = "$TransitionTimeTotal$" TransitionTimeElapsed = "$TransitionTimeElapsed);

			CurrentFOVAngle = Lerp( TransitionStartFOV, TargetFOV, TransitionDelta );
			super.SetFOV(CurrentFOVAngle);
		}
	}

	// Call this after the FOV has been adjusted
	if( CameraLensEffects.Length > 0 )
	{
		UpdateCameraLensEffects( OutVT );
	}
}

/** Function that allows us to control the FOV value. Needed for half-res checkerboard rendering */
function float GetActualFOV()
{
	local LocalPlayer LP;
	local vector2D ViewportSize;
	local float ActualFOV;

	// Scale FOV by aspect ratio
	if( WorldInfo.IsNeoCheckerboardRendering() )
	{
		LP = LocalPlayer( PCOwner.Player );
		if( LP != none && LP.ViewportClient != none )
		{
			// Grab our viewport size, not our canvas size
			LP.ViewportClient.GetViewportSize( ViewportSize );
			class'KFPlayerController'.static.CalcFOVForAspectRatio( GetFOVAngle(), ViewportSize.X, ViewportSize.Y, ActualFOV );

			return ActualFOV;
		}
	}

	return super.GetActualFOV();
}

/** Update any attached camera lens effects (e.g. blood) **/
simulated function UpdateCameraLensEffects( const out TViewTarget OutVT )
{
	local EmitterCameraLensEffectBase CameraEffect;
	local float ActualFOV;

	ActualFOV = GetActualFOV();
	foreach CameraLensEffects( CameraEffect )
	{
		if( CameraEffect != none )
		{
			if( class'WorldInfo'.static.IsNeoCheckerboardRendering() )
            {
                CameraEffect.UpdateLocation( OutVT.POV.Location, OutVT.POV.Rotation, UnModifiedFOV );
            }
            else
            {
                CameraEffect.UpdateLocation( OutVT.POV.Location, OutVT.POV.Rotation, ActualFOV );
            }
		}
	}
}

/**
 * Handle smoothly transitioning between FOVs
 * @param NewFOV specifies the new TargetFOV
 * @param TransitionTime specifies how long in seconds the transition should take
 */
function TransitionFOV(float NewFOV, float TransitionTime)
{
	NewFOV *= GetOptionsFOVScale();

	if( TransitionTime > 0.0f )
	{
		TargetFOV = NewFOV;
		TransitionTimeTotal = TransitionTime;
		TransitionStartFOV = GetFOVAngle();
		TransitionTimeElapsed = 0.0f;
	}
	else
	{
		SetFOV(NewFOV);
		TransitionTimeTotal = 0.0f; // The system won't attempt an FOV transition if TimeTotal is 0.
	}
}

function  float GetOptionsFOVScale()
{
	local float FOVScale;
	local KFProfileSettings Settings;

	FOVScale = 1.0f;

	if(class'WorldInfo'.static.IsConsoleBuild())
	{
		Settings = KFProfileSettings(class'GameEngine'.static.GetOnlineSubsystem().PlayerInterface.GetProfileSettings(LocalPlayer(PCOwner.Player).ControllerId));
		if(Settings != None)
		{
			FOVScale = Settings.GetProfileFloat(KFID_FOVOptionsPercentageValue);
		}
	}
	else // PC
	{
		FOVScale = class'KFGameEngine'.default.FOVOptionsPercentageValue;
	}
	return FClamp(FOVScale, 0.75f, 1.25f);
}

/**
 * Directly set the FOV with no transition
 */
function SetFOV(float NewFOV)
{
    TransitionTimeTotal = 0.0f;
	TargetFOV = NewFOV;
	super.SetFOV(NewFOV);
}

/** Overriden to use CameraCache.Pov.Location */
static function float CalcRadialShakeScale(Camera Cam, vector Epicenter, float InnerRadius, float OuterRadius, float Falloff)
{
	local Vector			POVLoc;
	local float				DistPct;

	// using camera location so stuff like spectator cameras get shakes applied sensibly as well
	// need to ensure server has reasonably accurate camera position
	POVLoc = Cam.CameraCache.POV.Location;

	if (InnerRadius < OuterRadius)
	{
		DistPct = (VSize(Epicenter - POVLoc) - InnerRadius) / (OuterRadius - InnerRadius);
		DistPct = 1.f - FClamp(DistPct, 0.f, 1.f);
		return DistPct ** Falloff;
	}
	else
	{
		// ignore OuterRadius and do a cliff falloff at InnerRadius
		return (VSize(Epicenter - POVLoc) < InnerRadius) ? 1.f : 0.f;
	}
}

/**
 * Polls game state to determine best camera to use.
 */
protected function GameCameraBase FindBestCameraType(Actor CameraTarget)
{
	if (CameraStyle == 'ThirdPerson')
	{
		return ThirdPersonCam;
	}
	else if (CameraStyle == 'Boss')
	{
		return BossCam;
	}
	else if (CameraStyle == 'Customization')
	{
		return CustomizationCam;
	}
	else if( CameraStyle == 'FirstPerson' )
	{
		return FirstPersonCam;
	}
	else if( CameraStyle == 'Emote' )
	{
		return EmoteCam;
	}

	return Super.FindBestCameraType(CameraTarget);
}

simulated function Reset();

defaultproperties
{
	// Our default FOV is in 16:9, and then scaled based on the aspect ratio
    DefaultFOV=90.0.f
	FreeCamOffset=(X=0,Y=0,Z=68)
	ThirdPersonCameraClass=class'KFThirdPersonCamera'
	CustomizationCameraClass=class'KFCustomizationCamera'
	BossCameraClass=class'KFBossCamera'
	FirstPersonCameraClass=class'KFFirstPersonCamera'
	EmoteCameraClass=class'KFEmoteCamera'
}