function Portal.AddToWorld(Y,T)T.Parent=Y.ViewportFrame end function Portal.ClipModel(Y,T)local J,I=Y:GetSurfaceInfo()local G=T:GetDescendants()for T=1,#G,1 do local Y=G[T]if Y:IsA("\066\097\115\101\080\097\114\116")then local T=getCorners(Y)table.insert(T,1,Y.Position)local I=false for Y=1,#T,1 do if(J:PointToObjectSpace(T[Y])).z<=0 then I=true break end end if not I then Y:Destroy()end end end return T end function Portal.GetPart(T)return T.SurfaceGUI.Adornee end function Portal.GetSurfaceInfo(T)local Y=T.SurfaceGUI.Adornee local J,I=Y.CFrame,Y.Size local G=-Vector3.FromNormalId(T.SurfaceGUI.Face)local h=math.abs(G.y)==1 and Vector3.new(G.y,0,0)or UP local P=CFrame.fromAxisAngle(h,PI2)*G local K=(G:Cross(P)).Unit local U=J*CFrame.fromMatrix((-G*I)/2,P,K,G)local D=Vector3.new((I*P).Magnitude,(I*K).Magnitude,(I*G).Magnitude)return U,D end function Portal.RenderFrame(I,T,Y,J)local G=I.ViewportFrame local h=I.SurfaceGUI local P=game.Workspace.CurrentCamera local K=I.Camera local U=T or P.CFrame if not(Y and J)then Y,J=I:GetSurfaceInfo()end local D=Y:PointToObjectSpace(U.p)local o,u=D.x/J.x,D.y/J.y local e=1+math.max(J.y/J.x,J.x/J.y,math.max(math.abs(o),math.abs(u))*2)local t=J.y/2 local R=(U.p-Y.p):Dot(Y.LookVector)local x=2*math.atan2(t,R)local r=math.clamp(math.deg(x),1,120)local B=t/math.tan(math.rad(r)/2)local i=R/B local N=(x>FOV120 and i or 1)/e local S=CFrame.new(0,0,0,N,0,0,0,N,0,0,0,1)G.Position=UDim2.new(G.AnchorPoint.x-o,0,G.AnchorPoint.y-u,0)G.Size=UDim2.new(e,0,e,0)G.BackgroundColor3=h.Adornee.Color local w=P.ViewportSize.y h.CanvasSize=Vector2.new(w*(J.x/J.y),w)K.FieldOfView=r K.CFrame=((CFrame.new(U.p)*(Y-Y.p))*CFrame.Angles(0,math.pi,0))*S end


function Portal:AddToWorld(item)
	item.Parent = self.ViewportFrame
end

function Portal:ClipModel(model)
	local cf, size = self:GetSurfaceInfo()
	local descendants = model:GetDescendants()
	for i = 1, #descendants do
		local part = descendants[i]
		if (part:IsA("BasePart")) then
			local corners = getCorners(part)
			table.insert(corners, 1, part.Position)
			
			local pass = false
			for j = 1, #corners do
				if (cf:PointToObjectSpace(corners[j]).z <= 0) then
					pass = true
					break
				end
			end
			
			if (not pass) then
				part:Destroy()
			end
		end
	end
	return model
end

function Portal:GetPart()
	return self.SurfaceGUI.Adornee
end

function Portal:GetSurfaceInfo()
	local part = self.SurfaceGUI.Adornee
	local partCF, partSize = part.CFrame, part.Size
	
	local back = -Vector3.FromNormalId(self.SurfaceGUI.Face)
	local axis = (math.abs(back.y) == 1) and Vector3.new(back.y, 0, 0) or UP
	local right = CFrame.fromAxisAngle(axis, PI2) * back
	local top = back:Cross(right).Unit
	
	local cf = partCF * CFrame.fromMatrix(-back*partSize/2, right, top, back)
	local size = Vector3.new((partSize * right).Magnitude, (partSize * top).Magnitude, (partSize * back).Magnitude)

	return cf, size
end

function Portal:RenderFrame(camCF, surfaceCF, surfaceSize)
	local vpf = self.ViewportFrame
	local surfaceGUI = self.SurfaceGUI
	local camera = game.Workspace.CurrentCamera
	local nCamera = self.Camera
	
	local camCF = camCF or camera.CFrame
	if not (surfaceCF and surfaceSize) then 
		surfaceCF, surfaceSize = self:GetSurfaceInfo()
	end
	
	local rPoint = surfaceCF:PointToObjectSpace(camCF.p)
	local sX, sY = rPoint.x / surfaceSize.x, rPoint.y / surfaceSize.y
	
	local scale = 1 + math.max(
		surfaceSize.y / surfaceSize.x, 
		surfaceSize.x / surfaceSize.y, 
		math.max(math.abs(sX), math.abs(sY))*2
	)
	
	local height = surfaceSize.y/2
	local rDist = (camCF.p - surfaceCF.p):Dot(surfaceCF.LookVector)
	local newFov = 2*math.atan2(height, rDist)
	local clampedFov = math.clamp(math.deg(newFov), 1, 120)
	local pDist = height / math.tan(math.rad(clampedFov)/2)
	local adjust = rDist / pDist
	
	local factor = (newFov > FOV120 and adjust or 1) / scale
	local scaleCF = CFrame.new(0, 0, 0, factor, 0, 0, 0, factor, 0, 0, 0, 1)
	
	vpf.Position = UDim2.new(vpf.AnchorPoint.x - sX, 0, vpf.AnchorPoint.y - sY, 0)
	vpf.Size = UDim2.new(scale, 0, scale, 0)
	vpf.BackgroundColor3 = surfaceGUI.Adornee.Color
	
	local viewportSizeY = camera.ViewportSize.y
	surfaceGUI.CanvasSize = Vector2.new(viewportSizeY*(surfaceSize.x/surfaceSize.y), viewportSizeY)
	
	nCamera.FieldOfView = clampedFov
	nCamera.CFrame = CFrame.new(camCF.p) * (surfaceCF - surfaceCF.p) * CFrame.Angles(0, math.pi, 0) * scaleCF
end
