

function editor.cantDraw(panel)
	if not (panel.l.visible or panel.solo == panel.layer) and stageHovered then
		mouse.set(function()
			editor.tempTip("Layer Hidden")
		end)
	end
	return namer.enabled
	or not panel.f
	or namer.enabled
	or mouse.x == nil
	or mouse.y == nil
	or editState == "Context Menu"
	or contextMenu.items == 1
	or editState == "Panning"
	or not (panel.l.visible or panel.solo == panel.layer)
end

function editor.drawingTools(panel)
	gfx.push("all")
	if editor.cantDraw(panel) then gfx.pop() return end
	
	-- if keypressed("lshift") and not panel.canvasClicked then
	-- 	if drawingPanel.tool ~= "move" then
	-- 		drawingPanel.prevTool = drawingPanel.tool
	-- 		drawingPanel.tool = "move"
	-- 	else
			
	-- 	end
	-- end
	
	panel.pickingColor = altDown and not shiftDown and (drawingPanel.tool == "brush" or drawingPanel.tool == "fill")
	
	if not editor.prepareToolMouse (panel) then gfx.pop() return end
	
	editor.toolPreview(panel)
	
	if stageHovered and not lkeyboard.isDown("space") then
		if not (altDown and cmdDown) and (drawingPanel.tool == "move" and not panel.selection.mesh) then
			if (level.isAnim or editor.entityHovered == panel.instance) and not multiTool.hovered then
				mouse.set(function()
					-- panel.pushUndoState()
					-- editor.startDrag(panel.transformer)
				end)
			end
		else
			mouse.set(function()
				editor.startStroke(panel)
			end)
		end
	end
	
	if panel.canvasClicked == true then
		
		editor.prepareTool(panel)

		if panel.pickingColor then editor.pickColor (drawingPanel)
		elseif drawingPanel.tool == "brush" then editor.brushTool (panel)
		elseif drawingPanel.tool == "erase" then editor.eraserTool (panel)
		elseif drawingPanel.tool == "fill" then editor.fillTool  (panel,true)
		elseif drawingPanel.tool == "move" then editor.moveTool (panel)
		elseif drawingPanel.tool == "select"then editor.selectionTool(panel)
		end
		
		panel.brushPrevPrev = deepcopy(panel.brushPrev)
		panel.brushPrev = deepcopy(panel.brushCoords)
		
		mouse.pushUp(function()
			setVSync(true)
			editor.drawStroke (panel)

			--panel.f.ox = mf(panel.f.ox)
			--panel.f.oy = mf(panel.f.oy)
			
			panel.canvasClicked = false
			panel.drawn = 0
			panel.stroke = nil
			
			--collectgarbage ("collect")
			
			drawingPanel.tool = not shiftDown and drawingPanel.startTool or drawingPanel.tool
			drawingPanel.startTool = nil
		end)
		
		gfx.setShader()
		gfx.setLineWidth(2)
		panel.drawn = panel.drawn + 1
	end
	
	-- if drawingPanel.tool == "move" and keyreleased("lshift") and not panel.canvasClicked then
	-- 	drawingPanel.tool = drawingPanel.prevTool
	-- end
	
	gfx.pop()
end

function editor.toolPreview(panel)
	if stageHovered then
		if lkeyboard.isDown("space") then
			lmouse.setVisible(true)
		else
			if altDown and not shiftDown and (drawingPanel.tool == "brush" or drawingPanel.tool == "fill") then
				editor.colorPickerPreview()
				
			elseif drawingPanel.tool == "erase" or drawingPanel.tool == "brush" then
				if panel.brushCoords.x < 0 or panel.brushCoords.y < 0 or panel.brushCoords.x > panel.f.w or panel.brushCoords.y > panel.f.h then
					
				end
				editor.brushPreview(panel)
				
			elseif drawingPanel.tool == "move" then
				lmouse.setVisible(true)
				--lmouse.setCursor(cursors.move)
				
			elseif drawingPanel.tool == "fill" then
				editor.brushPreview(panel,"fill")
				
			elseif drawingPanel.tool == "depth" then
				--editor.depthTool(panel)
				
			elseif drawingPanel.tool == "select" then
				lmouse.setCursor(crossCursor)
				
			end
		end
	end
end

function editor.colorPickerPreview()
	lmouse.setVisible(false)
	editor.pickerCanvas = editor.pickerCanvas or newCanvas(5, 5)
	
	gfx.push("all")

		gfx.push("all")
			gfx.setCanvas(editor.pickerCanvas)
			gfx.draw(canvasMain, gfx.newQuad(mouse.x-2, mouse.y-2, 5, 5, canvasMain:getWidth(), canvasMain:getHeight())) 
		gfx.pop()

		local verts = {}
		local radius =16
		for i = 0, 32, 1 do
			local x,y =  math.cos((i / 16) * pi), math.sin((i / 16) * pi)
			verts[i] = {radius*x,radius*y, 0, 1, x*0.5+0.5,y*0.5+0.5}
		end
		editor.pickerMesh = gfx.newMesh(zformat5,verts, "fan")
		gfx.setTexture(editor.pickerMesh,editor.pickerCanvas)
		
		gfx.translate(mouse.x, mouse.y)
		gfx.draw(editor.pickerMesh)
		gfx.setLineWidth(1)
		gfx.arc("line","open", 0, 0, 32 / 2, 0,pi,16)
		gfx.setColor(0,0,0,1)
		gfx.arc("line","open", 0, 0, 32 / 2, pi,2*pi,16)
		local s = 4
		gfx.setColor(1,1,1,1)
		gfx.line(-s,-s,s,-s)
		gfx.line(-s,-s,-s,s)
		gfx.setColor(0,0,0,1)
		gfx.line(s,s,s,-s)
		gfx.line(s,s,-s,s)
		
	gfx.pop()
end

function editor.brushPreview(panel,mode)
	if lmouse.getRelativeMode() then return end

	local r,g,b,a = unpackColor(drawingPanel.color)
	if mode=="fill" and drawingPanel.fillRadius==0 then 
		lmouse.setVisible(true)
		lmouse.setCursor(cursors.fill)
		-- if size<100 and size>0 and panel.previewSize ~= size then 
		-- 	print("CHANNGNENENGNENGENNGENGNEGENNEGNEG")
		-- 	panel.previewSize = size
		-- 	local data = limage.newImageData(size+2,size+2)
		-- 	local radius = size*0.5
		-- 	local its = size
		-- 	for i = 0,its*2, 1 do
		-- 		data:setPixel(mr(size/2+math.cos((i / its) * pi)*radius), mr(size/2+math.sin((i / its) * pi)*radius), r,g,b,a)
		-- 	end
		-- 	cursors.circle		= 	lmouse.newCursor(data, size/2,size/2 )
		-- end
	else
		local siz = mode=="fill" and drawingPanel.fillRadius*0.5 or drawingPanel.pen.size*0.2
		local size = (siz/editor.panMult.x)/game.resolution
	-- print(mouseScroll.y)
	-- if math.abs(mouseScroll.y)>0 then 
		lmouse.setVisible( mode=="fill")
		lmouse.setCursor(cursors.fill)
		pushPost()
		gfx.push("all")
		gfx.setBlendMode("alpha")
		gfx.setLineWidth(1)
		gfx.setColor(1,1,1,1)
		gfx.translate(mouse.x/game.resolution,mouse.y/game.resolution)
		gfx.circle("line",0, 0, size-1)
		-- gfx.arc("line","open", mouse.x, mouse.y, size, 0,pi,size+8)
		gfx.setColor(0,0,0,1)
		gfx.circle("line",0, 0, size)
		-- gfx.arc("line","open", mouse.x, mouse.y, size, pi,2*pi,size+8)
		gfx.setColor(r,g,b,a)
		gfx.circle ("fill", 0, 0, math.min(size,4))
		gfx.pop()
		popPost()
	-- else
	-- 	lmouse.setVisible(true)
	-- 	lmouse.setCursor(cursors.circle)
	-- end
	end
	-- gfx.setLineWidth(0.5)
	-- if panel.vector then 
	-- 	editor.applyBrushJitter(drawingPanel, true)
	-- 	-- print(unpackColor(drawingPanel.brush.color))
	-- 	gfx.setColor(unpackColor(drawingPanel.brush.color))
	-- else
	-- 	gfx.setColor (drawingPanel.color.r, drawingPanel.color.g, drawingPanel.color.b, drawingPanel.brush.opacity * 1)
	-- end

	-- if drawingPanel.tool == "brush" and editor.panMult then 
	-- 	print(game.resolution)
	-- 	gfx.circle ("line", mouse.x, mouse.y, size)
	-- end
	
	-- local whichBrush =
	-- drawingPanel.tool == "erase" and drawingPanel.eraser.size
	-- or lerp(drawingPanel.sliders.size.min, drawingPanel.sliders.size.max, drawingPanel.sliders.size.pct)
	
	-- gfx.setLineStyle("rough")
	
	-- lmouse.setCursor(cursors.fill)
	-- gfx.setLineStyle("smooth")
	-- gfx.setColor (1, 1, 1, 1)
	-- gfx.arc ("line", "open", mouse.x, mouse.y, whichBrush * 0.5 * game.resolution, pi, 0, 20)
	-- gfx.setColor (0, 0, 0, 1)
	-- gfx.arc ("line", "open", mouse.x, mouse.y, whichBrush * 0.5 * game.resolution, 0, -pi, 20)
end

function editor.brushPreviewCanvas(panel)
	if lmouse.getRelativeMode() then return end
	lmouse.setVisible(false)
	gfx.setLineWidth(0.75)
	gfx.setColor (drawingPanel.color.r, drawingPanel.color.g, drawingPanel.color.b, drawingPanel.brush.opacity * 1)
	
	local whichBrush =
	drawingPanel.tool == "erase" and drawingPanel.eraser.size
	or lerp(drawingPanel.sliders.size.min, drawingPanel.sliders.size.max, drawingPanel.sliders.size.pct)
	
	if drawingPanel.tool == "brush" then 
		gfx.circle ("fill", panel.brushCoords.x, panel.brushCoords.y, whichBrush * 0.5)
	end
	gfx.setLineStyle("rough")
	gfx.setColor (1, 1, 1, 1)
	gfx.arc ("line", "open", panel.brushCoords.x, panel.brushCoords.y, whichBrush * 0.5, pi, 0, 20)
	gfx.setColor (0, 0, 0, 1)
	gfx.arc ("line", "open", panel.brushCoords.x, panel.brushCoords.y, whichBrush * 0.5, 0, -pi, 20)
end


function editor.moveTool(panel)
	
	if panel.selection.mesh then

		if panel.movingSelection then
			local f = panel.l.format=="normal" and mr or returnValue
			panel.selection.position = {x = f(panel.selection.offset.x + panel.brushCoords.x - panel.brushStart.x), y = f(panel.selection.offset.y + panel.brushCoords.y - panel.brushStart.y)}
			editor.refreshStrokes()
			
			mouse.pushRelease(function()
				panel.rotatingSelection = false
				panel.selection.offset = {x = panel.selection.position.x, y = panel.selection.position.y}
			end)
		end
		
	else
		if cmdDown then
			-- panel.f.ang = panel.f.ang and panel.f.ang - round(panel.brushCoords.py-panel.brushPrev.py,2) or 0
			-- else
			-- panel.f.ox = panel.f.ox + round(panel.brushCoords.px - panel.brushPrev.px, 2)
			-- panel.f.oy = panel.f.oy + round(panel.brushCoords.py - panel.brushPrev.py, 2)
		end
	end
	
	panel.brushPrev = deepcopy(panel.brushCoords)
end

function editor.selectionTool(panel)
	
	editor.resetBrushCanvas (panel)
	
	if not panel.selection.canvas then
		panel.selection.canvas = newCanvas(panel.f.w, panel.f.h, panel.l.format)
	end
	
	local p = {drawingPanel.brush.size, drawingPanel.brush.spacing, drawingPanel.brush.jitter}
	drawingPanel.brush.size, drawingPanel.brush.spacing, drawingPanel.brush.jitter = 0.1, 0, 0
	editor.curveStroke(panel)
	trace("selection points "..tostring(#panel.selection.shape))
	if panel.selection.shape and #panel.selection.shape > 5 then
		panel.selection.verts = {}
		for i = 1, #panel.selection.shape - 2, 2 do
			local b = 1--i%4==1 and 1 or 0
			table.insert(panel.selection.verts, {panel.selection.shape[i], panel.selection.shape[i + 1], 0, 1, 0, 0, b, b, b, 1})
			table.insert(panel.selection.verts, {panel.selection.shape[i + 2], panel.selection.shape[i + 3], 0, 1, 0, 0, b, b, b, 1})
			table.insert(panel.selection.verts, {panel.selection.shape[i], panel.selection.shape[i + 1], 0, 1, 0, 0, b, b, b, 1})
		end
		panel.selection.mesh = gfx.newMesh(zformat, panel.selection.verts, "triangles")
		-- gfx.setWireframe(true)
		-- gfx.setColor(1, 1, 1, 1)
		-- gfx.draw(panel.selection.mesh)
		-- gfx.setWireframe(false)
	end
	
	drawingPanel.brush.size, drawingPanel.brush.spacing, drawingPanel.brush.jitter = p[1], p[2], p[3]
	panel.tempCanvas = copyCanvas(panel.brushCanvas)
	
end

function editor.adjLineCoord(x, y)
	return x, --+ animationPanel.f.ox - animationPanel.f.w * animationPanel.l.resolution * 0.5,
	y --+ animationPanel.f.oy - animationPanel.f.h * animationPanel.l.resolution * 0.5
end

local cos = math.cos
local sin = math.sin
function adjLine(line,frame,transform,length,adj)
	local res = 1
	local adj = adj or {}
	local f = frame or animationPanel.f
	local c,s
	local function trans(tab,i,j)
		if transform then 
			c,s 			= cos(transform.angle),   sin(transform.angle)
			tab[i]    = tab[i] -(transform.bbox[1]+transform.bbox.w/2)*res 
			tab[j] 		= tab[j] -(transform.bbox[2]+transform.bbox.h/2)*res 
			tab[i]    = tab[i] * transform.scale.x
			tab[j] 		= tab[j] * transform.scale.y
			tab[i],tab[j] = c * tab[i] - s * tab[j], s * tab[i] + c * tab[j]
			tab[i]    = tab[i] + (transform.position.x or 0)*res
			tab[j] 		= tab[j] + (transform.position.y or 0)*res
		end
	end
	if type(line[1])=="table" then
		for i = 1, (length or #line), 1 do
			adj[i]     = line[i] 			
			trans(adj[i],1,2)
			trans(adj[i],3,4)
			trans(adj[i],5,6)
		end
	else
		for i = 1, (length or #line) - 1, 2 do
			adj[i]     = line[i] 			
			adj[i + 1] = line[i + 1] 	
			trans(adj,i,i+1)
			if not out then 
				if not adj[i] then print(inspect(line)) error("cant adjust line")  end
				adj[i]     = adj[i] 			+ f.ox - f.w * res * 0.5
				adj[i + 1] = adj[i + 1] 	+ f.oy - f.h * res * 0.5
			end
		end
		
	end
	return adj
end

function editor.eraserTool(panel)
	if panel.vector then
		while editor.eraseLines(panel) do 
			editor.refreshStrokes() 
		end
	else
		panel.f.canvas:renderTo(function()
			gfx.setLineWidth (drawingPanel.eraser.size)
			gfx.setBlendMode ('replace')
			gfx.setColor (0, 0, 0, 0)
			gfx.line (panel.brushPrev.x, panel.brushPrev.y, panel.brushCoords.x, panel.brushCoords.y)
			gfx.circle ("fill", panel.brushCoords.x, panel.brushCoords.y, drawingPanel.eraser.size * 0.5, 20)
			panel.brushPrev = deepcopy(panel.brushCoords)
		end)
	end
end

function editor.eraseLines(panel)
	local mull = catmullLine(mouse.line,3)
	if #mull < 4  then return end 

	gfx.setColor(1, 0.3, 0.3, 1)
	gfx.setLineWidth(3)
	gfx.setLineJoin("none")
	gfx.line(mull)
		
	local splits = {}
	local cuts = {}

	if not panel.f.strokes then return end

	for s, stroke in ipairs(panel.f.strokes) do
		local line = stroke.line
		local erase = (drawingPanel.eraseGroup=="all pen" or stroke.group==drawingPanel.pen.group) 
		if #line > 1 and erase then
			for i = 1, #line-1, 1 do
				local j = i+1
				local x1,y1= intersect (
					panel.brushPrevPrev.ax, panel.brushPrevPrev.ay, panel.brushCoords.ax, panel.brushCoords.ay,
					line[i][1], line[i][2], line[j][1], line[j][2]
				) 
				if x1	then
					if drawingPanel.eraseMode=="segment" then
						table.insert(cuts, s)
						for l=i,#line-1,1 do 
							
						end
					elseif drawingPanel.eraseMode=="stroke" then
						table.insert(cuts, s)
					elseif drawingPanel.eraseMode=="circle" then
						-- table.insert(cuts, s)
					end
				end
			end
		end
	end

	if #splits > 0 then
		for s, split in ipairs(splits) do
			table.insert(panel.f.strokes, split)
			print("add one")
		end
	end
	if #cuts > 0 then
		for c, cut in lume.ripairs(cuts) do
			print("cut   one")
			table.remove(panel.f.strokes, cut)
		end
		mouse.line={}
		return true
	end
	return false
end

function editor.startStroke(panel)
	if not (altDown) and not (drawingPanel.tool=="select") then
		if panel.vector then 
			panel.pushUndoState(drawingPanel.tool=="fill" and "VecFill" or "Stroke") 
		else 
			panel.pushUndoState("Stroke") 
		end
	end
	panel.strokeTime = 0
	
	if drawingPanel.tool == "brush" then 
		-- setVSync(false)
		editor.applyBrushJitter(drawingPanel, true)
		panel.f.lastDrawn=os.time()
		if panel.vector then
			panel.f.strokes = type(panel.f.strokes)=="table" and panel.f.strokes or {}

			table.insert (panel.f.strokes, {
				size = drawingPanel.pen.size,
				ends = drawingPanel.pen.ends,
				group = drawingPanel.pen.group,
				color = lume.clone(drawingPanel.brush.color),
				line = {}
			})
			panel.stroke = panel.f.strokes[#panel.f.strokes]
			panel.previewStroke = {
				size = drawingPanel.pen.size,
				ends = drawingPanel.pen.ends,
				group = drawingPanel.pen.group,
				color = lume.clone(drawingPanel.brush.color),
				line = {}
			}
			panel.tipDist = panel.l.vector and 0 or 1 
			panel.tipDist2 = 0
			panel.f.preVerts = {}
			panel.drawVector = 1
			panel.strokeSmoothStart = 3
		else
			editor.addToPalette(panel,drawingPanel.brush.color)
			gfx.reset()
			-- gfx.setDefaultFilter(panel.filter)
			panel.brushFormat = {format="normal",msaa=drawingPanel.brush.antialias and 8 or 0}
			panel.l.canvas = newCanvas(panel.f.w, panel.f.h, panel.l.format)	
			panel.brushCanvas = newCanvas(panel.f.w, panel.f.h, panel.brushFormat)
			panel.l.canvas:renderTo(function() gfx.clear(0,0,0,0) end)
			panel.brushCanvas:renderTo(function() gfx.clear(0,0,0,0) end)
		end
	end

	if drawingPanel.tool == "depth" then
		panel.markDragging = -1
	end
	
	if panel.selection.selected and drawingPanel.tool == "select" then
		editor.pasteSelectionContents(panel,true)
	end
	
	
	if drawingPanel.tool == "select" or drawingPanel.tool == "erase" then
		editor.releaseSelection(panel)
		panel.brushCanvas = newCanvas(panel.f.w, panel.f.h, panel.brushFormat)
		panel.selection = {}
		panel.selection.shape = {}
		panel.selection.verts = {}
		panel.selection.offset = {}
		if panel.selection.mesh then
			panel.selection.mesh:release()
			panel.selection.mesh = nil
		end
	end
	
	panel.movingSelection = false
	if drawingPanel.tool == "move"  then
		if panel.selection.mesh and (panel.hoveringSelection or panel.selection.preTransform) then 
			panel.movingSelection = true

			editor.cutStrokeSelection(panel)
			editor.refreshStrokes()
			if shiftDown then 
				drawingPanel.startTool = "select" 
			end
			panel.selection.offset = lume.clone(panel.selection.position)
		else 
			editor.dropSelection(panel)
		end
	end
	
	if drawingPanel.tool =="fill" then 
		editor.fillTool (panel)
	end

	
	panel.brushCoords.px = mouse.x * game.resolution
	panel.brushCoords.py = mouse.y * game.resolution
	editor.prepareToolMouse(panel)
	panel.brushStart = {
		x  = panel.brushCoords.x,  y  = panel.brushCoords.y,
		ax = panel.brushCoords.ax, ay = panel.brushCoords.ay
	}
	panel.diff = {x = 0, y = 0, w = 0, h = 0}
	panel.canvasClicked = true
	panel.brushPrev = deepcopy(panel.brushCoords)
end

function editor.cutStrokeSelection(panel,remove)
	local function sliceSort(a,b)
		return a[5]<b[5]
	end
	if not panel.selection.cut then 
		-- INTERSECT
		local succ,int 
		local region,shape = {},lume.clone(panel.selection.shape)


		for l=1,#shape-1,2 do 
			if not (l>1 and shape[l]==shape[l-2] and shape[l+1]==shape[l-1]) then 
				table.insert(region,shape[l])
				table.insert(region,shape[l+1])
			end
		end

		print("slice reguin")
		local strokesSliced = {}

		for s=1,#panel.f.strokes,1  do
			local slicedStroke = false
			if (drawingPanel.selectGroup=="all pen" or panel.f.strokes[s].group==drawingPanel.pen.group)  then 
				local line = panel.f.strokes[s].line
				for i = 1, #line - 1, 1 do
					local slicedSeg = false
					for r=1,#region-1,2 do 
						local j = i+1
						local x,y = intersect (
							region[r],region[r+1],r==#region-1 and region[1] or region[r+2],r==#region-1 and region[2] or region[r+3],
							line[i][1], line[i][2], line[j][1], line[j][2]) 
						if x then
							if not slicedStroke then 
								table.insert(strokesSliced,{})
								slicedStroke=true
							end
							if not slicedSeg then 
								table.insert(strokesSliced[#strokesSliced],{})
								slicedSeg=true
							end
							local segSlices = strokesSliced[#strokesSliced]
							local dd = math.dist(line[i][1], line[i][2],line[j][1], line[j][2])
							local d  = math.dist(line[i][1], line[i][2],x,y)
							local w  = lerp(line[i][7],line[j][7],d/dd)
							table.insert(segSlices[#segSlices],{x,y,s,i,d,w})
							print("SLICEEEE",x,y,s,i,d,w)
						end
					end
				end
			end
		end


		local temp = {}
		local removals = {}
		print("strokesSliced",inspect(strokesSliced))
		for s1=#strokesSliced,1,-1 do 
			local strokeSlices = strokesSliced[s1]
			local strokeIndex = strokeSlices[1][1][3]
			local start = 1
			local sx,sy
			local w = 1
			local stroke = panel.f.strokes[strokeIndex]
			local line = stroke.line
			for s2=1,#strokeSlices,1 do 
				table.sort(strokeSlices[s2],sliceSort)
				local segSlices = strokeSlices[s2]
				print("slices",s1,s2)
				print(inspect(segSlices))
				for s3=1,#segSlices,1 do 
					local slice = segSlices[s3]
					local l = slice[4]
					local l2 = (l+1)/2
					local left 	= lume.clone(stroke)
					left.line = splice(line,start,l)
					if sx then 
						table.insert(left.line,1,{ sx,sy, ax,ay, bx,by, w})
					end
					sx,sy,w = slice[1],slice[2],slice[6]
					ax,ay,bx,by=sx,sy,sx,sy -- temp
					table.insert(left.line,{ sx,sy, ax,ay, bx,by, w})
					start = l+1
					table.insert(temp,left)
					-- print(inspect(slice))
				end
			end
			local right = lume.clone(stroke)
			right.line = splice(line,start)
			table.insert(right.line,1,{ sx,sy, ax,ay, bx,by, w})
			table.insert(temp,right)
			table.insert(removals,strokeIndex)
		end

		removals = lume.sort(removals)
		for r=#removals,1,-1 do 
			table.remove(panel.f.strokes,removals[r])
		end
		for t=1,#temp,1 do 
			table.insert(panel.f.strokes,temp[t])
		end

		-- CONTAINED
		panel.selection.strokes={}
		panel.selection.strokeKeys={}
		panel.selection.strokeBuffer = {}
		local tried,tris = pcall(mth.triangulate,region)
		if tried then 
			log("good selection shape")
			for s=1,#panel.f.strokes,1 do
				if panel.f.strokes[s].line and #panel.f.strokes[s].line>1 and (drawingPanel.selectGroup=="all pen" or panel.f.strokes[s].group==drawingPanel.pen.group)  then 
					local line = panel.f.strokes[s].line
					local n,m = #line,#line-1
					if 
								point_in_poly(tris,{x=(line[1][1]+line[2][1])/2,y=(line[1][2]+line[2][2])/2}) 
						and point_in_poly(tris,{x=(line[m][1]+line[n][1])/2,y=(line[m][2]+line[n][2])/2}) 
						then 
						panel.selection.strokes[s] = true
						table.insert(panel.selection.strokeKeys,s)
						table.insert(panel.selection.strokeBuffer,panel.f.strokes[s])
					end
				end
			end
			print("selected ",#panel.selection.strokeKeys," strokes")
		else
			log("Bad selection shape")
		end

		panel.selection.cut = true
	end

	local buffer = panel.selection.strokeBuffer

	if remove then 
		if panel.selection.strokeKeys then 
			for i,key in lume.ripairs(lume.sort(panel.selection.strokeKeys)) do 
				table.remove(panel.f.strokes,key)
			end
		else
			panel.f.strokes = {}
		end
		panel.sudoForceRestroke=true
	end

	return buffer
end

function editor.dropSelection(panel)
	if panel.selection.selected then 
		editor.pasteSelectionContents(panel,true)
		panel.selection = {}
	end
end

function editor.releaseSelection(panel)
	if panel.selection.canvas then
		panel.selection.canvas:release()
		panel.selection.canvas = nil
		panel.selection.shape = {}
		if panel.selection.mesh then
			panel.selection.mesh:release()
			panel.selection.mesh = nil
		end
		panel.selection = {}
	end
end

function editor.brushTool(panel)
	if panel.f.blank then 
		panel.f.blank = false
		panel.unblanked = true
	end
	if panel.l.format=="vector" then 
		editor.curveStroke (panel)
	else
		if panel.brushCanvas then 
			editor.expandCanvas (panel)
			editor.applyBrushJitter (drawingPanel, false)
			editor.resetBrushCanvas (panel)
			editor.curveStroke (panel)
			editor.renderStroke (panel)
		end
	end
end

function editor.prepareToolMouse(panel,pan)
	panel.brushCoords.px = easeTo(panel.brushCoords.px, mouse.x * game.resolution, panel.brushEase)
	panel.brushCoords.py = easeTo(panel.brushCoords.py, mouse.y * game.resolution, panel.brushEase)
	
	local model = panel.f--panel.instance.adata.layers[panel.layer].frames[panel.frame]
	
	if panel.l.type ~= "drawing" or not model or (not model.tris or not model.tris[1]) then
		trace("No valid frame")
		return
	end
	
	
	--trace("Editing model")
	
	local tri = model.tris[1]
	local sideA, sideB = tri[2] - tri[1], tri[3] - tri[1]
	local cross = vec3.cross(sideA, sideB)
	local transform = -(panel.f.transform or mat4()) *- panel.instance.transform
	local normal = transform * (true and vec3(0, 0, -9999999) or cross) --TEMP
	
	if not panel.f.transform then
		if not applyTransform(panel.f) then
			log("fuggg")
			return
		end
	end
	
	local pt = panel.instance.transform * panel.f.transform * vec3(0)
	cam.lookTarg = pt
	--cam.relative=
	
	animationPanel.drawingPosition = -(transform * vec3(0, 0, -vec3.dist(zcam.pos, cam.lookTarg)))
	
	local ttri = {
		transform * tri[1],
		transform * tri[2],
	transform * tri[3]}
	
	--panel.frameNormal = cpml.mesh.normal()
	if not zcam.ray then return end


	local intersect, dist = cpml.intersect.ray_plane(zcam.ray, {position = ttri[1], normal = normal})
	local intersect2 

	if pan then 
		local x ,y =lmouse.getX()*game.resolution,(lmouse.getY())*game.resolution
		intersect = cpml.intersect.ray_plane(getCursorRay(x,y,view), {position = ttri[1], normal = normal})
		intersect2 = cpml.intersect.ray_plane(getCursorRay(x+1,y+1,view), {position = ttri[1], normal = normal})
	end
	--editor.testTri =gfx.newMesh(zformat,{{ttri[1].x,ttri[1].y,ttri[1].z,1,1,0},{ttri[2].x,ttri[2].y,ttri[2].z,1,1,1},{ttri[3].x,ttri[3].y,ttri[3].z,1,0,0}},"fan")
	--editor.testTri:setTexture(panel.instance.img)
	
	if intersect then
		local w = vec3.dist(ttri[1], ttri[3])
		local h = vec3.dist(ttri[1], ttri[2])
		local x = vec3.dot(ttri[3] - ttri[1], intersect - ttri[1])
		local y = vec3.dot(ttri[2] - ttri[1], intersect - ttri[1])
		panel.mouse = intersect
		
		if tostring((x / (w ^ 2))) == "nan" then
			
			return false
		else
			local stabilizer = mc(math.max(0,cam.soom-1)*2,drawingPanel.pen.stabilizer,1)
			-- trace("stabilizer",stabilizer)
			if stabilizer>0.05 and panel.brushCoords.ax  then 
				panel.brushCoords.ax = easeTo(panel.brushCoords.ax, (x / (w)) , mc(1,stabilizer*4,99))
				panel.brushCoords.ay = easeTo(panel.brushCoords.ay, (y / (h)) , mc(1,stabilizer*4,99))
			else
				panel.brushCoords.ax = (x / (w))
				panel.brushCoords.ay = (y / (h))
			end
			
			if intersect2 then 

				return vec3.dot(ttri[3] - ttri[1], intersect2 - ttri[1])/w-x/w,
							 vec3.dot(ttri[2] - ttri[1], intersect2 - ttri[1])/h-y/h
			end

			panel.brushCoords.x = (x / (w ^ 2)) * panel.f.w
			panel.brushCoords.y = (y / (h ^ 2)) * panel.f.h
			
			if panel.debugView then
				-- trace("raw  ", w, h)
				-- trace("raw  ", x, y)
				-- trace("raw  ", (x / (w ^ 2)), (y / (h ^ 2)))
				-- trace("intrs", intersect.x, intersect.y, intersect.z)
				-- trace("cords", panel.brushCoords.x, panel.brushCoords.y)
				-- trace("curds", panel.brushCoords.ax, panel.brushCoords.ay)
				-- trace("dims ", panel.f.w, panel.f.h)
				-- trace("penco",unpack(adjLine({panel.brushCoords.ax, panel.brushCoords.ay},panel.f)))
			end
			
			panel.brushCoords.angle = 0
			return true
		end
		
	end
			-- trace("pbc",panel.brushCoords.ax,panel.brushCoords.ay)
	
	return false
end

function editor.prepareTool(panel)
	drawingPanel.pressure = drawingPanel.brush.pressureSensitivity and mouse.pressure or 1

	panel.strokeTime = panel.strokeTime + 1
	if panel.brushPrev == nil or panel.drawn < 2 then panel.brushPrev = deepcopy(panel.brushCoords) end
	if panel.brushPrevPrev == nil or panel.drawn < 2 then panel.brushPrevPrev = deepcopy(panel.brushCoords) end
	
	local mouseDiff = {x = panel.brushCoords.x - panel.brushPrev.x, y = panel.brushCoords.y - panel.brushPrev.y}
	drawingPanel.brush.mouseAng = math.angle(panel.brushCoords.x, panel.brushCoords.y, panel.brushPrev.x, panel.brushPrev.y) - pi / 2
	drawingPanel.brush.mouseDist = math.ddist(mouseDiff.x, mouseDiff.y)
	
	panel.brushCoords.angle = drawingPanel.brush.mouseAng
	
	if panel.f.blank then
		if panel.blankAnim then
			panel.blankAnim = false
			--panel.instance:move (panel.brushCoords.x-50, panel.brushCoords.y-50)
		else
			--panel.f.ox = -panel.brushCoords.x
			--panel.f.oy = -panel.brushCoords.y
			mouse.pushRelease(function() editor.clipFrame(panel.f) end)
		end
		panel.f.blank = false
		panel.unblanked = true
		editor.prepareTool(panel)
	end
	-- gfx.push("all")
end

function editor.resetBrushCanvas(panel)
	
	if panel.vector then return end
	
	-- gfx.push("all")
	if not panel.brushCanvas then
		panel.brushCanvas = newCanvas(panel.f.w, panel.f.h, panel.brushFormat)
	end
	gfx.setShader()
	gfx.setCanvas (panel.brushCanvas)
	gfx.setColor (1, 1, 1, 1)
	gfx.setBlendMode ('alpha', 'premultiplied')
end

function editor.expandCanvas(panel, selection, bounds)
	
	if panel.vector and not(drawingPanel.tool=="fill" or drawingPanel.tool=="select") then return end

	-- ltrb
	local addSize = selection and 0 or 64
	local push = bounds 
		or (selection 
			and {panel.selection.position.x - panel.selection.scale.x * (panel.selection.bbox.w / 2), panel.selection.position.y - panel.selection.scale.y * (panel.selection.bbox.h / 2), panel.selection.position.x + panel.selection.scale.x * (panel.selection.bbox.w / 2), panel.selection.position.y + panel.selection.scale.y * (panel.selection.bbox.h / 2)} 
			or {panel.brushCoords.x - addSize, panel.brushCoords.y - addSize, panel.brushCoords.x + addSize, panel.brushCoords.y + addSize})
	local frame = {0, 0, panel.f.w, panel.f.h}
	local pushed = {}
	local add = {x = 0, y = 0, w = 0, h = 0}
	if selection then panel.selection.expanded = {x = 0, y = 0, w = 0, h = 0} end
	

	if panel.f.w * panel.f.h < panel.maxPixels then
		
		if bounds then 
			--print(inspect(bounds))
		end

		pushed = {
			math.min(frame[1], push[1]),
			math.min(frame[2], push[2]),
			math.max(frame[3], push[3]),
			math.max(frame[4], push[4]),
		}
		
		add = {
			x = frame[1] - pushed[1],
			y = frame[2] - pushed[2],
			w = pushed[3] - frame[3],
			h = pushed[4] - frame[4],
		}
		-- print(add.x,add.y)
		add = {
			x = add.x > 0 and add.x + 128 or 0,
			y = add.y > 0 and add.y + 128 or 0,
			w = add.w > 0 and add.w + 128 or 0,
			h = add.h > 0 and add.h + 128 or 0,
		}
		
		panel.f.w = panel.f.w + mf(math.abs(add.x) + add.w)
		panel.f.h = panel.f.h + mf(math.abs(add.y) + add.h)

		panel.f.ox = panel.f.ox - ((add.x - add.w) / 2) * (panel.l.resolution)

		panel.f.oy = panel.f.oy - ((add.y - add.h) / 2) * (panel.l.resolution)

		editor.shiftLines(add.x,add.y)
		
		if (add.w ~= 0 or add.h ~= 0 or add.x ~= 0 or add.y ~= 0) then
				panel.f.canvas = copyCanvas(panel.f.canvas, {release = true, x = add.x, y = add.y, nw = panel.f.w, nh = panel.f.h,filter=panel.filter})
			if not selection then
				panel.brushCanvas = copyCanvas(panel.brushCanvas, {release = true, x = add.x, y = add.y, nw = panel.f.w, nh = panel.f.h,filter=panel.filter})
			end
			panel.updateMesh = true
		end
			
			panel.brushCoords.x = panel.brushCoords.x + add.x
			panel.brushCoords.y = panel.brushCoords.y + add.y
		if panel.brushPrev then
			panel.brushPrev.x = panel.brushPrev.x + add.x
			panel.brushPrevPrev.x = panel.brushPrevPrev.x + add.x
			panel.diff.x = panel.diff.x + add.x
			
			panel.brushPrev.y = panel.brushPrev.y + add.y
			panel.brushPrevPrev.y = panel.brushPrevPrev.y + add.y
			panel.diff.y = panel.diff.y + add.y
		end
		
		if selection then
			panel.selection.expanded = add
		end
	else
		print('Canvas Too Big!')
	end
end

function editor.shiftLines(x,y)
	if not (animationPanel.f.strokes and type(animationPanel.f.strokes)=="table") then return end
	for s,stroke in ipairs(animationPanel.f.strokes) do
		local line = stroke.line
		for i=1,#line,1 do
			line[i][1],line[i][2]=line[i][1]+x*animationPanel.l.resolution,line[i][2]+y*animationPanel.l.resolution
		end
	end 
	editor.refreshStrokes()
end

function editor.bezierStroke(c1, c2, c3, pen)
	local x, y = pen and "ax" or "x", pen and "ay" or "y"
	c2[x], c2[y] = c2[x] or c3[x], c2[y] or c3[y]
	c1[x], c1[y] = c1[x] or c2[x], c1[y] or c2[y]
	
	local projectedPoint = {
		x = c2[x] + (c2[x] - c1[x]) / 2,
		y = c2[y] + (c2[y] - c1[y]) / 2
	}
	
	projectedPoint.x = (projectedPoint.x + (c3[x] + c2[x]) / 2) / 2
	projectedPoint.y = (projectedPoint.y + (c3[y] + c2[y]) / 2) / 2
	projectedPoint.angle = c3.angle or 0
	
	return mth.newBezierCurve(c2[x], c2[y], projectedPoint.x, projectedPoint.y,projectedPoint.x, projectedPoint.y, c3[x], c3[y])
end

function editor.bezierControlPoint(ax,ay, bx,by, cx,cy)
	local lenl,lenr = math.dist(ax,ay,bx,by),math.dist(bx,by,cx,cy)
	local dl        = lenl/(lenl+lenr)
	local lx,ly 		= (ax+bx)/2, (ay+by)/2
	local rx,ry 		= (bx+cx)/2, (by+cy)/2
	local mx,my     = lerp(lx,rx,dl),lerp(ly,ry,dl)
	local k = 0.8
	return 
		bx+(lx-mx)*k, by+(ly-my)*k,
		bx+(rx-mx)*k, by+(ry-my)*k
end

function editor.insertStrokePoint(panel,line,point,stable)
	if line[1] and math.dist(point.x,point.y,line[#line][1],line[#line][2])<1 then 
		return 
	end

	local l = #line

	local ax,ay,bx,by = point.x,point.y

	if l>0 then 
		ax,ay = (line[l][1]+point.x)/2,(line[l][2]+point.y)/2
	end

	table.insert(line,{
		point.x,point.y,
		ax,ay, point.x,point.y, -- temp
		drawingPanel.pressure
	})

	l = #line
	if #line>2 then 
		ax,ay,bx,by  = editor.bezierControlPoint(
			line[l-2][1],line[l-2][2],
			line[l-1][1],line[l-1][2],
			line[l][1],  line[l][2]
		)
		line[l-1][3],line[l-1][4] = ax,ay
		line[l-1][5],line[l-1][6] = bx,by
		if panel.debugView then 
			-- table.insert(panel.f.strokes,{size=0.1, ends=1, color={1,0,0,1}, group="note", 
			-- 	line={{ax,ay},{bx,by},{ax,ay}}
			-- })
		end
	end

	
end

function editor.curveStroke(panel)
	-- if true then return end
	if mouse.release() then
		return
	end
	panel.mouseTip = panel.mouseTip or lume.clone(panel.brushCoords)

	panel.tipDist =  panel.tipDist + math.dist(panel.brushCoords.x,panel.brushCoords.y,panel.brushPrev.x,panel.brushPrev.y) 
	panel.tipDist2 =  panel.tipDist2 + math.dist(panel.brushCoords.x,panel.brushCoords.y,panel.brushPrev.x,panel.brushPrev.y) 
	local brushLim = 1--((drawingPanel.brush.spacing + 0.01) * (drawingPanel.brush.size) * 4) or (panel.drawn and (panel.drawn < 5))
	local penLim   = panel.stroke and (#panel.stroke.line<2 and -1 or 5)
	if level.isAnim then 
		penLim= (panel.stroke and #panel.stroke.line<2) and -1 or utils.map(currentRooms[1].camera.zoom, 4.92, 6.6, 2, 6) 
	end
		
	local lim = panel.vector and penLim or brushLim
	-- lim =  panel.l.format=="vector" and 1 or lim

	local point = vec2()
	local curve = editor.bezierStroke(panel.brushPrevPrev, panel.brushPrev, panel.brushCoords, panel.vector)
	local stable = (panel.tipDist<20 and 0.02 or 0)+drawingPanel.pen.stabilizer/3

	trace("td",panel.tipDist2,lim/(2*panel.cat))
	if panel.tipDist2>lim/(4*panel.cat) then 
		if panel.vector and panel.previewStroke then
			point.x, point.y = panel.brushCoords.ax,panel.brushCoords.ay
			editor.insertStrokePoint(panel,panel.previewStroke.line,point,stable)
			-- if panel.stroke and #panel.stroke==0 then 
			-- 	panel.stroke.line[1][1]=panel.previewStroke.line[1][1]
			-- 	panel.stroke.line[1][2]=panel.previewStroke.line[1][2]
			-- end
			-- if #panel.previewStroke.widths>10 then 
				-- editor.deleteStrokePoint(panel.previewStroke,1)
			-- end
		end
		panel.tipDist2=0
	end

	local mul = 0.5--drawingPanel.pen.smoothing>0.5 and 2 or 1
	if panel.tipDist > lim/(2*mul) then
		
		panel.mouseTip = lume.clone(panel.brushCoords)
		local brushimg = getImage(brushes[drawingPanel.brush.shape])
		
		gfx.setFilter(brushimg,panel.filter) 

		if drawingPanel.tool == "select" and panel.selection.shape then
			table.insert(panel.selection.shape, panel.vector and panel.brushCoords.x or mf(panel.brushCoords.x))
			table.insert(panel.selection.shape, panel.vector and panel.brushCoords.y or mf(panel.brushCoords.y))

		elseif panel.vector and panel.stroke then
			point.x, point.y = panel.brushCoords.ax,panel.brushCoords.ay
			editor.insertStrokePoint(panel,panel.stroke.line,point,stable)
			if drawingPanel.pen.smoothing>0.01 then 
				editor.smoothStroke(panel,panel.stroke,drawingPanel.pen.smoothing)
			end

		else 
			local iterations = drawingPanel.tool == "select" and 2
			or 	(mc(1,  
								40 
								* (panel.tipDist / drawingPanel.brush.size) 
								* (1 - drawingPanel.brush.spacing), 
							50))

			iterations=mf(iterations)
			-- print("tipdist",panel.tipDist,"iterations",iterations)
			panel.tipDist=0


			for i = 0, iterations-1,1 do
				local tipAngle = math.abs((drawingPanel.brush.mouseAng + 10) - (panel.brushPrev.angle + 10)) < pi / 2 and lerpang(panel.brushPrev.angle, drawingPanel.brush.mouseAng, i / iterations) or drawingPanel.brush.mouseAng

				point.x, point.y = curve:evaluate(i / iterations)

				local lerpSize = lerp(drawingPanel.brush.size or panel.brushPrev.size, drawingPanel.brush.size, i / iterations)
				
				if not panel.vector and drawingPanel.brush.scatter > 0.05 then
					local scatterAngle = math.random() * 2 * pi
					local scatterDist = math.random() * drawingPanel.brush.scatter * 64
					point.x = point.x + math.sin(scatterAngle) * scatterDist
					point.y = point.y + math.cos(scatterAngle) * scatterDist
				end
				
				if panel.drawn > 1 then


					if drawingPanel.tool == "select" and panel.selection.shape then
						table.insert(panel.selection.shape, panel.vector and panel.brushCoords.x or mf(panel.brushCoords.x))
						table.insert(panel.selection.shape, panel.vector and panel.brushCoords.y or mf(panel.brushCoords.y))
					end
					
					if drawingPanel.tool ~= "select" and not panel.vector then

						local alpha = (mouse.pressure and drawingPanel.brush.pressureSensitivity) and 1.2*mouse.pressure-0.15 or 1
						panel.brushAlpha = panel.brushAlpha or alpha
						panel.brushAlpha = mc(0,panel.strokeTime>4 and easeTo(panel.brushAlpha,alpha,16) or alpha,1)
						trace("panel.brushAlpha",panel.brushAlpha)
						gfx.push("all")
						if LOVE then 
							gfx.setBlendMode("lighten","premultiplied")
						else 
							gfx.setBlendMode("lighten")
							gl.BlendEquation(gle.MAX);
							gl.BlendFuncSeparate(gle.ONE,gle.ZERO,gle.ONE,gle.ZERO)
						end
						gfx.setColor(1,1,1,panel.brushAlpha*drawingPanel.brush.opacity)
						gfx.setFilter(brushimg,"linear")
						gfx.push()
							gfx.translate(point.x,point.y)
							gfx.rotate(drawingPanel.brush.angle + (drawingPanel.brush.follow and tipAngle or 0))
							gfx.scale(math.max(0.05,drawingPanel.brush.flatness),1)
							gfx.circle("fill",0,0,(lerpSize) ,10)
							local s = 100000
							testmesh= testmesh or gfx.newMesh(zformat3,{
								{-s,-s,0,1, 1,1,1,1},
								{-s,-s,0,1, 1,1,1,1},
								{-s,-s,0,1, 1,1,1,1},
							},"triangles")
							gfx.draw(testmesh)
						gfx.pop()
						gl.BlendEquation(gle.FUNC_ADD);
						-- gfx.draw(
						-- 	brushimg,
						-- 	curvex,
						-- 	curvey,
						-- 	drawingPanel.brush.angle + (drawingPanel.brush.follow and tipAngle or 0),
						-- 	(lerpSize * drawingPanel.brush.flatness) / brushimg:getWidth(),
						-- 	(lerpSize) / brushimg:getHeight(),
						-- 	brushimg:getWidth() / 2,
						-- 	brushimg:getHeight() / 2
						-- )
						gfx.pop()
					end
				end
			end
		end
		panel.brushCoords.size = drawingPanel.brush.size
		
	end
	trace("mouse.pressure",mouse.pressure)
end




function editor.renderStroke(panel)
	if not (panel.vector or mouse.release()) then
		if drawingPanel.brush.texture ~= 0 or (drawingPanel.brush.mouseDist > drawingPanel.brush.size / 4) then
			if drawingPanel.brush.texture ~= 0 then
				panel.tempCanvas = copyCanvas(panel.brushCanvas)
				editor.drawBrushTexture(panel, panel.tempCanvas)
			end
			
			if drawingPanel.sliders.opacity.stroke == false then
				editor.drawStroke(panel)
				panel.brushCanvas = newCanvas(panel.f.w, panel.f.h, panel.brushFormat)
			end
		end
	end
end

function mapPixel(data,func)
	local w,h = data:getWidth(),data:getHeight()
	for x=1,w-1,1 do 
		for y=1,h-1,1 do 
			r,g,b,a = data:getPixel(x,y)
			data:setPixel(x,y,func(x,y,r,g,b,a))
		end
	end
	return data
end

mapPixelString = [[
require "love.image"
require "love.math"
local data = ...

func = function(x, y, r, g, b, a)
   r, g, b = love.math.gammaToLinear(r, g, b)
   r, g, b = love.math.linearToGamma((r / a), (g / a), (b / a))
   return r, g, b, a
end
	local w,h = data:getWidth(),data:getHeight()
	for x=1,w-1,1 do 
		for y=1,h-1,1 do 
			r,g,b,a = data:getPixel(x,y)
			data:setPixel(x,y,func(x,y,r,g,b,a))
		end
	end
	lthread.getChannel("map"):push(data)

]]

local function selectRegion(panel)
	if panel.selection.shape and not shiftDown and #panel.selection.shape > 5 then
		panel.selection.bbox = bboxLine(panel.selection.shape)
		if panel.selection.bbox.w > 1 and panel.selection.bbox.h > 1 then
			panel.pushUndoState()
			gfx.setColor (1, 1, 1, 1)
			--editor.splitPoly(panel.selection.shape)
			panel.selection.verts = lume.concat(panel.selection.verts, {
				panel.selection.verts[#panel.selection.verts],
				panel.selection.verts[1],
			panel.selection.verts[#panel.selection.verts]})
			panel.selection.mesh = gfx.newMesh(zformat, panel.selection.verts, "triangles")


			local preCanvas

			if panel.l.format=="vector" then
				-- CUT
				-- panel.selection.strokes = {}
				-- panel.selection.strokeKeys={}
				-- for i=1,#panel.f.strokes,1 do 
				-- 	panel.selection.strokes[i]=true
				-- 	table.insert(panel.selection.strokeKeys,i)
				-- end

			else
				preCanvas = newCanvas(panel.f.w, panel.f.h, panel.l.format)
				gfx.setFilter(preCanvas,panel.filter)

				if panel.l.format=="r8" then 
					gfx.setCanvas ({preCanvas, stencil = true})
					gfx.stencil(function()
						gfx.polygon("fill", panel.selection.shape)
					end, "replace",1)
					gfx.setStencilTest("greater", 0)

					gfx.setShader (gfx.newShader[[
				    vec4 effect(vec4 color, Image texture, vec2 textureCoords, vec2 screenCoords){
			        vec4 col = Texel(texture , textureCoords );
			        if(col.r>0 && col.r<1){
		            return vec4(vec3(col.r),1);
			        }else{
		            discard;
			        }
				    }
					]])
					gfx.draw(panel.f.canvas)
					gfx.setStencilTest()
				else
					gfx.setCanvas ({preCanvas, stencil = true})
					gfx.clear()
					gfx.stencil(function()
						gfx.setColor (1, 1, 1, 1)
						gfx.polygon("fill", panel.selection.shape)
					end, "replace", 1)
					gfx.setStencilTest("greater", 0)
					gfx.draw(panel.f.canvas)
					gfx.setStencilTest()
				end
				
				gfx.setCanvas()

				preCanvas:newImageData():encode("png","pre.png")
				gfx.setShader()
				panel.selection.canvas = newCanvas(mf(panel.selection.bbox.w), mf(panel.selection.bbox.h), panel.l.format)
				if LOVE then panel.selection.canvas:setFilter("nearest", "nearest")end
				panel.selection.canvas:renderTo(function()
					gfx.draw(preCanvas, -panel.selection.bbox[1], -panel.selection.bbox[2])
				end)

				gfx.setShader()
				preCanvas:release()
				
				panel.f.canvas:renderTo(function()
					gfx.setBlendMode ('replace')
					gfx.setColor (0, 0, 0, 0)
					gfx.polygon("fill", panel.selection.shape)
				end)
				
				gfx.setCanvas()
			end

			panel.selection.format = panel.l.format
			panel.selection.palette = panel.l.format=="r8" and vecPalette(panel.l.palette)	
			
			panel.selection.selected = true
			panel.selection.angle = 0
			panel.selection.scale = vec2(1)
			panel.selection.position = {x = panel.selection.bbox[1] + panel.selection.bbox.w / 2, y = panel.selection.bbox[2] + panel.selection.bbox.h / 2}
			panel.selection.diff = {x = panel.selection.position.x - panel.f.w / 2, y = panel.selection.position.y - panel.f.h / 2}
			panel.selection.offset = lume.clone(panel.selection.position)
			-- panel.selection.f = {x=panel.f.ox - panel.f.w , y=panel.f.oy - panel.f.h}
			panel.selection.quad = gfx.newQuad(0, 0, panel.selection.bbox.w, panel.selection.bbox.h, panel.selection.bbox.w, panel.selection.bbox.h)
			panel.selection.cut = false

		else
			panel.selection = {}
		end
	end
end

local p0, p1, p2, p3 = vec2(),vec2(),vec2(),vec2()
local function evaluateBezierFromSegmentPoint(cx,cy,bx,by,ax,ay)
	p1.x,p1.y = 0,0
	p1.x,p1.y = cx,cy -- control 
	p2.x,p2.x = bx,by -- baseline
	p3.x,p3.x = ax,ay -- segmentpoint
	local dx = p2:len()
	local bot,top = 0,1
	local normed = p2:normalize()
	local k = vec2.dot(p3,normed)
	local f = vec2.dot(p1,normed)
	if f>dx*0.8 or f<0+dx*0.2 then 
		return false
	end
	if k>dx or k<0 then 

		return false
	end
	local diff=1
	local mid
	-- print("k",k)
	for i=1,8,1 do
		mid = mc(0,(bot+top)/2,1)
		local pt = quadBezier(mid, p0, p1, p2)
		local dist = vec2.dot(pt,normed)
		-- print("	 mid",mid)
		-- print("  	       dist",dist)
		diff = math.abs(k-dist)/dx
		-- print("diff",diff)
		top = dist>k and mid or top
		bot = dist<k and mid or bot
		if i==8 then 
			return math.abs(vec2.dot(pt,normed:perpendicular()))
		end
	end
end

local function replaceSmoothedStrokeSegments(stroke,cuts)
	-- print("before",#stroke.line)
	for c,cut in lume.ripairs(cuts) do 
		for i=1,cut[2]-cut[1]-1,1 do 
			table.remove(stroke.line,cut[1]+1)
		end
		local a = stroke.line[cut[1]]
		local b = stroke.line[cut[1]+1]
		a[5],a[6]=cut[3][2][1],cut[3][2][2]
		b[3],b[4]=cut[3][3][1],cut[3][3][2]
		if animationPanel.debugView then  
			-- table.insert(animationPanel.f.strokes,{size=0.1, ends=1, color={1,0,1,1}, group="note", 
			-- 		line={{b[3],b[4]},{b[3]+1,b[4]+2},{b[3]-1,b[4]+2},{b[3],b[4]}}
			-- 	})
		end
	end	
	-- print("after",#stroke.line)
end
local function basicLine(x)
	return {x[1],x[2]}
end
function editor.smoothStroke(panel,stroke,smoothing,finish)
	local line = stroke.line
	local cuts = {}
	local a,b = vec2(),vec2()
	if #line<panel.strokeSmoothStart+3 then return end 
	-- bline = lume.map(line,basicLine)
	local wound = 0
	_beziertime = ltimer.getTime() 

	for l=panel.strokeSmoothStart,#line-1,1 do -- for each point on line 
		if l>panel.strokeSmoothStart+3  then 

			-- for each possible baseline from point
			-- for i=l+2,#line-1,2 do 
			-- 	-- print("  base")
			-- 	low1=i
			-- 	l2[1],l2[2] = line[i],line[i+1]

			a:set(line[l][1]-  line[l-1][1],line[l][2]-  line[l-1][2])
			b:set(line[l-1][1]-line[l-2][1],line[l-1][2]-line[l-2][2])
			wound = wound + (1-math.abs(vec2.dot(a:normalize(),b:normalize())))
			-- print(wound)
			if  wound>0.15 or (finish and l==#line-1) then 
				-- print(l,#line,wound)
				local section = splice(line,panel.strokeSmoothStart,l)
				print("#section",#section)
				local succ,pts=pcall(fitCurve,section,smoothing*10+3)
				if succ and pts then 
					wound= 0
					pts = pts[1]
					if animationPanel.debugView then 
						-- print("#pts",#pts)
						-- for p=2,#pts,1 do 
						-- 	local pt = pts[p]
						-- 	table.insert(animationPanel.f.strokes,{size=0.1, ends=1, color={1,0,0,1}, group="note", 
						-- 		line={{pt[1],pt[2]},{pt[1]+1,pt[2]+1},{pt[1]-1,pt[2]+1},{pt[1],pt[2]}}
						-- 	})
						-- 	table.insert(animationPanel.f.strokes,{size=0.1, ends=1, color={1,0,1,1}, group="note", 
						-- 		line={{pt[1],pt[2]},{pts[p-1][1],pts[p-1][2]},{pt[1],pt[2]}}
						-- 	})
						-- 	-- editor.refreshStrokes()
						-- end
					end
					table.insert(cuts,{panel.strokeSmoothStart,l,pts})
				else 
					print("failet")
				end
				panel.strokeSmoothStart=l+1
			end
		end
	end	
	replaceSmoothedStrokeSegments(stroke,cuts)
end

function editor.drawStroke(panel)

	if panel.l.format=="vector" and drawingPanel.tool~="brush" then 
		editor.refreshStrokes()
		if drawingPanel.tool == "select" then
			selectRegion(panel)
		end

	elseif panel.vector and drawingPanel.tool=="brush" then
		panel.drawVector = 0
		panel.f.strokePreview = nil 
		editor.refreshStrokes()
		
		if drawingPanel.pen.smoothing>0.01 then 
			editor.smoothStroke(panel,panel.stroke,drawingPanel.pen.smoothing,true)
		end
		local v = vec2(panel.brushCoords.ax,panel.brushCoords.ay)
		editor.insertStrokePoint(panel,panel.stroke,v,0)
		local tail = panel.stroke.line
		tail[#tail][3],tail[#tail][4] = tail[#tail][1],tail[#tail][2]
		tail[#tail][5],tail[#tail][6] = tail[#tail][1],tail[#tail][2]

	elseif panel.brushCanvas ~= nil then
		local dpb = drawingPanel.brush
		local data

		if drawingPanel.tool ~= "select" then
			editor.drawBrushTexture(panel, panel.brushCanvas)
		end

		if drawingPanel.tool == "select" then
			selectRegion(panel)

		else
			if panel.l.format=="r8" then 
				gfx.setShader ( shaders.r8 )
				gfx.setFilter(panel.f.canvas,"nearest")
				gfx.setFilter(panel.brushCanvas,"nearest")
				gfx.setBlendMode ('replace')
				shaders.r8:send("index",editor.paletteCheck(dpb.color.r, dpb.color.g, dpb.color.b)/255)
			else
				gfx.setShader ( shaders.unmul )
				gfx.setBlendMode ("alpha")
				gfx.setColor (dpb.color.r, dpb.color.g, dpb.color.b, 1)
				gfx.setFilter(panel.brushCanvas,drawingPanel.brush.antialias and "linear" or "nearest")
			end
			gfx.setCanvas (panel.f.canvas)
			
			gl.BlendEquation(gle.FUNC_ADD);
			gl.BlendFuncSeparate(gle.SRC_ALPHA,gle.ONE_MINUS_SRC_ALPHA,gle.ONE,gle.ONE_MINUS_SRC_ALPHA)

			gfx.draw(panel.brushCanvas)
			gfx.setShader ()
		end

		-- gfx.push("all")
		gfx.setCanvas()

		data = panel.f.canvas:newImageData()
		-- mapPixel(data,UnmultiplyGammaPixel)
		data:encode("png","tmp.png")

		data = panel.brushCanvas:newImageData()
		-- mapPixel(data,UnmultiplyGammaPixel)
		data:encode("png","tmp2.png")

		-- data:release()
		-- gfx.pop()
	end


end

function editor.paletteCheck(r,g,b)
	local g = g or r.g 
	local b = b or r.b
	local r = type(r)=="table" and r.r or r
	animationPanel.l.palette = animationPanel.l.palette or {}
	for c,color in ipairs(animationPanel.l.palette) do 
		if math.abs(color.r-r)<0.001 and math.abs(color.g-g)<0.001 and math.abs(color.b-b)<0.001 then 
			return c
		end
	end
	editor.addToPalette(animationPanel,{r=r,g=g,b=b,a=1})
	return #animationPanel.l.palette
end


function editor.addToPalette(panel,color)
	if panel.l.format~="r8" then return end
	print("ADDED")
	table.insert(panel.l.palette,deepcopy(color))
end


function editor.drawBrushTexture(panel, canv)
	if drawingPanel.brush.texture > 0 then
		-- local img = getImage(textures[drawingPanel.brush.texture])
		-- gfx.push("all")
		-- gfx.setCanvas (canv)
		-- gfx.setShader ()
		-- gfx.setBlendMode ('multiply')
		-- gfx.setColor (1, 1, 1, 1)
		-- gfx.draw (img, gfx.newQuad(panel.diff.x, panel.diff.y, canv:getWidth(), canv:getHeight(), img:getWidth(), img:getHeight()))
		-- gfx.pop()
		-- gfx.setFilter(canv,panel.filter)
	end
end
