var Scene = (function() {
	var lerp = function(s, e, p) {
		return s - ((s - e) * p);
	}

	return {
		id: getIdForLastLoadedScript(),
		load: function()
		{
			this.scene = new THREE.Scene();
/*
			var ambient = new THREE.AmbientLight( 0xffffff );
			ambient.color.setHSL( 0.1, 0.3, 0.2 );
			this.scene.add( ambient );

			var dirLight = new THREE.DirectionalLight( 0xffffff, 0.125 );
			dirLight.position.set( 0, 10, -20 ).normalize();
			dirLight.color.setHSL( 0.1, 0.7, 0.7 );
			this.scene.add( dirLight );

			var light = new THREE.PointLight( 0xffffff, 1.5, 4500 );
			light.color.setHSL( 0.55, 0.9, 0.5 );
			light.position.set( -10, 10, -10 );
			this.scene.add( light );
*/

			this.axishelper = new THREE.AxisHelper(5);
			this.scene.add(this.axishelper);

			var light = new THREE.HemisphereLight( 0xff7a81, 0x000000, .5 );
			light.position.y = 100;
			this.scene.add( light );

			this.mat = new THREE.MeshLambertMaterial({
					ambient: 0xADFFB2,
					color: 0x099723,
					emissive: 0x099723,
					shading: THREE.FlatShading,
					side: THREE.DoubleSide,
					wireframe: true
				});
			this.mat.type='terrain';

			this.mat.uniforms = THREE.UniformsUtils.clone( THREE.ShaderLib.terrain.uniforms ) ;
			this.mat.vertexShader = THREE.ShaderLib.terrain.vertexShader;
			this.mat.fragmentShader = THREE.ShaderLib.terrain.fragmentShader;

			//renderer.initMaterial( this.mat, null, null, null );

			console.log(this.mat);

			var groundMaterial = new THREE.ShaderMaterial({
				uniforms: {
					grow: { type: 'f', value: 0.0 }
				},
				vertexShader: THREE.ShaderLib.terrain.vertexShader,
				fragmentShader: THREE.ShaderLib.terrain.fragmentShader,
					ambient: 0xADFFB2,
					color: 0x099723,
					emissive: 0x099723,
					shading: THREE.FlatShading,
					side: THREE.DoubleSide,
					wireframe: true
			});

			var size = 500;

			//this.planeGeometry = new THREE.PlaneGeometry(500,500, 250,250)
			this.planeGeometry = new THREE.PlaneGeometry(size,size, 20,20)

			// Flip the ground so it becomes the ground
			for (var i=0; i < this.planeGeometry.vertices.length; i++)
			{
				var dong = this.planeGeometry.vertices[i].z;
				this.planeGeometry.vertices[i].z = this.planeGeometry.vertices[i].y;
				this.planeGeometry.vertices[i].y = dong;
				
			}


			this.mountains = [
				{
					position: new THREE.Vector2(0,0),
					apex: 50,
					radius: 50,
					easing: 'easeInCubic'
				},
				{
					position: new THREE.Vector2(150,150),
					apex: 20,
					radius: 70,
					easing: 'easeInOutQuint'
				},
				{
					position: new THREE.Vector2(15,15),
					apex: 10,
					radius: 200,
					easing: 'easeInOutQuint'
				}
			];

			for (var i=0; i < this.planeGeometry.vertices.length; i++)
			{
				this.planeGeometry.vertices[i].x += Math.random()*0.2-0.5;
				this.planeGeometry.vertices[i].y += Math.random()*0.2-0.5;
				this.planeGeometry.vertices[i].z += Math.random()*0.2-0.5;
			}

			this.planeGeometry = reduceGeometry(this.planeGeometry,0.7);

			// Add some fjells and some noise
			for (var i=0; i < this.planeGeometry.vertices.length; i++)
			{
				var xz = new THREE.Vector2(this.planeGeometry.vertices[i].x,this.planeGeometry.vertices[i].z);


				var fjelloffset = 0;
				var height = 0;
				for (var f=0; f < this.mountains.length; f++)
				{
					
					var dist = this.mountains[f].position.distanceTo(xz);
					//console.log('dist is '+dist+', radius is '+ this.mountains[f].radius);
					if (dist < this.mountains[f].radius)
					{
						// null, current_time, start_value, end_value, total_time)
						height = jQuery.easing[this.mountains[f].easing](null, (this.mountains[f].radius-dist), 0, this.mountains[f].apex, this.mountains[f].radius);
						//height = (this.mountains[f].radius - dist);
					}
					if (height > fjelloffset)
					{
						fjelloffset = height;
					}
				}
				//console.log(fjelloffset);
				
				var n2 = noise.simplex2(xz.x/25,xz.z/25)*2;
				//console.log('n2' + n2);

				this.planeGeometry.vertices[i].y += fjelloffset;

				//console.log(this.planeGeometry.vertices[i].y);

			}

			this.planeGeometry = reduceGeometry(this.planeGeometry,0.7);
			this.planeGeometry.computeFaceNormals();
			this.planeGeometry.computeVertexNormals();

			this.plane = new THREE.Mesh(
				this.planeGeometry,
				this.mat
				//groundMaterial
			);


			this.plane.position.y = -5;

			this.scene.add(this.plane);

			this.composer = new THREE.EffectComposer(renderer);

			this.camera = new THREE.PerspectiveCamera(45, 16/9, 0.1, 1000);
			this.camera.position.set(0, 10, -30);
			this.camera.lookAt(new THREE.Vector3(0, 0, 0));

			this.renderPass = new THREE.RenderPass(this.scene, this.camera);
			this.composer.addPass(this.renderPass);
/*
			this.blurPass1 = new THREE.ShaderPass(THREE.VerticalBlurShader);
			this.blurPass1.uniforms["v"].value = 1 / wHeight;
			this.composer.addPass(this.blurPass1);

			this.blurPass2 = new THREE.ShaderPass(THREE.HorizontalBlurShader);
			this.blurPass2.uniforms["h"].value = 1 / wWidth;
			this.composer.addPass(this.blurPass2);
*/

			// Set up the depth pass for the SSAO shader
			var depthShader = THREE.ShaderLib[ "depthRGBA" ];
			var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
			this.depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } );
			this.depthTarget = new THREE.WebGLRenderTarget( 512, 512, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat } );

			// Init the SSAO shader and set up the correct uniforms
			this.ssao = new THREE.ShaderPass(THREE.SSAOShader);
			this.ssao.uniforms['tDepth'].value = this.depthTarget;
			this.ssao.uniforms[ 'size' ].value.set( 512, 512 );
			this.ssao.uniforms[ 'cameraNear' ].value = this.camera.near;
			this.ssao.uniforms[ 'cameraFar' ].value = this.camera.far;
			this.composer.addPass(this.ssao);


			this.composer.addPass(final_pass);

			this.controls = new THREE.OrbitControls( this.camera );
			this.controls.addEventListener('change',render);

			// Force the materials to be init'ed so we can hack the ground material together.
			renderer.render(this.scene, this.camera);

			this.mat.__webglShader.vertexShader = THREE.ShaderLib.terrain.vertexShader;
			this.mat.__webglShader.fragmentShader = THREE.ShaderLib.terrain.fragmentShader;
			this.mat.needsUpdate = true;
		},

		render: function(time, percent) 
		{
			// Render the depth map of the scene
			this.scene.overrideMaterial = this.depthMaterial;
			renderer.render(this.scene, this.camera, this.depthTarget);

			// Do the actual render
			this.scene.overrideMaterial = null;
			this.composer.render();
		}
	};
})();

var scenes = scenes || [];
scenes[Scene.id] = Scene;


THREE.ShaderLib.terrain = {

	uniforms: THREE.UniformsUtils.merge( [

		THREE.UniformsLib[ "common" ],
		THREE.UniformsLib[ "fog" ],
		THREE.UniformsLib[ "lights" ],
		THREE.UniformsLib[ "shadowmap" ],

		{
			"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
			"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
			"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
		}

	] ),

	vertexShader: [

		"#define LAMBERT",

		"varying vec3 vLightFront;",

		"#ifdef DOUBLE_SIDED",

		"	varying vec3 vLightBack;",

		"#endif",


		THREE.ShaderChunk[ "map_pars_vertex" ],
		THREE.ShaderChunk[ "lightmap_pars_vertex" ],
		THREE.ShaderChunk[ "envmap_pars_vertex" ],
		THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
		THREE.ShaderChunk[ "color_pars_vertex" ],
		THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
		THREE.ShaderChunk[ "skinning_pars_vertex" ],
		THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
		THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],
		THREE.ShaderChunk[ "terrainuniforms" ],

		"void main() {",


			THREE.ShaderChunk[ "map_vertex" ],
			THREE.ShaderChunk[ "lightmap_vertex" ],
			THREE.ShaderChunk[ "color_vertex" ],

			THREE.ShaderChunk[ "morphnormal_vertex" ],
			THREE.ShaderChunk[ "skinbase_vertex" ],
			THREE.ShaderChunk[ "skinnormal_vertex" ],
			THREE.ShaderChunk[ "defaultnormal_vertex" ],

			THREE.ShaderChunk[ "morphtarget_vertex" ],
			THREE.ShaderChunk[ "skinning_vertex" ],
			//THREE.ShaderChunk[ "default_vertex" ],
			THREE.ShaderChunk[ "terrainvertex" ],
			THREE.ShaderChunk[ "logdepthbuf_vertex" ],

			THREE.ShaderChunk[ "worldpos_vertex" ],
			THREE.ShaderChunk[ "envmap_vertex" ],
			THREE.ShaderChunk[ "lights_lambert_vertex" ],
			THREE.ShaderChunk[ "shadowmap_vertex" ],

		"}"

	].join("\n"),

	fragmentShader: [

		"uniform float opacity;",

		"varying vec3 vLightFront;",

		"#ifdef DOUBLE_SIDED",

		"	varying vec3 vLightBack;",

		"#endif",

		THREE.ShaderChunk[ "color_pars_fragment" ],
		THREE.ShaderChunk[ "map_pars_fragment" ],
		THREE.ShaderChunk[ "alphamap_pars_fragment" ],
		THREE.ShaderChunk[ "lightmap_pars_fragment" ],
		THREE.ShaderChunk[ "envmap_pars_fragment" ],
		THREE.ShaderChunk[ "fog_pars_fragment" ],
		THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
		THREE.ShaderChunk[ "specularmap_pars_fragment" ],
		THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

		"void main() {",

		"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",

			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
			THREE.ShaderChunk[ "map_fragment" ],
			THREE.ShaderChunk[ "alphamap_fragment" ],
			THREE.ShaderChunk[ "alphatest_fragment" ],
			THREE.ShaderChunk[ "specularmap_fragment" ],

		"	#ifdef DOUBLE_SIDED",

				//"float isFront = float( gl_FrontFacing );",
				//"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",

		"		if ( gl_FrontFacing )",
		"			gl_FragColor.xyz *= vLightFront;",
		"		else",
		"			gl_FragColor.xyz *= vLightBack;",

		"	#else",

		"		gl_FragColor.xyz *= vLightFront;",

		"	#endif",

			THREE.ShaderChunk[ "lightmap_fragment" ],
			THREE.ShaderChunk[ "color_fragment" ],
			THREE.ShaderChunk[ "envmap_fragment" ],
			THREE.ShaderChunk[ "shadowmap_fragment" ],

			THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

			THREE.ShaderChunk[ "fog_fragment" ],

			THREE.ShaderChunk[ "redc" ],

		"}"

	].join("\n")

};