function ViewportWindow.AddSkybox(C,d)C.skyboxFrame:ClearAllChildren()local G=Instance.new("\077\111\100\101\108")local W=Instance.new("\080\097\114\116")W.Anchored=true W.CanCollide=false W.CanTouch=false W.Transparency=1 W.Size=Vector3.new(1,1,1)local q=Instance.new("\066\108\111\099\107\077\101\115\104")q.Scale=Vector3.new(10000,10000,10000)q.Parent=W local Y=W:Clone()local D=W:Clone()for C,G in pairs(SIDES)do local q=Instance.new("\068\101\099\097\108")q.Texture=d[C]q.Face=G q.Parent=W end local E=Instance.new("\068\101\099\097\108")E.Texture=d.SkyboxUp E.Face=Enum.NormalId.Top E.Parent=Y local Q=Instance.new("\068\101\099\097\108")Q.Texture=d.SkyboxDn Q.Face=Enum.NormalId.Bottom Q.Parent=D W.CFrame=SIDE_CFRAME Y.CFrame=TOP_CFRAME D.CFrame=BOTTOM_CFRAME W.Parent=G Y.Parent=G D.Parent=G G.Name="\083\107\121\098\111\120\077\111\100\101\108"G.Parent=C.skyboxFrame end function ViewportWindow.GetWorldFrame(d)return d.worldFrame end function ViewportWindow.GetWorldRoot(d)return d.worldRoot end function ViewportWindow.GetPart(d)return d.surfaceGui.Adornee end function ViewportWindow.GetSurface(d)local C=d.surfaceGui.Adornee local G=-Vector3.FromNormalId(d.surfaceGui.Face)local W=Vector3.new(G.y,math.abs(G.x+G.z),0)local q=CFrame.fromMatrix(Vector3.new(),W:Cross(G),W,G)local Y=(C.CFrame*CFrame.new((-G*C.Size)/2))*q return Y,Vector3.new(math.abs(q.XVector:Dot(C.Size)),math.abs(q.YVector:Dot(C.Size)),math.abs(q.ZVector:Dot(C.Size)))end function ViewportWindow.Render(W,d,C,G)local q=workspace.CurrentCamera d=d or q.CFrame if not(C and G)then C,G=W:GetSurface()end if(C:PointToObjectSpace(d.Position)).Z>0 then return end local Y=C.YVector:Cross(d.ZVector)local D=Y:Dot(Y)>0 and Y.Unit or d.XVector local E=CFrame.fromMatrix(d.Position,D,C.YVector)local Q=C*Vector3.new(0,G.y/2,0)local h=C*Vector3.new(0,-G.y/2,0)local B=E:PointToObjectSpace(Q)local e=E:PointToObjectSpace(h)local z=(B*VEC_YZ).Unit local H=(e*VEC_YZ).Unit local S=math.sign(z.y)*math.acos(-z.z)local x=math.sign(H.y)*math.acos(-H.z)local i=2*math.tan(math.rad(q.FieldOfView/2))local u=math.tan(S)-math.tan(x)local v=u/i local n=C:VectorToObjectSpace(C.Position-d.Position)local f=(n*VEC_XZ).Unit local l=n*VEC_YZ local r=-f.z local N=(C:VectorToObjectSpace(d.LookVector)*VEC_XZ).Unit local g=N:Dot(f)/r local K=math.sqrt(1-r*r)/r local X,F=1,1 if W.surfaceGui.SizingMode==Enum.SurfaceGuiSizingMode.FixedSize then F=G.x/G.y end local Z=math.sign(n.x*n.z)*K local I=(l.y/l.z)*F local p=math.abs((g*v)*F)local t=((C-C.Position)*Y_SPIN)*CFrame.new(0,0,0,X,0,0,0,F,0,Z,I,p)local o=0 local J={t:GetComponents()}for d=1,#J,1 do o=math.max(o,math.abs(J[d]))end for d=1,#J,1 do J[d]=J[d]/o end local s=CFrame.new(unpack(J))+d.Position W.camera.FieldOfView=q.FieldOfView W.camera.CFrame=s end
-- Public

function ViewportWindow:AddSkybox(skybox)
	self.skyboxFrame:ClearAllChildren()

	local model = Instance.new("Model")

	local side = Instance.new("Part")
	side.Anchored = true
	side.CanCollide = false
	side.CanTouch = false
	side.Transparency = 1
	side.Size = Vector3.new(1, 1, 1)

	local mesh = Instance.new("BlockMesh")
	mesh.Scale = Vector3.new(10000, 10000, 10000)
	mesh.Parent = side

	local top = side:Clone()
	local bottom = side:Clone()

	for property, enum in pairs(SIDES) do
		local decal = Instance.new("Decal")
		decal.Texture = skybox[property]
		decal.Face = enum
		decal.Parent = side
	end

	local decalTop = Instance.new("Decal")
	decalTop.Texture = skybox.SkyboxUp
	decalTop.Face = Enum.NormalId.Top
	decalTop.Parent = top

	local decalBottom = Instance.new("Decal")
	decalBottom.Texture = skybox.SkyboxDn
	decalBottom.Face = Enum.NormalId.Bottom
	decalBottom.Parent = bottom

	side.CFrame = SIDE_CFRAME
	top.CFrame = TOP_CFRAME
	bottom.CFrame = BOTTOM_CFRAME

	side.Parent = model
	top.Parent = model
	bottom.Parent = model

	model.Name = "SkyboxModel"
	model.Parent = self.skyboxFrame
end

function ViewportWindow:GetWorldFrame()
	return self.worldFrame
end

function ViewportWindow:GetWorldRoot()
	return self.worldRoot
end

function ViewportWindow:GetPart()
	return self.surfaceGui.Adornee
end

function ViewportWindow:GetSurface()
	local part = self.surfaceGui.Adornee

	local v = -Vector3.FromNormalId(self.surfaceGui.Face)
	local u = Vector3.new(v.y, math.abs(v.x + v.z), 0)
	local lcf = CFrame.fromMatrix(Vector3.new(), u:Cross(v), u, v)
	local cf = part.CFrame * CFrame.new(-v * part.Size / 2) * lcf

	return cf,
		Vector3.new(
			math.abs(lcf.XVector:Dot(part.Size)),
			math.abs(lcf.YVector:Dot(part.Size)),
			math.abs(lcf.ZVector:Dot(part.Size))
		)
end

function ViewportWindow:Render(cameraCFrame, surfaceCFrame, surfaceSize)
	local camera = workspace.CurrentCamera

	cameraCFrame = cameraCFrame or camera.CFrame
	if not (surfaceCFrame and surfaceSize) then
		surfaceCFrame, surfaceSize = self:GetSurface()
	end

	if surfaceCFrame:PointToObjectSpace(cameraCFrame.Position).Z > 0 then
		return
	end

	local xCross = surfaceCFrame.YVector:Cross(cameraCFrame.ZVector)
	local xVector = xCross:Dot(xCross) > 0 and xCross.Unit or cameraCFrame.XVector
	local levelCameraCFrame = CFrame.fromMatrix(cameraCFrame.Position, xVector, surfaceCFrame.YVector)

	local tc = surfaceCFrame * Vector3.new(0, surfaceSize.y / 2, 0)
	local bc = surfaceCFrame * Vector3.new(0, -surfaceSize.y / 2, 0)
	local cstc = levelCameraCFrame:PointToObjectSpace(tc)
	local csbc = levelCameraCFrame:PointToObjectSpace(bc)

	local tv = (cstc * VEC_YZ).Unit
	local bv = (csbc * VEC_YZ).Unit
	local alpha = math.sign(tv.y) * math.acos(-tv.z)
	local beta = math.sign(bv.y) * math.acos(-bv.z)

	local fovH = 2 * math.tan(math.rad(camera.FieldOfView / 2))
	local surfaceFovH = math.tan(alpha) - math.tan(beta)
	local fovRatio = surfaceFovH / fovH

	local dv = surfaceCFrame:VectorToObjectSpace(surfaceCFrame.Position - cameraCFrame.Position)
	local dvXZ = (dv * VEC_XZ).Unit
	local dvXY = dv * VEC_YZ

	local dvx = -dvXZ.z
	local camXZ = (surfaceCFrame:VectorToObjectSpace(cameraCFrame.LookVector) * VEC_XZ).Unit
	local scale = camXZ:Dot(dvXZ) / dvx
	local tanArcCos = math.sqrt(1 - dvx * dvx) / dvx

	local w, h = 1, 1
	if self.surfaceGui.SizingMode == Enum.SurfaceGuiSizingMode.FixedSize then
		h = surfaceSize.x / surfaceSize.y
	end

	local dx = math.sign(dv.x * dv.z) * tanArcCos
	local dy = dvXY.y / dvXY.z * h
	local d = math.abs(scale * fovRatio * h)

	local newCFrame = (surfaceCFrame - surfaceCFrame.Position)
		* Y_SPIN
		* CFrame.new(0, 0, 0, w, 0, 0, 0, h, 0, dx, dy, d)

	local max = 0
	local components = { newCFrame:GetComponents() }
	for i = 1, #components do
		max = math.max(max, math.abs(components[i]))
	end

	for i = 1, #components do
		components[i] = components[i] / max
	end

	local scaledCFrame = CFrame.new(unpack(components)) + cameraCFrame.Position

	self.camera.FieldOfView = camera.FieldOfView
	self.camera.CFrame = scaledCFrame

	-- this eats performance!
	-- self:_refreshVisibility(cameraCFrame, surfaceCFrame, surfaceSize, 0.001)
end
