local d=require(cameraModule)local x=IDENTITYCF d.UpVector=Vector3.new(0,1,0)d.TransitionRate=.15 d.UpCFrame=IDENTITYCF d.SpinPart=TERRAIN d.LastSpinPart=TERRAIN d.LastSpinCFrame=TERRAIN.CFrame d.SpinCFrame=IDENTITYCF function d.GetUpVector(x,d)return d end function d.CalculateUpCFrame(d)local z=d.UpVector local q=d:GetUpVector(z)local N=game.Workspace.CurrentCamera.CFrame.RightVector local f=getRotationBetween(z,q,N)local H=IDENTITYCF:Lerp(f,d.TransitionRate)d.UpVector=H*z d.UpCFrame=H*d.UpCFrame x=d.UpCFrame end function d.SetSpinPart(x,d)x.SpinPart=d end function d.CalculateSpinCFrame(d)local x=0 local z=d.SpinPart if z==d.LastSpinPart then local q=d.LastSpinCFrame local N=z.CFrame-z.CFrame.p local f=q-q.p local H=N:VectorToObjectSpace(d.UpVector)x=twistAngle(f:ToObjectSpace(N),H)end d.SpinCFrame=CFrame.fromEulerAnglesYXZ(0,x,0)d.LastSpinPart=z d.LastSpinCFrame=z.CFrame end function d.Update(z,x)if z.activeCameraController then if d.FFlagUserCameraToggle then z.activeCameraController:UpdateMouseBehavior()end local q,N=z.activeCameraController:Update(x)z.activeCameraController:ApplyVRTransform()z:CalculateUpCFrame()z:CalculateSpinCFrame()z.activeCameraController:UpdateUpCFrame(z.UpCFrame)local f=Vector3.new(0,0,0)if z.activeMouseLockController and z.activeMouseLockController:GetIsMouseLocked()then f=z.activeMouseLockController:GetMouseLockOffset()end local H=N:ToObjectSpace(q)local G=(z.UpCFrame*z.SpinCFrame)*H N=(N-q:VectorToWorldSpace(f))+G:VectorToWorldSpace(f)q=N*G if z.activeCameraController.lastCameraTransform then z.activeCameraController.lastCameraTransform=q z.activeCameraController.lastCameraFocus=N end if z.activeOcclusionModule then q,N=z.activeOcclusionModule:Update(x,q,N)end game.Workspace.CurrentCamera.CFrame=q game.Workspace.CurrentCamera.Focus=N if z.activeTransparencyController then z.activeTransparencyController:Update()end end end function d.IsFirstPerson(d)if d.activeCameraController then return d.activeCameraController:InFirstPerson()end return false end function d.IsMouseLocked(d)if d.activeCameraController then return d.activeCameraController:GetIsMouseLocked()end return false end function d.IsToggleMode(d)if d.activeCameraController then return d.activeCameraController.isCameraToggle end return false end function d.IsCamRelative(d)return d:IsMouseLocked()or d:IsFirstPerson()end


local Camera = require(cameraModule)

local lastUpCFrame = IDENTITYCF

Camera.UpVector = Vector3.new(0, 1, 0)
Camera.TransitionRate = 0.15
Camera.UpCFrame = IDENTITYCF

Camera.SpinPart = TERRAIN
Camera.LastSpinPart = TERRAIN
Camera.LastSpinCFrame = TERRAIN.CFrame
Camera.SpinCFrame = IDENTITYCF

function Camera:GetUpVector(oldUpVector)
	return oldUpVector
end

function Camera:CalculateUpCFrame()
	local oldUpVector = self.UpVector
	local newUpVector = self:GetUpVector(oldUpVector)
	
	local backup = game.Workspace.CurrentCamera.CFrame.RightVector
	local transitionCF = getRotationBetween(oldUpVector, newUpVector, backup)
	local vecSlerpCF = IDENTITYCF:Lerp(transitionCF, self.TransitionRate)
	
	self.UpVector = vecSlerpCF * oldUpVector
	self.UpCFrame = vecSlerpCF * self.UpCFrame
	
	lastUpCFrame = self.UpCFrame
end

function Camera:SetSpinPart(part)
	self.SpinPart = part
end

function Camera:CalculateSpinCFrame()
	local delta = 0
	local part = self.SpinPart
	
	if (part == self.LastSpinPart) then
		local lastCF = self.LastSpinCFrame
	
		local rotation = part.CFrame - part.CFrame.p
		local prevRotation = lastCF - lastCF.p
		
		local direction = rotation:VectorToObjectSpace(self.UpVector)
		delta = twistAngle(prevRotation:ToObjectSpace(rotation), direction)
	end
	
	self.SpinCFrame = CFrame.fromEulerAnglesYXZ(0, delta, 0)
	self.LastSpinPart = part
	self.LastSpinCFrame = part.CFrame
end

function Camera:Update(dt)
	if self.activeCameraController then
		if Camera.FFlagUserCameraToggle then
			self.activeCameraController:UpdateMouseBehavior()
		end
		
		local newCameraCFrame, newCameraFocus = self.activeCameraController:Update(dt)
		self.activeCameraController:ApplyVRTransform()
		
		self:CalculateUpCFrame()
		self:CalculateSpinCFrame()
		self.activeCameraController:UpdateUpCFrame(self.UpCFrame)
		
		-- undo shift-lock offset

		local lockOffset = Vector3.new(0, 0, 0)
		if (self.activeMouseLockController and self.activeMouseLockController:GetIsMouseLocked()) then
			lockOffset = self.activeMouseLockController:GetMouseLockOffset()
		end
		
		local offset = newCameraFocus:ToObjectSpace(newCameraCFrame)
		local camRotation = self.UpCFrame * self.SpinCFrame * offset
		newCameraFocus = newCameraFocus - newCameraCFrame:VectorToWorldSpace(lockOffset) + camRotation:VectorToWorldSpace(lockOffset)
		newCameraCFrame = newCameraFocus * camRotation
		
		--local offset = newCameraFocus:Inverse() * newCameraCFrame
		--newCameraCFrame = newCameraFocus * self.UpCFrame * offset
		
		if (self.activeCameraController.lastCameraTransform) then
			self.activeCameraController.lastCameraTransform = newCameraCFrame
			self.activeCameraController.lastCameraFocus = newCameraFocus
		end
		
		if self.activeOcclusionModule then
			newCameraCFrame, newCameraFocus = self.activeOcclusionModule:Update(dt, newCameraCFrame, newCameraFocus)
		end

		game.Workspace.CurrentCamera.CFrame = newCameraCFrame
		game.Workspace.CurrentCamera.Focus = newCameraFocus

		if self.activeTransparencyController then
			self.activeTransparencyController:Update()
		end
	end
end

function Camera:IsFirstPerson()
	if self.activeCameraController then
		return self.activeCameraController:InFirstPerson()
	end
	return false
end

function Camera:IsMouseLocked()
	if self.activeCameraController then
		return self.activeCameraController:GetIsMouseLocked()
	end
	return false
end

function Camera:IsToggleMode()
	if self.activeCameraController then
		return self.activeCameraController.isCameraToggle
	end
	return false
end

function Camera:IsCamRelative()
	return self:IsMouseLocked() or self:IsFirstPerson()
	--return self:IsToggleMode(), self:IsMouseLocked(), self:IsFirstPerson()
end
