var _gl;
var _canvas;
var _lastTime = 0;
var _elapsed = 0;
var _shaderProgram;
var _mvMatrix;
var _mvMatrixStack = [];
var _pMatrix;
var _eye;
var _lookAt;
var _fullScreen = false;
var _fov = 45;
var _near = 1;
var _far = 100000;
var _fukidashiFontSize = 48;
var _fontColor = "rgba(0,0,0,255)";
var _boldFont = false;
var _screenWidth = 0;
var _screenHeight = 0;

function setWebGL()
{
	try
	{
		_gl = _canvas.getContext("webgl") || _canvas.getContext("experimental-webgl");
		_gl.viewportWidth = _canvas.width;
		_gl.viewportHeight = _canvas.height;
	}
	catch (e)
	{
	}
	if (!_gl)
	{
		alert("WebGLの動作には、最新のブラウザIE11・Chrome・Safari・Firefoxが必要です！");
		return false;
	}
	return true;
}

function resize()
{
	if( _canvas && _fullScreen )
	{
		if ( _screenWidth < 0 )
		{
			_canvas.width = window.innerWidth + _screenWidth;
		}
		else if ( _screenWidth > 0 )
		{
			_canvas.width = _screenWidth;
		}
		else
		{
			_canvas.width = window.innerWidth;
		}
		if ( _screenHeight < 0 )
		{
			_canvas.height = window.innerHeight + _screenHeight;
		}
		else if ( _screenHeight > 0 )
		{
			_canvas.height = _screenHeight;
		}
		else
		{
			_canvas.height = window.innerHeight;
		}
		if ( _gl )
		{
			_gl.viewportWidth = _canvas.width;
			_gl.viewportHeight = _canvas.height;
		}
	}
}

function getVertexShader()
{
	var strVertex = "attribute vec3 a_VertexPosition;"+
		"attribute vec3 a_VertexNormal;"+
		"attribute vec2 a_TextureCoord;"+
		"attribute vec4 a_Bone;"+
		"attribute vec4 a_Weight;"+
		"uniform mat4 u_MVMatrix;"+
		"uniform mat4 u_PMatrix;"+
		"uniform mat3 u_NMatrix;"+
		"uniform mat4 u_BoneMatrix[28];"+
		"uniform bool u_UseBone;"+
		"varying vec3 v_TransformedNormal;"+
		"varying vec4 v_Position;"+
		"varying vec2 v_TextureCoord;"+
		"void main(void)"+
		"{"+
		"	if (u_UseBone)"+
		"	{"+
		"		mat4 m = u_BoneMatrix[int(a_Bone.x)]*a_Weight.x;"+
		"		m += u_BoneMatrix[int(a_Bone.y)]*a_Weight.y;"+
		"		m += u_BoneMatrix[int(a_Bone.z)]*a_Weight.z;"+
		"		m += u_BoneMatrix[int(a_Bone.w)]*a_Weight.w;"+
		"		v_Position = u_MVMatrix * m * vec4(a_VertexPosition, 1.0);"+
		"		v_TransformedNormal = u_NMatrix * mat3(m) * a_VertexNormal;"+
		"	}"+
		"	else"+
		"	{"+
		"		v_Position = u_MVMatrix * vec4(a_VertexPosition, 1.0);"+
		"		v_TransformedNormal = u_NMatrix * a_VertexNormal;"+
		"	}"+
		"	gl_Position = u_PMatrix * v_Position;"+
		"	v_TextureCoord = a_TextureCoord;"+
		"}";
	var shader = _gl.createShader(_gl.VERTEX_SHADER);

	_gl.shaderSource(shader, strVertex);
	_gl.compileShader(shader);

	if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS))
	{
		alert(_gl.getShaderInfoLog(shader));
		return null;
	}

	return shader;
}

function getFragmentShader()
{
	var strFragment = "precision mediump float;"+
		"varying vec3 v_TransformedNormal;"+
		"varying vec4 v_Position;"+
		"varying vec2 v_TextureCoord;"+
		"uniform sampler2D u_Sampler;"+
		"uniform vec4 u_AmbientColor;"+
		"uniform float u_Emissive;"+
		"uniform float u_Diffuse;"+
		"uniform float u_Power;"+
		"uniform vec4 u_SpecularColor;"+
		"uniform vec4 u_Color;"+
		"uniform bool u_UseTexture;"+
		"void main(void)"+
		"{"+
		"	vec3 lightDirection = normalize(vec3(-1.0,-2.0,-4.0));"+
		"	vec3 normal = normalize(v_TransformedNormal);"+
		"	float diffuseLightWeighting = dot(normal,lightDirection);"+
		"	diffuseLightWeighting = 0.5+diffuseLightWeighting/2.0;"+
		"	vec3 reflect = normalize(2.0*diffuseLightWeighting*normal-lightDirection);"+
		"	float specular = pow(clamp(dot(reflect,lightDirection),0.0,1.0),u_Power);"+
		"	if ( u_UseTexture )"+
		"	{"+
		"		vec4 textureColor = texture2D(u_Sampler,vec2(v_TextureCoord.s,v_TextureCoord.t));"+
		"		vec4 colorTex = u_AmbientColor+textureColor*u_Color*(u_Emissive+u_Diffuse*clamp(diffuseLightWeighting,0.0,1.0))+u_SpecularColor*specular;"+
		"		gl_FragColor = vec4(colorTex.rgb,textureColor.a*u_Color.a);"+
		"	}"+
		"	else"+
		"	{"+
		"		vec4 color = u_AmbientColor+u_Color*(u_Emissive+u_Diffuse*clamp(diffuseLightWeighting,0.0,1.0))+u_SpecularColor*specular;"+
		"		gl_FragColor = vec4(color.rgb,u_Color.a);"+
		"	}"+
		"}";

	var shader = _gl.createShader(_gl.FRAGMENT_SHADER);

	_gl.shaderSource(shader, strFragment);
	_gl.compileShader(shader);

	if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS))
	{
		alert(_gl.getShaderInfoLog(shader));
		return null;
	}

	return shader;
}

function setShaders()
{
	var fragmentShader = getFragmentShader();
	var vertexShader = getVertexShader();

	_shaderProgram = _gl.createProgram();
	_gl.attachShader(_shaderProgram, vertexShader);
	_gl.attachShader(_shaderProgram, fragmentShader);
	_gl.linkProgram(_shaderProgram);

	if (!_gl.getProgramParameter(_shaderProgram, _gl.LINK_STATUS))
	{
		alert("Could not initialise shaders");
		return false;
	}

	_gl.useProgram(_shaderProgram);

	_shaderProgram.a_vertexPosition = _gl.getAttribLocation(_shaderProgram, "a_VertexPosition");
	_gl.enableVertexAttribArray(_shaderProgram.a_vertexPosition);
	_shaderProgram.a_vertexNormal = _gl.getAttribLocation(_shaderProgram, "a_VertexNormal");
	_gl.enableVertexAttribArray(_shaderProgram.a_vertexNormal);
	_shaderProgram.a_bone = _gl.getAttribLocation(_shaderProgram, "a_Bone");
	_gl.enableVertexAttribArray(_shaderProgram.a_bone);
	_shaderProgram.a_weight = _gl.getAttribLocation(_shaderProgram, "a_Weight");
	_gl.enableVertexAttribArray(_shaderProgram.a_weight);
	_shaderProgram.a_textureCoord = _gl.getAttribLocation(_shaderProgram, "a_TextureCoord");
	_gl.enableVertexAttribArray(_shaderProgram.a_textureCoord);

	_shaderProgram.u_pMatrix = _gl.getUniformLocation(_shaderProgram, "u_PMatrix");
	_shaderProgram.u_mvMatrix = _gl.getUniformLocation(_shaderProgram, "u_MVMatrix");
	_shaderProgram.u_nMatrix = _gl.getUniformLocation(_shaderProgram, "u_NMatrix");
	_shaderProgram.u_boneMatrix = _gl.getUniformLocation(_shaderProgram, "u_BoneMatrix");
	_shaderProgram.u_ambientColor = _gl.getUniformLocation(_shaderProgram, "u_AmbientColor");
	_shaderProgram.u_diffuse = _gl.getUniformLocation(_shaderProgram, "u_Diffuse");
	_shaderProgram.u_emissive = _gl.getUniformLocation(_shaderProgram, "u_Emissive");
	_shaderProgram.u_power = _gl.getUniformLocation(_shaderProgram, "u_Power");
	_shaderProgram.u_specularColor = _gl.getUniformLocation(_shaderProgram, "u_SpecularColor");
	_shaderProgram.u_useBone = _gl.getUniformLocation(_shaderProgram, "u_UseBone");
	_shaderProgram.u_useTexture = _gl.getUniformLocation(_shaderProgram, "u_UseTexture");
	_shaderProgram.u_sampler = _gl.getUniformLocation(_shaderProgram, "u_Sampler");
	_shaderProgram.u_color = _gl.getUniformLocation(_shaderProgram, "u_Color");

	return true;
}

function mvPushMatrix()
{
	var copy = _mvMatrix.copy();
	_mvMatrixStack.push(copy._e);
}

function mvPopMatrix()
{
	if (_mvMatrixStack.length == 0)
	{
		throw "Invalid popMatrix!";
	}
	_mvMatrix._e = _mvMatrixStack.pop();
}

function setMatrixUniforms(pMatrix)
{
	_gl.uniformMatrix4fv(_shaderProgram.u_pMatrix, false, pMatrix);
	_gl.uniformMatrix4fv(_shaderProgram.u_mvMatrix, false, _mvMatrix._e);

	var normalMatrix = _mvMatrix.inverseMat33();
	normalMatrix = normalMatrix.transpose();
	_gl.uniformMatrix3fv(_shaderProgram.u_nMatrix, false, normalMatrix._e);
}

function beginDraw()
{
	_gl.viewport(0, 0, _gl.viewportWidth, _gl.viewportHeight);
	_gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT);

	_pMatrix.perspective(_fov, _gl.viewportWidth / _gl.viewportHeight, _near, _far);
	_mvMatrix.identity();
}

function animate()
{
	var timeNow = new Date().getTime();
	if (_lastTime != 0)
	{
		_elapsed = (timeNow - _lastTime) / 1000.0;
	}
	_lastTime = timeNow;
}

window.requestAnimationFrame = (function()
{
	return window.requestAnimationFrame ||
		window.webkitRequestAnimationFrame ||
		window.mozRequestAnimationFrame ||
		window.oRequestAnimationFrame ||
		window.msRequestAnimationFrame ||
		function(callback, element)
		{
			window.setTimeout(callback, 1000/30);
		};
}());

function mainLoop()
{
	beginDraw();
	drawWebGL();
	animate();
	requestAnimationFrame(mainLoop);
}

function initWebGL(fullScreen)
{
	_canvas = document.getElementById("PsychoVision3D-Canvas");

	if ( fullScreen )
	{
		_fullScreen = true;
		window.addEventListener("resize", resize, false);
		resize();
	}
	if ( !setWebGL() )
	{
		return;
	}
	if ( !setShaders() )
	{
		return;
	}
	_canvas.addEventListener("contextmenu", function(e){
		e.preventDefault();
	}, false);

	document.documentElement.style.webkitTouchCallout = "none";

	_gl.clearColor(0.4, 0.7, 1.0, 1.0);
	_gl.enable(_gl.DEPTH_TEST);
	_gl.enable(_gl.CULL_FACE);
//	_gl.blendColor(0,0,0,0);
	_gl.blendFuncSeparate(_gl.SRC_ALPHA,_gl.ONE_MINUS_SRC_ALPHA,_gl.ZERO,_gl.ONE);
	_gl.blendEquation(_gl.FUNC_ADD);
	_gl.enable(_gl.BLEND);
	_gl.cullFace(_gl.FRONT);

	_mvMatrix = new Matrix3D();
	_pMatrix = new Matrix3D();
	_eye = new Vector3D(0,0,500);
	_lookAt = new Vector3D(0,0,0);

	beginWebGL();

	if (navigator.userAgent.indexOf('iPhone')  >= 0
	||  navigator.userAgent.indexOf('iPad')    >= 0
	||  navigator.userAgent.indexOf('iPod')    >= 0
	||  navigator.userAgent.indexOf('Android') >= 0 )
	{
		_canvas.addEventListener('touchstart',onMouseDown,false);
		_canvas.addEventListener('touchmove',onMouseMove,false);
		_canvas.addEventListener('touchend',onMouseUp,false);
	}
	else
	{
		_canvas.onmousedown = onMouseDown;
		_canvas.onmousemove = onMouseMove;
		document.onmouseup  = onMouseUp;
	}
	document.onkeydown = onKeyDown;
	document.onkeyup   = onKeyUp;
	if(document.layers)
	{
		document.captureEvents(Event.KEYDOWN);
		document.captureEvents(Event.KEYUP);
	}

	mainLoop();
}

function degreeToRadian(degree)
{
	return degree * Math.PI / 180;
}

function radianToDegree(radian)
{
	return radian * 180 / Math.PI;
}

function mouseX(event)
{
	var rect = _canvas.getBoundingClientRect();

	if (navigator.userAgent.indexOf('iPhone')  >= 0
	||  navigator.userAgent.indexOf('iPad')    >= 0
	||  navigator.userAgent.indexOf('iPod')    >= 0
	||  navigator.userAgent.indexOf('Android') >= 0 )
	{
		var x = event.touches[0].clientX;
		if ( rect.left > x )
		{
			return 0;
		}
		else if ( rect.right > x )
		{
			return ~~(x - rect.left);
		}
		else
		{
			return ~~(rect.right - rect.left);
		}
	}
	else
	{
		if ( rect.left > event.clientX )
		{
			return 0;
		}
		else if ( rect.right > event.clientX )
		{
			return ~~(event.clientX - rect.left);
		}
		else
		{
			return ~~(rect.right - rect.left);
		}
	}
}

function mouseY(event)
{
	var rect = _canvas.getBoundingClientRect();

	if (navigator.userAgent.indexOf('iPhone')  >= 0
	||  navigator.userAgent.indexOf('iPad')    >= 0
	||  navigator.userAgent.indexOf('iPod')    >= 0
	||  navigator.userAgent.indexOf('Android') >= 0 )
	{
		var y = event.touches[0].clientY;
		if ( rect.top > y )
		{
			return 0;
		}
		else if ( rect.bottom > y )
		{
			return ~~(y - rect.top);
		}
		else
		{
			return ~~(rect.bottom - rect.top);
		}
	}
	else
	{
		if ( rect.top > event.clientY )
		{
			return 0;
		}
		else if ( rect.bottom > event.clientY )
		{
			return ~~(event.clientY - rect.top);
		}
		else
		{
			return ~~(rect.bottom - rect.top);
		}
	}
}

function mouseXY(event,mouse)
{
	mouse[0] = mouseX(event);
	mouse[1] = mouseY(event);
}

function getKeyCode(event)
{
	if(document.all)
	{
		return event.keyCode;
	}
	else if(document.getElementById)
	{
		return ((event.keyCode!=0)?event.keyCode:event.charCode);
	}
	else if(document.layers)
	{
		return event.which;
	}
}

function bindTexture(texture)
{
	_gl.bindTexture(_gl.TEXTURE_2D, texture);
	_gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, texture.image);
	_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.LINEAR);
	_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR);
	_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.REPEAT);
	_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.REPEAT);
	_gl.bindTexture(_gl.TEXTURE_2D, null);
}

function initTexture(textureName)
{
	var texture;
	texture = _gl.createTexture();
	texture.image = new Image();
	texture.image.onload = function(){ bindTexture(texture); }
	texture.image.src = textureName;
	return texture;
}

function getCanvasLeft()
{
	var rect = _canvas.getBoundingClientRect();

	return rect.left;
}

function getCanvasTop()
{
	var rect = _canvas.getBoundingClientRect();

	return rect.top;
}

function getCanvasPosition(pos)
{
	var v  = new Vector4D(pos.x,pos.y,pos.z,1);
	var v2 = _mvMatrix.transform(v);
	var v3 = _pMatrix.transform(v2);

	var half = new Vector2D(_gl.viewportWidth/2, _gl.viewportHeight/2);

	return new Vector2D(~~(v3.x / v3.w * half.x) + half.x,
		-~~(v3.y / v3.w * half.y) + half.y);
}

function getCookie(cookieName)
{
	var cookieTxt = document.cookie+";";
	var startNo = cookieTxt.indexOf(cookieName);
	var txt;
	if (startNo != -1)
	{
		var endNo = cookieTxt.indexOf(";",startNo);
		txt = unescape(cookieTxt.substring(startNo+cookieName.length+1,endNo));
	}
	else
	{
		txt = "";
	}
	return txt;
}

function saveCookie(cookieName,str,span)
{
	day = new Date();
	day.setTime(day.getTime()+span*24*60*60*1000);
	endDay = day.toGMTString();
	document.cookie = cookieName+"="+escape(str)+";expires="+endDay;
}
