// ---------------------------
//      In-Game Objects 
// ---------------------------
// mesh_asteroid - all unique, no shared geometry
// mesh_ship - shared geometry (geo_ship)
// mesh_proj - shared geometry (geo_proj)

var geo_ship = create_geo_ship(); // geometry shared by all ships //
var geo_proj = create_geo_proj(); // geometry shared by all projectiles //
var geo_exp  = create_geo_exp(); // geometry shared by all explosions //
var geo_ring = create_geo_ring(); // geometry shared by powerups //

// -----------
//  Materials 
// -----------
var mat_rock = [];
	mat_rock[0] = new THREE.MeshLambertMaterial( { map: THREE.ImageUtils.loadTexture("images/rock1.png") } );
	mat_rock[1] = new THREE.MeshLambertMaterial( { map: THREE.ImageUtils.loadTexture("images/rock2.png") } );
	mat_rock[2] = new THREE.MeshLambertMaterial( { map: THREE.ImageUtils.loadTexture("images/rock3.png") } );

var tex_fuel = THREE.ImageUtils.loadTexture( 'images/fuelbar.png' );
var tex_shield = THREE.ImageUtils.loadTexture( 'images/shieldbar.png' );
var tex_pause = THREE.ImageUtils.loadTexture( 'images/pause_play.png' );
var tex_music = THREE.ImageUtils.loadTexture( 'images/sound.png' );
var tex_left = THREE.ImageUtils.loadTexture( 'images/arrow_left.png' );
var tex_right = THREE.ImageUtils.loadTexture( 'images/arrow_right.png' );
var tex_site = THREE.ImageUtils.loadTexture( 'images/site.png' );

var mat_blue = new THREE.SpriteMaterial( { map: tex_fuel} );
var mat_yellow = new THREE.SpriteMaterial( { map: tex_shield } );
var mat_pause = new THREE.SpriteMaterial( { map: tex_pause} );
var mat_music = new THREE.SpriteMaterial( { map: tex_music } );
var mat_left = new THREE.SpriteMaterial( { map: tex_left} );
var mat_right = new THREE.SpriteMaterial( { map: tex_right } );
var mat_site = new THREE.SpriteMaterial( { map: tex_site } );

var tex_pop_fuel = THREE.ImageUtils.loadTexture( 'images/msg_fuel.png' );
var tex_pop_shield = THREE.ImageUtils.loadTexture( 'images/msg_shield.png' );
var tex_pop_pow = THREE.ImageUtils.loadTexture( 'images/msg_pow.png' );
var tex_pop_wide = THREE.ImageUtils.loadTexture( 'images/msg_wide.png' );
var tex_pop_level = THREE.ImageUtils.loadTexture( 'images/msg_level.png' );
var tex_pop_hit = THREE.ImageUtils.loadTexture( 'images/msg_hit.png' );
var tex_pop_nofuel = THREE.ImageUtils.loadTexture( 'images/msg_nofuel.png' );
var tex_pop_noshield = THREE.ImageUtils.loadTexture( 'images/msg_noshield.png' );
var tex_pop_end = THREE.ImageUtils.loadTexture( 'images/msg_end.png' );
var tex_pop_hiscore = THREE.ImageUtils.loadTexture( 'images/msg_hiscore.png' );

var mat_pop = [];
mat_pop["fuel"] = new THREE.SpriteMaterial( { map: tex_pop_fuel } );
mat_pop["shield"] = new THREE.SpriteMaterial( { map: tex_pop_shield } );
mat_pop["pow"] = new THREE.SpriteMaterial( { map: tex_pop_pow } );
mat_pop["wide"] = new THREE.SpriteMaterial( { map: tex_pop_wide } );
mat_pop["level"] = new THREE.SpriteMaterial( { map: tex_pop_level } );
mat_pop["hit"] = new THREE.SpriteMaterial( { map: tex_pop_hit } );
mat_pop["nofuel"] = new THREE.SpriteMaterial( { map: tex_pop_nofuel } );
mat_pop["noshield"] = new THREE.SpriteMaterial( { map: tex_pop_noshield } );
mat_pop["end"] = new THREE.SpriteMaterial( { map: tex_pop_end } );
mat_pop["hiscore"] = new THREE.SpriteMaterial( { map: tex_pop_hiscore } );

// ---- //

var mat_fire_red = new THREE.MeshLambertMaterial( { color:0xFF8080, emissive: 0xFF0000 } );
var mat_fire_blue = new THREE.MeshLambertMaterial( { color:0x8080FF, emissive: 0x0000FF } );
var mat_fire_green = new THREE.MeshLambertMaterial( { color:0x40FF40, emissive: 0x004400 } );
var mat_fire_yellow = new THREE.MeshLambertMaterial( { color:0xFFFF80, emissive: 0xFFFF00 } );

var mat_exp = new THREE.MeshLambertMaterial( { color:0xFF4040, emissive: 0x880000 } );

var mat_ring_blue = new THREE.MeshLambertMaterial( { color:0x4040FF, emissive: 0x000044 } );
var mat_ring_green = new THREE.MeshLambertMaterial( { color:0x40FF40, emissive: 0x004400 } );
var mat_ring_yellow = new THREE.MeshLambertMaterial( { color:0xFFFF40, emissive: 0x444400 } );

// --------------------------------------------------------------------------------------------- //
	function mesh_ring(material)
	{
		return new THREE.Mesh(geo_ring, new THREE.MeshFaceMaterial( [material] ));
	}

	function create_geo_ring()
	{
		var geo = new THREE.Geometry();
		geo.vertices = [new THREE.Vector3( -1, -12, -1 ), new THREE.Vector3(  1, -12, -1 ), 
						new THREE.Vector3( -1, -12, 1 ), new THREE.Vector3(  1, -12, 1 ), 
						new THREE.Vector3(  0, -10, 0 ), new THREE.Vector3(  0, -15, 0 )  ];
		geo.faces = [ new THREE.Face3(4,0,1), new THREE.Face3(4,1,3), new THREE.Face3(4,3,2), new THREE.Face3(4,2,0), 
					  new THREE.Face3(5,2,3), new THREE.Face3(5,3,1), new THREE.Face3(5,1,0), new THREE.Face3(5,0,2) ];

		geo.computeFaceNormals(); geo.computeCentroids(); geo.computeVertexNormals();

		var part = new THREE.Mesh(geo, new THREE.MeshFaceMaterial());
		var g = new THREE.Geometry();

		for (var i=0;i<12;i++)
		{
			part.rotation.z = i*(Math.PI/6);
			THREE.GeometryUtils.merge(g, part);
		}
		g.materials = [];
		g.materials[0] = mat_ring_blue;
		set_face_material(g, 0);
		
		return THREE.BufferGeometryUtils.fromGeometry(g);
	}
	

	function mesh_exp()
	{
		return new THREE.Mesh(geo_exp, mat_exp); //new THREE.MeshFaceMaterial([mat_exp]) );
	}

	function create_geo_exp()
	{
		var geo = new THREE.Geometry();
		geo.vertices = [new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3(  1, -1, -1 ), 
						new THREE.Vector3( -1, -1, 1 ), new THREE.Vector3(  1, -1, 1 ), 
						new THREE.Vector3( -1, 1, -1 ), new THREE.Vector3(  1, 1, -1 ), 
						new THREE.Vector3( -1, 1, 1 ), new THREE.Vector3(  1, 1, 1 ), 
						new THREE.Vector3(  0,-5, 0 ),	new THREE.Vector3( -5, 0, 0 ),
						new THREE.Vector3(  0, 5, 0 ),	new THREE.Vector3(  5, 0, 0 ),
						new THREE.Vector3(  0, 0, 5 ),	new THREE.Vector3(  0, 0,-5 )  ];

		geo.faces = [ new THREE.Face3(8,0,1), new THREE.Face3(8,1,3), new THREE.Face3(8,3,2), new THREE.Face3(8,2,0), 
					  new THREE.Face3(9,4,0), new THREE.Face3(9,0,2), new THREE.Face3(9,2,6), new THREE.Face3(9,6,4), 
					  new THREE.Face3(10,6,7), new THREE.Face3(10,7,5), new THREE.Face3(10,5,4), new THREE.Face3(10,4,6),
					  new THREE.Face3(11,3,1), new THREE.Face3(11,1,5), new THREE.Face3(11,5,7), new THREE.Face3(11,7,3),
					  new THREE.Face3(12,2,3), new THREE.Face3(12,3,7), new THREE.Face3(12,7,6), new THREE.Face3(12,6,2),
					  new THREE.Face3(13,1,0), new THREE.Face3(13,0,4), new THREE.Face3(13,4,5), new THREE.Face3(13,5,1) ];

		geo.materials = [];
		geo.materials.push(mat_exp);
		set_face_material(geo, 0);

		geo.computeFaceNormals();
		geo.computeCentroids();
		geo.computeVertexNormals();

		return THREE.BufferGeometryUtils.fromGeometry(geo);
	}

	function mesh_proj(material)
	{
		return new THREE.Mesh(geo_proj, material);
	}

	function create_geo_proj()
	{
		var geo = new THREE.Geometry();
		geo.vertices = [ new THREE.Vector3(  0, 0,-5),
						new THREE.Vector3(  0, -2, 5), new THREE.Vector3( -1.73,  1.0, 5), new THREE.Vector3(  1.73,  1.0, 5),
						new THREE.Vector3(  0,  0.5, 4), new THREE.Vector3(  0.43, -0.25, 4), new THREE.Vector3( -0.43, -0.25, 4)  ];

		geo.faces = [ new THREE.Face3(0,1,6), new THREE.Face3(0,6,2), new THREE.Face3(0,2,4),
					new THREE.Face3(0,4,3), new THREE.Face3(0,3,5), new THREE.Face3(0,5,1),
					new THREE.Face3(0,6,1), new THREE.Face3(0,2,6), new THREE.Face3(0,4,2),
					new THREE.Face3(0,3,4), new THREE.Face3(0,5,3), new THREE.Face3(0,1,5)  ];

		geo.computeFaceNormals();
		geo.computeCentroids();
		geo.computeVertexNormals();

		return THREE.BufferGeometryUtils.fromGeometry(geo);
	}

	function mesh_asteroid(material)
	{
		var geo = new THREE.SphereGeometry(5,5,4); // 5,8,8 radius, segments, rings
		remove_similar_points(geo, 0.01);

		// make asteroids bumpy //
		for (var i=0;i<geo.vertices.length;i++)
		{
				var d = 1+(rnd(-15, 15)/100);
				geo.vertices[i].x *= d;
				geo.vertices[i].y *= d;
				geo.vertices[i].z *= d;
		}
		// stretch/squash them a little one way
		var a = rnd(0, 2);
		var d = 1+(rnd(-40,40)/100);
		for (var i=0;i<geo.vertices.length;i++)
		{
			switch (a)
			{
				case 0: geo.vertices[i].x *= d; break;
				case 1: geo.vertices[i].y *= d; break;
				case 2: geo.vertices[i].z *= d; break;
			}
		}
		//geo.verticesNeedUpdate = true;
		geo.computeVertexNormals();
		geo.computeFaceNormals();
		return new THREE.Mesh(THREE.BufferGeometryUtils.fromGeometry(geo), material);
	}

	function mesh_ship()
	{
		return new THREE.Mesh(geo_ship, new THREE.MeshFaceMaterial(geo_ship.materials));
	}

	function create_geo_ship()
	{
		var mat_ship_body = new THREE.MeshLambertMaterial( { color: 0x7092BE } );
		var mat_ship_dome = new THREE.MeshLambertMaterial( { color: 0x303080 } );
		var mat_ship_light = new THREE.MeshBasicMaterial( { color: 0xFFFFFF } );

		var geo = new THREE.Geometry();
		
		materials = [];
		materials.push(mat_ship_body);
		materials.push(mat_ship_dome);
		materials.push(mat_ship_light);
		
		var body = new THREE.SphereGeometry(5,8,6);
		remove_similar_points(body, 0.01);
		for (var i=0;i<body.vertices.length;i++) { body.vertices[i].y *= 0.35; }
		set_face_material(body, 0);
		THREE.GeometryUtils.merge(geo, body);

		// add dome //
		var dome = new THREE.SphereGeometry(2,8,6);
		remove_similar_points(dome, 0.01);
		for (var i=0;i<dome.vertices.length;i++) { dome.vertices[i].y += 1.8; }
		set_face_material(dome, 1);
		THREE.GeometryUtils.merge(geo, dome);

		// add lights //
		var shiplight = new THREE.SphereGeometry(0.5,6,3);
		set_face_material(shiplight, 2);
		remove_similar_points(shiplight, 0.01);
		for (var i=0;i<shiplight.vertices.length;i++) { shiplight.vertices[i].z += 4.7; }
		var mshiplight = new THREE.Mesh(shiplight, mat_ship_light);
		for (var i=0; i<8; i++)
		{
			mshiplight.rotation.y = i*(Math.PI/4);
			THREE.GeometryUtils.merge(geo, mshiplight);
		}
		geo.materials = materials;
		return geo;
	}

// **************************************************************************
// **********************  Helpful Utility Functions  ***********************
// **************************************************************************

	function set_face_material(geo, matindex)
	{
		for (var i=0;i<geo.faces.length;i++) { geo.faces[i].materialIndex = matindex; }
	}

	function remove_duplicate_points(geo) { remove_similar_points(geo, 0); }

	function remove_similar_points(geo, level)
	{
		for (var i=0;i<geo.vertices.length;i++)
		{
			for (var j=(i+1);j<geo.vertices.length;j++)
			{
				if ( (geo.vertices[i].x <= geo.vertices[j].x+level && geo.vertices[i].x >= geo.vertices[j].x-level) &&
					 (geo.vertices[i].y <= geo.vertices[j].y+level && geo.vertices[i].y >= geo.vertices[j].y-level) &&
					 (geo.vertices[i].z <= geo.vertices[j].z+level && geo.vertices[i].z >= geo.vertices[j].z-level) )
				{
					for (var k=0; k<geo.faces.length; k++)
					{
						if (geo.faces[k].a == j) { geo.faces[k].a = i; }
						if (geo.faces[k].b == j) { geo.faces[k].b = i; }
						if (geo.faces[k].c == j) { geo.faces[k].c = i; }
						if (geo.faces[k].d == j) { geo.faces[k].d = i; }
						if (geo.faces[k].a > j) { geo.faces[k].a--; }
						if (geo.faces[k].b > j) { geo.faces[k].b--; }
						if (geo.faces[k].c > j) { geo.faces[k].c--; }
						if (geo.faces[k].d > j) { geo.faces[k].d--; }
					}
					geo.vertices.splice(j, 1); j--;
				}
			}
		}
	}