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

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
