var Model3D = function()
{
	this._vertices = [];
	this._normals = [];
	this._materials = [];
	this._material = [];
	this._uvs = [];
	this._vertexPositionBuffer = [];
	this._vertexNormalBuffer = [];
	this._textureCoordBuffer = [];
	this._pos = new Vector3D(0,0,0);
	this._rotate = new Vector3D(0,0,0);
	this._scale = new Vector3D(1,1,1);
	this._distance = 0;
	this._distance2 = 0;
	this._intersectU = 0;
	this._intersectV = 0;
	this._visible = true;
	this._useTexture = false;
	this._count = 0;
	this._mvMatrix = new Matrix3D();
};

Model3D.prototype =
{
	init : function()
	{
		this._pos = new Vector3D(0,0,0);
		this._rotate = new Vector3D(0,0,0);
		this._scale = new Vector3D(1,1,1);
		this._distance = 0;
		this._distance2 = 0;
		this._intersectU = 0;
		this._intersectV = 0;
		this._visible = true;
		this._vertexPositionBuffer = [];
		this._vertexNormalBuffer = [];
		this._textureCoordBuffer = [];
		this._vertices = [];
		this._normals = [];
		this._materials = [];
		this._material = [];
		this._uvs = [];
		this._count = 0;
		this._mvMatrix = new Matrix3D();
	},
	setVertex : function(x,y,z,nx,ny,nz,material)
	{
		this._vertices[material].push(x,y,z);
		this._normals[material].push(nx,ny,nz);
		this._material.push(material);
	},
	setUV : function(u,v)
	{
		this._uvs[this._material[this._count]].push(u,v);
		this._count++;
	},
	setMaterial : function(r,g,b,a,dif,amb,emi,spc,power,texture)
	{
		this._materials.push(new Material(r,g,b,a,dif,amb,emi,spc,power,texture));
		this._vertices.push([]);
		this._normals.push([]);
		this._uvs.push([]);
	},
	changeTexture : function(material,texture)
	{
		this._materials[material].changeTexture(texture);
	},
	getVerticesLength : function(index)
	{
		return ~~(this._vertices[index].length/3);
	},
	initBuffers : function()
	{
		for ( var i = 0; i < this._materials.length; i++ )
		{
			if ( this.getVerticesLength(i) > 0 )
			{
				this._vertexPositionBuffer[i] = _gl.createBuffer();
				_gl.bindBuffer(_gl.ARRAY_BUFFER, this._vertexPositionBuffer[i]);
				_gl.bufferData(_gl.ARRAY_BUFFER, new Float32Array(this._vertices[i]), _gl.STATIC_DRAW);
				this._vertexPositionBuffer[i].itemSize = 3;
				this._vertexPositionBuffer[i].numItems = this.getVerticesLength(i);

				this._vertexNormalBuffer[i] = _gl.createBuffer();
				_gl.bindBuffer(_gl.ARRAY_BUFFER, this._vertexNormalBuffer[i]);
				_gl.bufferData(_gl.ARRAY_BUFFER, new Float32Array(this._normals[i]), _gl.STATIC_DRAW);
				this._vertexNormalBuffer[i].itemSize = 3;
				this._vertexNormalBuffer[i].numItems = this.getVerticesLength(i);

				if ( this._uvs[i].length )
				{
					this._textureCoordBuffer[i] = _gl.createBuffer();
					_gl.bindBuffer(_gl.ARRAY_BUFFER, this._textureCoordBuffer[i]);
					_gl.bufferData(_gl.ARRAY_BUFFER, new Float32Array(this._uvs[i]), _gl.STATIC_DRAW);
					this._textureCoordBuffer[i].itemSize = 2;
					this._textureCoordBuffer[i].numItems = this.getVerticesLength(i);
				}
			}
		}
	},
	draw : function()
	{
		if ( !this._visible )
		{
			return;
		}
		mvPushMatrix();

		_gl.uniform1i(_shaderProgram.u_useBone, false);
		_gl.disableVertexAttribArray(_shaderProgram.a_bone);
		_gl.disableVertexAttribArray(_shaderProgram.a_weight);

		_mvMatrix.translate(this._pos);
		_mvMatrix.rotateX(degreeToRadian(this._rotate.x));
		_mvMatrix.rotateY(degreeToRadian(this._rotate.y));
		_mvMatrix.rotateZ(degreeToRadian(this._rotate.z));
		_mvMatrix.scale(this._scale);
		this._mvMatrix = _mvMatrix.copy();
		setMatrixUniforms(_pMatrix._e);

		for ( var i = 0; i < this._materials.length; i++ )
		{
			if ( this.getVerticesLength(i) > 0 )
			{
				this.setVertices(i);
				_gl.drawArrays(_gl.TRIANGLES, 0, this.getVerticesLength(i) );
			}
		}

		mvPopMatrix();
	},
	drawLength : function(length)
	{
		if ( !this._visible )
		{
			return;
		}
		mvPushMatrix();

		_gl.uniform1i(_shaderProgram.u_useBone, false);
		_gl.disableVertexAttribArray(_shaderProgram.a_bone);
		_gl.disableVertexAttribArray(_shaderProgram.a_weight);

		_mvMatrix.translate(this._pos);
		_mvMatrix.rotateX(degreeToRadian(this._rotate.x));
		_mvMatrix.rotateY(degreeToRadian(this._rotate.y));
		_mvMatrix.rotateZ(degreeToRadian(this._rotate.z));
		_mvMatrix.scale(this._scale);
		this._mvMatrix = _mvMatrix.copy();
		setMatrixUniforms(_pMatrix._e);

		for ( var i = 0; i < this._materials.length; i++ )
		{
			var l = this.getVerticesLength(i);
			if ( length < l )
			{
				l = length;
			}
			if ( l > 0 )
			{
				this.setVertices(i);

				_gl.drawArrays(_gl.TRIANGLES, 0, l );
			}
		}

		mvPopMatrix();
	},
	setVertices : function(index,animations)
	{
		_gl.enableVertexAttribArray(_shaderProgram.a_vertexNormal);

		_gl.bindBuffer(_gl.ARRAY_BUFFER, this._vertexPositionBuffer[index]);
		_gl.vertexAttribPointer(_shaderProgram.a_vertexPosition, this._vertexPositionBuffer[index].itemSize, _gl.FLOAT, false, 0, 0);

		_gl.bindBuffer(_gl.ARRAY_BUFFER,this._vertexNormalBuffer[index]);
		_gl.vertexAttribPointer(_shaderProgram.a_vertexNormal, this._vertexNormalBuffer[index].itemSize, _gl.FLOAT, false, 0, 0);

		var material;
		if ( animations == null )
		{
			material = this._materials[index];
		}
		else
		{
			material = this._materials[animations[index]];
		}
		if ( material._fukidashi )
		{
			_gl.uniform4f(_shaderProgram.u_color,1,1,1,1);
		}
		else
		{
			_gl.uniform4f(_shaderProgram.u_color,material._r,material._g,material._b,material._a);
		}
		_gl.uniform1f(_shaderProgram.u_diffuse,material._dif);
		_gl.uniform1f(_shaderProgram.u_emissive,material._emi);
		_gl.uniform4f(_shaderProgram.u_ambientColor,material._amb/4,material._amb/4,material._amb/4,1);
		_gl.uniform1f(_shaderProgram.u_power,material._power);
		_gl.uniform4f(_shaderProgram.u_specularColor,material._spc,material._spc,material._spc,1);

		if ( material.setTexture() )
		{
			_gl.bindBuffer(_gl.ARRAY_BUFFER, this._textureCoordBuffer[index]);
			_gl.vertexAttribPointer(_shaderProgram.a_textureCoord, this._textureCoordBuffer[index].itemSize, _gl.FLOAT, false, 0, 0);

			_gl.enableVertexAttribArray(_shaderProgram.a_textureCoord);
			_gl.uniform1i(_shaderProgram.u_useTexture, true);
		}
		else
		{
			_gl.disableVertexAttribArray(_shaderProgram.a_textureCoord);
			_gl.uniform1i(_shaderProgram.u_useTexture, false);
		}
	},
	intersect : function(origin, dir)
	{
		var flg = false;
		this._distance = 1000000;
		for ( var i = 0; i < this._materials.length; i++ )
		{
			for ( var j = 0; j < this._vertices[i].length; j += 9 )
			{
				var v = this._vertices[i];
				var v0 = new Vector3D(v[j  ],v[j+1],v[j+2]);
				var v1 = new Vector3D(v[j+3],v[j+4],v[j+5]);
				var v2 = new Vector3D(v[j+6],v[j+7],v[j+8]);
				if ( this.intersectTriangle(origin,dir,v0,v1,v2) )
				{
					if ( this._distance2 >= 0 && this._distance > this._distance2 )
					{
						this._distance = this._distance2;
						flg = true;
					}
				}
			}
		}
        
		return flg;
	},
	intersectTriangle : function(origin, dir, v0, v1, v2)
	{
			var e1 = new Vector3D();
			var e2 = new Vector3D();
			var pv = new Vector3D();
			var tv = new Vector3D();
			var qv = new Vector3D();
			var det;
			var t, u, v;
			var inv_det;

			e1 = v1.subtract(v0);
			e2 = v2.subtract(v0);

			pv = dir.crossProduct(e2);
			det = e1.dotProduct(pv);

			if (det > (1e-3))
			{
				tv = origin.subtract(v0);
				u = tv.dotProduct(pv);
				if (u < 0.0 || u > det)
				{
					return false;
				}
				qv = tv.crossProduct(e1);

				v = dir.dotProduct(qv);
				if (v < 0.0 || u + v > det)
				{
					return false;
				}
			}
			else if (det < -(1e-3))
			{
				tv = origin.subtract(v0);

				u = tv.dotProduct(pv);
				if (u > 0.0 || u < det)
				{
					return false;
				}
				qv = tv.crossProduct(e1);

				v = dir.dotProduct(qv);
				if (v > 0.0 || u + v < det)
				{
					return false;
				}
			}
			else
			{
				return false;
			}

			inv_det = 1.0 / det;

			t = e2.dotProduct(qv);
			t *= inv_det;
			u *= inv_det;
			v *= inv_det;

			this._distance2 = t;
			this._intersectU = u;
			this._intersectV = v;

			return true;
	},
	dirRadian : function(dest)
	{
		var dir = new Vector3D(0,0,0);

		dir = dest.subtract(this._pos);

		if (dir.x > 0.0)
		{
			return -Math.atan(dir.z / dir.x) + Math.PI / 2;
		}
		else if (dir.x < 0.0)
		{
			return -Math.atan(dir.z / dir.x) - Math.PI / 2;
		}
		else if ( dir.z < 0 )
		{
			return Math.PI;
		}
		return 0;
	},
	dirDegree : function(dest)
	{
		var degree;

		degree = radianToDegree(this.dirRadian(dest));

		if ( degree < 0 )
		{
			degree += 360;
		}
		if ( degree >= 360 )
		{
			degree -= 360;
		}

		return degree;
	},
	forward : function(delta)
	{
		var pos = new Vector3D(0,0,0);
		var radian = degreeToRadian(this._rotate.y);

		pos.x = this._pos.x + Math.sin(radian) * delta * _elapsed;
		pos.y = this._pos.y;
		pos.z = this._pos.z + Math.cos(radian) * delta * _elapsed;

		return pos;
	},
	forward2 : function(delta)
	{
		var pos = new Vector3D(0,0,0);
		var radian = degreeToRadian(this._rotate.y);

		pos.x = this._pos.x + Math.sin(radian) * delta;
		pos.y = this._pos.y;
		pos.z = this._pos.z + Math.cos(radian) * delta;

		return pos;
	},
	addRotateX : function(delta)
	{
		this._rotate.x += delta * _elapsed;

		if ( this._rotate.x < 0 )
		{
			this._rotate.x += 360;
		}
		if ( this._rotate.x >= 360 )
		{
			this._rotate.x -= 360;
		}
	},
	addRotateX2 : function(delta)
	{
		this._rotate.x += delta;

		if ( this._rotate.x < 0 )
		{
			this._rotate.x += 360;
		}
		if ( this._rotate.x >= 360 )
		{
			this._rotate.x -= 360;
		}
	},
	addRotateY : function(delta)
	{
		this._rotate.y += delta * _elapsed;

		if ( this._rotate.y < 0 )
		{
			this._rotate.y += 360;
		}
		if ( this._rotate.y >= 360 )
		{
			this._rotate.y -= 360;
		}
	},
	addRotateY2 : function(delta)
	{
		this._rotate.y += delta;

		if ( this._rotate.y < 0 )
		{
			this._rotate.y += 360;
		}
		if ( this._rotate.y >= 360 )
		{
			this._rotate.y -= 360;
		}
	},
	getPos : function()
	{
		return new Vector3D(this._pos.x,this._pos.y,this._pos.z);
	},
	posPlus : function(x,y,z)
	{
		var pos = new Vector3D();
		pos.x = this._pos.x + x;
		pos.y = this._pos.y + y;
		pos.z = this._pos.z + z;
		return pos;
	},
	mousePick : function(x,y)
	{
		var vPickRayDir = new Vector3D();
		var vPickRayOrig = new Vector3D();
		var v = new Vector3D();

		v.x =  ( ( ( 2 * x ) / _gl.viewportWidth  ) - 1 ) / _pMatrix._e[0];
		v.y = -( ( ( 2 * y ) / _gl.viewportHeight ) - 1 ) / _pMatrix._e[5];
		v.z = -1;

		var m = new Matrix3D();
		m = m.inverse(this._mvMatrix);

		vPickRayDir.x  = v.x*m._e[0] + v.y*m._e[4] + v.z*m._e[8];
		vPickRayDir.y  = v.x*m._e[1] + v.y*m._e[5] + v.z*m._e[9];
		vPickRayDir.z  = v.x*m._e[2] + v.y*m._e[6] + v.z*m._e[10];
		vPickRayOrig.x = m._e[12];
		vPickRayOrig.y = m._e[13];
		vPickRayOrig.z = m._e[14];

		if( this.intersect(vPickRayOrig,vPickRayDir) )
		{
			return true;
		}

		return false;
	},
	setText : function(text,state,checkBox,promptTxt)
	{
		for ( var i = 0; i < this._materials.length; i++ )
		{
			var mat = this._materials[i];
			if ( mat._fukidashi )
			{
				var str = "";
				var txt = text.split("￥ｎ");
				if ( txt.length <= 0 )
				{
					return;
				}
				var index = txt[0].indexOf("http");
				var index2 = txt[0].indexOf("./");
				var index3 = txt[0].indexOf("=");
				var index4 = txt[0].indexOf(";");
				switch ( state )
				{
				case 0:
					if ( index >= 0 || index2 >= 0 || index3 >= 0 || index4 >= 0 )
					{
						text = text.substring(txt[0].length+2);
					}
					mat.setText(text,this._scale);
					if ( index4 >= 0 )
					{
						return "";
					}
					else if ( index == 0 || index2 >= 0 )
					{
						if ( txt[0].indexOf("?") == txt[0].length-1 )
						{
							for ( j = 0; j < _getData.length-1; j++ )
							{
								txt[0] += _getData[j] + "&";
							}
							for ( ; j < _getData.length; j++ )
							{
								txt[0] += _getData[j];
							}
						}
						location.href = txt[0];
					}
					break;
				case 1:
					if ( index < 0 && index2 < 0 && index3 >= 0 && index4 < 0 )
					{
						if ( txt[0].indexOf("CheckBox=true") >= 0 )
						{
							_getData.push(checkBox);
						}
						else if ( txt[0].indexOf("=") == txt[0].length-1 )
						{
							str = window.prompt("入力してください",promptTxt);
							str = str.replace( /[A-Za-z0-9-!"#$%&'()=<>,.?_\[\]{}@^~\\]/g, function(s) {
					            return String.fromCharCode(s.charCodeAt(0) + 65248);
					        });
							_getData.push(txt[0]+str);
							_time = 0;
						}
						else
						{
							_getData.push(txt[0]);
						}
					}
					break;
				case 2:
					if ( index < 0 && index2 < 0 && index3 >= 0 && index4 < 0 )
					{
						_getData.pop();
					}
					break;
				}
				return str;
			}
		}
		return "";
	},
	fade : function(time)
	{
		for ( var i = 0; i < this._materials.length; i++ )
		{
			this._materials[i]._a = time;
		}
	},
};
