local D={}do local K do local D=2.0 local n=.15 local function b(K)return(exp(D*K)-1)/(exp(D)-1)end local function Z(D)return b((D-n)/(1-n))end function K(D)return sign(D)*clamp(Z(abs(D)),0,1)end end local n={ButtonX=0,ButtonY=0;DPadDown=0;DPadUp=0,ButtonL2=0,ButtonR2=0,Thumbstick1=Vector2.new(),Thumbstick2=Vector2.new()}local b={W=0,A=0,S=0;D=0;E=0;Q=0;U=0;H=0;J=0;K=0;I=0;Y=0,Up=0,Down=0,LeftShift=0,RightShift=0}local Z={Delta=Vector2.new();MouseWheel=0}local k=Vector3.new(1,1,1)local f=Vector3.new(1,1,1)local R=Vector2.new(1,1)*(pi/64)local W=Vector2.new(1,1)*(pi/8)local g=1.0 local h=.25 local s=.75 local l=.25 local j=1 function D.Vel(D)j=clamp(j+(D*(b.Up-b.Down))*s,.01,4)local Z=Vector3.new(K(n.Thumbstick1.x),K(n.ButtonR2)-K(n.ButtonL2),K(-n.Thumbstick1.y))*k local R=Vector3.new(((b.D-b.A)+b.K)-b.H,((b.E-b.Q)+b.I)-b.Y,((b.S-b.W)+b.J)-b.U)*f local W=UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)return(Z+R)*(j*(W and l or 1))end function D.Pan(D)local b=Vector2.new(K(n.Thumbstick2.y),K(-n.Thumbstick2.x))*W local k=Z.Delta*R Z.Delta=Vector2.new()return b+k end function D.Fov(D)local K=(n.ButtonX-n.ButtonY)*h local b=Z.MouseWheel*g Z.MouseWheel=0 return K+b end do local function K(D,K,n)b[n.KeyCode.Name]=K==Enum.UserInputState.Begin and 1 or 0 return Enum.ContextActionResult.Sink end local function k(D,K,b)n[b.KeyCode.Name]=K==Enum.UserInputState.Begin and 1 or 0 return Enum.ContextActionResult.Sink end local function f(D,K,n)local b=n.Delta Z.Delta=Vector2.new(-b.y,-b.x)return Enum.ContextActionResult.Sink end local function R(D,K,b)n[b.KeyCode.Name]=b.Position return Enum.ContextActionResult.Sink end local function W(D,K,b)n[b.KeyCode.Name]=b.Position.z return Enum.ContextActionResult.Sink end local function g(D,K,n)Z[n.UserInputType.Name]=-n.Position.z return Enum.ContextActionResult.Sink end local function h(D)for K,n in pairs(D)do D[K]=n*0 end end function D.StartCapture()ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\075\101\121\098\111\097\114\100\050",K,false,INPUT_PRIORITY,Enum.KeyCode.W,Enum.KeyCode.U,Enum.KeyCode.A,Enum.KeyCode.H,Enum.KeyCode.S,Enum.KeyCode.J,Enum.KeyCode.D,Enum.KeyCode.K,Enum.KeyCode.E,Enum.KeyCode.I,Enum.KeyCode.Q,Enum.KeyCode.Y,Enum.KeyCode.Up,Enum.KeyCode.Down)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\077\111\117\115\101\080\097\110\050",f,false,INPUT_PRIORITY,Enum.UserInputType.MouseMovement)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\077\111\117\115\101\087\104\101\101\108\050",g,false,INPUT_PRIORITY,Enum.UserInputType.MouseWheel)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\066\117\116\116\111\110\050",k,false,INPUT_PRIORITY,Enum.KeyCode.ButtonX,Enum.KeyCode.ButtonY)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\114\105\103\103\101\114\050",W,false,INPUT_PRIORITY,Enum.KeyCode.ButtonR2,Enum.KeyCode.ButtonL2)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\104\117\109\098\115\116\105\099\107\050",R,false,INPUT_PRIORITY,Enum.KeyCode.Thumbstick1,Enum.KeyCode.Thumbstick2)end function D.StopCapture()j=1 h(n)h(b)h(Z)ContextActionService:UnbindAction("\070\114\101\101\099\097\109\075\101\121\098\111\097\114\100\050")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\077\111\117\115\101\080\097\110\050")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\077\111\117\115\101\087\104\101\101\108\050")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\066\117\116\116\111\110\050")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\114\105\103\103\101\114\050")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\104\117\109\098\115\116\105\099\107\050")end end end local function K(D)local K=.1 local n=Camera.ViewportSize local b=2*tan(cameraFov/2)local Z=(n.x/n.y)*b local k=D.rightVector local f=D.upVector local R=D.lookVector local W=Vector3.new()local g=512 for n=0,1,.5 do for h=0,1,.5 do local s=(n-.5)*Z local l=(h-.5)*b local j=(k*s-f*l)+R local E=D.p+j*K local U,G=Workspace:FindPartOnRay(Ray.new(E,j.unit*g))local d=(G-E).magnitude if g>d then g=d W=j.unit end end end return R:Dot(W)*g end


local Input = {} do
	local thumbstickCurve do
		local K_CURVATURE = 2.0
		local K_DEADZONE = 0.15

		local function fCurve(x)
			return (exp(K_CURVATURE*x) - 1)/(exp(K_CURVATURE) - 1)
		end

		local function fDeadzone(x)
			return fCurve((x - K_DEADZONE)/(1 - K_DEADZONE))
		end

		function thumbstickCurve(x)
			return sign(x)*clamp(fDeadzone(abs(x)), 0, 1)
		end
	end

	local gamepad = {
		ButtonX = 0,
		ButtonY = 0,
		DPadDown = 0,
		DPadUp = 0,
		ButtonL2 = 0,
		ButtonR2 = 0,
		Thumbstick1 = Vector2.new(),
		Thumbstick2 = Vector2.new(),
	}

	local keyboard = {
		W = 0,
		A = 0,
		S = 0,
		D = 0,
		E = 0,
		Q = 0,
		U = 0,
		H = 0,
		J = 0,
		K = 0,
		I = 0,
		Y = 0,
		Up = 0,
		Down = 0,
		LeftShift = 0,
		RightShift = 0,
	}

	local mouse = {
		Delta = Vector2.new(),
		MouseWheel = 0,
	}

	local NAV_GAMEPAD_SPEED  = Vector3.new(1, 1, 1)
	local NAV_KEYBOARD_SPEED = Vector3.new(1, 1, 1)
	local PAN_MOUSE_SPEED    = Vector2.new(1, 1)*(pi/64)
	local PAN_GAMEPAD_SPEED  = Vector2.new(1, 1)*(pi/8)
	local FOV_WHEEL_SPEED    = 1.0
	local FOV_GAMEPAD_SPEED  = 0.25
	local NAV_ADJ_SPEED      = 0.75
	local NAV_SHIFT_MUL      = 0.25

	local navSpeed = 1

	function Input.Vel(dt)
		navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down)*NAV_ADJ_SPEED, 0.01, 4)

		local kGamepad = Vector3.new(
			thumbstickCurve(gamepad.Thumbstick1.x),
			thumbstickCurve(gamepad.ButtonR2) - thumbstickCurve(gamepad.ButtonL2),
			thumbstickCurve(-gamepad.Thumbstick1.y)
		)*NAV_GAMEPAD_SPEED

		local kKeyboard = Vector3.new(
			keyboard.D - keyboard.A + keyboard.K - keyboard.H,
			keyboard.E - keyboard.Q + keyboard.I - keyboard.Y,
			keyboard.S - keyboard.W + keyboard.J - keyboard.U
		)*NAV_KEYBOARD_SPEED

		local shift = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)

		return (kGamepad + kKeyboard)*(navSpeed*(shift and NAV_SHIFT_MUL or 1))
	end

	function Input.Pan(dt)
		local kGamepad = Vector2.new(
			thumbstickCurve(gamepad.Thumbstick2.y),
			thumbstickCurve(-gamepad.Thumbstick2.x)
		)*PAN_GAMEPAD_SPEED
		local kMouse = mouse.Delta*PAN_MOUSE_SPEED
		mouse.Delta = Vector2.new()
		return kGamepad + kMouse
	end

	function Input.Fov(dt)
		local kGamepad = (gamepad.ButtonX - gamepad.ButtonY)*FOV_GAMEPAD_SPEED
		local kMouse = mouse.MouseWheel*FOV_WHEEL_SPEED
		mouse.MouseWheel = 0
		return kGamepad + kMouse
	end

	do
		local function Keypress(action, state, input)
			keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
			return Enum.ContextActionResult.Sink
		end

		local function GpButton(action, state, input)
			gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
			return Enum.ContextActionResult.Sink
		end

		local function MousePan(action, state, input)
			local delta = input.Delta
			mouse.Delta = Vector2.new(-delta.y, -delta.x)
			return Enum.ContextActionResult.Sink
		end

		local function Thumb(action, state, input)
			gamepad[input.KeyCode.Name] = input.Position
			return Enum.ContextActionResult.Sink
		end

		local function Trigger(action, state, input)
			gamepad[input.KeyCode.Name] = input.Position.z
			return Enum.ContextActionResult.Sink
		end

		local function MouseWheel(action, state, input)
			mouse[input.UserInputType.Name] = -input.Position.z
			return Enum.ContextActionResult.Sink
		end

		local function Zero(t)
			for k, v in pairs(t) do
				t[k] = v*0
			end
		end

		function Input.StartCapture()
			ContextActionService:BindActionAtPriority("FreecamKeyboard2", Keypress, false, INPUT_PRIORITY,
				Enum.KeyCode.W, Enum.KeyCode.U,
				Enum.KeyCode.A, Enum.KeyCode.H,
				Enum.KeyCode.S, Enum.KeyCode.J,
				Enum.KeyCode.D, Enum.KeyCode.K,
				Enum.KeyCode.E, Enum.KeyCode.I,
				Enum.KeyCode.Q, Enum.KeyCode.Y,
				Enum.KeyCode.Up, Enum.KeyCode.Down
			)
			ContextActionService:BindActionAtPriority("FreecamMousePan2",          MousePan,   false, INPUT_PRIORITY, Enum.UserInputType.MouseMovement)
			ContextActionService:BindActionAtPriority("FreecamMouseWheel2",        MouseWheel, false, INPUT_PRIORITY, Enum.UserInputType.MouseWheel)
			ContextActionService:BindActionAtPriority("FreecamGamepadButton2",     GpButton,   false, INPUT_PRIORITY, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY)
			ContextActionService:BindActionAtPriority("FreecamGamepadTrigger2",    Trigger,    false, INPUT_PRIORITY, Enum.KeyCode.ButtonR2, Enum.KeyCode.ButtonL2)
			ContextActionService:BindActionAtPriority("FreecamGamepadThumbstick2", Thumb,      false, INPUT_PRIORITY, Enum.KeyCode.Thumbstick1, Enum.KeyCode.Thumbstick2)
		end

		function Input.StopCapture()
			navSpeed = 1
			Zero(gamepad)
			Zero(keyboard)
			Zero(mouse)
			ContextActionService:UnbindAction("FreecamKeyboard2")
			ContextActionService:UnbindAction("FreecamMousePan2")
			ContextActionService:UnbindAction("FreecamMouseWheel2")
			ContextActionService:UnbindAction("FreecamGamepadButton2")
			ContextActionService:UnbindAction("FreecamGamepadTrigger2")
			ContextActionService:UnbindAction("FreecamGamepadThumbstick2")
		end
	end
end

local function GetFocusDistance(cameraFrame)
	local znear = 0.1
	local viewport = Camera.ViewportSize
	local projy = 2*tan(cameraFov/2)
	local projx = viewport.x/viewport.y*projy
	local fx = cameraFrame.rightVector
	local fy = cameraFrame.upVector
	local fz = cameraFrame.lookVector

	local minVect = Vector3.new()
	local minDist = 512

	for x = 0, 1, 0.5 do
		for y = 0, 1, 0.5 do
			local cx = (x - 0.5)*projx
			local cy = (y - 0.5)*projy
			local offset = fx*cx - fy*cy + fz
			local origin = cameraFrame.p + offset*znear
			local _, hit = Workspace:FindPartOnRay(Ray.new(origin, offset.unit*minDist))
			local dist = (hit - origin).magnitude
			if minDist > dist then
				minDist = dist
				minVect = offset.unit
			end
		end
	end

	return fz:Dot(minVect)*minDist
end
