camera={}
zcam = {perspective=mat4(),viewMatrix=mat4(),pos=vec3(),angle=vec3(),transform=mat4()}

function matrix(m)
  if type(m) == "table" then return m end

  for i=1, 16 do
    matrix[i]=m[i]
  end

  return matrix
end

local viewMatrix=mat4()
local perspective = makeProper(mat4.from_perspective(30, gfx.getWidth()/gfx.getHeight(), 0.1, 10000))
local lightPerspective = perspective


function camera.setup(cam1,cam2)
	local cam1 = cam1 or {}
	local newCam 	= {
		x		 	= 0,
		y		 	= 0,
		z 		 	= 0,
		offset 		= {x=0,y=0},
		sx 			= 0,
		sy 			= 0,
		sz 		 	= 0,
		tilt 	 	= 0,
		soomMax 	= 1,
		soom 	 		= 0.9,
		zoom 			= 1,
		izoom 		= 1,
		shake 	 	= 0,
		fade 	 		= 0,
		focalM 	 	= 0,
		focalL 	 	= 0,
		focalS 		= 1,
		track 	 	= 0,
		speed 	 	= 0,
		ztest 		= 20,
		blur	 	= false,
		lineZoom 	= 0.3,
		angle 		= {x=0,y=0,z=0,tx=0,ty=0,tz=0},
		wobbles 	= {},
		stored 		= {x=0,y=0},
		storedOffset= {x=0,y=0},
		dof 	 	= {
			frontLimit	= 2,
			backLimit	= 1,
			frontStrength	= 7,
			backStrength	= 7
		},
		center 			= {
			x=0,
			y=0,
		},
		zoomBounds 		= {0,1}
	}
		
	local cam = cam2 and {} or cam1

	if cam2 then 
		for k,v in pairs(newCam) do 
			cam[k] = cam1[k] or deepcopy(newCam[k])
		end
	else
		for k,v in pairs(newCam) do 
			cam[k] = cam1[k] or deepcopy(newCam[k])
		end
	end

	cam.zoomRange  = cam.zoomBounds[2]-cam.zoomBounds[1]
	cam.zoomPct 	= cam.zoom-cam.zoomBounds[1]/cam.zoomRange

	return cam
end


local yeet=vec3()
function camera.project(obj,v)
	local vert = vec3.is_vec3(obj) and obj or vec3(obj)
	local p,proj = nil,yeet
	local view = currentRoom
	local cam = view.camera

	if v or view.bounds then 
		-- if cam.lookDirection and (level.isAnim or cpml.mesh.signed_distance(vert,{origin=cam.pos,normal=cam.lookDirection})>0) then 
			p,proj = pcall(
				mat4.project , 
				vert, 
				cam.viewMatrix , 
				cam.perspective , 
				v or {view.bounds.l,view.bounds.t,view.bounds.w,view.bounds.h} 
			)
			-- trace("PRO",proj)
		-- end
	end

	return proj,p
end

function camera.adjust(cam,view)
	bench.push("adjust camera")
	if type(cam.angle)=="number" then 
		cam.angle = {x=0,y=0,z=0,tx=0,ty=0,tz=0} 
	end
	--cam  			=  lume.merge(cam,effects.wobble(cam.wobbles))
	
	local maxZoom = level.isAnim and (animationPanel.debugView and 0.77 or 0.81) or 0.85
	cam.zoomBounds  = {-1.2,1.2,2.4}
	
	cam.dropz 		= mc(room.zbounds.back,cam.z,room.zbounds.front)
	cam.ztest 		= 20
	--cam.focalL 		= mc(0,cam.focalL,0.5)

	cam.tilt 			= mc(0,cam.tilt,1)
	cam.soomMax 	= animationPanel.open and 1.2 or 1
	cam.soom 			= cam.soom>cam.soomMax and easeTo(cam.soom,cam.soomMax,2,5) or cam.soom<maxZoom and easeTo(cam.soom,maxZoom,2,5) or cam.soom
	cam.zoom 			= cam.soom*6 * (1+cam.focalL)
	cam.izoom 		= 1/cam.zoom
	cam.overhead 	= cam.tilt*cam.focalL*2>0.5
	cam.pfov      = cam.fov or 0
	cam.fov 			= (cam.soom-0.7)*360-20

	-- print("")
	if animationPanel.exporting then 
		cam.fov = math.deg(pi/4)
		cam.x,cam.y,cam.z = 0,0,-(animationPanel.stageWidth*0.678)
		cam.angle.tx,cam.angle.ty = 2*pi,0
	end

	local num = 1000

	if view  then 
		
		local aspect = animationPanel.exporting and animationPanel.stageAspect or (view and view.bounds.w/view.bounds.h or game.aspectRatio)
		if cam.ortho then 
			local num2 = num*(cam.soom^16)
			cam.perspective = mat4.from_ortho(-num2*aspect, num2*aspect, num2, -num2, 0.1, 2000)
		else
		 cam.perspective = mat4.from_perspective(cam.fov, aspect, level.isAnim and 1 or 1, level.isAnim and 1000 or 4000)
		end

		cam.viewMatrix = cam.viewMatrix or mat4()
		
		local preCam 	


		if not editingLevel then  

			if cam.shake>0 then 
				cam.x = cam.x + cam.shake*(math.random()*2-1)
				cam.y = cam.y + cam.shake*(math.random()*2-1)
				cam.shake = cam.shake-1
			end

			preCam  	 =  lume.merge(cam,effects.wobble(cam))

			postDraw = {}
		else 
			preCam = cam
		end

		cam.viewMatrix = getView(preCam)

		if LOVR then 
			zcam.perspective = cam.perspective
			zcam.viewMatrix = cam.viewMatrix
		else
			zcam.perspective:transpose(cam.perspective)
			zcam.viewMatrix:transpose(cam.viewMatrix)
		end

		shaders.forwardRender:send("cameraPosition",{-cam.x,-cam.y,-cam.z})
		zcam.ray 		= editingLevel and getCursorRay(mouse.x,mouse.y,view) or zcam.ray

		cam.vp = mat4.mul(cam.vp or mat4() 	,	 cam.perspective, cam.viewMatrix)
		zcam.vp = mat4.mul(zcam.vp or mat4() 	,	 zcam.perspective, zcam.viewMatrix)


		--zcam.frustum = mat4.to_frustum(viewMatrix, false) -- GC 
	end

	camera.orbit(cam)
-- trace("  cam.focalL   "..round(cam.focalL,2))
-- 		trace("  cam.tilt     "..round(cam.tilt,2))
-- 		trace("  cam.soom     "..round(cam.soom,2))
-- 		trace("  cam.zoom     "..round(cam.zoom))
-- 		trace("  cam.izoom    "..round(cam.izoom,2))

	if not light and editor.debug.trace_camera then 
		trace("")

		trace("camera:  ")
		trace(" cam.pos  ",zcam.pos)
		if zcam.lookDirection then 
			trace(" cam.dir  ",zcam.lookDirection)
		end
		-- trace("  cam.focalL   "..round(cam.focalL,2))
		-- trace("  cam.tilt     "..round(cam.tilt,2))
		-- trace("  cam.soom     "..round(cam.soom,2))
		-- trace("  cam.zoom     "..round(cam.zoom))
		-- trace("  cam.izoom    "..round(cam.izoom,2))
		trace(" cam.fov    "..tostring(cam.fov))

		trace("")
	end

	zcam.lookDirection = vec3.rotate(vec3.rotate(vec3(0,0,1), cam.angle.y , vec3.unit_x), pi-cam.angle.x , vec3.unit_y) 
	cam.lookDirection = zcam.lookDirection:clone()
	cam.pos = zcam.pos:clone()
	bench.pop("adjust camera")
end


function camera.orbit(cam)
	if editor.orbiting and editor.orbiting.target and not scene.drawingShadow then 
		editor.orbiting.ease = animationPanel.open and 1 or lerp(editor.orbiting.ease,0.8,0.04)
		local newx = pi/2+editor.orbiting.angx - (mouse.x-editor.orbiting.mouse.x)/200
		local newy = editor.orbiting.angy- (mouse.y-editor.orbiting.mouse.y)/200
		local pre = vec3.rotate(vec3(0,0,1), newy, vec3.unit_x)
		local new = editor.orbiting.target + vec3.rotate(pre, newx, vec3.unit_y)*editor.orbiting.dist
		local ease = editor.orbiting.ease
		cam.angle.x = lerpang( cam.angle.x, pi-newx,ease )
		cam.angle.tx=cam.angle.x
		cam.angle.y = lerpang( cam.angle.y,  newy,ease )
		cam.angle.ty=cam.angle.y
		while cam.angle.tx<0 do 
			cam.angle.tx=cam.angle.tx+pi*2
			cam.angle.x=cam.angle.x+pi*2
		end
		while cam.angle.tx>2*pi do 
			cam.angle.tx=cam.angle.tx-pi*2
			cam.angle.x=cam.angle.x-pi*2
		end
		cam.x = lerp(cam.x,new.x,ease)
		cam.y = lerp(cam.y,new.y,ease)
		cam.z = lerp(cam.z,new.z,ease)

		if lkeyboard.isDown("w", "up") then 
			editor.orbiting.dist = editor.orbiting.dist * 0.97
		elseif lkeyboard.isDown("s", "down") then 
			editor.orbiting.dist = editor.orbiting.dist * 1.03
		end

	else

		cam.angle.x = easeTo(cam.angle.x,cam.angle.tx or cam.angle.x,camera.ease,20)
		cam.angle.y = easeTo(cam.angle.y,cam.angle.ty or cam.angle.y,camera.ease,20)

		while cam.angle.tx<0 do 
			cam.angle.tx=cam.angle.tx+pi*2
			cam.angle.x=cam.angle.x+pi*2
		end
		while cam.angle.tx>2*pi do 
			cam.angle.tx=cam.angle.tx-pi*2
			cam.angle.x=cam.angle.x-pi*2
		end

	end

	if math.abs(cam.angle.tx-cam.angle.x)<0.01 then cam.angle.x=cam.angle.tx end
	if math.abs(cam.angle.ty-cam.angle.y)<0.01 then cam.angle.y=cam.angle.ty end
	cam.stopped = cam.angle.tx==cam.angle.x and cam.angle.ty==cam.angle.y
end

function camera.reset(cam,snap)
	cam.x,cam.y,cam.z = 0,0,-145
	cam.angle.tx,cam.angle.ty = 2*pi,0

	if snap then 
		cam.angle.x,cam.angle.y = cam.angle.tx,cam.angle.ty
	end
end

function camera.control(cam)
	if currentRoom.camera ~= cam then return end
	if cmdDown and keypressed("o") then
		cam.fov=cam.fov+0.01
	end
	if cmdDown and keypressed("i") then
		cam.fov=cam.fov-0.01
	end

	if keypressed("0") then
		
		if not level.isAnim and animationPanel.open then 
			if cmdDown then 
				--cam.x,cam.y,cam.z = animationPanel.drawingPosition:unpack()
			end
			cam.angle.tx = math.angle(cam.x,cam.z,cam.lookTarg.x,cam.lookTarg.z)-pi/2
			cam.angle.ty = math.angle(0,0,math.dist(cam.x,cam.z,cam.lookTarg.x,cam.lookTarg.z),cam.lookTarg.y-cam.y)
		else 	
			if cmdDown then 
				camera.reset(cam)
			end
		end
		lmouse.setRelativeMode(false)
	end

	mouse.pushClickR(function() if lmouse.getRelativeMode() then  lmouse.setRelativeMode(false) restoreFreeMouse() end end)
	if stageHovered then 
		mouse.pushClickM(function() 
			if level.isAnim and animationPanel.l.type and animationPanel.l.type~="model" then return end
			local orbit 
			if animationPanel.open and animationPanel.orbit then 
				orbit = not altDown
			else
				orbit = altDown 
			end
			if orbit then 
				local target
				if animationPanel.open then 
					-- if not editor.lastIntersect then 
						-- if not animationPanel.orbitPosition then 
							target=animationPanel.instance.position 
					-- 	else 
					-- 		target=animationPanel.orbitPosition 
					-- 	end
					-- else
					-- 	animationPanel.orbitPosition = editor.lastIntersect 
					-- 	target = animationPanel.orbitPosition 
					-- end
				else
					target=editor.lastIntersect
				end

				if target then 

					editor.orbiting = {
						ease    = 0,
						mouse 	= vec2(mouse),
						start 	= vec3(cam),
						base 		= vec3(cam)-target,
						angx 		= pi-math.angle(		cam.x,cam.z,target.x,target.z),
						dist 	= vec3.dist( vec3(cam), target),
						target 	= target 
					}
					editor.orbiting.angy = math.angle(0,0,vec2.dist(vec2(target.x,target.z),vec2(cam.x,cam.z)),target.y-cam.y)
				end
			else
				lmouse.setRelativeMode(true)
				storeFreeMouse() 
			end
		end)
	end

	editor.mouseRelative = lmouse.getRelativeMode() or editor.orbiting

	mouse.pushReleaseM(function() 
		if editor.orbiting then 
			editor.orbiting = nil
		end
		if  lmouse.getRelativeMode()  and stageHovered then 
			restoreFreeMouse() 
		end
		lmouse.setRelativeMode(false)   
	end)

	
	if (keypressed("tab") ) and not (animationPanel.open or overviewPanel.open) then
		if lmouse.getRelativeMode() then restoreFreeMouse() else storeFreeMouse() end
		lmouse.setRelativeMode(not lmouse.getRelativeMode())
		if type(cam.angle)=="number" then cam.angle = {x=0,y=0,z=0,tx=0,ty=0,tz=0} end
	end

	if cmdDown and keypressed("p") then
		local room = currentRoom.room
		room.lighting.enabled = true 
		room.lighting.render.run=not room.lighting.render.run
		room.lighting.render.enabled=room.lighting.render.run
		-- editor.debug.draw_ground_planes = not editor.debug.draw_ground_planes
	end

	camera.ease = 2

	if  lmouse.getRelativeMode() then 
		camera.ease = 4
		local slow = animationPanel and animationPanel.open 
		local preSpeed = 200
		local altSpeed = slow and 0.2 or 3
		local speed = preSpeed * main_dt * ((shiftDown or rightTrigButtonDown) and altSpeed or 1)
		local target

		target = (leftAnalogVert or 0)+(lkeyboard.isDown("w", "up") and 1 or (lkeyboard.isDown("s", "down") and -1 or 0))
		cam.forwardVelocity = easeTo(cam.forwardVelocity or 0, target,(slow and math.abs(target)>math.abs(cam.forwardVelocity)) and 16 or 4)
		cam.x = cam.x + math.sin(-cam.angle.x) * cam.forwardVelocity * speed
		cam.z = cam.z + math.cos(-cam.angle.x) * cam.forwardVelocity * speed
		
		target = -(leftAnalogHori or 0)+(lkeyboard.isDown("d", "right") and -1 or (lkeyboard.isDown("a", "left") and 1 or 0))
		cam.sideVelocity = easeTo(cam.sideVelocity or 0,target,(slow and math.abs(target)>math.abs(cam.sideVelocity)) and 16 or 4)
		cam.x = cam.x + math.cos(cam.angle.x) * cam.sideVelocity * speed
		cam.z = cam.z + math.sin(cam.angle.x) * cam.sideVelocity * speed

		cam.upVelocity = easeTo(cam.upVelocity or 0,(lkeyboard.isDown("e") and 1 or (lkeyboard.isDown("q") and -1 or 0)),4)
		cam.y = cam.y + cam.upVelocity  * speed
	end

	if LOVE and lmouse.getRelativeMode() then
		lmouse.setPosition( mouse.preRelative.x, mouse.preRelative.y )
	end
end

function storeFreeMouse()
	mouse.preRelative = {x=mouse.x,y=mouse.y}
end

function restoreFreeMouse()
	mouse.x = mouse.preRelative.x; mouse.y = mouse.preRelative.y 
	lmouse.setPosition( mouse.preRelative.x, mouse.preRelative.y )
end

function getCamera(n)
	return currentRooms[n].camera
end

function moveCamera(n,m)
	for k,c in pairs(m) do
		currentRooms[n].camera[k] = currentRooms[n].camera[k] + c
		
	end
end

function moveCameraTo(n,m)
	trace("movvecam1")
	for k,c in pairs(m) do
		currentRooms[n].camera[k] = c
		trace("movvecam2",currentRooms[n].camera[k])
	end
end

function onScreen(t)
	return bboxCollide2(t,screenBox)
end

function getView(cam,light)
		if type(cam.angle)=="number" then cam.angle ={x=0,y=0,z=0,tx=0,ty=0,tz=0}  end
		zcam.pos.x,zcam.pos.y,zcam.pos.z		=cam.x,cam.y,cam.z
		zcam.angle.x, zcam.angle.y, zcam.angle.z=cam.angle.x, cam.angle.y, cam.angle.z
		zcam.transform:identity() 

		if _flipView then 
			zcam.transform[6]=-1
			zcam.pos.y = -cam.y
		end
		zcam.transform:translate(zcam.transform, zcam.pos) 

		zcam.transform:rotate(zcam.transform, zcam.angle.z, vec3.unit_z)
		zcam.transform:rotate(zcam.transform, zcam.angle.x, vec3.unit_y)
		zcam.transform:rotate(zcam.transform, zcam.angle.y, vec3.unit_x)
		
	
		cam.viewMatrix = zcam.transform:clone()

		return zcam.transform
end

function rotateMatrix(m,r)
	m:rotate(m, r.y, vec3.unit_x)
	m:rotate(m, r.x, vec3.unit_y)
	m:rotate(m, r.z, vec3.unit_z)
	return m
end

function getScreenRay(x,y)
	local view = view or currentRoom
	local x = x
	local y = y
	local dx,dy = (x-view.bounds.l-view.bounds.w/2)/(view.bounds.w/2),(y-view.bounds.t-view.bounds.h/2)/(view.bounds.h/2)

	local ax 	= cam.angle.x 
	local ay 	= cam.angle.y 

	local raw = vec3(-1*view.bounds.w,dy*view.bounds.h,1000)
	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-zcam.pos),nil,nil,true)
	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,1000)
	new = vec3.rotate(vec3.rotate(raw, cam.angle.y, vec3.unit_x), pi-cam.angle.x, vec3.unit_y) 

	return -zcam.pos+vec2.normalize(new)*1.1, -zcam.pos+new*5
end

local screenPos = LOVR  and vec2():cast() or vec2()
function getCursorRay(x,y,view)
	local view = view or currentRoom
	local new =vec3()
	if not view.camera.pos or not view.bounds.t then return end

	local x = type(x)=="number" and x or mouse.x
	local y = type(y)=="number" and y or mouse.y

	y=y-view.bounds.t*2

	local succ,unp

		succ,unp = pcall(mat4.unproject,
			vec3(x, view.bounds.h-y, 1), 
			mat4():transpose(mat4.identity()),
			view.camera.perspective, 
			{view.bounds.l,view.bounds.t,view.bounds.w,view.bounds.h}
		)
		if unp then 
			new:set(-unp.x,-unp.y,-unp.z)
		else 
			print("unproject failed")
		end

		view.camera.lookDirection = vec3.rotate(vec3.rotate(vec3(0,0,1), view.camera.angle.y  , vec3.unit_x), pi-view.camera.angle.x  , vec3.unit_y) 
		new = vec3.rotate(vec3.rotate(new*1000, view.camera.angle.y  , vec3.unit_x), pi-view.camera.angle.x  , vec3.unit_y) 

		return {
			position 	= vec3(-view.camera.pos.x,(_flipView and 1 or -1)* view.camera.pos.y,-view.camera.pos.z),
			direction 	= lmouse.getRelativeMode() 
				and 	view.camera.lookDirection
				or 		new
		}

	
end

local matvec4 = {1,1,1,1}
local matvec = {1,1,1,1}
local ray,iray = {},{position=vec3(),direction=vec3()}
local function matvecmul(m,v)
	matvec[1],matvec[2],matvec[3] =  v.x, v.y, v.z
	local s,r = pcall(mat4.mul_vec4,matvec4, m, matvec )
	return matvec4[1],matvec4[2],matvec4[3]
end

local cursorModelHit = vec3()
local imat = mat4()

local function hitSet(hit,r,r1,r2,r3)
	if r then 
		hit:set(r1,r2,r3)
		return hit, r
	else
		return false
	end
end

local cursorTransform = mat4()
local blankMat = mat4()

function testCursorModel(model,parent,override,nomul)
	-- if true then return end
	bench.disable()
	if contextMenu.open or not zcam.ray then 
		bench.enable()
		return false 
	end
	
	local success = false
	if model.models then 
		for s,submodel in ipairs(model.models) do
			if testCursorModel(submodel,model,override) then 
				editor.preEntityHovered = model
				success = true
			end
		end
	else 

		bench.push("tcm1")
		local tris
		
		if animationPanel.instance  then 
			if animationPanel.open and  animationPanel.instance == parent then 
				tris = animationPanel.l.data and animationPanel.l.data.tris
			end
		else
			-- if not model.isTerrain then 
				model.tris = model.tris or {}
				model.verts = model.verts or {}
				local makeTris,makeVerts = (#model.tris==0),(#model.verts==0)
				if not makingTerrain and  (makeTris or makeVerts) then 
					if not model.mesh then bench.enable() return end
					if makeTris then 
						for i=3,model.mesh:getVertexCount(),3 do
							table.insert( model.tris, {
								vec3(model.mesh:getVertex( i-2 )),
								vec3(model.mesh:getVertex( i-1 )),
								vec3(model.mesh:getVertex( i ))
							})
						end
						model.bbox = calcBBOX2(model.tris)
						model.setBBmesh = true
					end
				end
			-- end
			-- trace("#model.tris",#model.tris,makingTerrain)
			tris = model.tris
		end
		bench.pop("tcm1")

		if  not tris then bench.enable() return end

		ray.position = zcam.ray.position
		ray.direction= zcam.ray.direction

		bench.push("tcm2")
		local transform = mat4.invert(cursorTransform,model.transform or blankMat)
		local x,y,z
		x,y,z = matvecmul(transform,ray.position) 
		iray.position:set (x,y,z)
		x,y,z = matvecmul(transform,ray.direction)
		iray.direction:set(x,y,z)
		bench.pop("tcm2")

		local hit,dist  = cursorModelHit

		bench.push("tcm3")

		if (model.newbb or  not model.bbox) and model.tris and not editor.isCurrentPath(model)  then 
			model.newbb = false
			-- model.bbox = calcBBOX2(model.tris)
		end

		if model.verts and ((not model.bbox) or (makingTerrain and model.isTerrain)) and not editor.transforming  then
			-- trace("recalec")
			-- model.bbox = calcBBOX(model.verts)
		end

		bench.pop("tcm3")

		bench.push("tcm4")
		if model.bbox then 
			if LOVR then 
				hit = true--testTempBBOX(ray,model.bbox)
				model.rayBB = hit
			else
				if nomul then 
					if editor.isCurrentPath(model) then 
						hit = true 
					else
						hit = hitSet(hit,cpml.intersect.ray_aabb(ray, model.bbox))
						model.rayBB = hit
					end
				else 
					hit = cpml.intersect.ray_aabb(iray, model.bbox) 
					hit = true
				end
			end
		end
		bench.pop("tcm4")

		bench.push("tcm5")
		if hit or override then 
			dist = 999999
			if LOVR then 
				local hit,distance,position,normal = testTempModel (ray, model.mesh, model.transform or blankMat)
				if hit and (distance<editor.nearestPlane or override)  then 
					editor.nearestPlane 		= distance
					editor.intersect 				= position
					editor.lastIntersect 		= position
					-- editor.intersectTri 		= tris[t]
					editor.preModelHovered  = model

					if parent.isEntity then 
						editor.intersectMat = parent.transform
					else 
						editor.intersectMat = nil
					end
					success = true
				end
			else
				for t=1 ,#tris,1 do
					hit = false
					
					if nomul then 
						hit,dist = cpml.intersect.ray_triangle(ray, tris[t])
						if hit then hit = -hit end
					else 
						hit,dist = cpml.intersect.ray_triangle(iray, tris[t])
						if transform and hit then 
							hit:set(matvecmul(imat:invert(transform),hit))
							hit:set(hit:scale(-1))
						end
					end

					if hit and (dist<editor.nearestPlane or override)  then 
						editor.nearestPlane 		= dist  
						editor.intersect 				= hit
						editor.lastIntersect 		= hit
						editor.intersectTri 		= tris[t]
						editor.preModelHovered  = model

						if parent.isEntity then 
							editor.intersectMat = parent.transform
						else 
							editor.intersectMat = nil
						end
						success = true
					end
				end
				
			end
		end
		bench.pop("tcm5")

	end
	bench.enable()
	return success
end


local tempMat=mat4()
local tempMat2=mat4()
local tempMat3=mat4()
function getTransform(model,t)
	return 
		(model.parent and model.parent.transform and model.transform) 
			and tempMat:mul(tempMat2:invert(model.transform),tempMat3:invert(getTransform(model.parent))) 
			or model.transform 
end



function getFrontCoords(position,ray,view)
	local view = view or currentRoom
	local ray  	= ray or view.camera.ray
	trace("Ray")
	trace(ray.position,ray.direction)
	local intersect,dist = cpml.intersect.ray_plane(ray, {position = position, normal=vec3(view.camera.lookDirection.x,0,view.camera.lookDirection.z)})
	return (intersect or vec3(0))
end

function getFloorCoords(position,ray)
	local ray  	= ray or zcam.ray
	local intersect,dist = cpml.intersect.ray_plane(ray, {position = vec3(0,position.y,0), normal=vec3(0,1,0)})
	return intersect and intersect or nil
end

function getCameraPlaneCoords(position,ray)
	local ray  	= ray or zcam.ray
	local intersect,dist = ray and cpml.intersect.ray_plane(ray, {position = position or zcam.ray.position+zcam.lookDirection*500, normal=zcam.lookDirection}) or false
	return intersect and intersect or nil
end

function getPlaneCoords(position,normal,tri,ray)
	local ray  	= ray or zcam.ray
	local plane = {position = vec3(position.x,position.y,position.z), normal=-normal}
	local intersect,dist = cpml.intersect.ray_plane(ray, plane)
	if not intersect then 
		trace("no intersect!!")
	end
	if tri then 
		if intersect then 
			return vec2(vec3.dot(tri[2] - tri[1] , intersect - tri[1] )/vec3.dist(tri[2], tri[1]),vec3.dot(tri[3] - tri[1] , intersect - tri[1] )/vec3.dist(tri[3], tri[1])),-intersect
		else 
			return vec2(0,0),vec3(position)
		end
	else
		return -(intersect or plane.position)
	end
end

function vec3Table(vec)
	return vec and {x=vec.x,y=vec.y,z=vec.z} or {x=0,y=0,z=0}
end

function vec3Table2(vec)
	return vec and {vec.x,vec.y,vec.z} or {0,0,0}
end

