
function editor.createNewModel(shape)
	editor.drawNewImage(shape)
	editor.createNewModelLayer(shape)
end

function editor.createNewModelLayer(shape)
	local data = {}
	local panel = animationPanel
	mkdir(ZIP_MODE and LINK_DIR or GAME_DIR,"images",panel.object.name,".models/")

	local id,meshName,texName,skelName   	= uuid(),"Untitled Mesh","Untitled Texture","Untitled Skeleton"

	if shape == "test" then 
		data = importIQM(editor.testModel.verts,editor.testModel.map,editor.testModel.tex)

		mkdir(ZIP_MODE and LINK_DIR or GAME_DIR,"images",panel.object.name,".textures/")
		if editor.testModel.texdir then 
			os.execute(os.copy().." \""..editor.testModel.texdir.."\" \""..GAME_DIR.."images/"..panel.object.name.."/.textures/\"")
			panel.l.texture = "project"
		end
		if editor.testModel.skeleton then 
			game.skeletons[id] = editor.testModel.skeleton 
		end
	end

	if shape == "Cube" or not shape then 
		local n = 50
		data.vertices = {
			vec3(-n,-n,-n),
			vec3( n,-n,-n),
			vec3( n,-n, n),
			vec3(-n,-n, n),
			vec3(-n, n,-n),
			vec3( n, n,-n),
			vec3( n, n, n),
			vec3(-n, n, n),
		}
		data.edges    = {
			{1,2},{2,3},{3,4},{4,1},
			{1,5},{2,6},{3,7},{4,8},
			{5,6},{6,7},{7,8},{8,5}
		}
		data.polygons = {
			{{1,4},{4,3},{3,2},{2,1}},
			{{1,1},{2,6},{6,9}, {5,5}},
			{{2,2},{3,7},{7,10},{6,6}},
			{{3,3},{4,8},{8,11},{7,7}},
			{{4,4},{1,5},{5,12},{8,8}},
			{{5,9},{6,10},{7,11},{8,12}},
		}
	end
	
	if shape == "Cylinder" then 
		
	end

	data.id = id
	panel.object.models = panel.object.models or {}
	panel.object.models[id] = data

	if shape == "test" then 
		panel.repose = true
		if editor.testModel.anims then 
			local switch
			for a,anim in pairs(editor.testModel.anims) do 
				local animation = newAnimation(a,false,true)
				switch = animation.key
				animation.layers[1].data = panel.object.models[id]
				animation.layers[1].type = "model"
				animation.layers[1].skeleton = editor.testModel.skeleton --game.skeletons[id]
				for f,frame in ipairs(anim) do 
					animation.layers[1].frames[f] = animation.layers[1].frames[f] or editor.defaultFrame(panel)
					animation.layers[1].frames[f].pose = frame
				end
			end
			print("anid",panel.anims)

			print("anim",switch)
			editor.switchAnimation(switch)
			panel.anims.default = nil
			panel.setDefault = switch
		end
	else 
		panel.l.data = panel.object.models[id]
		panel.l.type = "model"
	end

end

function importIQM(verts,map,tex)
	local vertices,edges,polygons={},{},{}
	local overwriteColors = tex

	local isEdge=function(a,b) 
		for e=1,#edges,1 do 
			if (edges[e][1]==a and edges[e][2]==b) or (edges[e][2]==a and edges[e][1]==b) then 
				return e
			end
		end
		return false
	end

	local addEdge = function(p1,p2)
		local edge = isEdge(p1,p2) 
		if edge then 
			return edge
		end
		table.insert(edges,{p1,p2})
		return #edges
	end

	for v=1,#verts,1 do 
		table.insert(vertices,vec3(verts[v]))
	end
	
	-- print("vec1",verts[1])
	-- print("vec2",vec3(verts[1]))

	local w,h = tex:getDimensions()

	for i=1,#map,3 do 
		local m1,m2,m3 = map[i],map[i+1],map[i+2]
		local e1,e2,e3 = addEdge(m1,m2),addEdge(m2,m3),addEdge(m3,m1)
		local c1,c2,c3 
		local u1,u2,u3, v1,v2,v3 

		if overwriteColors then 
			-- print("verts[m1][5]",verts[m1][5],verts[m1][6])
			-- print(w,h)
			c1,c2,c3 = 
				{tex:getPixel(verts[m1][5]*w,verts[m1][6]*h)},
				{tex:getPixel(verts[m2][5]*w,verts[m2][6]*h)},
				{tex:getPixel(verts[m3][5]*w,verts[m3][6]*h)}
			u1,v1 = 1,1
			u2,v2 = 1,1
			u3,v3 = 1,1
		else
			c1,c2,c3 = 
				{verts[m1][7],verts[m1][8],verts[m1][9]},
				{verts[m2][7],verts[m2][8],verts[m2][9]},
				{verts[m3][7],verts[m3][8],verts[m3][9]}

			u1,v1 = verts[m1][5],verts[m1][6] 
			u2,v2 = verts[m2][5],verts[m2][6] 
			u3,v3 = verts[m3][5],verts[m3][6] 
		end

		table.insert(polygons,{
			{m1,e1,  u1,v1,  c1[1],c1[2],c1[3],1, unpack(splice(verts[m1],11))},
			{m2,e2,  u2,v2,  c2[1],c2[2],c2[3],1, unpack(splice(verts[m2],11))},
			{m3,e3,  u3,v3,  c3[1],c3[2],c3[3],1, unpack(splice(verts[m3],11))}
		})
	end

	print("polys",#polygons)

	return {vertices=vertices,edges=edges,polygons=polygons},anims
end

function setMeshReferences(data)
	if type(data)~="table" then return end

	data.refs 					= data.refs or {nocopy=true}

	data.refs.edges 		= data.refs.edges or {}
	data.refs.polygons 	= data.refs.polygons or {}
	data.refs.normals 	= data.refs.normals or {}
	data.refs.prenorm 	= data.refs.prenorm or {}
	data.refs.origins 	= data.refs.origins or {}


	if not vec3.is_vec3(data.vertices[1]) then 
		for v,vert in ipairs(data.vertices) do 
			data.vertices[v]=vec3(vert)
		end
	end
	

	for e=1,#data.edges,1 do 
		data.refs.edges[e] = data.refs.edges[e] or {}
		data.refs.edges[e][1]=data.vertices[data.edges[e][1]]
		data.refs.edges[e][2]=data.vertices[data.edges[e][2]]
	end
	

	local poly,loop,ref 
	for p=1,#data.polygons,1 do 
		poly = data.polygons[p]
		poly.points = poly.points or {nocopy=true}
		data.refs.polygons[p] = data.refs.polygons[p] or {}
		for l=1 ,#poly, 1 do 
			loop = poly[l]
			data.refs.polygons[p][l] = data.refs.polygons[p][l] or {}
			ref = data.refs.polygons[p][l]
			 
			ref[1] = data.vertices[loop[1]]
			ref[2] = data.edges[loop[2]]
			
			if not ref[3] then
				for i=3,#loop,1 do 
					ref[i] = loop[i]
				end
			end
		end
	end
end

function trisToQuads()
	-- calc normals
	-- create connectivity table
	-- compare shape angles created at edge, choose quad with angles closest to right angles
	-- queue join edge for deletion
	-- remove triangles from polys1
	-- insert new face to polys2
	-- concat polys1+2
end

function updateMeshData(data,edit,panel)
	if edit and not panel.open then return end

	local hr,hg,hb = 0.9,0.7,0.3
	local br,bg,bb = 0,0,0

	bench.push("premake")
	if edit then 
		
		data.dotVerts  	= data.dotVerts or {nocopy=true}
		data.lineVerts  = data.lineVerts or {nocopy=true}

		local line

		local check, colorDot = (panel and panel.selectedVerts),false
		for v=1,#data.vertices,1 do 
			colorDot = check and panel.vertsSelected[v]

			data.dotVerts[v] = data.dotVerts[v] or {}
			data.dotVerts[v][1] = data.vertices[v].x
			data.dotVerts[v][2] = data.vertices[v].y
			data.dotVerts[v][3] = data.vertices[v].z
			data.dotVerts[v][4] = 1
			if colorDot then 
				data.dotVerts[v][5],data.dotVerts[v][6],data.dotVerts[v][7] = hr,hg,hb
			else 
				data.dotVerts[v][5],data.dotVerts[v][6],data.dotVerts[v][7] = br,bg,bb
			end
		end

		local v,v1,v2,k,color = 0
		for e=1 , #data.edges,1 do 
			if panel and panel.selectedVerts then 
				v1,v2 = panel.vertsSelected[data.edges[e][1]],panel.vertsSelected[data.edges[e][2]]
				if v1 and v2 and not inTable(panel.selectedEdges,e) then 
					panel.selectedEdges[#panel.selectedEdges] = e
				end
			else 
				v1,v2 = false,false
			end

			line = data.refs.edges[e]

			for i=1,3,1 do 
				v=v+1
				k=i==2 and 2 or 1
				if k==2 then 
					color = v2 
				else 
					color = v1
				end
				data.lineVerts[v] = data.lineVerts[v] or {}
				data.lineVerts[v][1] = line[k].x
				data.lineVerts[v][2] = line[k].y
				data.lineVerts[v][3] = line[k].z
				data.lineVerts[v][4] = 1
				if color then 
					data.lineVerts[v][5],data.lineVerts[v][6],data.lineVerts[v][7] = hr,hg,hb
				else 
					data.lineVerts[v][5],data.lineVerts[v][6],data.lineVerts[v][7] = br,bg,bb
				end
			end
		end


		local poly 
		for p=1,#data.polygons,1 do
			poly=data.polygons[p]

			if data.refs.origins[p] then 
				line = {data.refs.origins[p],data.refs.origins[p]+data.refs.prenorm[p]*5}

				table.insert(data.lineVerts, {line[1].x,line[1].y,line[1].z,1, 0,0, 0,0,1})
				table.insert(data.lineVerts, {line[2].x,line[2].y,line[2].z,1, 0,0, 0,0,1})
				table.insert(data.lineVerts, {line[1].x,line[1].y,line[1].z,1, 0,0, 0,0,1})

				line = {data.refs.origins[p],data.refs.origins[p]+data.refs.normals[p]*10}

				table.insert(data.lineVerts, {line[1].x,line[1].y,line[1].z,1, 0,0, 0,0,0})
				table.insert(data.lineVerts, {line[2].x,line[2].y,line[2].z,1, 0,0, 0,0,0})
				table.insert(data.lineVerts, {line[1].x,line[1].y,line[1].z,1, 0,0, 0,0,0})
			end


			local looped = true
			for l=1,#poly,1 do 
				if not panel.vertsSelected[poly[l][1]] then 
					looped = false 
				end
			end
			if  panel.selectMode[3] and looped and not panel.facesSelected[p] then 
				table.add(panel.selectedFaces,p)
			end
		end

	else 
		data.dotVerts  	= nil
		data.lineVerts  = nil
	end

	bench.pop("premake")

	bench.push("make verts n tris")
	if (not data.tris) or (not data.verts) or data.changed then 
		data.tris 			= {nocopy=true}
		data.verts  		= {nocopy=true}
	end

	local plane = {position=vec3(),normal=vec3()}
	local angle,axis,rot,rotted=0,vec3(),mat4(),vec3()
	local vec = vec3()
	local t,v = 0,0
	local p1,p2,p3
	for p,poly in ipairs(data.refs.polygons) do 
		local r,g,b = 1,1,1
		local shade = false

		if panel and panel.l and panel.selectedFaces and lume.find(panel.selectedFaces,p) then 
			r,g,b = 1,0.8,0.4
			shade = true
		end
		
		if #poly==3 then 
			if poly[1] and poly[1][1] then
				t = t + 1 
				data.tris[t] = data.tris[t] or {}

				for i=1,3,1 do 
					data.verts[v+i]	= data.verts[v+i]	or {}
					vert 						= data.verts[v+i]
					pt 							= poly[i]
					vert[1],vert[2],vert[3],vert[4] = pt[1].x,pt[1].y,pt[1].z,1
					data.tris[t][i]=pt[1]
					for a=3,#pt,1 do 
						vert[a+2] = pt[a]
					end
					if shade then 
						vert[7],vert[8],vert[9] = vert[7]*(r)+0.2,vert[8]*(g)+0.2,vert[9]*(b)+0.2
					end
				end

				data.tris[t][4]=p
				v=v+3
			end
		else

			poly.shape = poly.shape or {}
			poly.points = poly.points or {}

			lume.clear(poly.shape)
			lume.clear(poly.points)

			for l,loop in ipairs(poly) do 
				poly.points[l]=loop[1]
			end

			local checkflip = true
			local flipped={}
			local flip = false

			local ys
			local keys
			local normal = vec3()

			


			plane.position,plane.normal = plane_from_points(poly.points)
			
			if plane.normal then 

				angle = math.acos(axes.y:dot(plane.normal) / (axes.y:len() * plane.normal:len()))
				axis  = axes.y:cross(plane.normal)
				local base = angle>0 and mat4.from_angle_axis(angle, axis) or blankMat
				rot = rot or mat4()
				print("trr",rot)

				rot = rot:translate(base,-plane.position)

				print("rotor",tostring(base),tostring(rot))
				
				ys = {}

				for l,loop in ipairs(poly) do
					rotted = rot*loop[1]
					poly.shape[l*2-1] = rotted.x
					poly.shape[l*2]   = rotted.z
					table.insert(ys,rotted:clone())
				end

				success,triangles = pcall(mth.triangulate,poly.shape)
				if success then 
					
					for _,tri in ipairs(triangles) do 
						t = t + 1 
						data.tris[t] = {}
						
						keys,keys2,keys3 = {}

						for i=1,3,1 do
							v = v + 1 
							vec.x,vec.y,vec.z = tri[i*2-1],0,tri[i*2]
							for j=1,#ys,1 do 
								if math.sdist(vec.x,vec.z,ys[j].x,ys[j].z)<0.5 then 
									vec.y = ys[j].y 
									keys[#keys+1]= j
									break
								end
							end
							vec = -rot*vec
							data.verts[v] = {vec.x,vec.y,vec.z,1, 0,0, r,g,b,1}
							data.tris[t][i] = vec:clone()
						end

						keys2 = reverse(lume.sort(keys))
						keys3 = { lume.find(keys2,keys[1]), lume.find(keys2,keys[2]), lume.find(keys2,keys[3]) }

						flipped[1],flipped[2],flipped[3]=lume.clone(data.verts[v-2]),lume.clone(data.verts[v-1]),lume.clone(data.verts[v])
						data.tris[t]={ data.tris[t][keys3[1]], data.tris[t][keys3[2]], data.tris[t][keys3[3]] }
						normal=cpml.mesh.normal(data.tris[t])
						for i,v in ipairs(flipped) do
							flipped[i][11]=normal.x
							flipped[i][12]=normal.y
							flipped[i][13]=normal.z
						end
						data.verts[v-2],data.verts[v-1],data.verts[v] = flipped[keys3[1]],flipped[keys3[2]],flipped[keys3[3]]

						data.tris[t][4] = p
					end

					
				end
			end
		end
	end

	bench.pop("make verts n tris")
end

function editor.meshTools(panel)
	if not panel.l.remodel then return end
	trace("")
	trace("verts: "..tostring(#(panel.selectedVerts or empty)).." / "..tostring(#panel.l.data.vertices))
	trace("edges: "..tostring(#(panel.selectedEdges or empty)).." / "..tostring(#panel.l.data.edges))
	trace("faces: "..tostring(#(panel.selectedFaces or empty)).." / "..tostring(#panel.l.data.polygons))
	trace("")
		mouse.set(function() 
			if not stageHovered then 
				return 
			end

			if panel.meshTransformMatrix then 
				editor.stopMeshTransform(panel)
				return 
			end

			panel.selectedVerts  		= shiftDown and panel.selectedVerts  		or {}
			panel.selectedEdges  		= shiftDown and panel.selectedEdges 	  or {}
			panel.selectedFaces 		= shiftDown and panel.selectedFaces  		or {}

			local clickedVert=false
			panel.l.updots = true

			if panel.selectMode[1] then 
				editor.selectVerts(panel,true)
			end

			if panel.selectMode[3] and editor.intersectTri and editor.intersectTri[4] and not clickedVert then 
				local p = editor.intersectTri[4]

				if panel.selectMode[1] then 
					for l,loop in ipairs(panel.l.data.polygons[p]) do
						table.add(panel.selectedVerts,loop[1])
					end
				elseif panel.selectMode[2] then 

				else 
					print(inspect(panel.selectedFaces))
					addrem(panel.selectedFaces,p)
					print(inspect(panel.selectedFaces))
				end
			end
		end)

	if editor.selectingRect and selectBounds.w>8 and  selectBounds.h>8 then 
		editor.selectVerts(panel)
		if mouse.moved then 
			panel.l.updots = true
		end
	end



	panel.selectModeDraws = {
	 		function()
	 			gfx.circle("fill",panel.row/2,panel.row/2,2)
	 		end,
	 		function()
	 			gfx.line(6,6,panel.row-7,panel.row-7)
	 		end,
	 		function()
	 			gfx.setLineStyle("rough")
	 			gfx.rectangle("fill",5,5,panel.row-10,panel.row-10,2)
	 		end,
	 	}


	gfx.push()
		gfx.translate(0,panel.y-3)
		for d,draw in ipairs(panel.selectModeDraws) do
			local selected = panel.selectMode[d]
			gfx.push()
			local hovered = false 
			if mouseIn({x=(d-1)*18,y=panel.y+1,w=16,h=16}) then 
				hovered = true
				editor.setToolTip(({"vertices","edges","faces"})[d])
				mouse.set(function()
					editor.selectMeshSelectMode(panel,d)
				end)
			end
			gfx.translate((d-1)*18,0)
			gfx.setColor(0.1,0.1,0.1,(selected or hovered) and 0.7 or 0.2)
			gfx.rectangle("fill",2,2,16,16,4)
			gfx.setColor(1,1,1,selected and 1 or 0.1)
			draw()
			gfx.pop()
		end
	gfx.pop()

	for t,toggle in ipairs(panel.meshViewToggles) do
		editor.drawButton({
			x				=		16*4+(t-1)*18,
			y				=		panel.y-2,
			w   		= 	panel.row-2,
			h 			= 	panel.row-2,
			img     =   toggle,
			tip 		= 	toggle,
			imgScaleOverride=   1,
			a  	= 	panel[panel.meshViewToggles[t]]  and 0.8 or 0.2,
			func 		= 	function() 
				panel[panel.meshViewToggles[t]] =  not panel[panel.meshViewToggles[t]] 
			end
		})
	end

	for o,option in ipairs(panel.meshModeNames) do
		local x = 16*8+(o-1)*18
		local img = option.."_"..panel[option.."Mode"]
		panel[option.."Button"]= {
			tip 		=  	option.." mode",
			w   		= 	panel.row-2,
			h 			= 	panel.row-2,
			x 			=   x,
			y 			=   panel.y-2,
			img     =   img,
			imgScaleOverride=   1,
			release = 	 function()
				if not panel.listOpen then 
					local items = {}
					local modes = panel[option.."Modes"]
					table.insert(items, {name=option.." mode",static=true})
					for m,mode in ipairs(modes) do 
						table.insert(items, {{size=-1,static=true,img=option.."_"..mode},{name=mode, func=function() 
							panel[option.."Mode"] = mode
						end, col ={a=panel[option.."Mode"]==mode and 0.5 or 0}}})
					end
					editor.openContextMenu (items,{x=x,y=panel.y-(lume.count(modes)+1.7)*20,width=200})
				end
			end
		}
		editor.drawButton(panel[option.."Button"])
	end

	panel.selectedVerts  		= panel.selectedVerts  		or {}
	panel.vertsSelected  		= panel.vertsSelected  		or {}
	panel.selectedEdges  		= panel.selectedEdges  		or {}
	panel.edgesSelected  		= panel.edgesSelected  		or {}
	panel.selectedFaces 		= panel.selectedFaces 		or {}
	panel.facesSelected 		= panel.facesSelected 		or {}

	panel.meshSelections = {
		panel.selectedVerts,
		panel.vertsSelected,
		panel.selectedEdges,
		panel.edgesSelected,
		panel.selectedFaces,
		panel.facesSelected
	}

	editor.intersectTri = nil
	
	if panel.selectedVerts[1] then 
		trace("selected verts: "..tostring(panel.l.data.vertices[panel.selectedVerts[1]]))
	end

	for i=1,#panel.vertsSelected,1 do panel.vertsSelected[i]=false 													end
	for i=1,#panel.selectedVerts,1 do panel.vertsSelected[panel.selectedVerts[i]]=true      end

	for i=1,#panel.facesSelected,1 do panel.facesSelected[i]=false 													end
	for i=1,#panel.selectedFaces,1 do panel.facesSelected[panel.selectedFaces[i]]=true      end

	gfx.setColor(1,1,1,1)
	gfx.setLineWidth(4)
	gfx.setLineJoin("bevel")
	editor.updateMeshTransform(panel)
end

function editor.selectVerts(panel,single)
	local size = 8
	local sb = single and {x=mouse.x-size,y=mouse.y-size,w=size*2,h=size*2} or selectBounds
	local n,f = {},{}

	n.a,f.a=getScreenRay(sb.x, 			sb.y		 ) -- tl
	n.b,f.b=getScreenRay(sb.x+sb.w,	sb.y		 ) -- tr
	n.c,f.c=getScreenRay(sb.x+sb.w,	sb.y+sb.h) -- br
	n.d,f.d=getScreenRay(sb.x,			sb.y+sb.h) -- bl
	
	local t = getTransform(panel.instance.models[panel.layer])
	
	for p,pt in pairs(n) do
		n[p] = -t*n[p]
		f[p] = -t*f[p]
	end

	local frustum = {
		top  	 = cpml.mesh.plane_from_triangle({f.a,f.b,n.a}),
		bottom = cpml.mesh.plane_from_triangle({f.c,f.d,n.d}),
		left   = cpml.mesh.plane_from_triangle({f.d,f.a,n.d}),
		right  = cpml.mesh.plane_from_triangle({f.b,f.c,n.b}),
	}

	local contained = true
	local dist = 0
	local closest = (not panel.seeThru and editor.modelIntersect) and vec3.dist(editor.modelIntersect,zcam.pos) or 999999
	local close = closest
	local closestVert

	--log(closest)

	for v,vert in ipairs(panel.l.data.vertices) do
		contained = true
		for s,side in pairs(frustum) do
			if contained then 
				dist = cpml.mesh.signed_distance(vert,side)
				if dist>0 then 
					contained=false 
				end
			end
		end
		if contained then 
			if single then 
				close = vec3.dist(zcam.pos,-(t*vert))
				log("close",round(close),round(closest))
				if close<closest+10 then 
					closest=close
					closestVert=v
				end
			else
				table.add(panel.selectedVerts,v)
			end
		end
	end

	if single then 
		if shiftDown then 
			addrem(panel.selectedVerts,closestVert)
		else
			table.add(panel.selectedVerts,closestVert)
		end
	end
end

function editor.toggleMeshSelect(panel)
	if #panel.selectedVerts==0 or #panel.selectedEdges==0 or #panel.selectedVerts==0 then 
		for v,vert in ipairs(panel.l.data.vertices) do 
			table.insert(panel.selectedVerts,v)
		end
	else
		editor.deselectMesh(panel)
	end
end

function editor.invertMeshSelect(panel)

end

function editor.deselectMesh(panel)
	for s,selection in ipairs(panel.meshSelections) do 
		lume.clear(selection)
	end
end

function editor.startMeshTranslate(panel)
	editor.startMeshTransform(panel)
	panel.meshTransform.translation = vec3()
	panel.meshTransform.mode = "Translate"
end

function editor.updateMeshTranslate(panel)
	local p1 = getCameraPlaneCoords(panel.meshTransform.origin,getCursorRay(panel.meshTransform.mouse.x,panel.meshTransform.mouse.y))
	local p2 = getCameraPlaneCoords(panel.meshTransform.origin,getCursorRay(mouse.x,mouse.y))
	if not p1 then return end
	panel.meshTransform.translation = p1-p2
	panel.meshTransformMatrix = panel.meshTransformMatrix:translate(blankMat,panel.instance.orientation*panel.meshTransform.translation)
	local screenOrigin = camera.project(-panel.instance.transform*-panel.meshTransformMatrix*panel.meshTransform.origin)
	gfx.line(panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y,screenOrigin.x,screenOrigin.y)
end


function editor.startMeshRotate(panel)
	editor.startMeshTransform(panel)
	panel.meshTransform.rotation = 0
	panel.meshTransform.mode = "Rotate"
end

function editor.updateMeshRotate(panel)
	local screenAngle =  vec2.angle_to(panel.meshTransform.screenOrigin,mouse)
	local angle = screenAngle-panel.meshTransform.screenAngle+pi*2
	local diff = angDiff (screenAngle,panel.meshTransform.screenAngle)

	local e1,e2 =  panel.meshTransform.screenAngle,panel.meshTransform.screenAngle+angle
	local a1,a2 = math.min(e1,e2),math.max(e1,e2)

	local az = zcam.pos - panel.meshTransform.origin
	local axis = zcam.lookDirection
	
	--gfx.circle("line",panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y,32)
	gfx.push()
	gfx.translate(panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y)
	gfx.rotate(panel.meshTransform.screenAngle+pi)
	gfx.arc("line",0,0,30,0,-diff)
	gfx.circle("line",0,0,30)
	gfx.pop()
	gfx.line(panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y,mouse.x,mouse.y)

	 panel.meshTransformMatrix = panel.meshTransformMatrix
	 	:translate(panel.meshTransformMatrix
	 		:rotate(panel.meshTransformMatrix
	 			:translate(blankMat,panel.meshTransform.origin),-angle,axis),-panel.meshTransform.origin)
end


function editor.startMeshScale(panel)
	editor.startMeshTransform(panel)
	panel.meshTransform.scale = vec3(1)
	panel.meshTransform.mode = "Scale"
end

function editor.updateMeshScale(panel)
	local dist = vec2.dist(panel.meshTransform.screenOrigin,mouse)
	panel.meshTransform.scale = vec3(dist/panel.meshTransform.screenDist)

	gfx.circle("line",panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y,8)
	gfx.line(panel.meshTransform.screenOrigin.x,panel.meshTransform.screenOrigin.y,mouse.x,mouse.y)

	panel.meshTransformMatrix = panel.meshTransformMatrix
		:translate(panel.meshTransformMatrix
			:scale(panel.meshTransformMatrix
				:translate(blankMat,panel.meshTransform.origin),panel.meshTransform.scale),-panel.meshTransform.origin)
end

function editor.startMeshInset(panel)
	editor.startMeshTransform(panel)
	local center = {}
	local faceNormal = vec3(0,1,0)
	local edgeNormal,vertNormal 
	panel.meshTransform.mode = "Inset"
	for f,face in ipairs(panel.selectedFaces) do 
		local poly = panel.l.data.refs.polygons[face]
		local poly2 = panel.l.data.polygons[face]
		local prevEdgeDir = poly[#poly][2][2]-poly[#poly][1]
		for l,loop in ipairs(poly) do
			local edgeDir = loop[2][2]-loop[1]
			vertNormal = vec3.cross(prevEdgeDir+edgeDir)
			local newVertex = loop[2][2]+vertNormal*5

			table.insert(panel.l.data.vertices,					newVertex)
			table.insert(panel.l.data.edges,						{poly2[face][l][1], #panel.l.data.vertices})

			if l>1 then 
				table.insert(panel.l.data.edges,					{#panel.l.data.vertices-1,#panel.l.data.vertices})
				table.insert(panel.l.data.polygons[face],	{poly2[face][l][1], #panel.l.data.edges})
			end

			table.insert(panel.l.data.polygons[face],		{poly2[face][l][1], #panel.l.data.edges})
			table.insert(panel.l.data.polygons[face],		{poly2[face][l][1], #panel.l.data.edges})

			prevEdgeDir = edgeDir
		end
	end
end

function editor.updateMeshInset(panel)

end

function editor.startMeshExtrude(panel)
	panel.pushUndoState()
	panel.selectedVerts={}

	for f,face in ipairs(panel.selectedFaces) do 
		
		local poly = panel.l.data.polygons[face]
		local edges= panel.l.data.edges
		local firstVert=#panel.l.data.vertices+1 
		local firstEdge=#panel.l.data.edges+1 
		local topFace = {}
		local sideFaces={}


		for l,loop in ipairs(poly) do  
			table.insert(panel.l.data.vertices,		panel.l.data.vertices[loop[1]]:clone())
			table.insert(panel.selectedVerts, 	#panel.l.data.vertices)
			table.insert(panel.l.data.edges,			{loop[1], #panel.l.data.vertices})
			table.insert(panel.l.data.edges,			{#panel.l.data.vertices, l==#poly and firstVert or #panel.l.data.vertices+1})

			table.insert(topFace, 								{#panel.l.data.vertices, #panel.l.data.edges})

			local sideFace = {}

			table.insert(sideFace, {poly[l<#poly and l+1 or 1][1], 	l<#poly and #panel.l.data.edges+1 or poly[1][2]})
			table.insert(sideFace, {l==#poly and firstVert or #panel.l.data.vertices+1, 		#panel.l.data.edges})
			table.insert(sideFace, {#panel.l.data.vertices, 			#panel.l.data.edges-1})
			table.insert(sideFace, {loop[1], 							 	poly[l<#poly and l+1 or 1][2]		})
			
			table.insert(sideFaces,sideFace)	
		end

		table.remove(panel.l.data.polygons,face)
		table.insert(panel.l.data.polygons,topFace)

		for s=1,#sideFaces,1 do 
			table.insert(panel.l.data.polygons, sideFaces[s])	
		end
	end


	panel.selectedFaces={}

	editor.startMeshTranslate(panel)
end

function oppositeVertex(v,e)
	return v == e[1] and e[2] or e[1]
end

function editor.startMeshTransform(panel)
	if not keypressed("e") then 
		panel.pushUndoState() 
	end

	for a,axis in ipairs({"x","y","z"})do
		if keypressed(axis) then 
			if panel.axisName == axis then
				local baseAxis = axes[axis]
				
			else
				panel.axisName = axis 
			end

			if panel.transformMode=="global" then 
				panel.axis = baseAxis
			elseif panel.transformMode=="local" then 
				panel.axis = baseAxis
			elseif panel.transformMode=="normal" then 
				panel.axis = baseAxis
			end
		end
	end
 
	panel.meshTransformMatrix = mat4()
	panel.meshTransform = {mouse = vec2(mouse) }
	panel.selectedVertices = panel.selectedVertices or {}
	lume.clear(panel.selectedVertices)
	
	if panel.selectMode[3] and #panel.selectedFaces>0 then
		for f,face in ipairs(panel.selectedFaces) do
			for l,loop in ipairs(panel.l.data.polygons[face]) do
				if panel.selectedVerts and loop[1] then 
					table.add(panel.selectedVerts,loop[1])
				end
			end
		end
	end

	local sum = vec3()
	for v,vert in ipairs(panel.selectedVerts) do
		panel.selectedVertices[v] = panel.l.data.vertices[vert]:clone()
		sum = sum + panel.selectedVertices[v]
	end

	panel.meshTransform.origin = sum/#panel.selectedVerts
	panel.meshTransform.screenOrigin = camera.project(-panel.instance.transform*panel.meshTransform.origin)
	panel.meshTransform.screenDist  = vec2.dist(panel.meshTransform.screenOrigin,mouse)
	panel.meshTransform.screenAngle  = vec2.angle_to(panel.meshTransform.screenOrigin,mouse)
end

function editor.updateMeshTransform(panel)
	if not panel.meshTransformMatrix then return end

	editor["updateMesh"..panel.meshTransform.mode](panel)

	local a,b = panel.meshTransformMatrix
	for v,vert in ipairs(panel.selectedVerts) do  
		b = panel.selectedVertices[v]
		if b then 
			--trace(panel.l.data.vertices[v])
			panel.l.data.vertices[vert].x = b.x * a[1] + b.y * a[5] + b.z * a[9]  + a[13]
			panel.l.data.vertices[vert].y = b.x * a[2] + b.y * a[6] + b.z * a[10] + a[14]
			panel.l.data.vertices[vert].z = b.x * a[3] + b.y * a[7] + b.z * a[11] + a[15]
		end
	end

	panel.transformer.visible=false
end

function editor.stopMeshTransform(panel)
	panel.meshTransformMatrix = nil
	panel.meshTransform.mode = nil
	panel.l.updots = true
end

function editor.selectMeshSelectMode(panel,i)
	if shiftDown then 
		if not panel.selectMode[i] or lume.count(panel.selectMode , function(x) return x end) > 1 then 
			panel.selectMode[i] = not panel.selectMode[i]
		end
	else
		panel.selectMode = {false,false,false}
		panel.selectMode[i]=true
	end
	panel.l.updots = true
end



