function scene.load()
	scene.stiffness   = 1.8
	scene.time        = 0
	scene.meter       = 32
	scene.transfers 	= {}

	rooms = {}
	roomStack 			= {}
	cards 				= {}
	cameras 			= {}
	rooms  				= level.rooms
	controls:reset 		()

	loadSet 			( game.state=="Edit" and editor.editingSet or level.defaultSet)
	currentRooms 		= game.state=="Edit" and editor.currentRooms or game.currentRooms 
	currentRoom  		= game.state=="Edit" and currentRooms[editor.curoom]  or currentRooms[2] or currentRooms[1]

	roomsView 			= editingLevel and roomsView or roomsView
	roomZoom  			= editingLevel and roomZoom or (roomsView and 1 or 0)

	game.setNames  		= {}
	for s,set in pairs(level.sets) do 
		set.ox = set.x or set.ox or 0
		set.oy = set.y or set.oy or 0
		if not set.preview and lfs.exists("setCache/"..set.key..".png") then
			set.preview = gfx.newImage("setCache/"..set.key..".png")
			editor.setPreviews[set.key] = set.preview
		end
		table.insert(game.setNames,set.name)
		set.dateCreated = set.dateCreated or os.time()
	end

	game.spawned = {}
	game.activeRooms = {}
	game.toUnload = {}
	game.toLoad = {}
	game.loadDepth = 1

	scene.views = {}
	--scene.loadAssets(game.loadDepth)
	scene.loadRooms 	()
	scene.setView(currentRoom)

	editor.keepCamera = nil

	gfx.setLineJoin( "none" )

	
end

function scene.loadRooms()
	for r,room in pairs(level.rooms) do
		scene.loadRoom(r)
	end
	for r,room in ipairs(currentRooms) do 
		scene.setView(room,not (editingLevel or editor.keepCamera) )
	end
	roomHovered   	= nil
end

function scene.updateActiveRooms(depth)
	local key = currentRoom.key
	local active = {}

	for r,room in pairs(currentRooms) do 
		key = room.key
		if not lume.find(active,room.key) then
			table.insert(active, room.key)
		end
		if depth>0 then
			for c,connect in pairs(level.connections) do 
				local side1 = connect[1].room == key and 1 or (connect[2].room == key and 2 or 0)
				local side2 = side1==1 and 2 or side1==2 and 1 or 0
				if side1>0 then 
					if not lume.find(active,connect[side2].room) then
						table.insert(active,connect[side2].room)
					end
				end
			end
		end
	end

	return active
end

function scene.activeRoomsChanged(t1,t2)

	if #t1~=#t2 then 
		return true
	end

	for i=1,#t1,1 do 
		if not lume.find(t2,t1[i]) then
			return true
		end
	end
	return false
end

function scene.loadAssets(depth)

	local new = scene.updateActiveRooms(1)

	if editor.debug.trace_active_rooms then 
		trace("")
		trace("Active Rooms:")
		for i,v in ipairs(new)do
			trace("  "..level.rooms[v].name)
		end
	end

	game.toUnload = {}
	game.toLoad = {}

	if editor.refresh or scene.activeRoomsChanged(new,game.activeRooms) then 

		game.images      = game.images or {}
		game.activeRooms = new 

		local images =  {}
		for i,v in ipairs(new)do
			print("  "..v)
		end

		for r,room in pairs(game.activeRooms) do 
			for o,obj in ipairs(level.rooms[room].objects) do
				if objects[obj.key] then 
					if not lume.find(images,obj.key) and multicheckOR(room,game.activeRooms) then 
						table.insert(images,obj.key)
						print("preload symbol",obj.key)
					end
				end
			end
		end

		for i,v in ipairs(game.images) do 
			print("check ",v)
			if not lume.find(images,v) then 
				print("unload ",v)
				table.insert(game.toUnload,v)
			end
		end
		
		game.images = images

		for i,v in pairs(game.images) do 
			if not objects[v].image then
				table.insert(game.toLoad,v)
			end
		end

		bench.push("unload")

		local garbage = collectgarbage ("count")
		for i,v in ipairs (game.toUnload) do 
			print("unload "..v)
			-- print("imgs"..gfx.getStats().images)
			if allSymbols[v] and allSymbols[v].image then 
				releaseImage(allSymbols[v].image)
			end
			objects[v].image=nil
			for a,anim in pairs(objects[v].animations) do 
				for l,layer in pairs(anim.layers) do 
					for f,frame in pairs(layer.frames) do 
						frame.strokeMesh:release() 
					end
				end
			end
			clearTable(objects[v].animations)
			objects[v].animations=nil
			allSymbols[v] = nil
			-- print("imgs"..gfx.getStats().images)
		end
		collectgarbage("collect")
		print("diff: ",collectgarbage ("count")-garbage)
		bench.pop("unload")

		bench.push("load")

		imageLoader:loadGameImages(game.toLoad)
	 	bench.pop("load")
	 	-- collectgarbage("collect")
	end

	imageLoader:loadLoop()

	if config.debug and config.debug.trace_loaded_images then 
		trace("") trace("Loaded:")
		for i,img in ipairs(game.images) do 
			trace(" "..objects[img].name)
		end
	end
end



function scene.loadRoom(r)
	room 					= level.rooms[r]

	room.isRoom 			= true
	room.onStage           	= 0
	room.resort            	= false
	room.shapeToUpdate     	= ""
	room.zbounds.range  	= room.zbounds.front-room.zbounds.back

	--room.x,room.y,room.z 	= 0,0,0
	room.bx,room.by,room.bz = 0,0,0
	room.links 				= {}
	room.entities          	= {nocopy=true}
	room.entitiesByID          	= {nocopy=true}
	room.wind              	= {}
	room.planes 			= {}
	room.nextPlanes 		= {}
	room.toDelete          	= {}
	room.entsToAdd         	= {}
	room.parentFinder      	= {}
	room.draws 				= {}
	room.cards 				= {}
	room.lights = {}
	room.delayed = {}
	room.dialogue 		= room.dialogue or {}
	room.transform = mat4()
	room.lighting = room.lighting or {enabled=false,
		ambient={amount=1,color={r=1,g=1,b=1},enabled=false},
		dynamic={amount=1,color={r=1,g=1,b=1},enabled=false},
		shadows={amount=1,color={r=1,g=1,b=1},enabled=false},
	}
	room.lighting.toon = room.lighting.toon or {}
	room.lighting.map = room.lighting.map or {}
	room.lighting.static = room.lighting.static or {}
	room.lighting.render = room.lighting.render or {}
	room.lighting.probes = room.lighting.probes or {}
	room.lighting.vct = room.lighting.vct or {}
	room.sky.skybox = room.sky.skybox or {}

	room.x = 0
	room.y = 0
	
	room.lightPosition 	= {nocopy=true,setAll({0,0,0})}
	room.lightColor 		= {nocopy=true,setAll({1,1,1})}
	room.lightPower 		= {nocopy=true,setAll(1)}
	room.lightRange 		= {nocopy=true,setAll(50)}
	room.lightAperture  = {nocopy=true,setAll(45)}
	room.lightFalloff   = {nocopy=true,setAll(0)}
	room.lightShadowed 	= {nocopy=true,setAll(false)}
	room.lightDirection = {nocopy=true,setAll({0,0,0})}
	room.lightType 			= {nocopy=true,setAll(1)}
	room.lightQuad 			= {nocopy=true,setAll({0,0,1,1})}

	room.selectedEntities  	= room.selectedEntities  or {}
	room.pushDraw 			= pushRoomDraw

	if not room.preview and lfs.exists("previewCache/"..room.key..".png") then
		room.preview = gfx.newImage("previewCache/"..room.key..".png")
		editor.roomPreviews[room.key] = room.preview
		room.dateCreated = room.dateCreated or os.time()
	end

	for c,cam in ipairs(room.cameras) do 
		cam.index = c
		camera.adjust(cam)
	end

	if not editingLevel then 
	end
	
	room.setCamPosition 	= function()

	end


	scene.loadEntities    (room)
	scene.computePath 		(room)
	scene.addPlanes 	 		(room)
	scene.updatePlanes 		(room)
	scene.setScripts      (room)

end



function scene.setView(r,reset)
	if not r or not level.rooms[r.key]  then return nil end
	local room 				= level.rooms[r.key] 
	local view 				= r
	r.room      = level.rooms[r.key] 
	r.camera 			= reset and deepcopy(room.cameras[r.cameraID]) or (r.camera 		or (r.cameraID>0 	and deepcopy(room.cameras[r.cameraID]) 	 or camera.setup()))
	r.viewport 			= r.viewport 	or ((r.viewportID and r.viewportID>0) 	and room.viewports[r.viewportID] or room.viewports[1])
	cam  				= r.camera
	selectedEntities 	= level.rooms[r.key].selectedEntities or {}


	if r.room and r.viewport and r.camera then 
		return room,view
	else
		return false
	end
end



function scene.updateRoom(view,draw)
	bench.push("updateRoom")
	local room = scene.setView(view)
	numSegs = 0

	if room then

		if not room.updated then 
			scene.addEnts 		  (room)
			scene.updateWorld 	(room)
			scene.sortEntities 	(room)
		end

		local update 
		if editingLevel and currentRoom.key == view.key  then 
			update = view == currentRoom 
		else 
			update = not room.updated
		end

		if update and not editor.slowDraw then 	
			scene.updateEntities 	(room) 				
		end

		if not room.updated then 
			scene.updateScripts (room) 				
			scene.addPlanes  		(room) 				
			scene.updatePlanes 	(room) 				
			room.updated 			= true
		end

		if draw then 
			if view.viewport and  not overviewPanel.skipBehind then
				camera.control(view.camera)
				updateViewport 	(view)
				pushView(view)
			end
		end
	end
	bench.pop("updateRoom")
end



function scene.transfer()
	for i,t in ipairs(scene.transfers) do
		if t.dest then 
			scene.destroyEntity 			(t.entity)
			lume.remove						(level.rooms[t.source].entities, t.entity)
			table.insert					(level.rooms[t.dest].entities , t.entity)
			t.entity.x,t.entity.y,t.entity.z = t.pos.x,t.pos.y,t.pos.z	
			scene.updateEntityShape 		(t.entity,true)
		end
		t.entity:setPosition 			(t.pos.x,t.pos.y,t.pos.z)	
		t.entity.floor 					= t.pos.y
		t.entity:setVelocity 			(nil,0,nil)
		t.entity.transferring 			= false
		
		if t.entity.switchOnTransfer and not game.setContains(game.set,t.dest) then
			--game.loadSet(game.findSet(t.dest))
		end
	end
	scene.transfers={}
end

function scene.destroy()
	for r,room in pairs(level.rooms) do
		room.draws = {}
		room.entities={}
		for l,light in lume.ripairs(room.lights) do 
			if light.canvasCache then light.canvasCache:release() end
			if light.canvas then light.canvas:release() end
			if light.canvas2 then light.canvas2:release() end
			room.lights[l]=nil
		end
	end
end

function scene.update()
	bench.push("scene.update")

	scene.reset 		()
	scene.sortRooms 	()
	scene.transfer 	()
	scene.updateRooms ()
	scene.setView 	(currentRoom)
	effects.drawCard 	()
	scene.deleteEntities()
	scene.depthSelection(false)

	shapeToUpdate 		= ""
	scene.loadAssets(game.loadDepth)

	bench.pop("scene.update")
end

function scene.reset()
	roomHovered   		= nil
	scene.time     	= scene.time+1
	hoveredEntity    	= nil
	anySelectedSimple = false
	tags.Level  			= {}
	tags.Room 				= {}

	if (not contextMenu.open) then 
		editor.modelHovered 	= nil
		editor.entityHovered 	= nil
		editor.intersect 			= nil

		if editor.preModelHovered then 
			editor.modelHovered = editor.preModelHovered
			if  editor.modelHovered.parent and editor.modelHovered.parent.isEntity then 
				editor.entityHovered = editor.modelHovered.parent
			else
				if not pathsPanel.open then 
					pathsPanel.preview = true
					pathsPanel.id 			= room.key
					pathsPanel.hoveredPath  = editor.modelHovered.id
					pathsPanel.mode 		= editor.modelHovered.mode
				end
			end
		end

		editor.preModelHovered = nil
	end
end


function scene.sortRooms()
	if lume.count(currentRooms)>1 then 
		table.sort(currentRooms,function(a,b) 
			if a.depth==b.depth then 
				if a.room.name==b.room.name  then 
					return a.viewportID<b.viewportID 
				else
					return a.room.name<b.room.name 
				end
			else
				return a.depth<b.depth 
			end
		end)
		--local _,i = lume.match(currentRooms,function(x) return x==currentRoom end)
		--if editingLevel and i and i>0 and roomsView then 
		--	table.remove(currentRooms,i)
		--	table.insert(currentRooms,currentRoom)
		--end
	end
end

function scene.updateRooms()


	for v,view in ipairs(roomZoom>0.01 and currentRooms or {currentRoom}) do 
		view.room.updated 		= false
		view.room.draws       = {}
	end

	bench.push("updateRooms")

	lume.clear(scene.views)

	for r,room in ipairs(roomZoom>0.01 and currentRooms or {currentRoom}) do 
		room.i = r
		scene.updateRoom(room,(roomZoom>0.01 or (roomZoom<0.01 and room==currentRoom)))
	end

	bench.pop("updateRooms")
	

	if level.isAnim then return end

	if not LOVR then 
		bench.push("drawStacks")
		pushDrawUI(function()
			drawLinkPreview()
			-- drawRoomStack()
		end)
		bench.pop("drawStacks")
	end

	prevRoomZoom = roomZoom
	prevRoom = currentRoom.room
	
end

function scene.renderViews()
	if not scene.views then return end
	for v,view in pairs(scene.views) do 
		drawView(view)
	end
end
renderViews = scene.renderViews

function scene.depthSelection(draw)
	
	if not editor.selectionCanvasEnabled then return end
	if contextMenu.open or not stageHovered then  return end
	local room = currentRoom and currentRoom.room
	
	if editingLevel and room and room.entities then 
		if draw then 
			local canv = canvasSelection
			pickerQuad:setViewport(mouse.x*game.resolution,mouse.y*game.resolution-2,1,1)
			pickerCanvas:renderTo( function () gfx.draw(canv,pickerQuad) end )
		elseif not mouse.down.L or #galleryPanel.selected~=0 then 
			
			pickerData = pickerData or pickerCanvas:newImageData()
			r,g = pickerData:getPixel( 0,0  )
			pickerColor={r=r, g=g}
			pickerData:release()
			pickerData = nil
			--trace("cols r"..r.." g"..g.." b"..b)
			if editor.selectingRect or editor.orbiting then return end
			
			if r>0 then 
				editor.entityHovered = room.entities[math.round(r*#room.entities)]
				--editor.modelHovered = editor.entityHovered.models[math.round(g*#editor.entityHovered.models)]
				if editor.entityHovered then
					--trace("ent "..editor.entityHovered.uid)
				end
			end

			
		end
	end
end



function scene.updateWorld(room)
	if not editingLevel then 
	end
end

function scene.sortEntities(room)
	--table.sort 		(room.entities, function(a, b) if a.z == b.z then return a.uid > b.uid else return a.z < b.z end end)
end
 
function scene.updateEntities(room)
	
	bench.push("entities")
	for i,entity in ipairs(room.entities) do
		entity.index=i

		if objects[entity.key]==nil then 
			scene.setDelete(entity)
		elseif not (animationPanel.open and drawingPanel.backing)   then 

			--scene.updateEntityRenderInfo(entity)	


			if editor.intersect then 
				-- editor.modelIntersect = editor.intersect:clone()
			end

			scene.updateEntityVars				 (entity,1)
			scene.updateScripts 					 (entity)
			scene.updateEntityAnimation 	 (entity)	
			scene.updateEntityAnimData  	 (entity)
			scene.updateEntityBounds    	 (entity)
			editor.updateEntityTransform 	 (entity)
			scene.updateEntityRenderInfo	 (entity)
			scene.updateEntityLasso				 (entity)    
			
			entity.colID = (entity.i or #room.entities+1)/#room.entities
			for m,model in ipairs(entity.models) do
				model.i = entity.colID
				model.m = (m)/#entity.models
			end
		end

		if not entity.simple then 
			if currentRoom.key == room.key then
				table.add(tags.Room,entity.key)
			end
			table.add(tags.Level,entity.key)
		end

	end
	bench.pop("entities")

	numSegments = 0
	numFrames = 0
end

function scene.loadEntities(room)
	for o,obj in ipairs(room.objects) do
		obj.i 	= o
		if objects[obj.key] then 
			scene.newEntity(obj,room)
		end
	end
end

function scene.setScripts(target)
	target.public = {test = 5}
	if not editor.debug.no_scripts then 
		if target.scripts~=nil and #target.scripts>0 and not editingLevel then
			for i,b in ipairs(target.scripts) do
				if scripts[b.key] then 
					local success,result 	= pcall(lfs.load,LINK_DIR..scripts[b.key].filename..".lua")
					if success  then  
						script,publics = result()
						scripts[b.key].broken 	= false
						script.target 			= target 
						b.file 		 			= script
						if publics then 
							for p, public in pairs(publics) do
								if target.public[p] then 
									log("Public \'"..p.."\' already defined")
								end
								target.public[p] = public
							end
						end
					else
						scripts[b.key].broken 	= true
					end
				else
					target.scripts[i]=nil
					log("RRRREMoved")
				end
			end
		end
	end

	if target.isEntity then 
		for k,m in pairs(entityMethods) do
			target[k] = m
		end
	end
end


function scene.setPlayer(entity)
	if entity.uid == room.player then 
		entity.category=4
		player = entity
	else 
		entity.category=2
	end
	entity.id = entity.uid
end



function scene.addEnts(room)
	for i,part in ipairs(room.entsToAdd or {}) do
		part()
	end
	room.entsToAdd           = {}
end
