
function drawLinks(view)
	if editor.debug.no_links or LOVR then return end 

	if view and not view.nolinks   then 
		bench.push("prepareLinks")

		view.room.links=view.room.links or {"nocopy"}
		for k,v in pairs(level.connections) do 
			local c = v[1].room==view.room.key and v[1] or (v[2].room==view.room.key and v[2] or nil)
			local c2 = c == v[1] and v[2] or v[1]
			if c then 
				if not view.room.links[k] then 
					local link = {room = c2.room, cameraID = c2.cameraID, inRoom = true, connection = k, linkRoom = view.room.key}
					if c.type == "edge" then 
						local pts = view.room[c.mode][c.id].points
						local pt 	= pts[c.index]
						local ptn = pts[c.index==#pts and 1 or c.index+1]
						if c.mode == "floors" then 
							
							link.x,link.y,link.z = ((vec3(pt)+vec3(ptn))/2):unpack()
						end
					end
					view.room.links[k] = link
				end
			end
		end

		bench.pop("prepareLinks")

		--trace("links",lume.count(view.room.links)-1)

		if view~=currentRoom or not editingLevel or animationPanel.open or lume.count(view.room.links)==0 then return end
		bench.push("drawLinks")
		local i = 1
		for l,link in pairs(view.room.links) do
			if type(link)=="table" then 
				link.linkID = l
				link.i = i/100--lume.count(view.room.links)
		    drawLink(link,link.room,nil)
		    i=i+1
			end
		end
		bench.pop("drawLinks")
	end
end


local linkMat = mat4()
function drawLink(link,r,t)
	bench.push("link")

	if not link or not editingLevel then bench.pop("link") return end

	local d		= link.room
	local size 	= 500
	local size2 = d and size * 0.5 or 250
	
	link.zoom  	= link.zoom or 0.25
	link.tip 	=  link.tip or {}

	if not t then 
		bench.push("1")	
		link.tip.w 			= (0.4-((link.zoom*4)^1.2)/4)*size2
		link.tip.h 			= (0.4-((link.zoom*4)^1.2)/4)*size2*0.8
		link.tip.x 	  	= 0--link.tip.w/2
		link.tip.y 	  	= 0--link.tip.h/2
		link.tip.ta 		= 1-(link.zoomNorm or 0)
		link.tip.free 	= true
		link.tip.matrix = mat4()
		if d then 
			link.tip.matrix = mat4()
			link.tip.matrix:translate(link.tip.matrix,vec3(	link.x,	link.y,	link.z))
			local look = mat4.look_at(mat4(),link.tip.matrix,vec3(	link.x,	link.y,	link.z),-zcam.pos,vec3(0,1,0))
			mat4.invert(link.tip.matrix,mat4.mul(link.tip.matrix,look,link.tip.matrix))
			link.tip.nocopy = true
		else 
			bench.pop("link") return 
		end
		shaders.forwardRender:send("wobble",0)
		shaders.forwardRender:send("MVP", mat4.mul(mat4(),zcam.vp,linkMat:transpose(link.tip.matrix)))
		bench.pop("1")
	end

	local text 		=  ""--d and (game.resolution<1 and "" or ellipses(level.rooms[link[2].room].name,(t and t.w or link.tip.w)-18)) or ""
	if t then t.text= text; t.free = true else link.tip.text = text end
	local todraw = t or link.tip
	todraw.noshadow=true
	bench.push("2")
	local tip 		= editor.drawTip(todraw)	
	bench.pop("2")
	local tp = {x=tip.x+2,y=tip.y+2,w=tip.w-4,h=tip.h-4}
	link.hovered 	= (t or editor.readyToClick) and  (t and mouseInRes(tip) or round(pickerColor and pickerColor.g or 0)==link.i)
	local wasHovered= link.tip.hovered
	if not t then 
		link.tip.hovered = link.hovered
	end

	link.cacheTime 	= (link.tip.hovered and not wasHovered)
	link.zoom 	 	= easeTo(link.zoom,(editor.linkSelected == link  or link.tip.hovered) and 0.15 or 0.25,4)
	mult 		 	= (t and t.stackPos) and 0.3 or (t and size or size2)/800

	link.zoomNorm 	= (link.zoom-0.15)*10
	local border  	= 4 
	local border2 	= border * (t and (link.hovered and 0.5 or 1) or link.zoomNorm)
	local add 		= (game.resolution<1 or t or (size2 and size2<300)) and 14 or ((link.zoom-0.15)*140)
	local s 		= {tip.x+border,tip.y+border*4.5-add,tip.w-border*2,tip.h-border*5.5+add}
	s 				= {s[1]-border2/2,s[2]-border2/2,s[3]+border2,s[4]+border2}

	local preview 	= {
		s[1],s[2],
		s[1]+s[3],s[2],
		s[1]+s[3],s[2]+s[4],
		s[1],s[2]+s[4],
	}
	

	bench.push("3")
	link.tip.mesh = gfx.newMesh(zformat,{
			{tp.x,tp.y,0,1,						1,0},
			{tp.x+tp.w,tp.y,0,1,			0,0},
			{tp.x+tp.w,tp.y+tp.h,0,1,	0,1},
			{tp.x,tp.y+tp.h,0,1, 			1,1},
		},
		"fan"
	)
	gfx.setTexture(link.tip.mesh,link.tip.canvas or getImage())
	
	gfx.setColor(1,1,1,1)
	shaders.forwardRender:send("overlay",2) 
	gfx.draw(link.tip.mesh)
	shaders.forwardRender:send("overlay",0) 
	bench.pop("3")

	bench.push("4")

	
	--local dest  		= d and level.rooms[d.room][d.mode][d.path] or nil
	
	local pos 		
	if dest then 
		local destCam 	= level.rooms[d.room].cameras[1] 
		local coords 	= lume.clone(dest.points[d.side=="source" and 1 or #dest.points])  
		local offset	= destCam.locked and {offset=coords} or coords
		local prepos 	= lume.merge(destCam, offset)
		pos 			= lume.merge(prepos,{zoom=0.2*mult,center={x=s[3]/2,y=(s[4])/2}}) 
	end

	--if editor.roomLink.room == r  then 
	--	pos = editor.roomLink.camera
	--end

	bench.pop("4")


	bench.push("5")
	mouse.pushDown(function() editor.linkSelected = nil end)

	if link.hovered then
		editor.linkHovered = true
		editState = "Transforming"
		lmouse.setCursor(hand)
		if t and t.stackPos then 
			if t.stackPos<#roomStack then 
				mouse.set(function()
					game.enterStackRoom(t.stackPos)
				end)
			end
		else
			mouse.setR(function()
				editor.linkSelected = link

				editor.openContextMenu(
					link.inRoom and   
						{{name="Remove Link",update=function()link.zoom=0.15 end,func=function() editor.removeLink(link)  end,col = {r=0.5,g=0.3,b=0.2,a=0.4}}}
						or {{name="Cancel Link",func=editor.cancelLink,col = {r=0.6,g=0.3,b=0.2,a=0.4}}}
				)
			end,true)
			
			mouse.set(function()
				local rm = r and r.key or (r or d.room)
				if currentRoom.key~=rm then 
					link.hovered=false
					link.tip.hovered=false
					if  roomsView then 
						game.enterRoom()
						roomZoom=-0.5
						game.enterRoom()
						delayedCall(function() game.enterRoom(level.rooms[rm],prepos,link,link.linkID)end,0.05)
					else
						game.enterRoom(level.rooms[rm],pos,link,link.linkID)
						
					end
				end
			end)
		end
	end

	bench.pop("5")


	bench.push("7")
	if t then 
		gfx.setColor(1,1,1,1)
		if t.canvas then 
			gfx.draw(t.canvas ,tip.x+mu(2*game.resolution),tip.y+mu(2*game.resolution),0,game.resolution,game.resolution)
		elseif link.tip.canvas then
			gfx.draw(link.tip.canvas ,tip.x+mu(2*game.resolution),tip.y+mu(2*game.resolution),0,(tp.w/link.tip.canvasSize.w)*game.resolution,(tp.h/link.tip.canvasSize.h)*game.resolution)
		end
		gfx.setColor(1,1,1,link.hovered and 0.3 or 0)
		gfx.setLineWidth(1)
		gfx.polygon("line",preview)
	else
		if not link.tip.canvas or link.cacheTime then 
			link.tip.canvasSize = {w=tp.w*editor.linkRes,h=tp.h*editor.linkRes}
			link.tip.canvas =  newCanvas(link.tip.canvasSize.w,link.tip.canvasSize.h)
			pushDraw(function()
				local room = level.rooms[link.room]
				if room then 
					drawRoom({
						room    = level.rooms[link.room],
						wobble 	= {speed = 0,dist  = 0},
						camera 	= camera.setup(room.cameras[link.cameraID or 1]),
						canvas 	= link.tip.canvas,
						bounds 	= {x=0,y=0,w=link.tip.canvasSize.w,h=link.tip.canvasSize.h},
						polys 	= {preview}, 
						linkID  = link.linkID,
						link 		= link,
						nolinks = true
					})
				end
			end,{z=1})
		end
	end
	bench.pop("7")

	if t and t.canvas then 
		
	end
	bench.pop("link")
end

function drawLinkPreview()
	editor.roomLinkPreview.x=easeTo(editor.roomLinkPreview.x,editor.roomLinkPreview.active and tracer.x+tracer.width+73 or -150,4)
	if editor.roomLink and editor.roomLinkPreview.active  then
		drawLink({},editor.roomLink.room,editor.roomLinkPreview)
	elseif editor.roomLinkPreview.x<-100 then
		editor.roomLink = nil 
	end
end

function drawRoomStack()
	if animationPanel.open then return end
	local newStack  = lume.concat({editor.setPreview},{editor.stackStart or {}},roomStack)
	local right = 0
	for i,p in ipairs(newStack) do 
		local x = i*(editor.roomPreview.w+5)-editor.roomPreview.w*0.5+zero(math.max(tracer.x+tracer.width,editor.roomLinkPreview.x+editor.roomLinkPreview.w*0.5))

		local t = {
			x 		 = x,
			w 		 = editor.roomPreview.w,
			h 		 = editor.roomPreview.h,
			y 		 = editor.roomLinkPreview.y - (suppressTrace and 128 or editor.roomPreview.h^0.5*0.5),
			notri 	 = true,
			noshadow = true,
			free 	 	 = true,
			scale =1,
			stackPos = i-2
		}

		if i==1   then 
			if not editor.setPreview and not roomsView then
				editor.setPreview = copyCanvas(currentSet.preview,{w=editor.roomPreview.w*0.945,h=editor.roomPreview.h*0.935,y=0})
			end
			if editor.setPreview then 
				t.canvas = editor.setPreview
				drawLink({},room,t)
			end
		elseif i==2   then 
			if #roomStack>0 then 
				cacheStackStart()
			else
				editor.stackStart=nil
			end
			if editor.stackStart then 
				t.canvas = editor.stackStart
				drawLink({},room,t)
			end
		elseif i<#newStack  then 
			if p[3].tip and p[3].tip.canvas then 
				drawLink(p[3],room,t)
			end
		end
		right = x > right and x or right
	end
	editor.stackEnd = easeTo(editor.stackEnd, right-editor.stackPreview.w/2, 4)
end


function cacheSetPreview()
	editor.setPreview = editor.setPreview or copyCanvas(canvasMain,{w=editor.stackPreview.w-4,h=editor.stackPreview.h-4,filter="linear"})
end

function cacheStackStart()
	editor.stackStart = editor.stackStart or copyCanvas(canvasMain,{w=editor.roomPreview.w-4,h=editor.roomPreview.h-4,filter="linear"})
end

function cacheRoomPreview()
	editor.roomPreviews[room.key] = copyCanvas(canvasMain,{w=editor.roomPreview.w*2-1,h=editor.roomPreview.h*2-2,filter="linear"})
	room.preview = editor.roomPreviews[room.key]
end

function cacheSetPreview()
	editor.setPreviews[currentSet.key] = copyCanvas(canvasMain,{w=editor.roomPreview.w*2-1,h=editor.roomPreview.h*2-2,filter="linear"})
	currentSet.preview = editor.setPreviews[currentSet.key]
end

function cacheLinkPreview()
	editor.roomLinkPreview.canvas =  copyCanvas(canvasMain,{w=editor.roomLinkPreview.w-4,h=editor.roomLinkPreview.h-4,filter="linear"})
end

function linkCached(port)
	return port and port.linkID and room.links[port.linkID] and room.links[port.linkID].cached
end

function drawRoomLink(room,port)
	if port.linkID and not port.link.cached and lfs.exists("linkCache/"..port.linkID..".png") then
		port.link.cached = gfx.newImage("linkCache/"..port.linkID..".png")
	end

	if time-editor.startTime>1 and port.linkID and roomZoom==0 and (prevRoom ~= currentRoom.key or prevRoomZoom~=0 or not port.link.cached or port.link.cacheTime) then
		--DRAW ROOM TO LINK>TIP>CANVAS
		--port.link.cached = copyCanvas(temp)
	end

	if port.link.cached then 
		--DRAW CACHED TO SCREEN??
	end

	if port.preview or (roomZoom>0 and not port.link.cached) or (port.link.cacheTime) or (roomZoom==0 and prevRoomZoom~=0) or (prevRoom ~= currentRoom.key) then 
		--DRAW ROOM TO LINK>TIP>CANVAS
	end
end