
local function setValues(t,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17)
	t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16],t[17]=
	v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17
	return t
end

local function dist(x1,y1,x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end
--------------------------------------------------------------

function scene.pushEntity(t,entity)
	if entity.simple   then return nil end

		table.insert(t, scene.returnObject(entity))

	return entity
end

function scene.setDelete(entity)
	table.insert(room.toDelete,entity)
end

function scene.deleteEntity(entity)
	lume.clear(entity)
	lume.remove(room.entities, entity)
	scene.destroyEntity(entity)
	entity = nil
end

function scene.destroyEntity(entity)

end

function  scene.deleteEntities()
	if room then 
		for i,entity in ipairs(room.toDelete) do
      scene.deleteEntity(entity)
    end
    room.toDelete={}
	end
end

function scene.entitySelected(ent)
	if #selectedEntities==0 then return false end
	local there = false
	for i,e in ipairs(selectedEntities) do 
		if e == ent then 
			there = true 
		end
	end
	return there
end

function scene.getEntityByID(id)
	return room.entitiesByID[id] 
end

function scene.getEntityIndexByID(id)
	local targ = -1
	for i,e in ipairs(room.entities) do 
		if e.uid == id then 
			targ = i
		end
	end
	return targ
end

function scene.findEntity(name)
	return lume.match(room.entities,function(x) return x.name == name end)
end


function scene.updateEntityAnimData(entity)

	if lume.find(game.toUnload,entity.key) then 
		for m,model in ipairs(entity.models) do 
			model.mesh:release()
		end
		entity.models = {}
		entity.img=nil
		entity.adata = nil
		entity.fdata = nil
		log("UNLOBe")
	end

	if  not objects[entity.key]  or entity.pointIndex or imageLoader:isLoading(entity.key) or not objects[entity.key].animations then return end
	
	entity.img = objects[entity.key].image

	if entity.img then 
		if editingLevel then 
			entity.previewing = (editor.animHovered.object == entity.uid and  editor.animHovered.key~="")
			if entity.previewing then
				entity.anim = editor.animHovered.key
				entity.adata = objects[entity.key].animations[entity.anim]

				scene.updateEntityAnimation(entity,1/60)
			else
				entity.frame=1
				entity.anim = entity.default or objects[entity.key].default
			end
		end

		entity.adata 		= objects[entity.key].animations[entity.anim]
		entity.fdata 		= scene.getEntityFrameData(entity)
		if not entity.adata then print("adata",entity.anim,inspect( objects[entity.key].animations)) end
		entity.animation= entity.adata.name
	end

end

function scene.updateEntityAnimation(entity,dt)
	if not editingLevel and not entity.playing then return end
	local dt = dt or (animationPanel.open and 0 or 1/60) or main_dt
	entity.tick = entity.tick+dt*(entity.playbackSpeed or 1)
	entity.animTime = entity.animTime + (1/60)
	-- print(dt,entity.playbackSpeed,entity.tick , (1/entity.fps))
	entity.ticked = false
	-- trace("frmam",entity.frame)
	-- trace("TICK",entity.tick)
	-- trace(dt*(entity.playbackSpeed or 1))
	-- trace(1/entity.fps)
	-- trace(entity.adata and entity.adata.length or 99999)
	if entity.tick > (1/entity.fps) then 
		-- trace("TICKING")
		entity.tick 	= entity.tick-1/entity.fps
		entity.frame 	=  entity.frame+1

		entity.ticked = true
		if entity.frame > (entity.adata and entity.adata.length or 99999) then 
			entity.frame = 1 
			entity.animTime = 0
		end
	end
end


function layerLength(layer)
	if not layer then print_info(5) error("nil layer") end
	local frameCount   = 0
	for f,frame in ipairs(layer.frames) do 
		frameCount=frameCount+frame.l
	end
	layer.length = frameCount
	return frameCount
end

function scene.updatePose(layer,pose)
	layer.current_pose, layer.current_matrices = anim9.update_matrices(layer.skeleton,layer.base,pose,layer.map)
end


local mat = mat4()
function scene.getEntityFrameData(entity,frame)

	bench.push("animData")
	local 	frameData 		= {}
	local 	panel 				= animationPanel
	local   object  			= objects[entity.key]
	local 	adata 				= entity.isEntity and entity.adata or entity
	local 	editing 			= panel and panel.instance==entity
	local 	frame 				= editing and panel.currentFrame or (frame or entity.frame)
	local 	onion 				= editing and panel.onion.enabled and not panel.playing
	local 	update 				= (panel.updateMesh and editing) 
	local 	layers 				= editing and panel.layers or entity.adata.layers 
	local		separate 			= editing or type(entity.img)=="table"

	if editing or keypressed("r") or lume.find(game.toLoad,entity.key) then 
		entity.models={}
	end


	entity.fps = adata.fps

	for l,layer in ipairs( layers ) do

		local onionStart = l==panel.layer and (#layer.frames==1 and 3 or 1) or 3 
		local onionSkip  = l==panel.layer and (#layer.frames==2 and 2 or 1) or 1
		for s=onion and onionStart or 3,3,onionSkip do 	
			local isOnion = s<3
			layerIndex = isOnion and #layers+s or l
			
			local looped = frame

			if layer.clips then 
				local fw,fdiff,rep
				for c,clip in ipairs(layer.clips) do 
					if frame>clip.f2 and frame<clip.f2+clip.f3 then 
						fw = fw or (clip.f2-clip.f1)+1
						fdiff = (frame-clip.f1)
						rep = mf(fdiff/fw)
						if clip.loopMode == "pingpong" and rep%2~=0 then 
							looped = fw-fdiff%fw-1
						else
							looped = fdiff%fw
						end
						looped = clip.f1+looped
					end
				end
			end

			local keyF = scene.getKeyFrame(layer ,looped)
			local wrapF = wrap(1,(keyF or 1)+(s==1 and -1 or (s==2 and 1 or 0)),#layer.frames) 
			
			--if editing and l==panel.layer then trace("lf "..layer.frame,"f "..frame,"kf "..keyF,"wf "..wrapF) end

			local currentFrame = wrapF--editing and wrapF  or keyF
			local layerFrame   = layer.frames[currentFrame]
			layerFrame.abs = layerFrame.abs or editor.getAbsoluteFrame(editing and panel or entity.adata,l,currentFrame)

			bench.push("framedata")

			if editing or  (#entity.models==0  or not entity.hasModels)  or (layer.type=="model" and not layer.mesh or lume.count(layerFrame.verts or {})==0 ) or imageLoader:isLoading(entity.key) then 

				layer.type = layer.type or "drawing"

				if layer.type == "model" then 
					local name,ext = layer.obj or layer.iqm, layer.obj and ".obj" or ".iqm"

					if name then 

						layer.file =  layer.file or LINK_DIR.."models/"..name..ext
						layer.texture = layer.texture or (lfs.exists(LINK_DIR.."models/"..name..".png") and gfx.newImage(LINK_DIR.."models/"..name..".png") or getImage())
						layer.mesh = layer.mesh or (layer.iqm and iqm.load(layer.file).mesh or gfx.newMesh(zformat,obj.load(layer.file),"triangles","static"))

					else

						if layer.data then
							if type(layer.updots)=="nil" then layer.updots = true end
							local remesh = layer.updots or (panel.meshTransform and panel.meshTransform.mode and mouse.moved)
							bench.push("modeldata")
							if type(layer.data)=="string" then  
								layer.data    =  object.models[layer.data]
							end
							local edit = layer.data.verts and panel and panel.l and panel.l.remodel and (panel.instance == entity)

							if (edit and remesh) or not layer.data.verts then 
								bench.push("meshrefs")
								setMeshReferences(layer.data)
								bench.pop("meshrefs")
								bench.push("meshsets")
								updateMeshData(layer.data,edit,panel)
								bench.pop("meshsets")
							end

							if type(layer.data.verts[1])=="table" then 
								bench.push("meshmakes")
								layer.isMesh = true
								if not layer.mesh or (edit and #layer.data.verts~=layer.mesh:getVertexCount()) then 
									layer.mesh = gfx.newMesh(layer.skeleton and animatedVertexFormat or zformat,layer.data.verts,"triangles")
								elseif edit then 
									if remesh then 
										layer.mesh:setVertices(layer.data.verts,1)
									end
								end
								layer.texture = type(layer.texture)=="string" and gfx.newImage(LINK_DIR.."images/"..panel.object.name.."/.textures/"..layer.texture..".png") or layer.texture
								if not gfx.getTexture(layer.mesh) then gfx.setTexture(layer.mesh,layer.texture) end
								bench.pop("meshmakes")
							end
							-- layerFrame.mesh = layer.mesh
							-- layerFrame.tris = layer.data.tris
							layer.dither = edit and panel.seeThru

							if edit then 
								bench.push("dotsNlines")
								layer.unlit = panel.unlit
								if layer.data.dotVerts and layer.data.dotVerts[1] then 
									if panel.selectMode[1] then 
										layer.dots  = layer.dots or gfx.newMesh(zformat3, #layer.data.dotVerts,"points")
										if layer.updots then 
											layer.dots:setVertices(layer.data.dotVerts)
										end
									else
										layer.dots = nil
									end
								end
								if layer.data.lineVerts and layer.data.lineVerts[1] then 
									layer.lines  = layer.lines or gfx.newMesh(zformat3,#layer.data.lineVerts,"triangles")
									if layer.updots then 
										layer.lines:setVertices(layer.data.lineVerts)
									end
								end
								layer.updots = false
								bench.pop("dotsNlines")
							else
								layer.dots  = nil
								layer.lines  = nil
							end
							bench.pop("modeldata")
						end
					end
				end

				for f,frame in ipairs(editing and {layerFrame} or layer.frames) do 

					if layer.type == "model" then 



					elseif layer.type == "drawing" or not layer.type then 
						if entity.name=="thing" then 
							log ("preshMade") 
						end

					 	if frame.blank and layer.external then 
					 		trace("blank?")
					 	else
					 		local layerRes = layer.resolution or 1
							frame.verts	= frame.verts or {{},{},{},{},{},{}} 	_no_copy[frame.verts]	= true
							setValues(frame.verts[1], -frame.w*0.5*layerRes+frame.ox,	-frame.h*0.5*layerRes+frame.oy, 0.5, 	1,  0 ,	0 )
							setValues(frame.verts[2], frame.w*0.5*layerRes+frame.ox,	-frame.h*0.5*layerRes+frame.oy, 0.5, 	1,  1 , 0 )
							setValues(frame.verts[3],  frame.w*0.5*layerRes+frame.ox,	frame.h*0.5*layerRes+frame.oy,  0.5, 	1,  1 , 1 )

							setValues(frame.verts[4], -frame.w*0.5*layerRes+frame.ox,	frame.h*0.5*layerRes+frame.oy,  0.5, 	1,  0 ,	1 ) 
							setValues(frame.verts[5],  frame.w*0.5*layerRes+frame.ox,	frame.h*0.5*layerRes+frame.oy,  0.5, 	1,  1 , 1 )
							setValues(frame.verts[6], -frame.w*0.5*layerRes+frame.ox,	-frame.h*0.5*layerRes+frame.oy, 0.5, 	1,  0 ,	0 )

							local draw=panel.drawing

							if panel.changed then 
								draw=false
								--editor.releaseSelection(panel)
							end

							local tex = editing and (((draw) and s==3) and layer.canvas or layer.canvas ) or entity.img

							if frame.mesh then 
								frame.mesh:setVertices( frame.verts,1)
							else
								frame.mesh = gfx.newMesh( zformat5 , frame.verts , "triangles" )
							end

							if type(tex)=="table" and entity.img and entity.img[frame.id] then 
								tex = entity.img[frame.id] 
							end

							-- print(entity.img[entity.anim],entity.img[entity.anim][l],entity.img[entity.anim][f])

							-- print("tex?",tostring(tex))
							-- editor.testTex = tex

							if tex and gfx.isTexture(tex) then
								gfx.setTexture(frame.mesh,tex)
							end


							frame.tris 			= {
								{
									vec3(frame.verts[1][1],frame.verts[1][2],frame.verts[1][3]),
									vec3(frame.verts[4][1],frame.verts[4][2],frame.verts[4][3]),
									vec3(frame.verts[2][1],frame.verts[2][2],frame.verts[2][3])
								},
								{
									vec3(frame.verts[4][1],frame.verts[4][2],frame.verts[4][3]),
									vec3(frame.verts[3][1],frame.verts[3][2],frame.verts[3][3]),
									vec3(frame.verts[2][1],frame.verts[2][2],frame.verts[2][3])
								}
							}
						end
					
					end

					if not frame.position or not vec3.is_vec3(frame.position) then 
						frame.position 			= vec3(frame.position) 
						frame.orientation 	= quat(frame.orientation) 
						frame.scale 				= vec3(frame.scale) 	
					end
					if not editing then 
						pcall(applyTransform, frame)

					end
				end
			end
			bench.pop("framedata")
			
			local palette = (layer.format=="r8" and layer.palette) and vecPalette(layer.palette) or {}

			layerFrame   = layer.frames[currentFrame]
			entity.models[layerIndex]  					= entity.models[layerIndex] or {nocopy = true,keyF=currentFrame}

			local model = entity.models[layerIndex]
			local keyChanged = model.keyF 	~= currentFrame 
			model.index     = layerIndex
			model.keyF 			= currentFrame
			model.color 		= {1,1,1,1}
			model.onion 		= isOnion
			model.isFrame 	= layer.type=="drawing" 
			--model.front 		= layer.type=="model" 
			model.tint 			= onion and (
				s==1 and lume.merge(panel.onion.before.tint , {a=panel.onion.before.amount*panel.onion.amount})
				or 
				s==2 and lume.merge(panel.onion.after.tint , {a=panel.onion.after.amount*panel.onion.amount})
			or nil) or nil
			model.tris 			= layer.data and layer.data.tris or layerFrame.tris
			model.mesh 			= layer.mesh or layerFrame.mesh
			
			model.wireframe = layer.wireframe
			model.unlit  		= layer.unlit
			model.dots  		= layer.dots
			model.lines  		= layer.lines
			model.dotlines  = (panel.instance == entity) and not (panel.meshTransform and panel.meshTransform.mode)
			model.isCustom  = layer.data
			model.dither  	= layer.dither
			model.vector 	  = layer.format=="vector" and not layer.data
			model.indexed 	= layer.format=="r8"
			model.alpha   	= layer.alpha
			model.palette   = palette

			bench.push("IK")
			if not editing then
				if layer.skeleton and layerFrame.transform and entity.transform and editor.debug.live_IK then 
					layer.mat = -layerFrame.transform*-entity.transform 
					scene.inverseKinematics(layer,layerFrame.pose)
					-- layer.poseMesh = nil
				end
			end
			bench.pop("IK")

			if layer.current_pose then 
				model.skelly = not layer.remodel
				model.current_pose = layer.current_pose
				model.poseMesh = layer.poseMesh
			end

			if isOnion then 
				if s==2  then 
					model.visible =    panel.onion.after.enabled
				else
					model.visible =    panel.onion.before.enabled
				end
			end

			bench.push("Vecterz")
			if model.vector then 
				scene.renderVectorFrame(panel,layer,layerFrame,isOnion)
				model.strokeWire = layer.onePixel and layer.fillIndex or 0
				model.strokeMesh = layerFrame.strokeMesh
				model.strokePreview = layerFrame.strokePreview
			end
			bench.pop("Vecterz")

			model.parent 		= entity
			model.layer 		= l

			if editing and panel.solo>0 then 
				model.visible   = panel.solo==l
			else
				model.visible   = layer.visible
			end

			layer.length = layer.length or layerLength(layer)
			if  frame>layer.length and not layer.loop then 
				model.visible=false 
			end


			bench.push("tween")
			local cf = editing and panel.currentFrame or frame
			local play = (not editingLevel) or (editing and (panel.playing or panel.layer~=l)) or entity.previewing
			local nextFrame = layer.frames[currentFrame+1] or layer.frames[1]
			local progress, progress2

			if not isOnion and #layer.frames>1 and layerFrame.tween and layerFrame.tween.enabled and play and nextFrame.position then 
				local time = panel.open and panel.time or entity.animTime 
				local fps = panel.open and panel.animation.fps or adata.fps
				
				local t1 = (layerFrame.abs-1)/fps
				local t2 = (layerFrame.abs+layerFrame.l-1)/fps
				progress  = ((cf-mf((cf-1)/layer.length)*layer.length)-layerFrame.abs)/(layerFrame.l)
				progress2 = mc(0,(time-t1)/(t2-t1),1)
				progress  = mc(0,easeInOut((not entity.previewing and layer.smooth) and progress2 or progress,layerFrame.tween.easeIn,layerFrame.tween.easeOut),1)
				if entity.ticked and cf == layerFrame.abs then progress=0 end

				checkTransform(layerFrame)
				checkTransform(nextFrame)

				model.transform = applyTransform({},
					vec3.lerp(layerFrame.position, nextFrame.position ,progress),
					quat.slerp(layerFrame.orientation,nextFrame.orientation ,progress),
					vec3.lerp(layerFrame.scale,nextFrame.scale ,progress)
				) 
			else
				model.transform = model.transform or mat4()
				model.transform:mul(entity.transform  or mat4(), layerFrame.transform or mat4())
			end
			bench.pop("tween")

			-- IQM ANIMS
			if layer.iqm  then  
				local iqmString = LINK_DIR.."models/"..layer.iqm
				layer.iqmAnims = layer.iqmAnims or iqm.load_anims(lfs.exists(iqmString..".exm") and iqmString..".exm" or iqmString..".iqm")
				layer.iqmAnims.nocopy = true
				layer.iqmAnims = layer.iqmAnims or layer.iqmAnims 
				bench.push("iqm")
				--scene.updateEntityIQM(entity,  model,   layer,   layerFrame,  layerIndex,  isOnion,entity.previewing or editing or not editingLevel,not editingLevel or panel.playing or entity.previewing,onion and layerFrame.abs or frame,currentFrame,nextFrame,layer.smooth and progress or progress2,model.transform)
				bench.pop("iqm")
			end

			model.drawBounds = editing and layer.type=="drawing" and panel.layer==l and (drawingPanel.tool == "move" and not panel.selection.mesh ) and not (keyDown("left") or keyDown("right"))
		end
	end

	entity.hasModels = #entity.models>0

	if update then 
		panel.updateMesh = false
	end

	if editing or (not panel.open) or not editingLevel then 
		panel.forceRestroke = false
		panel.sudoForceRestroke = false
	end
	bench.pop("animData")
	return frameData
end


function scene.inverseKinematics(layer,pose,panel)

	layer.repose  = layer.skeleton

	if pose and ((not panel) or (layer.repose and not layer.remodel)) then 

		if not layer.base then 
			local bound = anim9.rebind({},{skeleton=layer.skeleton})
			layer.base 		= bound.inverse_base
			layer.map 		= bound.index_map
		end

		if editingLevel and not panel then 	
			scene.updatePose(layer,pose)
			return
		end


		if panel then 
			currentTool="Select"
			layer.mat = -panel.f.transform*-panel.instance.transform
			if panel.changed or panel.playing then 
				lume.clear(selectedEntities)
				editor.clearBones(panel)
			end
		end

		if (not layer.bones) then 
			layer.boneLinks = {}
			scene.updatePose(layer,pose)

			layer.bones = {}
			for b,bone in ipairs(layer.skeleton) do 
				local mat = layer.current_matrices[bone.name]
				local pos = -(mat*(layer.mat)*vec3(0))
				layer.bones[b] = panel 
					and scene.newEntity({x=pos.x,y=pos.y,z=pos.z,simple=true}) 
					or {
						index = b,
						position=pos,
						getPosition=function(bone) return bone.position end,
						setPosition=function(bone,position) bone.position:set(position) end
					}
				layer.bones[b].bone = b
				layer.bones[b].name = bone.name
				layer.bones[b].visible = (panel)
				if bone.parent>0 then 
					layer.bones[b].parentID = bone.parent
					table.insert(layer.boneLinks,{b,bone.parent})
				else 
					layer.bones[b].visible=false
				end
			end
		else
			if (not editingLevel) or (not panel) then  
				for b,bone in ipairs(layer.bones) do 
					local mat = layer.current_matrices[bone.name]
					local pos = -(mat*(layer.mat)*vec3(0))
					-- layer.bones[b]:setPosition(pos)
					-- pos = camera.project(-pos)
					-- pushPost()
					-- gfx.push("all")
					-- 	gfx.setBlendMode ('alpha', 'premultiplied')
					-- 	gfx.setColor(1,1,1,1)
					-- 	gfx.print(tostring(b)..", "..bone.name,pos.x+8,pos.y+4)
					-- gfx.pop()
					-- popPost()
				end
			end
		end

		layer.pose=layer.pose or {}
		layer.nextPose = {}

		-----------------------------------------
		local function getRot(bone,diff) 
			local rotate = (diff and layer.nextPose[bone.bone]) 
				and (layer.nextPose[bone.bone]*pose[bone.bone].rotate):normalize()
				or pose[bone.bone].rotate
			if bone.parentID then 
				return getRot(layer.bones[bone.parentID],diff)*rotate
			else 
				return rotate
			end
		end

		if panel and selectedEntities[1] then 
			local selected = selectedEntities[1]

			for b,bone in ipairs(layer.bones ) do 
				if bone.parentID == selected.parentID then 
					table.add(selectedEntities,bone)
				end
			end
		end
		------------------------------------------
		layer.ik = true
		if layer.ik then 
			
			local first,last
			local seqs = {
				{
					1,8,11,
						{
							{11,16,19,21,23},
							{11,15,18,20,22},
							{11,14,17}
						}
				},
				{
					2,9,12
				},
				{
					4,10,13
				},
			}

			local function buildChains(seq,parent)
				local joints,bones,indexes = {},{},{}
				for j,joint in ipairs(seq) do 
					if type(joint)=="number" then 
						table.insert(joints,layer.bones[joint]:getPosition())
						table.insert(bones,layer.bones[joint])
						table.insert(indexes,joint)
					else
						for b,branch in ipairs(joint) do 
							buildChains(branch,joint)
						end
					end
				end
				local new = ik.new(joints,bones,indexes)
				new.parent = parent 
				table.insert(layer.chains,new)
			end

		  if not layer.chains then 
			 	layer.chains = {}
				for s,seq in ipairs(seqs) do 
					buildChains(seq)
				end
			end

						
			if layer.chains then 
				if not editingLevel then 
					
					for c,chain in ipairs(layer.chains) do 
						for j=1,chain.n,1 do 
							chain.joints[j]:set(chain.bones[j]:getPosition())
						end
					end

					for c,chain in ipairs(layer.chains) do 
						for b,bone in ipairs(chain.bones) do 
							if layer.bones[bone.parentID] and b>1 then 
								local target = (chain.joints[b]-chain.joints[b-1]):normalize()
								bone.last = target:clone()
							end
						end
					end

					for c,chain in ipairs(layer.chains) do 
						if chain.bones[chain.n].index==12 then
							chain.bones[chain.n].position.y = chain.bones[chain.n].position.y +0.01
							chain.bones[chain.n].position.z = chain.bones[chain.n].position.z +0.01
							chain.bones[chain.n]:setPosition(vec3())
						end

						for j=1,chain.n,1 do 
							chain.joints[j]:set(chain.bones[j]:getPosition())
						end
					end
				end

				
				for c,chain in ipairs(layer.chains) do 
					local selectedBone,sb = lume.match(chain.bones,function(item) return item.selected end)
					
					if not editingLevel then 
						sb = chain.n
					end

					if sb  then 
						local start = chain.parent and 2 or 1
						sb =  sb or chain.n
						first,last = start,sb
						chain.origin = chain.bones[first]:getPosition():clone()
						chain.target = chain.bones[last]:getPosition():clone()
						chain:solve(first,last)

						if sb~=chain.n then 
							first,last = sb,chain.n
							chain.origin = chain.bones[first]:getPosition():clone()
							chain.target = chain.bones[last]:getPosition():clone()
							chain:forward(first,last)
						end

						for j=start,#chain.bones,1 do 
							if not (multiTool.dragging and j==sb) then 
								chain.bones[j]:setPosition(chain.joints[j])
							end
						end

						for c2,chain2 in ipairs(layer.chains) do 
							-- if chain2.parent==chain.indexes[chain.n] then 
							-- 	first,last = 1,chain2.n
							-- 	chain2.origin = chain.joints[2]:clone()
							-- 	chain2:forward(first,last)
							-- 	for j2=1,chain2.n,1 do 
							-- 		chain2.bones[j2].nextPosition.x,chain2.bones[j2].nextPosition.y,chain2.bones[j2].nextPosition.z = chain2.joints[j2]:unpack()
							-- 	end
							-- end
							-- if chain2.indexes[1]==chain.indexes[1] then 
							-- 	first,last = 2,chain2.n
							-- 	chain2.origin = chain.joints[2]:clone()
							-- 	chain2:forward(first,last)
							-- 	for j2=1,chain2.n,1 do 
							-- 		chain2.bones[j2].nextPosition.x,chain2.bones[j2].nextPosition.y,chain2.bones[j2].nextPosition.z = chain2.joints[j2]:unpack()
							-- 	end
							-- end
						end
					end
				end

				for c,chain in ipairs(layer.chains) do 
					for b,bone in ipairs(chain.bones) do 
						layer.pose[chain.indexes[b]]= -chain.joints[b]
					end
				end
			end
		end

		----------------------------------------
		if layer.chains then 
			for c,chain in ipairs(layer.chains) do 
				for b,bone in ipairs(chain.bones) do 
					local vec = chain.joints[b]
					local pos = camera.project(-vec)
					if panel then 
						gfx.push("all")
							gfx.setBlendMode ('alpha', 'premultiplied')
							gfx.setColor(1,1,1,0.3-math.dist(mouse.x,mouse.y,pos.x,pos.y)/200)
							gfx.print(tostring(b)..", "..bone.name,pos.x+8,pos.y+4)
						gfx.pop()
						if bone.render then bone.render.ox,bone.render.oy = pos.x,pos.y end
					end

					
					local parent = layer.bones[bone.parentID]
					if parent and b>1 then 
						local parent2 = parent.parentID and layer.bones[parent.parentID]
						local target = (vec-chain.joints[b-1]):normalize()

						if bone.last  then 
							local prot1 = (parent2 and getRot(parent2,false) or quat()):inverse()
							local prot2 = (parent2 and getRot(parent2,true ) or quat()):inverse()
							local diff = quatBetweenVecs(prot1*bone.last,prot2*target)
							local rotation = diff

							local change = math.abs(diff.x)+math.abs(diff.y)+math.abs(diff.z)+math.abs(diff.w)

							-- trace(bone.parentID,change)

							layer.nextPose[bone.parentID] = rotation:normalize()

						end
						if editingLevel and panel then 
							bone.last = target:clone()
						end
					end
				end
			end

			for b,bone in pairs(layer.nextPose) do 

				if bone then 
					pose[b].rotate = bone*pose[b].rotate 
				end
			end
		end

		scene.updatePose(layer,pose)

		------------------------------------------
		if editingLevel and not panel then 
			layer.poseMesh = nil
		elseif layer.boneLinks[1] then 
			local verts = {}
			for i,link in ipairs(	 layer.boneLinks  )do
				local c1 = layer.bones[link[1]].selected and {1,0.5,0.3} or {1,1,1}
				local c2 = layer.bones[link[2]].selected and {1,0.5,0.3} or {1,1,1}
				-- local x1,y1,z1 = layer.pose[link[1]]:getPosition():unpack()
				-- local x2,y2,z2 = layer.pose[link[2]]:getPosition():unpack()
				table.insert(verts, {layer.pose[link[1]].x, layer.pose[link[1]].y, layer.pose[link[1]].z,1, unpack(c1)})
				table.insert(verts, {layer.pose[link[2]].x, layer.pose[link[2]].y, layer.pose[link[2]].z,1, unpack(c2)})
				table.insert(verts, {layer.pose[link[1]].x, layer.pose[link[1]].y, layer.pose[link[1]].z,1, unpack(c1)})
			end
			if not layer.poseMesh then 
				layer.poseMesh = gfx.newMesh(zformat3,#verts*2,"triangles")
			end 

			layer.poseMesh:setVertices(verts,1)

			local v = #verts+1
			if layer.chain and layer.chain.joints then 

				local joints = layer.chain.joints
				for j=0,#joints-2,1 do
					layer.poseMesh:setVertices({
						{-joints[j+1].x,  -joints[j+1].y,  -joints[j+1].z,1, 0.5,1,1},
						{-joints[j+2].x,  -joints[j+2].y,  -joints[j+2].z,1, 0.5,1,1},
						{-joints[j+1].x+0.1,-joints[j+1].y+0.1,-joints[j+1].z+0.1,1, 0.5,1,1}
					},v)
					v=v+3
				end
			end
		end



	else 
		layer.poseMesh = nil
		layer.bones=nil
	end

end

function checkTransform(t)
	t.position = vec3.is_vec3(t.position) and t.position or vec3(t.position) 
	t.orientation = quat.is_quat(t.orientation) and t.orientation or quat(t.orientation) 
	t.scale = vec3.is_vec3(t.scale) and t.scale or vec3(t.scale) 
end

function scene.updateEntityIQM(entity,target,layer,layerFrame,l,onion,update,play,f,cf,nextFrame,progress,transform)

	local update = update or (not target.anim)
	local trackChanged = false
	target.anim = target.anim or anim9(layer.iqmAnims) 
	--trace("#anims",lume.count(target.anim.timeline))

	if not play then 
		if target.track then
			target.track.blend=1
		end
		if target.track2 then 
			target.track2.blend=0
			if nextFrame.anim==layerFrame.anim then 
				target.track2=nil
			end
		end
	end

	if target.anim and layerFrame.anim and layerFrame.anim~="" then 
		if  (not target.track or layerFrame.anim~=target.nextAnim) then
			trackChanged=true
			--trace("NEWTRACK")
			target.nextAnim = layerFrame.anim
			target.nextAnim2= layerFrame.anim
			target.anim:stop()
			target.track2 = nil
			target.track = target.anim:new_track(target.nextAnim,1,1, function(anim) anim.time=0 end)
			target.anim:play(target.track)
		end
	end

	if not onion and layerFrame.tween and layerFrame.tween.blend==true  and (nextFrame.anim~=layerFrame.anim)==true and (target.nextAnim2~=nextFrame.anim)==true then 
		trackChanged=true
		target.nextAnim2 = nextFrame.anim
		--log("new blend track")

		target.track2 = target.anim:new_track(target.nextAnim2,1,1, function(anim) anim.time=0 end)
		target.anim:play(target.track2)
	end

	local length = target.anim:length(target.nextAnim)

	bench.push("5")
	if target.anim and update then 
		local start = scene.getStartFrame(layerFrame,layer,cf) or layerFrame.abs
		target.track.time = utils.wrap(((f-start)/(length*18))*length,length*0.99)
		--trace("1time",target.track.time)

		if target.track2 and progress and play then 
			local length2 = target.anim:length(target.nextAnim2)
			target.track2.time = utils.wrap((target.track.time/length)*length2,length2*0.99)--utils.wrap(((f-nextFrame.abs)/(length2*18))*length,length2*0.99)
			target.track2.blend  = mc(0,progress*2,1)
			target.track.blend   = 1-progress
			target.nextStartTime = target.track2.time
			--trace("2time",target.track2.name,target.track2.time)
		end

		if entity.ticked or trackChanged then 
			bench.push("A")
			target.anim:update(0)
			bench.pop("A")
		end
		
		bench.push("B")
		entity.models[l].skelly=true
		--entity.models[l].skelly = lume.map(target.anim.current_pose,makeProper)
		bench.pop("B")
		--entity.models[l].skelly.nocopy = true
		target.anim.nocopy = true
		target.track.nocopy = true
		target.nocopy = true
		
		if target.track.time >= target.anim:length(target.nextAnim) then 
			--target.anim:play(target.track)
			--target.track.time = 0
			--target.anim:update(0)
		end

		if not editingLevel then 
			if target.anim.current_matrices and entity.transform and transform then 
				pushPost()
				gfx.push("all")
				gfx.reset()
				local alpha = editor.debug.feet and 1 or 0
				local screenSpace,screenSpace2,screenSpace3
				local worldSpace
				local name 
				local range = 2.3
				local side 
				for b,bone in pairs(target.anim.current_matrices) do 
					gfx.setColor(1,1,1,1*alpha)
					name = target.anim.skeleton[b].name
					side = name:sub(6,6)
					if name:sub(1,4)=="Foot" then 
						worldSpace = bone*-transform*-entity.transform*blankVec
						screenSpace = camera.project(worldSpace)/game.resolution
						gfx.print(name,screenSpace.x+4,screenSpace.y)
						entity.footTurn = entity.footTurn or "R"

						if worldSpace.y>entity.floor-range and worldSpace.y<entity.floor+range*2 then
							if not entity[name] then 
								entity.stepPoint = worldSpace:clone()
								entity.footTurn = side
								entity.footEase = 0
								--target.anim.overrides = {[b]={worldSpace=worldSpace,translate=bone*vec3(0)}}
							end
							entity[name] = true
							gfx.setColor(1,0.2,0.3,1*alpha)
							gfx.circle("fill",screenSpace.x,screenSpace.y,7,20)
							gfx.setColor(1,1,1,1*alpha)
						else
							entity[name] = false
						end

						if side==entity.footTurn then 
							entity.footPoint = worldSpace:clone()
							if target.anim.overrides and target.anim.overrides[b] then 
								screenSpace2 = camera.project(target.anim.overrides[b].worldSpace)/game.resolution
								gfx.setColor(0.2,1,0.2,1*alpha)
								gfx.circle("fill",screenSpace2.x,screenSpace2.y,5,20)
								--target.anim.overrides[b].translate = -layerFrame.orientation * -entity.orientation * (entity.position+target.anim.overrides[b].worldSpace) * entity.scale
							end
							gfx.setColor(0.3,0.2,1,1*alpha)
							gfx.circle("fill",screenSpace.x,screenSpace.y,5,20)
						end
						gfx.circle("fill",screenSpace.x,screenSpace.y,5,20)
					end 
				end
				if entity.stepPoint then
					gfx.setColor(1,0,1,1*alpha)
					screenSpace3 = camera.project(entity.stepPoint)/game.resolution
					gfx.circle("fill",screenSpace3.x,screenSpace3.y,8,20)
					screenSpace3 = camera.project(entity.footPoint)/game.resolution
					gfx.circle("line",screenSpace3.x,screenSpace3.y,10,20)

					entity.footDiff = entity.stepPoint-entity.footPoint
					trace("entity.stepPoint-entity.footPoint",entity.stepPoint-entity.footPoint)

					
					--entity.footEase = 0.2
					
					--entity:move(-entity.footDiff.x*entity.footEase,0,-entity.footDiff.z*entity.footEase)
				end
				gfx.pop()
				popPost()
			end
		end
	end
	bench.pop("5")
end

function scene.getStartFrame(frame,layer,cf)
	local start = frame.abs
	for i=cf,1,-1 do 
		if layer.frames[i] and layer.frames[i].anim and layer.frames[i].anim==frame.anim then 
			start=layer.frames[i].abs
		else 
			break
		end
	end
	return start
end

function scene.getKeyFrame(layer,currentFrame)
 	local frameCount 	= 1
 	local frameMark 	= 1
 	for f,frame in ipairs(layer.frames) do 
		if (frameCount+frame.l>=currentFrame and frameCount<=currentFrame) or frameCount==currentFrame   then
			frameMark = f
		end
		frameCount=frameCount+frame.l
	end
	return frameMark
end


function scene.updateEntityLasso(entity)

	if  editState=="Normal" and currentRoom.key==room.key and entity.visible and   
		(
			selectAll
				or 
			(levelClicked 
			and currentTool == "Select" 
			and entity.render.x and simplePointInRect({x=entity.render.x/game.resolution,y=entity.render.y/game.resolution},selectBounds))
		) 
	then
		editor.deleteFromSelectedEntities(entity.uid)
		if not scene.entitySelected(entity) 
				and (not pathsPanel.open or entity.simple) 
				and (not animationPanel.open or entity.bone) then
			table.insert(selectedEntities,entity)
		end
	end
end

function scene.updateEntityVars( entity )
	entity.i = entity.index
	entity.time = entity.time +1
	entity.layer = entity.surface and -0.15 or 0

	if  (#selectedEntities~=numSelected) then
		entity.selected = scene.entitySelected(entity)
	elseif #selectedEntities==0 then 
		entity.selected = false
	end
	
	if entity.selected then 
		entity:move(0,0,0)
	end

	if entity.light.enabled and entity.light.isLight then 
		if not lume.find(room.lights,entity.light) then 
			entity.light.entity = entity.uid
			table.insert(room.lights, entity.light)
		end
	end

	entity.hovered 	= (hoveredEntity==entity)
	
	if entity.particle then 

	else 
		scene.updateEntityCollision(entity)
	end

	-- entity.pos =  entity.position
end

function scene.updateEntityCollision(entity)
	if  editingLevel then 
		return 
	else 
	 	entity:move 			()
	 	entity:damp 			()
	end

	entity.floor = entity.floor or 0
	entity.plane = nil
	entity.head = nil

	if entity.gravity then 
		scene.updateEntityPlane(entity)
	end

	scene.updateEntityPlaneVars(entity)

	local slideVec = vec2(0,0)
	local slidVec = vec2(0,0)
	local edgeVec = vec2(0,0)
	local dirVec = vec2(-entity.v.x,-entity.v.z)
	local slide = {}
	local edgeDot 
	local edgeIn
	local radius = 20
	local dist,dist2,dist3
	local collided = 999
	local newPos = vec2(0)
	local corner 

	entity.cantOffset=false
	entity.edgeResults = entity.edgeResults and lume.clear(entity.edgeResults) or {}

 	if not entity.ghost and entity.gravity then
		local nearfloor = math.abs(-entity.floor-entity.y)<10

 		if entity.plane and entity.plane.edges then 

 			scene.drawDebugPlanes(entity,6,{entity.planePos1.x,entity.planePos1.y,entity.planePos2.x,entity.planePos2.y})
 			
			for e,edge in ipairs(entity.plane.edges) do 

	 			scene.drawDebugPlanes(entity,5,edge)
	 			dist = distPointToLineSegment({entity.planePos1.x,entity.planePos1.y},{edge.p1.x,edge.p1.y},{edge.p2.x,edge.p2.y})
	 			dist3 = entity.planePos3 and distPointToLineSegment({entity.planePos3.x,entity.planePos3.y},{edge.p1.x,edge.p1.y},{edge.p2.x,edge.p2.y}) or 999
	 			if  dist3<radius then 
	 				entity.cantOffset=true
	 			end
	 			if  dist<radius then 
	 				local projected = {entity.planePos1.x+edge.norm.x*-dist,entity.planePos1.y+edge.norm.y*-dist}
	 				dist2 = distPointToLineSegment(projected,{edge.p1.x,edge.p1.y},{edge.p2.x,edge.p2.y})

	 				if dist2>1 then 
		 				local side = math.dist(edge.p1.x,edge.p1.y,projected[1],projected[2])<math.dist(edge.p2.x,edge.p2.y,projected[1],projected[2]) and edge.p1 or edge.p2
		 				local dv2 = (side-entity.planePos1):normalize()*radius
		 				local newCoords = side-dv2
		 				scene.drawDebugPlanes(entity,6,{side.x,side.y,entity.planePos1.x,entity.planePos1.y})
		 				if dist<collided then 
			 				entity:setPosition(-newCoords.x,nil,-newCoords.y)
			 				collided = dist
			 			end
	 				else 
		 				scene.drawDebugPlanes(entity,6,{entity.planePos1.x,entity.planePos1.y,projected[1],projected[2]})
		 			
		 				coords = {entity.planePos1.x+edge.norm.x*-dist,entity.planePos1.y+edge.norm.y*-dist}
		 				edgeVec 	= vec2(edge[3]-edge[1],edge[4]-edge[2]):normalize()
		 				coords 		= vec2(coords)
		 				local newCoords = coords+vec2(edge.norm.x*radius,edge.norm.y*radius)
		 				coords 		= coords+edgeVec:perpendicular()
		 				slideMul 	= (radius-dist)/radius
		 				dot 			= vec2.dot(dirVec,edgeVec)
		 				slideVec  = (edgeVec*dot):normalize()
		 				slideVec  = slideVec  * slideMul
		 				slidVec 	= coords+slideVec*100
		 				slide 		= {coords.x,coords.y,slidVec.x,slidVec.y}
		 		
		 				table.insert(entity.edgeResults,vec2(-newCoords.x,-newCoords.y))

		 				if dist<collided or #entity.edgeResults>1 then 
			 				entity:setPosition(-newCoords.x,nil,-newCoords.y)
			 				scene.updateEntityPlaneVars(entity)
			 				scene.drawDebugPlanes(entity,7,slide)
			 				collided = dist
			 			end
		 			end
	 			end
			end
	 	end
	 
	 	if nearfloor and entity.v.y<1 then
	 		entity.v.y=0
	 		entity:setPosition(nil,-entity.floor)
	 	else
	 		entity:changeVelocity      (0,-1,0)--keyDown("q") and -1 or keyDown("e") and 1 or 0,0)
	 	end

	 	entity:setPosition (nil,math.max(-entity.floor,entity.y))
	 	entity.position.y  = math.max(-entity.floor,entity.y)
	end
end

function scene.updateEntityPlaneVars(entity)
	entity.planeAng = math.angle(0,0,entity.v.x,entity.v.z)
	entity.planeDist  = math.max(1,math.dist(0,0,entity.v.x,entity.v.z))
	entity.planeDir = vec2.from_cartesian(entity.planeDist,entity.planeAng )
	entity.planePos1.x,entity.planePos1.y=-entity.x,-entity.z
	entity.planePos2.x,entity.planePos2.y=-entity.x-entity.planeDir.x,-entity.z-entity.planeDir.y
	if entity.frameOffsetStored then 
		entity.planePos3 = { x=-entity.x+entity.frameOffsetStored.x, y=-entity.z+entity.frameOffsetStored.z }
	end
end

function scene.drawDebugPlanes(entity,step,plane,color)
	if not editor.debug.draw_ground_planes then  return end
	pushPost()
	gfx.push("all") 
	gfx.setShader()
	gfx.translate(screenWidth/2,screenHeight/2) 
	gfx.rotate(-cam.angle.x)
	gfx.translate(cam.x,cam.z) 
	gfx.scale(0.5,0.5)
	--gfx.translate(-screenWidth/2,-screenHeight/2)
	
	if 			step == 1 then 
			gfx.setColor(1,1,1,0.5)
			gfx.circle("line",-entity.x,-entity.z,12)
			gfx.line(plane.shape) 
			
	elseif step == 2 then 
			gfx.setColor(1,1,1,1)
			gfx.polygon("line",plane.shape) 
			gfx.circle("line",-entity.x,-entity.z,9)

	elseif  step == 3 then 
			gfx.circle("fill",-entity.x,-entity.z,6)
			gfx.setColor(1,1,1,1)
			gfx.setLineWidth(3)
			gfx.polygon("line",plane.shape) 

	elseif  step == 4 then 
			gfx.setColor(1,0,0,1)
			gfx.line(entity.plane.shape) 
	elseif  step == 5 then 
			gfx.setLineWidth(2)
			gfx.setColor(0,1,0,1)
			gfx.line(plane) 
	elseif  step == 6 then 
			gfx.setLineWidth(2)
			gfx.setColor(0,0,1,1)
			gfx.line(plane) 
	elseif  step == 7 then 
			gfx.setLineWidth(4)
			gfx.setColor(1,0,1,1)
			gfx.line(plane) 
	end
	gfx.pop() 
	popPost()
end

function scene.updateEntityPlane(entity)
	local floored  = false
	local bottom = 0--entity.pointBottom and 0 or entity.bbox[5]
	if not entity.ghost and not (entity.simple and pathsPanel.open) and entity.gravity then 
		local ceiled  = false
		local highestFloor  = 0
		for p,plane in ipairs(room.planes) do
			local incline 	= 40--(plane.incline or 10)*2
			local ytest 	= -(entity.y+(entity.bbox and entity.bbox[5] or 0)+incline)
			local ytest2 	= -((entity.bbbox and entity.bbbox[2] or entity.y-20))--+(entity.prev.y-entity.y)+(entity.bbox and entity.bbox[5] or 0)-incline
		
			scene.drawDebugPlanes(entity,1,plane)
			if ytest < plane.y and plane.group~=8  then
				scene.drawDebugPlanes(entity,2,plane)
				
				if point_in_poly(plane.shape,{x=-entity.x,y=-entity.z}) then
					scene.drawDebugPlanes(entity,3,plane)
					if plane.isFloor then
						if plane.y<highestFloor then 
							highestFloor 	= plane.y
							entity.plane 	= plane
							entity.floor 	= plane.y
							floored 		= true
						end
					else
						local floor = scene.evaluateRamp(plane,-entity.x,-entity.z,true)
						trace("ramp",floor,ytest)
						if ytest<floor and floor<highestFloor  then 
							highestFloor 	= floor
							entity.plane 	= plane
							entity.floor 	= floor
							floored 		  = true
						end
					end
				end
			end
		end
		if entity.plane then 
			scene.drawDebugPlanes(entity,4)
		end

		entity.floor 	= floored and (entity.bbox and entity.floor-math.max(entity.bbox[5],0) or entity.floor) or (editor.gridEnabled and 0 or math.huge)
		entity.floorb = entity.floor+(entity.bbox and entity.bbox[5] or 0)--+entity.bbox[5]*2+40
	end
	-- LINK
	--trace("entity.transferring", entity.transferring)
	if not editingLevel and entity.transferring==false  and entity.plane and (entity.plane.dest or entity.plane.source) and floored then 
		local side,l2,ang,r1,r2,d,l
		local projected 		= 	{ x=entity.x-(entity.prev.x-entity.x)*2, z=entity.z-(entity.prev.z-entity.z)*2 }
		local s 				= 	entity.plane.shape
		local s					= 	entity.plane.source and {s[1],s[2],s[7],s[8]} or  {s[3],s[4],s[5],s[6]}
		local dist 			= 	distPointToLineSegment({entity.x,entity.z}, {s[1],s[2]}, {s[3],s[4]})
		d 							= 	entity.plane.source or entity.plane.dest
		if dist<10 and  point_in_poly(entity.plane.shape,{x=entity.x,y=entity.z})  then 
			ang  = math.angle( s[1],s[2],s[3],s[4])+pi/2
			entity.testline = {
				{x = s[1],		y=s[2]}, 			
				{x = s[3],		y=s[4]}
			}

			r1, r2 = math.intersect(
				{x = projected.x,	y=projected.z},	
				{x = entity.x,		y=entity.z}, 	
				entity.testline[1], 			
				entity.testline[2]
			)

			if r1 then 
				local dest = level.rooms[d.room][d.mode][d.path]
				if dest then 
					local progress = mc(0,(math.dist(entity.x,entity.z,s[1],s[2])-math.dist(entity.x,entity.z,s[3],s[4]))/math.dist(s[1],s[2],s[3],s[4])*0.5+0.5,1)
					local coords = dest.points[d.side=="source" and 1 or #dest.points]
					l = dest[d.side].line
					coords = {
						x = lerp( l[1],  	l[3] , progress),
						z = lerp( l[2], 	l[4] , progress),
						y = l[5]-10,
					}
					entity.transferring 	= true
					entity:transfer(coords,d.room~=room.key and d.room or nil)
				end
			end
		end
	end
end


function scene.updateScripts(entity)
	if  editingLevel then  return end
	local success
	for s,script in ipairs(entity.scripts) do
		if script.enabled and script.file and not script.broken then 
			if script.file.load and scene.time == 1 then 
				success = pcall(script.file.load)
			elseif 	script.file.loop and scene.time>1 then
		   	success = pcall(script.file.loop)
			end
		end
	end
end


function scene.updateEntityBounds(entity)
	
	-- HOVER
	if  --view==currentRoom 
		 not entity.particle
		and entity.visible
		and (lastroomHovered==currentRoom or roomZoom==0)
		and not editor.linkHovered
		and stageHovered
		--and entity.layer==layer
		and currentTool=="Select"
		and (editState == "Normal" or editState == "Transforming")
		and not(animationPanel.open and animationPanel.instance==entity)
		and (not pathsPanel.open or entity.simple) 	then 

		if (entity.simple or entity.light.enabled) and entity.render and entity.render.x then 
			if math.dist(mouse.x,mouse.y,entity.render.x,entity.render.y)<pathsPanel.pointSize*1.5 then
				
				editor.pointing = true
				editor.modelHovered = nil
				editor.entityHovered = entity
				scene.setHoveredEntity(entity)
				entity.hovered=true
			end
		elseif editor.entityHovered == entity then 
			if editingLevel  and currentRoom.key==room.key then 
				
				if hoveredEntity~=nil then 
					hoveredEntity.hovered = false
				end
				scene.setHoveredEntity(entity)
			end 
		end
	end
end

function scene.setHoveredEntity(entity)
	hoveredEntity = entity
	entity.hovered=true
end


function scene.generateEvents(entity)

end

