function UnmultiplyGammaPixel(x, y, r, g, b, a)
	r, g, b = mth.gammaToLinear(r, g, b)
	r = (r / a)
	g = (g / a)
	b = (b / a)
	r, g, b = mth.linearToGamma(r, g, b)
	return r, g, b, a
end

-- _test_line = _test_line or {}
-- if keyDown("i") and mf(time*5)~=mf(time*5+main_dt*5) then
--  table.insert(_test_line,mouse.x)
--  table.insert(_test_line,mouse.y)
-- end
-- gfx.setColor(1,0,0,1)
-- if #_test_line>3 then
--  gfx.line(_test_line)
--  splits = splitPolyLine(_test_line)
--  gfx.push()
--  for s,split in ipairs(splits)do
--    gfx.translate(300,0)
--    if #split>3 then
--      gfx.polygon("fill",split)
--    end
--  end
--  gfx.pop()
-- end

-- local boiserie
-- function createDepthMap(path,name)
--   boiserie=boiserie or {width=1000,height=1000}
--   if lfs.fileExists(LINK_DIR..path..name..".obj") then
--     boiserie.verts = obj_loader(path..name..".obj")
--     scene_calcVertNormals(boiserie.verts,nil,nil,nil,nil,5)
--     local first = boiserie.verts[1]
--     boiserie.t,boiserie.l,boiserie.r,boiserie.b = first[3],first[1],first[1],first[3]
--     print(#boiserie.verts)
--     print(inspect(boiserie.verts[1000]))
--     for v=1,#boiserie.verts,1 do
--       boiserie.t=boiserie.verts[v][3]<boiserie.t and boiserie.verts[v][3] or boiserie.t
--       boiserie.l=boiserie.verts[v][1]<boiserie.l and boiserie.verts[v][1] or boiserie.l
--       boiserie.b=boiserie.verts[v][3]>boiserie.b and boiserie.verts[v][3] or boiserie.b
--       boiserie.r=boiserie.verts[v][1]>boiserie.r and boiserie.verts[v][1] or boiserie.r
--     end
--     boiserie.width,boiserie.height = boiserie.r-boiserie.l,boiserie.b-boiserie.t
--     local scale = 1

--     print(boiserie.r,boiserie.l,boiserie.b,boiserie.t)
--     print(boiserie.width,boiserie.height)

--     boiserie.out = newCanvas(boiserie.width*scale,boiserie.height*scale)
--     boiserie.depthMap = newCanvas(boiserie.width*scale,boiserie.height*scale)
--     boiserie.normalMap = newCanvas(boiserie.width*scale,boiserie.height*scale)
--     boiserie.mesh = gfx.newMesh(zformat,boiserie.verts,"triangles")
--     gfx.push("all")
--       gfx.setShader(gfx.newShader[[
--         #pragma language glsl3
--         #ifdef VERTEX
--         attribute vec3 VertexNormal;
--         out vec3 vnorm;
--         vec4 position(mat4 transform_projection, vec4 vertex_position) {
--           vnorm = VertexNormal;
--           return transform_projection*vec4(vertex_position.x,vertex_position.z,8-vertex_position.y,vertex_position.w);
--         }

--         #endif

--         #ifdef PIXEL
--         in vec3 vnorm;
--         void main() {
--           love_Canvases[0] = vec4(vec3(gl_FragCoord.z),1);
--           love_Canvases[1] = vec4((vnorm+1)*0.5,1);
--         }

--         #endif
--       ]])
--       gfx.setColor(1,1,1,1)
--       gfx.setCanvas({boiserie.depthMap,boiserie.normalMap,depth=true})
--       gfx.setMeshCullMode("front")
--       gfx.setDepthMode("less",true)
--       gfx.draw(boiserie.mesh,-boiserie.l*scale,-boiserie.t*scale,0,scale,scale)
--       combineMaps = gfx.newShader[[
--         #pragma language glsl3
--         #ifdef VERTEX
--         vec4 position(mat4 transform_projection, vec4 vertex_position) {
--           return transform_projection*vertex_position;
--         }
--         #endif
--         #ifdef PIXEL
--         uniform sampler2D depthMap;
--         vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
--           vec2 tc2 = vec2(tc.x,1-tc.y);
--           float dm = Texel(depthMap,tc2).r;
--           return vec4(Texel(tex,tc2).rgb,dm);
--         }
--         #endif
--       ]]
--       combineMaps:send("depthMap",boiserie.depthMap)
--       gfx.setShader(combineMaps)
--       gfx.setCanvas(boiserie.out)
--       gfx.draw(boiserie.normalMap)
--       gfx.setCanvas()
--       boiserie.data = boiserie.out:newImageData()
--       boiserie.data:mapPixel(UnmultiplyGammaPixel)
--       boiserie.data:encode("tga",name..".tga")
--       os.rename(SAVE_DIR..name..".tga",GAME_DIR..path..name..".tga")
--     gfx.pop()
--     boiserie.depthMap:release()
--     boiserie.normalMap:release()
--     boiserie.out:release()
--     boiserie.mesh:release()
--     print("output depth/normals for"..name)
--     boiserie.verts=nil
--     collectgarbage()
--     collectgarbage()
--   end
-- end

-- function createBoiserieMaps()
--   for i=0,30, 1 do
--     createDepthMap("models/architecture/boiseries/",string.format("boiserie_%02d",i))
--   end
-- end

-- if game.testpolys and #game.testpolys>0 then
--  local s=24
--  for p,poly in ipairs(game.testpolys)do
--    if #poly>1 then
--      gfx.push()
--      gfx.scale(s,s)
--      gfx.setLineWidth(0.1,0.1)
--      gfx.translate(70,5)
--      gfx.setColor(1,p%2==0 and 0.2 or 1,0.4,1)
--      gfx.line(poly)
--      gfx.pop()
--      for i=1,#poly,2 do
--        gfx.print((i+1)/2,(poly[i]+70)*s,(poly[i+1]+5)*s+i)
--      end
--      -- gfx.setColor(0,0,0,1)
--      -- gfx.print(round(poly[1]).." "..round(poly[2]),(poly[1]+70)*8,(poly[2]+5)*8+10)
--    end
--  end
-- end
local fanMesh
function testFanStrip()
    local frame
  if time - mf(time) < 0.01 then collectgarbage("collect") end

  if not fanMesh then
    -- local x,y,s = 0,0,50

    -- local stripverts = {
    --   {0,0,0,0, 0,0, 1,1,1,1},
    --   {20,0,0,0, 1,0, 1,1,1,1},
    --   {0,20,0,0, 1,1, 1,1,1,1},
    --   {20,20,0,0, 1,1, 1,1,1,1},
    --   {10,30,0,0, 1,1, 1,1,1,1},
    --   {30,30,0,0, 1,1, 1,1,1,1}
    -- }
    local fanverts = {
      { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
      { 20, 0, 0, 0, 1, 0, 1, 1, 1, 1 },
      { 25, 10, 0, 0, 1, 0, 1, 1, 1, 1 },
      { 20, 20, 0, 0, 1, 1, 1, 1, 1, 1 },
    }
    fanMesh = gfx.newMesh(zformat, fanverts, "fan")
    print("MAKE FANMESH")
    -- stripMesh = gfx.newMesh(zformat,stripverts,"strip")
    -- testMesh:setTexture(load_imageTex("checkers"))

    -- frame = gfx.newImage("/path/to/user/Library/Application Support/Umoupen/test.png")
  end

  -- gfx.push("all")
  -- gfx.rectangle("fill",0,0,300,300)
  -- fanverts[3][1] = 100+math.sin(time)*25
  -- print("SETVERTS START")
  -- fanMesh:setVertices(fanverts,1,5)
  -- print("SETVERTS END")
  gfx.draw(fanMesh,100,100)
  -- gfx.draw(stripMesh,300,100)
  -- gfx.pop()

end
local cube, cube2
function drawTests(view)
	if not view.bounds.l or ctx.isAnim or not editor.debug.draw_tests then
		return
	end

	bench.push("_draw_tests")

	normalPlane = normalPlane or {}

	normalPlane.mesh = gfx.newMesh(zformat, {
		{ 0, 0, 100, 0, 0, 0, 1, 1, 1, 1 },
		{ 100, 0, 100, 0, 1, 0, 1, 1, 1, 1 },
		{ 100, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
		{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 },
	}, "fan")

	normalPlane.tex = normalPlane.tex or gfx.newImage(LINK_DIR .. "models/architecture/boiseries/boiserie_01.tga")
	normalPlane.tex:setFilter("nearest", "nearest")
	normalPlane.mesh:setTexture(normalPlane.tex)

	gfx.push("all")

	gfx.setColor(1, 1, 1, 1)
	gfx.setShader(shaders.deferredStatic)
	-- shaders.deferredStatic:send("modelMatrix",mat4.identity())
	-- shaders.deferredStatic:send("MVP","column",gfx.camera.vp)
	gfx.draw3D(normalPlane.mesh)
	gfx.pop()

	-- if keyDown("m") or not grassMesh then
	--  grassTexture = gfx.newImage("/models/grass.png")
	--  grassVerts = {}
	--  local num,spread,height,width = 200,200,16,16
	--  local variants = grassTexture:getWidth()/width
	--  for i=1, num, 1 do
	--    local bx,bz,br = math.random()*spread,math.random()*spread,math.random()*2*pi
	--    local ox,oz = math.sin(br)*16,math.cos(br)*16
	--    local px,pz = math.sin(br+pi/2)*16,math.cos(br+pi/2)*16
	--    local sway = 2
	--    local height = height * math.sin(bx+bz)
	--    local grassVariant = 1

	--    table.insert(grassVerts,{ bx-ox/2,0,bz-oz/2,1,      0,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx+ox/2,0,bz+oz/2,1,      1,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx-ox/2,-16,bz-oz/2,1,    0,0,  1,1,1,1, sway,sway/8,sway})
	--    table.insert(grassVerts,{ bx+ox/2,0,bz+oz/2,1,      1,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx-ox/2,-16,bz-oz/2,1,    0,0,  1,1,1,1, sway,sway/8,sway})
	--    table.insert(grassVerts,{ bx+ox/2,-16,bz+oz/2,1,    1,0,  1,1,1,1, sway,sway/8,sway})

	--    table.insert(grassVerts,{ bx-px/2,0,bz-pz/2,1,      0,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx+px/2,0,bz+pz/2,1,      1,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx-px/2,-16,bz-pz/2,1,    0,0,  1,1,1,1, sway,sway/8,sway})
	--    table.insert(grassVerts,{ bx+px/2,0,bz+pz/2,1,      1,1,  1,1,1,1, 0,0,0})
	--    table.insert(grassVerts,{ bx-px/2,-16,bz-pz/2,1,    0,0,  1,1,1,1, sway,sway/8,sway})
	--    table.insert(grassVerts,{ bx+px/2,-16,bz+pz/2,1,    1,0,  1,1,1,1, sway,sway/8,sway})

	--  end
	--  grassMesh = gfx.newMesh(zformat,grassVerts,"triangles")
	--  grassMesh:setTexture(grassTexture)
	--  grassModel = scene_newModel(grassMesh,newTransform(340,180,0))
	--  --grassModel = scene_newModel(grassMesh)

	-- end

	-- if grassMesh then
	--  gfx.setColor(1,1,1,1)
	--  shaders.forwardRender:send("time",time)
	--  trace("grass?",#grassVerts)
	--  drawModel(grassModel)
	-- end

	--gfx.draw(editor.testTri)

	editor.testTexture = editor.testTexture or gfx.newImage(LINK_DIR .. "models/castle.png")
	editor.testTexture:setFilter("nearest", "nearest")

	if not editor.tesMesh then
		local castle = gfx.newMesh(zformat, obj_loader("models/castle2.obj"), "triangles")
		local verts = {}
		local scale = 1000
		for i = 1, 1, 1 do
			local x, y, z, w, u, v
			local x1, y1, z1 = math.random() * scale, math.random() * scale, math.random() * scale
			for v = 1, castle:getVertexCount(), 1 do
				x, y, z, w, u, v = castle:getVertex(v)
				table.insert(verts, { x + x1, y + y1, z + z1, w, u, v })
			end
		end
		editor.tesMesh = gfx.newMesh(zformat, verts, "triangles")
	end

	if cmdDown and input_keyDown("n") and input_keyDown("c") then
		-- cube.mainTrack.time = 0
		--    cube.anim:update(0)
		-- cube.anim.playing=true
		-- cube.mainTrack = cube.anim:new_track(cube.nextAnim,1,1,function()  cube.nextAnim=cube.nextAnim end)
		-- cube.anim:play(cube.mainTrack)

		local testModel = { parent = room, transform = mat4(), mesh = editor.tesMesh, front = true }
		testModel.transform:translate(
			cpml.mat4():rotate(cpml.mat4(), -pi, vec3(1, 0, 0)),
			vec3(math.random() * 10 * 50, math.random() * 10 * 50, math.random() * 10 * 50)
		)
		testModel.matrix = scene_getMatrix(testModel)
		gfx.setTexture(testModel.mesh, editor.testTexture)
		table.insert(testModels, testModel)
		--shaders.forwardRender:send("MVP", ctx.viewport.camera.vp*ringModel.matrix)`
		--gfx.draw(ringShape)
		--drawModel(cube)
	end

	if not cube then
		cubez = 0
		cubeTransform = mat4.identity()
		cubeTransform:scale(cubeTransform, vec3(1, 1, 1))
		cubeTransform:translate(cubeTransform, vec3(0, 0, 0))
		cubeTransform:rotate(cubeTransform, -pi / 2, vec3(1, 0, 0))
		--buildings = gfx.newMesh(zformat, obj_loader("/models/build.obj"), "triangles")

		local projectData = gfx.newImageData(LINK_DIR .. "models/project.png")
		local projectTex = gfx.newImage(projectData)
		local w, h = projectTex:getDimensions()
		local col = function(x, y)
			return { projectData:getPixel(x * w, y * h) }
		end

		meshFile = LINK_DIR .. "models/project.iqm"
		animFile = LINK_DIR .. "models/project.iqm"

		model = iqm.load(meshFile)

		local form = model.mesh:getVertexFormat()

		-- print(inspect(form))

		local map = model.mesh:getVertexMap()
		local verts = {}
		for i = 1, model.mesh:getVertexCount(), 1 do
			local x, y, z = model.mesh:getVertexAttribute(i, 1)
			local bx, by, bz, bw = model.mesh:getVertexAttribute(i, 5)
			local wx, wy, wz, ww = model.mesh:getVertexAttribute(i, 6)
			table.insert(
				verts,
				lume.concat(
					{ x, y, z },
					{ 1 },
					{ model.mesh:getVertexAttribute(i, 2) },
					{ model.mesh:getVertexAttribute(i, 7) },
					{ model.mesh:getVertexAttribute(i, 3) },
					{ 0, 1, 1, 1 },
					{ bx, by, bz, bw },
					{ wx, wy, wz, ww }
				)
			)
		end

		-- print("verts1",#verts)
		-- print("map1",#map)
		local verts2 = {}
		local match
		local remap = {}
		local map2 = {}
		for i = 1, #verts, 1 do
			match = false
			for j = 1, #verts2, 1 do
				if verts[i][1] == verts2[j][1] and verts[i][2] == verts2[j][2] and verts[i][3] == verts2[j][3] then
					-- and simpleSame(col(verts[i][5],verts[i][6]), col(verts2[j][5],verts2[j][6])) then
					match = true
					remap[i] = j
				end
			end
			if not match then
				table.insert(verts2, verts[i])
				remap[i] = #verts2
			end
		end
		for i = 1, #map, 1 do
			map2[i] = remap[map[i]]
		end
		-- print("verts2",#verts2)

		cube = {
			iqm = true,
			nextAnim = "Walk",
			loopAnim = true,
			parent = room,
			transform = cubeTransform,
			mesh = model.mesh,
		}

		cube.iqmAnims = iqm.loadAnims(animFile)
		-- print(inspect(cube.iqmAnims.skeleton))

		local anims = {}
		local frames = cube.iqmAnims.frames
		for a, anim in ipairs(cube.iqmAnims) do
			anims[anim.name] = {}
			for i = anim.first, anim.last, 1 do
				table.insert(anims[anim.name], frames[i])
			end
		end

		editor.testModel = {
			verts = verts2,
			map = map2,
			texdir = GAME_DIR .. "models/project.png",
			tex = projectData,
			skeleton = cube.iqmAnims.skeleton,
			anims = anims,
			mesh = gfx.newMesh(animatedVertexFormat, verts, "triangles"),
			-- joints = cube.iqmAnims.joint_map
		}

		cube.anim = anim9(cube.iqmAnims)

		gfx.setTexture(cube.mesh, projectTex)

		cube.mainTrack = cube.anim:new_track(cube.nextAnim, 1, 1, function(anim)
			anim.time = 0
			cube.nextAnim = cube.nextAnim
		end)
		cube.anim:play(cube.mainTrack)
	end

	if cube then
		for a, anim in ipairs(cube.iqmAnims) do
			-- trace(anim.name)
		end

		if cube.mainTrack then
			cube.mainTrack.time = cube.mainTrack.time + 0.01
			cube.anim:update(0)
			editor.testPose = cube.anim.current_pose
			cube.skelly = true --cube.anim.current_pose
			-- trace(cube.mainTrack.time,cube.anim:length(cube.nextAnim),cube.mainTrack.playing)
			if engine.fourstep == 1 then
				--cube.anim:update(1/60)
				if cube.nextAnim ~= "" then
					if cube.mainTrack.time >= cube.anim:length(cube.nextAnim) - 0.1 then
						-- cube.anim.playing=true
						-- cube.mainTrack = cube.anim:new_track(cube.nextAnim,1,1,function()  cube.nextAnim=cube.nextAnim end)
						-- cube.anim:play(cube.mainTrack)
					end
				end
			end
		end
		--gfx.setMeshCullMode("front")

		--   shaders.forwardRender:send("skellyman",1)
		-- shaders.forwardRender:send("u_pose", "column", unpack(cube.anim.current_pose))
		-- -- gfx.draw(cube.mesh)
		-- shaders.forwardRender:send("skellyman",0)
		-- drawModel(cube)
	end

	cube.mesh = editor.testModel.mesh
	if cube2 then
		editor.testcube2 = cube2
		-- gfx.draw(cube2)
	end

	-- gfx.setWireframe(true)
	gfx.setColor(1, 1, 1, 1)
	gfx.setMeshCullMode("front")

	-- trace("castles",#testModels)

	for i, test in ipairs(testModels) do
		-- drawModel(test)
		gfx.draw(test.mesh)
		if i == #testModels and input_keyDown("m") then
			testModels[i] = nil
		end
	end

	-- --gfx.setMeshCullMode("none")

	--gfx.setWireframe(false)
	--gfx.setMeshCullMode("none")
	--shaders.forwardRender:send("skellyman",0)
	--gfx.draw(buildings)
	--gfx.setWireframe(true)
	--drawModel(ringModel)
	--gfx.setWireframe(false)

	--local dx,dy = (mouse.x-view.bounds.l-view.bounds.w/2)/(view.bounds.w/2),(mouse.y-view.bounds.t-view.bounds.h/2)/(--view.bounds.h/2)
	--
	--local raw = vec3(-1*view.bounds.w,dy*view.bounds.h,100)
	--local new =   vec3.rotate(vec3.rotate(raw, cam.angle.y, vec3.unit_x), pi-cam.angle.x, --vec3.unit_y)
	--local p = camera_project(new-ctx.viewport.camera.pos)
	--local d = (p.x-view.bounds.l-view.bounds.w/2)/(view.bounds.w/2)
	--local mult=1/d
	--raw = vec3(-dx*view.bounds.w*mult,dy*view.bounds.h*mult,100)
	--new =   vec3.rotate(vec3.rotate(raw, cam.angle.y, vec3.unit_x), pi-cam.angle.x, vec3.unit_y)

	--cube.transform:translate(mat4(), vec3(0,0,0))
	--cube.transform:scale(mat4(), vec3(20,20,20))
	--local look = mat4():look_at(cube.transform,vec3(0,0,0),-ctx.viewport.camera.pos,vec3(0,1,0))
	--cube.transform = cube.transform*-look

	--cube.transform:translate(cube.transform,new-ctx.viewport.camera.pos )

	bench.pop("_draw_tests")
end
