

function init()

	developer 		= true
	editState 		= "Normal"
	currentDisplay 	= 1
	lightImageLoad 	= false
	game 					= lume.merge(game or {},{
		state = "Load",
		newRes =1, 
		resolution=1,
		playRes=1,
		shadowRes  = hiSpec and 2048 or 1024,
		currentRooms={},
		patterns    = {}	,
		skeletons={},
		frameTimes = {},
		frameTime  = 0,
		lang="en"
	})
	contextMenu 	= {x=0, y=0, items={}}

	game.characters = {
		project = {},
	}
	game.characters.player = game.characters.project
	

	tags 						= {}
	textures 				= {}
	brushes 				= {}
	allSymbols   		= {}
	
	shaders 				= {}
	patterns 				= {}
	scene 					= {}
	levels 					= {}
	worlds 					= {}
	objects 				= {}
	library 				= {}
	editor 					= {}
	drawFuncs 			= {}
	sourceModTimes 	= {}
	allResolutions	= {}
	window 					= {x=0,y=0,display=1}
	roomZoom 				= 0
	sidebar 				= {}
	drawFuncsUI 		= {[0]=0}
	testModels 			= {}
	
	currentLevel = 1
	currentWorld = 1
	print("PRESHADE")
	shaders = require("source/scene/shaders")()
	requireSources()
	loader:init()
	defineEffects()
	namer:define ()

	levels 				= {}
	level					= {}
	layer  				= 1

	frostScale 		= 2
	time 					= 0
	scrollDir 		= 0
	mouseGrabbed 	= false
	traceEnabled 	= false
	logEnabled 		= false
	suppressTrace = false
	miplessMode 	= false
	windowFocused = true
	editOver			= false
	fileDropped 	= false
	thumbSize 		= 64
	buttons 			= nil
	buttons2 			= nil
	holdToPrint 	= {}
	keysPressed 	= {}
	keysReleased 	= {}
	keysDown 			= {}
	releaseFuncs 	= {}
	postDraw 			= {}
	defaultFont 	= gfx.getFont( )
	pathModes 		= {"paths","ramps","floors"}

	renderScale 	= 1
	iscale 				= 1

	orenderWidth 	= 1280
	orenderHeight 	= 720
	launchWidth 	= 580
	launchHeight 	= 480
	renderWidth 	= launchWidth
	renderHeight 	= launchHeight
	screenWidth 	= launchWidth
	screenHeight 	= launchHeight
	exactScale 		= false
	exactScaleTog 	= true
	fps 			= 60
	renderSelection 	= false
	canvasOffsetX	=	0
	canvasOffsetY	=	0
	
	controls:getJoys 				()
	lfs.createDirectory 		( "saveData" )
	lfs.createDirectory 		( "linkCache" )
	lfs.createDirectory 		( "setCache" )
	lfs.createDirectory 		( "previewCache" )
	lfs.createDirectory 		( "thumbnails" )
	lfs.createDirectory 		( "projects" )
	loadConfig 		 					()
	setCanvases 		()
	initDisplay 	 					()
	
end

function initGame()
	scrollDir 	= 0
	prevGame 	= lfs.exists( "project.sav" )
	prevPlus 	= prevGame and 0 or 1 
	game.paused 	= false
	
	if noLevel then return end

	if lume.count(levels)==0 then 
		if #worlds==0 then 
			table.insert(worlds,{
				name 	= "Untitled World",
				levels 	= {},
				index 	= 1
			})
			loader:saveDef("worlds",worlds) 
		end
		loader:addLevel("Untitled Level",1)
	end

	local l 
	if levels then 
		for k,v in pairs(levels) do 
			l = k
		end
	end
	print("resume level")
	print(config)
	print(config.editingLevel)
	print(levels[config.editingLevel])
	level = levels and ((config and levels[config.editingLevel]) and  levels[config.editingLevel] or (l and levels[l])) or nil
	if  level and developer  then 
		game.enterGame(level.key)
	end
end

function requireSources(swap)

	local folders   = {
		editor={
			"animationPanel",
			"bench",
			"buttons",
			"click",
			"contextMenu",
			"defineEditor",
			"drawing",
			"drawingPanel",
			"drawTests",
			"editor",
			"entityEdit",
			"fill",
			"galleryPanel",
			"headerPanel",
			"help",
			"links",
			"meshEdit",
			"overlays",
			"overviewPanel",
			"panels",
			"pathsPanel",
			"scriptsPanel",
			"selector",
			"shapeEditor",
			"shortcuts",
			"stackSheet",
			"timeline",
			"toolTip",
			"undos",
			"variablePanel",
			"vecFill",
			"curve"
		},
		load={
			"config",
			"defaultLevel",
			"defaultWorlds",
			"engine",
			"imageLoader",
			"init",
			"levelLoader",
			"loader",
			"os",
			"splash",
		},
		scene={
			"camera",
			"canvases",
			"cutWall",
			"effects",
			"entity",
			"entityRender",
			"entityUpdate",
			"floors",
			"game",
			"light",
			"newEntity",
			"paths",
			"scene",
			"shaders",
			"vertexFormats",
			"viewports",
			"vectorRender"
		},
		util={
			"controls",
			"font",
			"keyboard",
			"misc",
			"mouse",
			"namer",
			"pause",
			"trace",
		},
		shaders= {
			"probeLights",
			
			"forwardRender",
			"forwardStatic",

			"shadowStatic",
			"shadowPreview",

			"deferredStatic",
			"deferredDynamic",
			"deferredLight",
			"deferredCombine",

			"voxelRender",
			"voxelAlpha",
			"voxelAverage",
			"voxelFlip",
			"voxelTrace",
			"voxelInject",
			"voxelLight",
			"voxelCombine",
			"voxelOcclusion",
			"voxelBasemip",
			"voxelMipmap",
			"voxelLightmip",
			"voxelNormalmip",

			"postProcess",
			"pathTrace",
		}
	}
	local succ 
	
	for f,folder in pairs(folders) do 
		for s,sourceName in ipairs(folder) do 
			local sourcePath 			= "source/"..f.."/"..sourceName
			local sourceModTime 		= lfs.getLastModified(sourcePath..".lua")
			if f ~= "shaders" then
				if LOVE and sourceModTimes[sourceName] and swap then 
					if sourceModTime>sourceModTimes[sourceName] then
						local succ,ess = pcall(lume.hotswap,sourcePath)
						if succ and ess then 
							-- print(succ,ess,f,sourceName," required")
						else
							print("\n   FAILED TO REQUIRE : "..sourcePath.."\n")
							print(succ,ess)
						end
						sourceModTimes[sourceName]=sourceModTime
					end
				else
					local succ,ess = pcall(lume.hotswap,sourcePath)
					if succ and ess then 
						-- print(succ,ess,f,sourceName," required")
					else
						print("\n   FAILED TO REQUIRE : "..sourcePath.."\n")
						print(succ,ess)
					end
					sourceModTimes[sourceName] = LOVE and lfs.getLastModified(sourcePath..".lua") or ltimer.getTime()
				end
			else

				local file 

				file = lfs.read(sourcePath..".glsl")

				local _,v1 = string.find(file, "VERTEX")
				local v2,_ = string.find(file, "#endif")
				local _,f1 = string.find(file, "PIXEL")
				local f2,_ = string.find(file, "#endif", f1)

				local vert = string.sub(file,v1+1,v2-1)
				local frag = string.sub(file,f1+1,f2-1)

				-- vert = string.gsub(vert,"mat4 transform_projection","mat4 projection, mat4 transform")
				local multicanvas

				if LOVR then 
					vert,frag,multicanvas = convertShader(vert,frag)
				end

				if LOVE then 
					local prefix = LOVE and "#pragma language glsl3" or "#version 330 \n"
					vert = prefix..vert
					frag = prefix..frag
				end

				-- print("vert",vert)
				-- print("frag",frag)

				-- print("glsl",sourceName)
				-- print("vert-----------------------------------")
				-- print(vert)
				-- print("frag-----------------------------------")
				-- print(frag)
				-- print("-----------------------------------")
					
				succ,shade = pcall(gfx.newShader,frag,vert,{flags={multicanvas=multicanvas},name=sourceName})
				if succ then 
					shaders[sourceName:gsub(".glsl","")] = shade
				else 
					error(sourceName..shade,2)
				end
			end
		end
	end
	print("")
end

function convertShader(vert,frag)
	local multicanvas
	if vert then 
		vert:gsub("#pragma language glsl3","")
		vert = 
		[[
		#version 330
		in vec3 vertexPosition;
		in vec2 vertexTexCoord;
		in vec3 vertexNormal;
		in vec4 vertexColor;

		uniform vec4 rayColor;
		uniform mat4 mvp;

		out vec2 fragTexCoord;
		out vec4 fragColor;
		out vec2 screenSpace;

		float gammaToLinear(float c)
		{
			if (c <= 0.04045f)
				return c / 12.92f;
			else
				return pow((c + 0.055f) / 1.055f, 2.4f);
		}
		vec4 gammaCorrectColor(vec4 color)
		{
			return vec4(gammaToLinear(color.r),gammaToLinear(color.g),gammaToLinear(color.b),color.a);
		}
		]]
		..vert..
		[[
			void main() {
				fragTexCoord = vertexTexCoord.xy;
				fragColor = vertexColor;
				vec4 clipSpace = position(mvp, vec4(vertexPosition,1));
				//vec4 clipSpace = mvp*vec4(vertexPosition,1);
				screenSpace = clipSpace.xy;
				gl_Position = clipSpace;
			}
		]]
		-- vert = gfx.defaultVert
		-- vert = vert:gsub("ConstantColor","lovrGraphicsColor")
	end

	if frag then 
		local preFrag = 
		[[
		#version 330
		in vec2 fragTexCoord;
		in vec4 fragColor;
		in vec2 screenSpace;
		
		uniform sampler2D texture0;

		out vec4 finalColor;
		uniform vec2 screenSize;

		float gammaToLinear(float c)
		{
			if (c <= 0.04045f)
				return c / 12.92f;
			else
				return pow((c + 0.055f) / 1.055f, 2.4f);
		}
		vec4 gammaCorrectColor(vec4 color)
		{
			return vec4(gammaToLinear(color.r),gammaToLinear(color.g),gammaToLinear(color.b),color.a);
		}
		float shadowSample(sampler2D shadow, vec3 pos){
			return texture(shadow,pos.xy).r>pos.z ? 1.0 : 0.0;
		}
		]]


		if frag:find("effect%(%)") then 
			frag = frag:gsub("void effect%(%)","void colors(vec4 c, sampler2D s, vec2 tc)")
			multicanvas = true
		else
			frag = frag..[[
				void main() {
					vec4 eff = effect(fragColor,texture0,fragTexCoord,screenSpace);
					finalColor = eff;
				}
			]]
		end

		frag = preFrag..frag

		frag = frag:gsub("love_Canvases","lovrCanvas")
		frag = frag:gsub("love_ScreenSize","screenSize")
		frag = frag:gsub("love_PixelCoord","screenSpace")
		-- frag = frag:gsub(", vec2 screen_coords","")
		-- frag = frag:gsub("screen_coords","screenSpace")
		frag = frag:gsub("VaryingColor","fragColor")
		frag = frag:gsub("VaryingTexCoord","fragTexCoord")


		local fstart = frag:find("void")
		if fstart then 
			frag = frag:sub(1,fstart)..frag:sub(fstart+1):gsub("MainTex","texture0")
		end
		
	-- 	--temp
	-- 	local shadows = {}                   
	--   local i,_ = 0
	--   while true do
	--     _,i = string.find(frag, "sampler2DShadow", i+1)    
	--     if i == nil then break end
	--     local j  = string.find(frag, "\n", i+1)
	--     table.insert(shadows, string.sub(frag,i+2,j-2))
	--   end
	-- 	frag = frag:gsub("sampler2DShadow","sampler2D")

	-- 	local i,j = 0,0
	-- 	while true do
	--     i,j = string.find(frag, "Texel", j+1)    
	--     if i == nil then break end
	--     for s,shadow in ipairs(shadows) do 
	-- 	  	if select(2, frag:sub(j,j+20):gsub(shadow,""))>0 then
	-- 	  		frag = frag:sub(1,i-1).."shadowSample"..frag:sub(j+1)
	-- 	  		break 
	-- 	  	end
	--   	end
	--   end

		frag = frag:gsub("Texel","texture")

	end

	-- --temp
	-- function intBools(shdr)
	-- 	if not shdr then return nil end
	-- 	local bools = {}                   
	--   local i,j,_ = 0,0
	--   while true do
	--     _,i = string.find(shdr, "bool", i+1)    
	--     if i == nil then break end
	--     j  = string.find(shdr, "\n", i+1)
	--     table.insert(bools, string.sub(shdr,i+2,j-2))
	--   end
	-- 	shdr = shdr:gsub("bool","int")
	-- 	if j>0 then 
	-- 		local shdr1,shdr2 = shdr:sub(1,j-1),shdr:sub(j)
	--     for b,bool in ipairs(bools) do 
	--     	-- print("Rep ",bool)
	-- 	  	shdr2 = shdr2:gsub(bool,"bool("..bool.."==1)")
	-- 	  end
	-- 	  shdr = shdr1..shdr2
	-- 	end
	-- 	return shdr
	-- end

	-- vert = intBools(vert)
	-- frag = intBools(frag)

	return vert,frag,multicanvas
end

function initDisplay() 
	local hdfound 			= 0
	local preResolutions 	= {{width=1280,height=720}}

	table.sort(preResolutions, function(a, b) return a.width*a.height < b.width*b.height end)
 	
 	-- CHECK FOR SUPPORTED RESOLUTIONS --
	for i,v in ipairs(preResolutions) do
		if 			v.height<math.round( (v.width/16) *11) 
			and  	v.height>math.round( (v.width/16) *7 )  then 

			v.name  = v.width .. " x " .. v.height
			v.func 	= 	function(x) 
				config.fullScreenRes 	= x; 
				config.window.size=allResolutions[config.fullScreenRes] 
			end
			table.insert(allResolutions, v)

			if v.height ==720 and v.width==1280 then 
				hdfound=#allResolutions
			end
		end
	end

	-- LAUNCH IN 720 BY DEFAULT IF AVAILABLE 
	if config.fullScreenRes == nil then 
		if hdfound>0 then config.fullScreenRes = hdfound 
				 	else config.fullScreenRes = #allResolutions end
	end

	config.window.size = config.window.size or allResolutions[config.fullScreenRes]

	
	setLaunchRes() 

	game.aspectRatio = gfx.getWidth()/gfx.getHeight()
end

function setLaunchRes() 
		lwindow.setMode( 
			launchWidth, launchHeight, 
				{	
					fullscreen 	= false,  
					vsync 		= true, 
					minwidth 	= 580,
					minheight 	= 480,
					resizable = developer,
					display		= config.window.display
				} 
		)
end



