DIR : /home/kozerus/public_html/jkwii/js/jsdoit/kojsdoit01_index.js

/home/kozerus/public_html/jkwii/js/jsdoit

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 頂点シェーダー
var vshader_src =
	"#ifdef GL_ES                                                    \n" +
	"    precision highp float;                                      \n" +
	"#endif                                                          \n" +
	"                                                                \n" +
	"attribute vec3 vs_attr_pos;                                     \n" +
	"attribute vec3 vs_attr_col;                                     \n" +
	"attribute vec2 vs_attr_uvc;                                     \n" +
	"uniform mat4 vs_unif_mat;                                       \n" +
	"                                                                \n" +
	"varying vec4 color;                                             \n" +
	"varying vec2 texCoord;                                          \n" +
	"                                                                \n" +
	"void main() {                                                   \n" +
	"    color       = vec4(vs_attr_col, 1.0);                       \n" +
	"    texCoord    = vs_attr_uvc;                                  \n" +
	"    gl_Position = vs_unif_mat * vec4(vs_attr_pos, 1.0);         \n" +
	"}                                                               \n" +
"";

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// フラグメントシェーダー
var fshader_src =
	"#ifdef GL_ES                                                    \n" +
	"    precision highp float;                                      \n" +
	"#endif                                                          \n" +
	"                                                                \n" +
	"uniform sampler2D texture;                                      \n" +
	"                                                                \n" +
	"varying vec4 color;                                             \n" +
	"varying vec2 texCoord;                                          \n" +
	"                                                                \n" +
	"void main() {                                                   \n" +
	"    vec4 fragColor = texture2D(texture, texCoord) * color;      \n" +
	"    if(fragColor.a > 0.8){                                      \n" +
	"        gl_FragColor = fragColor;                               \n" +
	"    }else{                                                      \n" +
	"        discard;                                                \n" +
	"    }                                                           \n" +
	"}                                                               \n" +
"";

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 簡易3Dエンジンクラス
function Engine3d(){
	this.gl;
	this.shader;
	this.s_pos;
	this.s_col;
	this.s_uvc;
	this.s_mat;
	
	// ----------------------------------------------------------------
	// 初期化
	
	// エンジン初期化
	this.init = function(canvas){
		// コンテキストの獲得
		try{var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");}catch(e){}
		if(!gl){
			alert("WebGL がサポートされていません。");
			document.write("<img src='http://jsrun.it/assets/u/9/R/Q/u9RQx.png'>");
			return -1;
		}
		
		// 頂点シェーダーの作成
		var vshader = gl.createShader(gl.VERTEX_SHADER);
		gl.shaderSource(vshader, vshader_src);
		gl.compileShader(vshader);
		if(!gl.getShaderParameter(vshader, gl.COMPILE_STATUS)){
			alert(gl.getShaderInfoLog(vshader));
			return -1;
		}
		
		// フラグメントシェーダーの作成
		var fshader = gl.createShader(gl.FRAGMENT_SHADER);
		gl.shaderSource(fshader,  fshader_src);
		gl.compileShader(fshader);
		if(!gl.getShaderParameter(fshader, gl.COMPILE_STATUS)){
			alert(gl.getShaderInfoLog(fshader));
			return -1;
		}
		
		// プログラムオブジェクトを作成
		this.shader = gl.createProgram();
		gl.attachShader(this.shader, vshader);
		gl.attachShader(this.shader, fshader);
		
		// シェーダー内の変数を頂点属性に結びつける
		gl.bindAttribLocation(this.shader, this.s_pos = 0, "vs_attr_pos");
		gl.bindAttribLocation(this.shader, this.s_col = 1, "vs_attr_col");
		gl.bindAttribLocation(this.shader, this.s_uvc = 2, "vs_attr_uvc");
		
		// 頂点シェーダーとフラグメントシェーダーをリンクする
		gl.linkProgram(this.shader);
		if(!gl.getProgramParameter(this.shader, gl.LINK_STATUS)){
			alert(gl.getProgramInfoLog(this.shader));
			return -1;
		}
		
		// シェーダーパラメータのインデックスを取得保存
		this.s_mat = gl.getUniformLocation(this.shader, "vs_unif_mat");
		
		// opengl描画設定
		gl.clearColor(0.5, 0.8, 1, 1);
		gl.clearDepth(1000);
		// カリング
		gl.enable(gl.CULL_FACE);
		gl.cullFace(gl.BACK);
		// アルファブレンド
		//gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
		//gl.enable(gl.BLEND);
		// シェーダーを指定
		gl.useProgram(this.shader);
		
		this.gl = gl;
		return 0;
	}
	
	// ----------------------------------------------------------------
	// モデル作成
	
	// VBO作成
	this.createVBO = function(vertices){
		var gl = this.gl;
		var vertexBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
		return vertexBuffer;
	}
	
	// IBO作成
	this.createIBO = function(indexes){
		var gl = this.gl;
		var indexBuffer = gl.createBuffer();
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
		gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(indexes), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
		return indexBuffer;
	}
	
	// バッファ除去
	this.deleteBuffer = function(buffer){
		var gl = this.gl;
		gl.deleteBuffer(buffer);
	}
	
	// テクスチャ読込み
	this.loadTexture = function(url){
		var gl = this.gl;
		// テクスチャーオブジェクトを作成
		var texture = gl.createTexture();
		// 画像の読み込み完了時の処理
		var image = new Image();
		image.onload = function() {
			gl.enable(gl.TEXTURE_2D);
			gl.bindTexture(gl.TEXTURE_2D, texture);
			gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
			gl.generateMipmap(gl.TEXTURE_2D);
			gl.bindTexture(gl.TEXTURE_2D, null);
		}
		// 画像の読み込みを開始
		image.src = url;
		
		return texture;
	}
	
	// ----------------------------------------------------------------
	// 描画処理
	
	// 描画のクリア
	this.clear = function(){
		this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
	}
	
	// デプステスト設定
	this.setDepthMode = function(flag){
		var gl = this.gl;
		if(flag){
			gl.enable(gl.DEPTH_TEST);
		}else{
			gl.disable(gl.DEPTH_TEST);
		}
	}
	
	// 行列の設定
	this.setMatrix = function(matrix){
		var matrixArray = new Float32Array([
			matrix._11, matrix._12, matrix._13, matrix._14,
			matrix._21, matrix._22, matrix._23, matrix._24,
			matrix._31, matrix._32, matrix._33, matrix._34,
			matrix._41, matrix._42, matrix._43, matrix._44,
		]);
		this.gl.uniformMatrix4fv(this.s_mat, false, matrixArray);
	}
	
	// テクスチャを指定
	this.bindTex = function(texture, type){
		var gl = this.gl;
		gl.enable(gl.TEXTURE_2D);
		gl.bindTexture(gl.TEXTURE_2D, texture);
		if(type == 1){
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
		}else{
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
			gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
		}
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	}
	
	// VBO登録
	this.bindBuf = function(vertVBO, clorVBO, texcVBO, faceIBO){
		this.bindVertBuf(vertVBO);
		this.bindClorBuf(clorVBO);
		this.bindTexcBuf(texcVBO);
		this.bindFaceBuf(faceIBO);
	}
	
	// VBO登録 頂点座標
	this.bindVertBuf = function(vertVBO){
		var gl = this.gl;
		gl.enableVertexAttribArray(this.s_pos);
		gl.bindBuffer(gl.ARRAY_BUFFER, vertVBO);
		gl.vertexAttribPointer(this.s_pos, 3, gl.FLOAT, false, 0, 0);
	}
	
	// VBO登録 カラー
	this.bindClorBuf = function(clorVBO){
		var gl = this.gl;
		gl.enableVertexAttribArray(this.s_col);
		gl.bindBuffer(gl.ARRAY_BUFFER, clorVBO);
		gl.vertexAttribPointer(this.s_col, 3, gl.FLOAT, false, 0, 0);
	}
	
	// VBO登録 テクスチャ座標
	this.bindTexcBuf = function(texcVBO){
		var gl = this.gl;
		gl.enableVertexAttribArray(this.s_uvc);
		gl.bindBuffer(gl.ARRAY_BUFFER, texcVBO);
		gl.vertexAttribPointer(this.s_uvc, 2, gl.FLOAT, false, 0, 0);
	}
	
	// IBO登録 頂点インデックス
	this.bindFaceBuf = function(faceIBO){
		var gl = this.gl;
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, faceIBO);
	}
	
	// 描画
	this.draw = function(offset, count){
		var gl = this.gl;
		gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, offset * Uint16Array.BYTES_PER_ELEMENT);
	}
	
	// 描画の反映
	this.flush = function(){
		this.gl.flush();
	}
	
	// ----------------------------------------------------------------
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 行列クラス
// openGLと同じ右手座標系のつもりだが...?
//[ x ][ _11, _12, _13, _14 ]
//[ y ][ _21, _22, _23, _24 ]
//[ z ][ _31, _32, _33, _34 ]
//[ w ][ _41, _42, _43, _44 ]
function Matrix(){
	// ----------------------------------------------------------------
	// 初期化
	
	// 単位行列
	this.identity = function(){
		this._12 = this._13 = this._14 = 0;
		this._21 = this._23 = this._24 = 0;
		this._31 = this._32 = this._34 = 0;
		this._41 = this._42 = this._43 = 0;
		this._11 = this._22 = this._33 = this._44 = 1;
	}
	
	// 行列の複製
	this.copy = function(m){
		this._11 = m._11;
		this._12 = m._12;
		this._13 = m._13;
		this._14 = m._14;
		this._21 = m._21;
		this._22 = m._22;
		this._23 = m._23;
		this._24 = m._24;
		this._31 = m._31;
		this._32 = m._32;
		this._33 = m._33;
		this._34 = m._34;
		this._41 = m._41;
		this._42 = m._42;
		this._43 = m._43;
		this._44 = m._44;
	}
	
	this.identity();
	
	// ----------------------------------------------------------------
	// 行列の掛け合わせ
	
	// 行列の掛け合わせ m0 * m1
	this.mul = function(m0, m1){
		this._11 = m0._11 * m1._11 + m0._12 * m1._21 + m0._13 * m1._31 + m0._14 * m1._41;
		this._12 = m0._11 * m1._12 + m0._12 * m1._22 + m0._13 * m1._32 + m0._14 * m1._42;
		this._13 = m0._11 * m1._13 + m0._12 * m1._23 + m0._13 * m1._33 + m0._14 * m1._43;
		this._14 = m0._11 * m1._14 + m0._12 * m1._24 + m0._13 * m1._34 + m0._14 * m1._44;
		this._21 = m0._21 * m1._11 + m0._22 * m1._21 + m0._23 * m1._31 + m0._24 * m1._41;
		this._22 = m0._21 * m1._12 + m0._22 * m1._22 + m0._23 * m1._32 + m0._24 * m1._42;
		this._23 = m0._21 * m1._13 + m0._22 * m1._23 + m0._23 * m1._33 + m0._24 * m1._43;
		this._24 = m0._21 * m1._14 + m0._22 * m1._24 + m0._23 * m1._34 + m0._24 * m1._44;
		this._31 = m0._31 * m1._11 + m0._32 * m1._21 + m0._33 * m1._31 + m0._34 * m1._41;
		this._32 = m0._31 * m1._12 + m0._32 * m1._22 + m0._33 * m1._32 + m0._34 * m1._42;
		this._33 = m0._31 * m1._13 + m0._32 * m1._23 + m0._33 * m1._33 + m0._34 * m1._43;
		this._34 = m0._31 * m1._14 + m0._32 * m1._24 + m0._33 * m1._34 + m0._34 * m1._44;
		this._41 = m0._41 * m1._11 + m0._42 * m1._21 + m0._43 * m1._31 + m0._44 * m1._41;
		this._42 = m0._41 * m1._12 + m0._42 * m1._22 + m0._43 * m1._32 + m0._44 * m1._42;
		this._43 = m0._41 * m1._13 + m0._42 * m1._23 + m0._43 * m1._33 + m0._44 * m1._43;
		this._44 = m0._41 * m1._14 + m0._42 * m1._24 + m0._43 * m1._34 + m0._44 * m1._44;
	}
	
	// 平行移動行列の掛け合わせ
	//[  1,  0,  0,  0 ][ _11, _12, _13, _14 ]
	//[  0,  1,  0,  0 ][ _21, _22, _23, _24 ]
	//[  0,  0,  1,  0 ][ _31, _32, _33, _34 ]
	//[  x,  y,  z,  1 ][ _41, _42, _43, _44 ]
	this.mulTranslate = function(x, y, z){
		var temp41 = this._11 * x + this._21 * y + this._31 * z + this._41;
		var temp42 = this._12 * x + this._22 * y + this._32 * z + this._42;
		var temp43 = this._13 * x + this._23 * y + this._33 * z + this._43;
		var temp44 = this._14 * x + this._24 * y + this._34 * z + this._44;
		this._41 = temp41;
		this._42 = temp42;
		this._43 = temp43;
		this._44 = temp44;
	}
	
	// 拡大縮小行列の掛け合わせ
	//[  x,  0,  0,  0 ][ _11, _12, _13, _14 ]
	//[  0,  y,  0,  0 ][ _21, _22, _23, _24 ]
	//[  0,  0,  z,  0 ][ _31, _32, _33, _34 ]
	//[  0,  0,  0,  1 ][ _41, _42, _43, _44 ]
	this.mulScale = function(x, y, z){
		this._11 *= x;
		this._12 *= x;
		this._13 *= x;
		this._14 *= x;
		this._21 *= y;
		this._22 *= y;
		this._23 *= y;
		this._24 *= y;
		this._31 *= z;
		this._32 *= z;
		this._33 *= z;
		this._34 *= z;
	}
	
	// x軸中心回転行列の掛け合わせ
	//[  1,  0,  0,  0 ][ _11, _12, _13, _14 ]
	//[  0,  c,  s,  0 ][ _21, _22, _23, _24 ]
	//[  0, -s,  c,  0 ][ _31, _32, _33, _34 ]
	//[  0,  0,  0,  1 ][ _41, _42, _43, _44 ]
	this.mulRotX = function(r){
		var mr22 = Math.cos(r)
		var mr23 = Math.sin(r)
		var mr32 = -mr23;
		var mr33 = mr22;
		var temp21 = mr22 * this._21 + mr23 * this._31
		var temp22 = mr22 * this._22 + mr23 * this._32
		var temp23 = mr22 * this._23 + mr23 * this._33
		var temp24 = mr22 * this._24 + mr23 * this._34
		var temp31 = mr32 * this._21 + mr33 * this._31
		var temp32 = mr32 * this._22 + mr33 * this._32
		var temp33 = mr32 * this._23 + mr33 * this._33
		var temp34 = mr32 * this._24 + mr33 * this._34
		this._21 = temp21;
		this._22 = temp22;
		this._23 = temp23;
		this._24 = temp24;
		this._31 = temp31;
		this._32 = temp32;
		this._33 = temp33;
		this._34 = temp34;
	}
	
	// y軸中心回転行列の掛け合わせ
	//[  c,  0, -s,  0 ][ _11, _12, _13, _14 ]
	//[  0,  1,  0,  0 ][ _21, _22, _23, _24 ]
	//[  s,  0,  c,  0 ][ _31, _32, _33, _34 ]
	//[  0,  0,  0,  1 ][ _41, _42, _43, _44 ]
	this.mulRotY = function(r){
		var mr33 = Math.cos(r)
		var mr31 = Math.sin(r)
		var mr13 = -mr31;
		var mr11 = mr33;
		var temp11 = mr11 * this._11 + mr13 * this._31;
		var temp12 = mr11 * this._12 + mr13 * this._32;
		var temp13 = mr11 * this._13 + mr13 * this._33;
		var temp14 = mr11 * this._14 + mr13 * this._34;
		var temp31 = mr31 * this._11 + mr33 * this._31;
		var temp32 = mr31 * this._12 + mr33 * this._32;
		var temp33 = mr31 * this._13 + mr33 * this._33;
		var temp34 = mr31 * this._14 + mr33 * this._34;
		this._11 = temp11;
		this._12 = temp12;
		this._13 = temp13;
		this._14 = temp14;
		this._31 = temp31;
		this._32 = temp32;
		this._33 = temp33;
		this._34 = temp34;
	}
	
	// z軸中心回転行列の掛け合わせ
	//[  c,  s,  0,  0 ][ _11, _12, _13, _14 ]
	//[ -s,  c,  0,  0 ][ _21, _22, _23, _24 ]
	//[  0,  0,  1,  0 ][ _31, _32, _33, _34 ]
	//[  0,  0,  0,  1 ][ _41, _42, _43, _44 ]
	this.mulRotZ = function(r){
		var mr11 = Math.cos(r)
		var mr12 = Math.sin(r)
		var mr21 = -mr12;
		var mr22 = mr11;
		var temp11 = mr11 * this._11 + mr12 * this._21;
		var temp12 = mr11 * this._12 + mr12 * this._22;
		var temp13 = mr11 * this._13 + mr12 * this._23;
		var temp14 = mr11 * this._14 + mr12 * this._24;
		var temp21 = mr21 * this._11 + mr22 * this._21;
		var temp22 = mr21 * this._12 + mr22 * this._22;
		var temp23 = mr21 * this._13 + mr22 * this._23;
		var temp24 = mr21 * this._14 + mr22 * this._24;
		this._11 = temp11;
		this._12 = temp12;
		this._13 = temp13;
		this._14 = temp14;
		this._21 = temp21;
		this._22 = temp22;
		this._23 = temp23;
		this._24 = temp24;
	}
	
	// ----------------------------------------------------------------
	// 行列の作成
	
	// 透視射影行列作成
	this.frustum = function(w, h, z_near, z_far){
		this._12 = this._13 = this._14 = 0;
		this._21 = this._23 = this._24 = 0;
		this._31 = this._32 = 0;
		this._41 = this._42 = 0;
		this._11 = 2 * z_near / w;
		this._22 = 2 * z_near / h;
		this._33 = -(z_far + z_near) / (z_far - z_near);
		this._34 = -1;
		this._43 = -2 * z_near * z_far / (z_far - z_near);
		this._44 = 0;
	}
	
	// 正射影行列作成
	this.ortho = function(x, y, w, h){
		this._12 = this._13 = this._14 = 0;
		this._21 = this._23 = this._24 = 0;
		this._31 = this._32 = this._34 = 0;
		this._43 = 0;
		this._33 = this._44 = 1;
		this._11 =  2 / w;
		this._22 = -2 / h;
		this._41 = -2 * x / w - 1;
		this._42 =  2 * y / h + 1;
	}
	
	// 4*4行列の逆行列作成
	this.inverse = function(m){
		this._11 =  m._22 * (m._33 * m._44 - m._34 * m._43) + m._23 * (m._34 * m._42 - m._32 * m._44) + m._24 * (m._32 * m._43 - m._33 * m._42);
		this._12 = -m._32 * (m._43 * m._14 - m._44 * m._13) - m._33 * (m._44 * m._12 - m._42 * m._14) - m._34 * (m._42 * m._13 - m._43 * m._12);
		this._13 =  m._42 * (m._13 * m._24 - m._14 * m._23) + m._43 * (m._14 * m._22 - m._12 * m._24) + m._44 * (m._12 * m._23 - m._13 * m._22);
		this._14 = -m._12 * (m._23 * m._34 - m._24 * m._33) - m._13 * (m._24 * m._32 - m._22 * m._34) - m._14 * (m._22 * m._33 - m._23 * m._32);
		this._21 = -m._23 * (m._34 * m._41 - m._31 * m._44) - m._24 * (m._31 * m._43 - m._33 * m._41) - m._21 * (m._33 * m._44 - m._34 * m._43);
		this._22 =  m._33 * (m._44 * m._11 - m._41 * m._14) + m._34 * (m._41 * m._13 - m._43 * m._11) + m._31 * (m._43 * m._14 - m._44 * m._13);
		this._23 = -m._43 * (m._14 * m._21 - m._11 * m._24) - m._44 * (m._11 * m._23 - m._13 * m._21) - m._41 * (m._13 * m._24 - m._14 * m._23);
		this._24 =  m._13 * (m._24 * m._31 - m._21 * m._34) + m._14 * (m._21 * m._33 - m._23 * m._31) + m._11 * (m._23 * m._34 - m._24 * m._33);
		this._31 =  m._24 * (m._31 * m._42 - m._32 * m._41) + m._21 * (m._32 * m._44 - m._34 * m._42) + m._22 * (m._34 * m._41 - m._31 * m._44);
		this._32 = -m._34 * (m._41 * m._12 - m._42 * m._11) - m._31 * (m._42 * m._14 - m._44 * m._12) - m._32 * (m._44 * m._11 - m._41 * m._14);
		this._33 =  m._44 * (m._11 * m._22 - m._12 * m._21) + m._41 * (m._12 * m._24 - m._14 * m._22) + m._42 * (m._14 * m._21 - m._11 * m._24);
		this._34 = -m._14 * (m._21 * m._32 - m._22 * m._31) - m._11 * (m._22 * m._34 - m._24 * m._32) - m._12 * (m._24 * m._31 - m._21 * m._34);
		this._41 = -m._21 * (m._32 * m._43 - m._33 * m._42) - m._22 * (m._33 * m._41 - m._31 * m._43) - m._23 * (m._31 * m._42 - m._32 * m._41);
		this._42 =  m._31 * (m._42 * m._13 - m._43 * m._12) + m._32 * (m._43 * m._11 - m._41 * m._13) + m._33 * (m._41 * m._12 - m._42 * m._11);
		this._43 = -m._41 * (m._12 * m._23 - m._13 * m._22) - m._42 * (m._13 * m._21 - m._11 * m._23) - m._43 * (m._11 * m._22 - m._12 * m._21);
		this._44 =  m._11 * (m._22 * m._33 - m._23 * m._32) + m._12 * (m._23 * m._31 - m._21 * m._33) + m._13 * (m._21 * m._32 - m._22 * m._31);
		var det =  m._11 * this._11 + m._21 * this._12 + m._31 * this._13 + m._41 * this._14;
		if(det == 0){return -1;}
		var idet = 1 / det;
		this._11 *= idet; this._12 *= idet; this._13 *= idet; this._14 *= idet;
		this._21 *= idet; this._22 *= idet; this._23 *= idet; this._24 *= idet;
		this._31 *= idet; this._32 *= idet; this._33 *= idet; this._34 *= idet;
		this._41 *= idet; this._42 *= idet; this._43 *= idet; this._44 *= idet;
		return 0;
	}
	
	// 四元数回転行列作成
	this.qRotate = function(q){
		var xx = q.x * q.x;
		var yy = q.y * q.y;
		var zz = q.z * q.z;
		var xy = q.x * q.y;
		var yz = q.y * q.z;
		var zx = q.z * q.x;
		var wx = q.w * q.x;
		var wy = q.w * q.y;
		var wz = q.w * q.z;
		this._11 = 1 - 2 * (yy + zz);
		this._12 =     2 * (xy + wz);
		this._13 =     2 * (zx - wy);
		this._21 =     2 * (xy - wz);
		this._22 = 1 - 2 * (zz + xx);
		this._23 =     2 * (yz + wx);
		this._31 =     2 * (zx + wy);
		this._32 =     2 * (yz - wx);
		this._33 = 1 - 2 * (xx + yy);
		this._14 = this._24 = this._34 = 0;
		this._41 = this._42 = this._43 = 0;
		this._44 = 1;
	}
	
	// ----------------------------------------------------------------
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 四元数クラス
function Quaternion(){
	// ----------------------------------------------------------------
	// 初期化
	
	// 単位四元数
	this.identity = function(){
		this.w = 1;
		this.x = 0;
		this.y = 0;
		this.z = 0;
	}
	
	// 四元数の複製
	this.copy = function(q){
		this.w = q.w;
		this.x = q.x;
		this.y = q.y;
		this.z = q.z;
	}
	
	this.identity();
	
	// ----------------------------------------------------------------
	// 四元数の掛け合わせ
	
	// 四元数の掛け合わせ q0 * q1
	this.mul = function(q0, q1){
		this.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
		this.x = q0.w * q1.x + q0.x * q1.w - q0.y * q1.z + q0.z * q1.y;
		this.y = q0.w * q1.y + q0.x * q1.z + q0.y * q1.w - q0.z * q1.x;
		this.z = q0.w * q1.z - q0.x * q1.y + q0.y * q1.x + q0.z * q1.w;
	}
	
	// 回転の四元数の掛け合わせ
	this.mulRot = function(r, x, y, z){
		var s = Math.sin(r / 2) / Math.sqrt(x * x + y * y + z * z);
		rw = Math.cos(r / 2);
		rx = s * x;
		ry = s * y;
		rz = s * z;
		var tw = this.w;
		var tx = this.x;
		var ty = this.y;
		var tz = this.z;
		this.w = tw * rw - tx * rx - ty * ry - tz * rz;
		this.x = tw * rx + tx * rw - ty * rz + tz * ry;
		this.y = tw * ry + tx * rz + ty * rw - tz * rx;
		this.z = tw * rz - tx * ry + ty * rx + tz * rw;
	}
	
	// ----------------------------------------------------------------
	// 四元数の作成
	
	// 回転の四元数作成
	this.rotate = function(r, x, y, z){
		var s = Math.sin(r / 2) / Math.sqrt(x * x + y * y + z * z);
		this.w = Math.cos(r / 2);
		this.x = s * x;
		this.y = s * y;
		this.z = s * z;
	}
	
	// 球面線形補間
	this.sleap = function(t, q0, q1){
		var r = q0.w * q1.w + q0.x * q1.x + q0.y * q1.y + q0.z * q1.z;
		var s = 1 - r * r;
		if(s == 0){
			this.w = q0.w;
			this.x = q0.x;
			this.y = q0.y;
			this.z = q0.z;
		}else{
			var sp = Math.sqrt(s);
			var ph = Math.acos(r);
			var pt = ph * t;
			var t1 = Math.sin(pt) / sp;
			var t0 = Math.sin(ph - pt) / sp;
			this.w = q0.w * t0 + q1.w * t1;
			this.x = q0.x * t0 + q1.x * t1;
			this.y = q0.y * t0 + q1.y * t1;
			this.z = q0.z * t0 + q1.z * t1;
		}
	}
	
	// ----------------------------------------------------------------
	// ユーティリティ
	
	// 正規化的な関数
	this.hoge = function(){
		
	}
	
	// ----------------------------------------------------------------
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------


var ctrl = new Controller();

// 簡易コントローラー
function Controller(){
	// キャンバスサイズ
	var w;
	var h;
	// ボタン状態
	this.kup = false;
	this.kdn = false;
	this.krt = false;
	this.klt = false;
	this.k_z = false;
	this.k_x = false;
	this.k_s = false;
	// マウス座標
	this.mousex = 0;
	this.mousey = 0;
	// 回転
	this.rotv = 0;
	this.roth = 0;
	this.roth_max = Math.PI / 180 *  60;
	this.roth_min = Math.PI / 180 * -60;
	this.size = 10;
	this.size_max = 20;
	this.size_min = 5;
	// メニュー系
	this.selectedLine = 0;
	this.selectedChip = -1;
	this.selectedx = -1;
	this.selectedy = -1;
	this.selectedz = -1;
	
	// ----------------------------------------------------------------
	// コントローラーの初期化 イベント登録
	var vertBuffer;
	var clorBuffer;
	var texcBuffer;
	var faceBuffer;
	
	// バッファに画像の情報を登録
	var pushBuffer = function(vert, texc, clor, face, w, h, tx, ty, vx, vy){
		var vx0 = vx;
		var vy0 = vy;
		var vx1 = vx + w;
		var vy1 = vy + h;
		var tx0 = tx / 256;
		var ty0 = ty / 128;
		var tx1 = (tx + w) / 256;
		var ty1 = (ty + h) / 128;
		var index = vert.length / 3;
		vert.push(vx1); vert.push(vy0); vert.push(0.0);
		vert.push(vx0); vert.push(vy0); vert.push(0.0);
		vert.push(vx0); vert.push(vy1); vert.push(0.0);
		vert.push(vx1); vert.push(vy1); vert.push(0.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		texc.push(tx1); texc.push(ty0);
		texc.push(tx0); texc.push(ty0);
		texc.push(tx0); texc.push(ty1);
		texc.push(tx1); texc.push(ty1);
		face.push(index + 0);
		face.push(index + 1);
		face.push(index + 2);
		face.push(index + 0);
		face.push(index + 2);
		face.push(index + 3);
	}
	
	// 初期化
	this.init = function(e3d, canvas){
		w = canvas.width;
		h = canvas.height;
		
		var vert = new Array();
		var texc = new Array();
		var clor = new Array();
		var face = new Array();
		// 矢印キー
		pushBuffer(vert, texc, clor, face, 40, 48,   0,  0, 10 + 36, h - 122 +  0);
		pushBuffer(vert, texc, clor, face, 40, 48,  88,  0, 10 + 36, h - 122 +  0);
		pushBuffer(vert, texc, clor, face, 40, 48,  48, 40, 10 + 36, h - 122 + 64);
		pushBuffer(vert, texc, clor, face, 40, 48, 136, 40, 10 + 36, h - 122 + 64);
		pushBuffer(vert, texc, clor, face, 48, 40,  40,  0, 10 + 64, h - 122 + 36);
		pushBuffer(vert, texc, clor, face, 48, 40, 128,  0, 10 + 64, h - 122 + 36);
		pushBuffer(vert, texc, clor, face, 48, 40,   0, 48, 10 +  0, h - 122 + 36);
		pushBuffer(vert, texc, clor, face, 48, 40,  88, 48, 10 +  0, h - 122 + 36);
		// ZXボタン
		pushBuffer(vert, texc, clor, face, 64, 64, 176,  0, w - 138, h -  84);
		pushBuffer(vert, texc, clor, face, 64, 64, 176, 64, w - 138, h -  84);
		pushBuffer(vert, texc, clor, face, 64, 64, 176,  0, w -  74, h - 116);
		pushBuffer(vert, texc, clor, face, 64, 64, 176, 64, w -  74, h - 116);
		pushBuffer(vert, texc, clor, face, 24, 24, 128, 88, w - 118, h -  64);
		pushBuffer(vert, texc, clor, face, 24, 24, 152, 88, w -  54, h -  96);
		// スペースボタン
		pushBuffer(vert, texc, clor, face, 128, 16, 0,  88, w / 2 -  64, h - 16);
		pushBuffer(vert, texc, clor, face, 128, 16, 0, 104, w / 2 -  64, h - 16);
		// スクロールバー
		pushBuffer(vert, texc, clor, face, 16, 96, 240,  0, w - 24, 40);
		pushBuffer(vert, texc, clor, face, 16, 16, 240, 96, w - 24, 40);
		// VBOとIBOを作成し、データを転送
		vertBuffer = e3d.createVBO(vert);
		clorBuffer = e3d.createVBO(clor);
		texcBuffer = e3d.createVBO(texc);
		faceBuffer = e3d.createIBO(face);
		
		canvas.addEventListener("mousedown", mdnEvent, true);
		canvas.addEventListener("mousemove", mmvEvent, true);
		canvas.addEventListener("mouseup", mupEvent, true);
		canvas.addEventListener("mouseout", mupEvent, true);
		canvas.addEventListener("touchstart", mdnEvent, true);
		canvas.addEventListener("touchmove", mmvEvent, true);
		canvas.addEventListener("touchend", mupEvent, true);
		document.addEventListener("keydown", kdnEvent, true);
		document.addEventListener("keyup", kupEvent, true);
	}
	
	// ----------------------------------------------------------------
	// コントローラーの描画
	var tmpmat = new Matrix();
	this.draw = function(e3d, mat){
		// 行列作成
		e3d.setMatrix(mat);
		// 描画
		e3d.bindBuf(vertBuffer, clorBuffer, texcBuffer, faceBuffer);
		if(!this.kup){e3d.draw( 0, 6);}else{e3d.draw( 6, 6);}
		if(!this.kdn){e3d.draw(12, 6);}else{e3d.draw(18, 6);}
		if(!this.krt){e3d.draw(24, 6);}else{e3d.draw(30, 6);}
		if(!this.klt){e3d.draw(36, 6);}else{e3d.draw(42, 6);}
		if(!this.k_z){e3d.draw(48, 6);}else{e3d.draw(54, 6);} e3d.draw(72, 6);
		if(!this.k_x){e3d.draw(60, 6);}else{e3d.draw(66, 6);} e3d.draw(78, 6);
		//if(!this.k_s){e3d.draw(84, 6);}else{e3d.draw(90, 6);}
		e3d.draw(96, 6);
		tmpmat.copy(mat);
		tmpmat.mulTranslate(0, 80 * (this.size - this.size_min) / (this.size_max - this.size_min), 0);
		e3d.setMatrix(tmpmat);
		e3d.draw(102, 6);
	}
	
	// ----------------------------------------------------------------
	// 引数の座標を中心とするワールド行列を作成する
	this.createWorldMatrix = function(mat, x, y, z){
		mat.frustum(0.1, 0.1, 0.1, 100);
		mat.mulTranslate(0, 0, -this.size);
		mat.mulRotX(ctrl.roth);
		mat.mulRotY(ctrl.rotv);
		mat.mulTranslate(-x, -z, -y);
	}
	
	// ----------------------------------------------------------------
	// マウスイベント
	var mouseMode = 0;
	var touchx;
	var touchy;
	// 回転
	var touchrv;
	var touchrh;
	
	// コントローラーをクリック時の動作
	var btnEvent = function(){
		// 矢印キー
		var x = ctrl.mousex - (10 + 56);
		var y = ctrl.mousey - (h - 10 - 56);
		if(x * x + y * y < 56 * 56){
			if(-6 < x && x < 6 && -6 < y && y < 6){ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = 0;} // ど真ん中の空白地帯
			else if(-18 < x && x <  18 && y < -18){ctrl.kup = 1; ctrl.kdn = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 上
			else if(-18 < x && x <  18 && y >  18){ctrl.kdn = 1; ctrl.kup = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 下
			else if(-18 < y && y <  18 && x >  18){ctrl.krt = 1; ctrl.kup = ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 右
			else if(-18 < y && y <  18 && x < -18){ctrl.klt = 1; ctrl.kup = ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 左
			else if(x >  18 && y < -18){ctrl.kup = ctrl.krt = 1; ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 右上
			else if(x >  18 && y >  18){ctrl.kdn = ctrl.krt = 1; ctrl.kup = ctrl.klt = 0; mouseMode = 1;} // 右下
			else if(x < -18 && y < -18){ctrl.kup = ctrl.klt = 1; ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 左上
			else if(x < -18 && y >  18){ctrl.kdn = ctrl.klt = 1; ctrl.kup = ctrl.krt = 0; mouseMode = 1;} // 左下
			else{
				if(x > y && x < -y){ctrl.kup = 1; ctrl.kdn = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 内側上
				if(x < y && x > -y){ctrl.kdn = 1; ctrl.kup = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 内側下
				if(x > y && x > -y){ctrl.krt = 1; ctrl.kup = ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 内側右
				if(x < y && x < -y){ctrl.klt = 1; ctrl.kup = ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 内側左
			}
		}else{ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = 0;} // 押していない
		
		// ZXボタン
		x = ctrl.mousex - (w - 10 - 64);
		y = ctrl.mousey - (h - 20 - 48);
		if(-8 < x && x < 8 && -8 < y && y < 8){ctrl.k_z =ctrl.k_x = 1; mouseMode = 1;} // 同時押し
		else if(-64 < x && x <  0 && -16 < y && y < 48){ctrl.k_z = 1; ctrl.k_x = 0; mouseMode = 1;} // z押し
		else if(  0 < x && x < 64 && -48 < y && y < 16){ctrl.k_x = 1; ctrl.k_z = 0; mouseMode = 1;} // x押し
		else{ctrl.k_z = ctrl.k_x = 0;}
		
		// スペースボタン
		x = ctrl.mousex - (w / 2);
		y = ctrl.mousey - (h - 8);
		if(-64 < x && x < 64 && -8 < y && y < 8){ctrl.k_s = 1; mouseMode = 1;}
		else{ctrl.k_s = 0;}
		
		// スクロールバー
		x = ctrl.mousex - (w - 24);
		y = ctrl.mousey - 40;
		if(0 < x && x < 16 && 0 < y && y < 96){
			if(y < 8){ctrl.size = ctrl.size_min;}
			else if(y > 88){ctrl.size = ctrl.size_max;}
			else{ctrl.size = (y - 8) * (ctrl.size_max - ctrl.size_min) / 80 + ctrl.size_min;}
			mouseMode = 1;
		}
	}
	
	// メニュー部分をクリック時の動作開始
	var mnuEvent0 = function(){
		if(ctrl.mousey < 32){
			mouseMode = 2;
			if(16 < ctrl.mousex && ctrl.mousex < 32){ctrl.selectedChip = 100;}
			if(32 < ctrl.mousex && ctrl.mousex < 48){ctrl.selectedChip = 101;}
			for(var i = 0; i < 9; i++){
				if(54 + i * 24 < ctrl.mousex && ctrl.mousex < 74 + i * 24){ctrl.selectedChip = i;}
			}
		}else if(ctrl.mousey > 288){
		}
	}
	
	// メニュー部分をクリック時の動作終了
	var mnuEvent2 = function(){
		if(ctrl.mousey < 32){
			if(ctrl.selectedChip == 100 && 16 < ctrl.mousex && ctrl.mousex < 32){ctrl.selectedLine = (ctrl.selectedLine + 7) % 8;}
			if(ctrl.selectedChip == 101 && 32 < ctrl.mousex && ctrl.mousex < 48){ctrl.selectedLine = (ctrl.selectedLine + 1) % 8;}
		}else if(ctrl.mousey > 288){
		}else{
			// マップチップ配置と除去
			if(map.getMapChip(ctrl.selectedx, ctrl.selectedz, ctrl.selectedy) >= 0 && 0 <= ctrl.selectedChip && ctrl.selectedChip <= 8){
				var chip = (ctrl.selectedChip < 8) ? ctrl.selectedLine * 8 + ctrl.selectedChip + 1 : 0;
				map.map[ctrl.selectedy][ctrl.selectedz][ctrl.selectedx] = chip;
				map.update(e3d);
			}
		}
	}
	
	// 回転開始
	var rotEvent0 = function(){
		touchx = ctrl.mousex;
		touchy = ctrl.mousey;
		mouseMode = 3;
		// 回転
		touchrv = ctrl.rotv;
		touchrh = ctrl.roth;
	}
	
	// 回転中
	var rotEvent1 = function(){
		// 回転
		ctrl.rotv = touchrv + (ctrl.mousex - touchx) * 0.03;
		ctrl.roth = touchrh + (ctrl.mousey - touchy) * 0.03;
		if(ctrl.roth > ctrl.roth_max){ctrl.roth = ctrl.roth_max;}
		if(ctrl.roth < ctrl.roth_min){ctrl.roth = ctrl.roth_min;}
	}
	
	// マウスを押す
	var mdnEvent = function(e){
		// コントローラークリックの確認
		btnEvent();
		if(mouseMode == 0){mnuEvent0();}
		if(mouseMode == 0){rotEvent0();}
		// マウスイベント終了
		e.preventDefault();
	}
	
	// マウス移動
	var mmvEvent = function(e){
		// 座標を獲得する
		var rect = e.target.getBoundingClientRect();
		ctrl.mousex = e.clientX - rect.left;
		ctrl.mousey = e.clientY - rect.top;
		// マウス移動イベント
		if(mouseMode == 1){btnEvent();}
		else if(mouseMode == 3){rotEvent1();}
		// マウスイベント終了
		e.preventDefault();
	}
	
	// マウスボタンを離す
	var mupEvent = function(e){
		if(mouseMode == 2 && e.type == "mouseup"){mnuEvent2();}
		mouseMode = 0;
		ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = ctrl.k_z = ctrl.k_x = ctrl.k_s = false;
		ctrl.selectedChip = -1;
		// マウスイベント終了
		e.preventDefault();
	}
	
	// ----------------------------------------------------------------
	// キーイベント
	
	// キーを押す
	var kdnEvent = function(e){
		var getkey = true;
		switch (e.keyCode){
			case 37: ctrl.klt = true; break;
			case 38: ctrl.kup = true; break;
			case 39: ctrl.krt = true; break;
			case 40: ctrl.kdn = true; break;
			case 88: ctrl.k_x = true; break;
			case 90: ctrl.k_z = true; break;
			case 32: ctrl.k_s = true; break;
			default: getkey = false;
		}
		// キーイベント終了
		if(getkey){
			e.preventDefault();
		}
	}
	
	// キーを離す
	var kupEvent = function(e){
		var getkey = true;
		switch (e.keyCode){
			case 37: ctrl.klt = false; break;
			case 38: ctrl.kup = false; break;
			case 39: ctrl.krt = false; break;
			case 40: ctrl.kdn = false; break;
			case 88: ctrl.k_x = false; break;
			case 90: ctrl.k_z = false; break;
			case 32: ctrl.k_s = false; break;
			default: getkey = false;
		}
		// キーイベント終了
		if(getkey){
			e.preventDefault();
		}
	}
	
	// ----------------------------------------------------------------
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// キャラクタクラス
function Character(){
	this.vertBuffer;
	this.clorBuffer;
	this.texcBuffer;
	this.faceBuffer;
	this.faceNum;
	
	// ----------------------------------------------------------------
	// 初期化
	
	var pushBuffer = function(vert, texc, clor, face, u0, v0){
		var u1 = u0 + 0.25;
		var v1 = v0 + 0.25;
		var index = vert.length / 3;
		vert.push( 0.5); vert.push( 1.0); vert.push( 0.0);
		vert.push(-0.5); vert.push( 1.0); vert.push( 0.0);
		vert.push(-0.5); vert.push( 0.0); vert.push( 0.0);
		vert.push( 0.5); vert.push( 0.0); vert.push( 0.0);
		texc.push(u1); texc.push(v0);
		texc.push(u0); texc.push(v0);
		texc.push(u0); texc.push(v1);
		texc.push(u1); texc.push(v1);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		face.push(index + 0);
		face.push(index + 1);
		face.push(index + 2);
		face.push(index + 0);
		face.push(index + 2);
		face.push(index + 3);
	}
	
	this.init = function(e3d){
		var vert = new Array();
		var clor = new Array();
		var texc = new Array();
		var face = new Array();
		
		for(var i = 0; i < 4; i++){
			for(var j = 0; j < 4; j++){
				pushBuffer(vert, texc, clor, face, 0.25 * i, 0.25 * j);
			}
		}
		
		this.faceNum = face.length;
		
		// VBOとIBOを作成し、データを転送
		this.vertBuffer = e3d.createVBO(vert);
		this.clorBuffer = e3d.createVBO(clor);
		this.texcBuffer = e3d.createVBO(texc);
		this.faceBuffer = e3d.createIBO(face);
	}
	
	// ----------------------------------------------------------------
	// 描画
	var tmpmat = new Matrix();
	this.draw = function(e3d, mat, rotate, type, x, y, z, size){
		var index = type * 4;
		// 回転
		rotate = (rotate - ctrl.rotv) / Math.PI * 180;
		while(rotate > 360 - 45){rotate -= 360;}
		while(rotate <=  0 - 45){rotate += 360;}
		if(rotate < 45){index += 3;}
		else if(rotate <= 135){index += 0;}
		else if(rotate < 225){index += 1;}
		else{index += 2;}
		// 行列作成
		tmpmat.copy(mat);
		tmpmat.mulTranslate(x, z, y);
		tmpmat.mulRotY(-ctrl.rotv);
		tmpmat.mulScale(size, size, size);
		e3d.setMatrix(tmpmat);
		// 描画
		e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
		e3d.draw(index * 6, 6);
	}
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 影クラス
function Shadow(texFile){
	this.vertBuffer;
	this.clorBuffer;
	this.texcBuffer;
	this.faceBuffer;
	this.faceNum;
	
	// ----------------------------------------------------------------
	// 初期化
	this.init = function(e3d){
		var vert = new Array();
		var clor = new Array();
		var texc = new Array();
		var face = new Array();
		
		vert.push(-0.5); vert.push( 0.05); vert.push( 0.5);
		vert.push( 0.5); vert.push( 0.05); vert.push( 0.5);
		vert.push( 0.5); vert.push( 0.05); vert.push(-0.5);
		vert.push(-0.5); vert.push( 0.05); vert.push(-0.5);
		texc.push(1.0); texc.push(0.0);
		texc.push(0.0); texc.push(0.0);
		texc.push(0.0); texc.push(1.0);
		texc.push(1.0); texc.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0);
		face.push(0); face.push(1); face.push(2);
		face.push(0); face.push(2); face.push(3);
		this.faceNum = face.length;
		
		// VBOとIBOを作成し、データを転送
		this.vertBuffer = e3d.createVBO(vert);
		this.clorBuffer = e3d.createVBO(clor);
		this.texcBuffer = e3d.createVBO(texc);
		this.faceBuffer = e3d.createIBO(face);
	}
	
	// ----------------------------------------------------------------
	// 描画
	var tmpmat = new Matrix();
	this.draw = function(e3d, mat, x, y, z, size){
		// 行列作成
		tmpmat.copy(mat);
		tmpmat.mulTranslate(x, z, y);
		tmpmat.mulScale(size, 1, size);
		e3d.setMatrix(tmpmat);
		// 描画
		e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
		e3d.draw(0, this.faceNum);
	}
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// 地形クラス
function Map(){
	this.vertBuffer;
	this.clorBuffer;
	this.texcBuffer;
	this.faceBuffer;
	this.faceNum;
	
	// 地形情報
	this.x = 0;
	this.y = 0;
	this.z = 0;
	this.map = null;
	
	var invmat = new Matrix();
	
	// ----------------------------------------------------------------
	// マップチップの範囲外チェック
	this.getMapChip = function(x, y, z){
		x = Math.floor(parseInt(x));
		y = Math.floor(parseInt(y));
		z = Math.floor(parseInt(z));
		if(isNaN(x) || x < 0 || this.x <= x){return -1;}
		if(isNaN(y) || y < 0 || this.y <= y){return -1;}
		if(isNaN(z) || z < 0 || this.z <= z){return -1;}
		return this.map[z][y][x];
	}
	
	// ----------------------------------------------------------------
	// マップチップの透過チェック
	this.isMapChipVisible = function(x, y, z){
		var chip = this.getMapChip(x, y, z);
		return chip != -1 && chip != 0 && chip != 1 && !(57 <= chip && chip <= 64);
	}
	
	// ----------------------------------------------------------------
	// マップチップの衝突チェック
	this.isMapChipHit = function(x, y, z){
		var chip = this.getMapChip(x, y, z);
		return chip != 0;
	}
	
	// ----------------------------------------------------------------
	// 初期化
	this.init = function(e3d, map){
		var vert = new Array();
		var clor = new Array();
		var texc = new Array();
		var face = new Array();
		
		this.map = map;
		this.x = this.map[0][0].length;
		this.y = this.map[0].length;
		this.z = this.map.length;
		
		// 頂点データを生成
		for(var i = 0; i < this.x; i++){
			for(var j = 0; j < this.y; j++){
				for(var k = 0; k < this.z; k++){
					if(this.map[k][j][i] > 0){
						if(!this.isMapChipVisible(i, j, k + 1)){this.pushSurfaces(vert, clor, texc, i, j, k, 1);}
						if(!this.isMapChipVisible(i, j, k - 1)){this.pushSurfaces(vert, clor, texc, i, j, k, 2);}
						if(!this.isMapChipVisible(i, j + 1, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 3);}
						if(!this.isMapChipVisible(i, j - 1, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 4);}
						if(!this.isMapChipVisible(i + 1, j, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 5);}
						if(!this.isMapChipVisible(i - 1, j, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 6);}
					}
				}
			}
		}
		
		// インデックスデータを生成
		var num = vert.length / 12;
		for(var i = 0; i < num; i++){
			face.push(i * 4 + 0); face.push(i * 4 + 1); face.push(i * 4 + 2);
			face.push(i * 4 + 0); face.push(i * 4 + 2); face.push(i * 4 + 3);
		}
		this.faceNum = face.length;
		
		// VBOとIBOを作成し、データを転送
		this.vertBuffer = e3d.createVBO(vert);
		this.clorBuffer = e3d.createVBO(clor);
		this.texcBuffer = e3d.createVBO(texc);
		this.faceBuffer = e3d.createIBO(face);
	}
	
	// 更新
	this.update = function(e3d){
		e3d.deleteBuffer(this.vertBuffer);
		e3d.deleteBuffer(this.clorBuffer);
		e3d.deleteBuffer(this.texcBuffer);
		e3d.deleteBuffer(this.faceBuffer);
		this.init(e3d, this.map);
	}
	
	// 面の頂点配列作成
	this.pushSurfaces = function(vert, clor, texc, x0, y0, z0, s){
		var chip = this.map[z0][y0][x0] - 1;
		var x1 = x0 + 1;
		var y1 = y0 + 1;
		var z1 = z0 + 1;
		var xm = x0 - 1;
		var ym = y0 - 1;
		var zm = z0 - 1;
		var u0 = (chip % 4) * 0.2500;
		var v0 = Math.floor(chip / 4) * 0.0625;
		var v1 = v0 + 0.0625;
		switch(s){
			case 1:
				vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, xm, y0, z1, xm, ym, z1);
				vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, xm, y0, z1, xm, y1, z1);
				vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, x1, y0, z1, x1, y1, z1);
				vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, x1, y0, z1, x1, ym, z1);
				break;
			case 2:
				u0 = u0 + 0.1875;
				vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, xm, y0, zm, xm, y1, zm);
				vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, xm, y0, zm, xm, ym, zm);
				vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, x1, y0, zm, x1, ym, zm);
				vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, x1, y0, zm, x1, y1, zm);
				break;
			case 3:
				u0 = u0 + 0.0625;
				vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, xm, y1, z0, xm, y1, z1);
				vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, xm, y1, z0, xm, y1, zm);
				vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, x1, y1, z0, x1, y1, zm);
				vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, x1, y1, z0, x1, y1, z1);
				break;
			case 4:
				u0 = u0 + 0.0625;
				vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, x1, ym, z0, x1, ym, z1);
				vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, x1, ym, z0, x1, ym, zm);
				vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, xm, ym, z0, xm, ym, zm);
				vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, xm, ym, z0, xm, ym, z1);
				break;
			case 5:
				u0 = u0 + 0.1250;
				vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x1, y0, z1, x1, y1, z0, x1, y1, z1);
				vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x1, y0, zm, x1, y1, z0, x1, y1, zm);
				vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x1, y0, zm, x1, ym, z0, x1, ym, zm);
				vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x1, y0, z1, x1, ym, z0, x1, ym, z1);
				break;
			case 6:
				u0 = u0 + 0.1250;
				vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, xm, y0, z1, xm, ym, z0, xm, ym, z1);
				vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, xm, y0, zm, xm, ym, z0, xm, ym, zm);
				vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, xm, y0, zm, xm, y1, z0, xm, y1, zm);
				vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, xm, y0, z1, xm, y1, z0, xm, y1, z1);
				break;
		}
		u1 = u0 + 0.0625;
		texc.push(u0); texc.push(v0);
		texc.push(u0); texc.push(v1);
		texc.push(u1); texc.push(v1);
		texc.push(u1); texc.push(v0);
	}
	
	// 影の確認
	this.setTopColor = function(clor, x1, y1, z1, x2, y2, z2, x3, y3, z3){
		var color = 1;
		if(this.isMapChipVisible(x1, y1, z1)){color -= 0.2;}
		if(this.isMapChipVisible(x2, y2, z2)){color -= 0.2;}
		if(this.isMapChipVisible(x3, y3, z3)){color -= 0.2;}
		clor.push(color); clor.push(color); clor.push(color);
	}
	
	// ----------------------------------------------------------------
	// 描画
	var tmpmat = new Matrix();
	this.draw = function(e3d, mat, x, y, z){
		// 行列作成
		tmpmat.copy(mat);
		tmpmat.mulTranslate(x, z, y);
		e3d.setMatrix(tmpmat);
		// 描画
		e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
		e3d.draw(0, this.faceNum);
		// 逆行列
		invmat.inverse(tmpmat);
		this.select();
	}
	
	// ----------------------------------------------------------------
	// マウス座標と逆行列からマップチップ選択
	this.select = function(){
		var mx = 2 * ctrl.mousex / 320 - 1;
		var my = 1 - 2 * ctrl.mousey / 320;
		var xyw1 = invmat._11 * mx + invmat._21 * my + invmat._41;
		var xyw2 = invmat._12 * mx + invmat._22 * my + invmat._42;
		var xyw3 = invmat._13 * mx + invmat._23 * my + invmat._43;
		var xyw4 = invmat._14 * mx + invmat._24 * my + invmat._44;
		var tempDepth = 1;
		var tempx1 = -1, tempx2 = -1;
		var tempy1 = -1, tempy2 = -1;
		var tempz1 = -1, tempz2 = -1;
		
		// マウス座標とx軸平面の交点
		for(var x = 0; x <= this.x; x++){
			var depth = -(xyw1 - xyw4 * x) / (invmat._31 - invmat._34 * x);
			var w = xyw4 + invmat._34 * depth;
			var y = Math.floor((xyw2 + invmat._32 * depth) / w);
			var z = Math.floor((xyw3 + invmat._33 * depth) / w);
			if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x - 1, z, y) > 0))){
				tempx1 = x; tempx2 = x - 1;
				tempy1 = y; tempy2 = y;
				tempz1 = z; tempz2 = z;
				tempDepth = depth;
			}
		}
		
		// マウス座標とy軸平面の交点
		for(var y = 0; y <= this.z; y++){
			var depth = -(xyw2 - xyw4 * y) / (invmat._32 - invmat._34 * y);
			var w = xyw4 + invmat._34 * depth;
			var x = Math.floor((xyw1 + invmat._31 * depth) / w);
			var z = Math.floor((xyw3 + invmat._33 * depth) / w);
			if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x, z, y - 1) > 0))){
				tempx1 = x; tempx2 = x;
				tempy1 = y; tempy2 = y - 1;
				tempz1 = z; tempz2 = z;
				tempDepth = depth;
			}
		}
		
		// マウス座標とz軸平面の交点
		for(var z = 0; z <= this.y; z++){
			var depth = -(xyw3 - xyw4 * z) / (invmat._33 - invmat._34 * z);
			var w = xyw4 + invmat._34 * depth;
			var x = Math.floor((xyw1 + invmat._31 * depth) / w);
			var y = Math.floor((xyw2 + invmat._32 * depth) / w);
			if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x, z - 1, y) > 0))){
				tempx1 = x; tempx2 = x;
				tempy1 = y; tempy2 = y;
				tempz1 = z; tempz2 = z - 1;
				tempDepth = depth;
			}
		}
		
		if((this.getMapChip(tempx1, tempz1, tempy1) > 0) ^ !(ctrl.selectedChip == 8)){
			ctrl.selectedx = tempx1;
			ctrl.selectedy = tempy1;
			ctrl.selectedz = tempz1;
		}else{
			ctrl.selectedx = tempx2;
			ctrl.selectedy = tempy2;
			ctrl.selectedz = tempz2;
		}
		
		if(this.getMapChip(ctrl.selectedx, ctrl.selectedz, ctrl.selectedy) < 0){
			ctrl.selectedx = -1;
			ctrl.selectedy = -1;
			ctrl.selectedz = -1;
		}
	}
	
	// ----------------------------------------------------------------
	// あたり判定
	
	// mapとキャラクタ情報の衝突判定
	this.isHit = function(px, py, pz, vx, vy, vz, radius, height){
		var h_length = 2 + Math.floor(radius * 2);
		var v_length = 2 + Math.floor(height);
		
		// x軸を等分割してmap上の点を得る
		var dx = new Array(h_length);
		var temp0 = px + vx + radius;
		var temp1 = px + vx - radius;
		for(var i = 0; i < h_length; i++){
			dx[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
		}
		// y軸を等分割してmap上の点を得る
		var dy = new Array(h_length);
		var temp0 = py + vy + radius;
		var temp1 = py + vy - radius;
		for(var i = 0; i < h_length; i++){
			dy[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
		}
		// z軸を等分割してmap上の点を得る
		var dz = new Array(v_length);
		var temp0 = pz + vz + height;
		var temp1 = pz + vz;
		for(var i = 0; i < v_length; i++){
			dz[i] = Math.floor(temp0 + (temp1 - temp0) * i / (v_length - 1));
		}
		
		// 各軸進行方向の点を得る
		var x0 = vx > 0 ? dx[0] : vx < 0 ? dx[dx.length - 1] : Math.floor(px + vx);
		var y0 = vy > 0 ? dy[0] : vy < 0 ? dy[dy.length - 1] : Math.floor(py + vy);
		var z0 = vz > 0 ? dz[0] : dz[dz.length - 1];
		
		// x軸進行方向の面
		for(var i = 0; i < dy.length; i++){
			for(var j = 0; j < dz.length; j++){
				if(this.isMapChipHit(x0, dy[i], dz[j])){
					return true;
				}
			}
		}
		
		// y軸進行方向の面
		for(var i = 0; i < dz.length; i++){
			for(var j = 0; j < dx.length; j++){
				if(this.isMapChipHit(dx[j], y0, dz[i])){
					return true;
				}
			}
		}
		
		// z軸進行方向の面
		for(var i = 0; i < dx.length; i++){
			for(var j = 0; j < dy.length; j++){
				if(this.isMapChipHit(dx[i], dy[j], z0)){
					return true;
				}
			}
		}
		
		return false;
	}
	
	// 地面までの距離
	this.getHeight = function(character){
		var h_length = 2 + Math.floor(character.radius * 2);
		
		// x軸を等分割してmap上の点を得る
		var dx = new Array(h_length);
		var temp0 = character.x + character.vx + character.radius;
		var temp1 = character.x + character.vx - character.radius;
		for(var i = 0; i < h_length; i++){
			dx[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
		}
		// y軸を等分割してmap上の点を得る
		var dy = new Array(h_length);
		var temp0 = character.y + character.vy + character.radius;
		var temp1 = character.y + character.vy - character.radius;
		for(var i = 0; i < h_length; i++){
			dy[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
		}
		
		// キャラクタ下方向で最も近い地面の高さを調べる
		var k0 = Math.floor(character.z + character.vz);
		var ground = 0;
		for(var i = 0; i < dx.length; i++){
			for(var j = 0; j < dy.length; j++){
				for(var k = k0; k > 0; k--){
					if(this.isMapChipHit(dx[i], dy[j], k - 1) && ground < k){
						ground = k;
					}
				}
			}
		}
		
		// 地面までの距離を返す
		return character.z + character.vz - ground - 0.01;
	}
	
	// mapとの衝突処理 衝突していた場合はキャラクタの位置と速度が変更される
	// 引数であるcharacterに必要なフィールド
	//  x, y, z 位置
	//  vx, vy, vz 速度
	//  radius あたり判定の半径
	//  height あたり判定の高さ
	this.collision = function(character){
		var v0x, v0y, v0z;
		var v1x, v1y, v1z;
		var vx, vy;
		
		// x軸方向で最初に衝突するマップチップ境界
		if(character.vx > 0){
			vx = Math.abs(Math.floor(character.x + character.radius + 1) - (character.x + character.radius));
			if(vx == 1){vx = 0;}
		}else{
			vx = Math.abs(Math.floor(character.x - character.radius + 0.001) - (character.x - character.radius));
		}
		
		// y軸方向で最初に衝突するマップチップ境界
		if(character.vy > 0){
			vy = Math.abs(Math.floor(character.y + character.radius + 1) - (character.y + character.radius));
			if(vy == 1){vy = 0;}
		}else{
			vy = Math.abs(Math.floor(character.y - character.radius + 0.001) - (character.y - character.radius));
		}
		
		// z軸上方向にシフトしたときに最初に現れるマップチップ境界
		var pz = Math.floor(character.z + 1) - character.z;
		if(pz == 1){pz = 0;}
		// z軸上方向への最大乗り越えシフト量 高さの30%までなら乗り越えることができる
		var pzmax = character.height * 0.3;
		
		// xy軸方向衝突判定
		var vxmax = Math.abs(character.vx);
		var vymax = Math.abs(character.vy);
		var hitFlagx = false;
		var hitFlagy = false;
		v0x = v0y = v1z = 0;
		while(vx < vxmax || vy < vymax){	
			if(!hitFlagx && vx / vxmax < vy / vymax){
				// x軸方向の衝突判定準備
				var axis = 0;
				var scale = vx / vxmax;
				vx += 1;
			}else if(!hitFlagy){
				// y軸方向の衝突判定準備
				var axis = 1;
				var scale = vy / vymax;
				vy += 1;
			}else{
				break;
			}
			
			if(!hitFlagx){v1x = v0x = character.vx * scale;}
			if(!hitFlagy){v1y = v0y = character.vy * scale;}
			
			// 衝突判定 判定する軸方向に0.5だけ進んだ状態で衝突するかを調べる
			if(axis == 0){
				v1x = v0x + (character.vx > 0 ? 0.5 : -0.5);
			}else{
				v1y = v0y + (character.vy > 0 ? 0.5 : -0.5);
			}
			if(this.isHit(character.x, character.y, character.z, v1x, v1y, v1z, character.radius, character.height)){
				// 乗り越え判定
				while(pz < pzmax){
					var pz1 = character.z + pz;
					if(character.vz >= 0 && !this.isHit(character.x, character.y, pz1, v1x, v1y, v1z, character.radius, character.height)){
						character.z = pz1;
						break;
					}else{
						pz += 1;
					}
				}
				// 乗り越えしていなかったら衝突処理
				if(pz >= pzmax){
					if(axis == 0){
						character.vx = v1x = v0x - (character.vx > 0 ? 0.01 : -0.01);
						hitFlagx = true;
					}else{
						character.vy = v1y = v0y - (character.vy > 0 ? 0.01 : -0.01);
						hitFlagy = true;
					}
				}
			}
		}
		
		// z軸方向で最初に衝突するマップチップ境界
		if(character.vz > 0){
			v1z = Math.floor(character.z + character.height + 1) - (character.z + character.height) - 0.01;
		}else{
			v1z = Math.floor(character.z) - (character.z);
		}
		
		// z軸方向衝突判定
		while(Math.abs(v1z) < Math.abs(character.vz)){
			v0z = v1z;
			v1z += character.vz > 0 ? 1 : -1;
			if(this.isHit(character.x, character.y, character.z, character.vx, character.vy, v1z, character.radius, character.height)){
				character.vz = v0z;
				break;
			}
		}
		
		// 最後に地面までの距離を返す
		return this.getHeight(character);
	}
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// メニュークラス
function Menu(){
	this.vertBuffer1;
	this.clorBuffer1;
	this.texcBuffer1;
	this.faceBuffer1;
	
	this.vertBuffer2;
	this.clorBuffer2;
	this.texcBuffer2;
	this.faceBuffer2;
	
	// ----------------------------------------------------------------
	// 初期化
	
	var pushBuffer = function(vert, texc, clor, face, r, g, b, vx0, vy0, vx1, vy1, tx0, ty0, tx1, ty1){
		var index = vert.length / 3;
		vert.push(vx1); vert.push(vy0); vert.push(0.0);
		vert.push(vx0); vert.push(vy0); vert.push(0.0);
		vert.push(vx0); vert.push(vy1); vert.push(0.0);
		vert.push(vx1); vert.push(vy1); vert.push(0.0);
		clor.push(r); clor.push(g); clor.push(b);
		clor.push(r); clor.push(g); clor.push(b);
		clor.push(r); clor.push(g); clor.push(b);
		clor.push(r); clor.push(g); clor.push(b);
		texc.push(tx1); texc.push(ty0);
		texc.push(tx0); texc.push(ty0);
		texc.push(tx0); texc.push(ty1);
		texc.push(tx1); texc.push(ty1);
		face.push(index + 0);
		face.push(index + 1);
		face.push(index + 2);
		face.push(index + 0);
		face.push(index + 2);
		face.push(index + 3);
	}
	
	this.init = function(e3d){
		// 黒幕その他
		var vert = new Array();
		var clor = new Array();
		var texc = new Array();
		var face = new Array();
		pushBuffer(vert, texc, clor, face, 0, 0, 0, 0, 0, 1, 1, 0.0625, 0.25, 0.0625, 0.25);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, -8, -8, 8, 8, 0.125, 0, 0.25, 0.5);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 16, 8, 32, 24, 0.750, 0, 0.875, 0.5);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 32, 8, 48, 24, 0.875, 0, 1.000, 0.5);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.000, 0.5, 0.125, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.125, 0.5, 0.250, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.250, 0.5, 0.375, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.375, 0.5, 0.500, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.500, 0.5, 0.625, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.625, 0.5, 0.750, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.750, 0.5, 0.875, 1);
		pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.875, 0.5, 1.000, 1);
		this.vertBuffer1 = e3d.createVBO(vert);
		this.clorBuffer1 = e3d.createVBO(clor);
		this.texcBuffer1 = e3d.createVBO(texc);
		this.faceBuffer1 = e3d.createIBO(face);
		
		// キューブ
		var vert = new Array();
		var clor = new Array();
		var face = new Array();
		vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push(-1);
		vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push( 1);
		vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1);
		vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1);
		vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1);
		vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
		face.push( 0); face.push( 1); face.push( 2); face.push( 0); face.push( 2); face.push( 3);
		face.push( 4); face.push( 5); face.push( 6); face.push( 4); face.push( 6); face.push( 7);
		face.push( 8); face.push( 9); face.push(10); face.push( 8); face.push(10); face.push(11);
		face.push(12); face.push(13); face.push(14); face.push(12); face.push(14); face.push(15);
		face.push(16); face.push(17); face.push(18); face.push(16); face.push(18); face.push(19);
		face.push(20); face.push(21); face.push(22); face.push(20); face.push(22); face.push(23);
		this.vertBuffer2 = e3d.createVBO(vert);
		this.clorBuffer2 = e3d.createVBO(clor);
		this.faceBuffer2 = e3d.createIBO(face);
		this.texcBuffer2 = new Array();
		for(var i = 0; i < 64; i++){
			var texc = new Array();
			var v0 = Math.floor(i / 4) * 0.0625;
			var v1 = v0 + 0.0625;
			var u = (i % 4) * 0.2500;
			var u0 = u + 0.0000; var u1 = u0 + 0.0625;
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			var u0 = u + 0.1875; var u1 = u0 + 0.0625;
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			var u0 = u + 0.0625; var u1 = u0 + 0.0625;
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			var u0 = u + 0.1250; var u1 = u0 + 0.0625;
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
			this.texcBuffer2[i] = e3d.createVBO(texc);
		}
	}
	
	// ----------------------------------------------------------------
	// 描画
	var tmpmat = new Matrix();
	
	this.draw1 = function(e3d, mat){
		e3d.bindBuf(this.vertBuffer1, this.clorBuffer1, this.texcBuffer1, this.faceBuffer1);
		// 黒幕
		tmpmat.copy(mat);
		tmpmat.mulScale(320, 32, 1);
		e3d.setMatrix(tmpmat);
		e3d.draw(0, 6);
		tmpmat.copy(mat);
		tmpmat.mulTranslate(0, 288, 0);
		tmpmat.mulScale(320, 32, 1);
		e3d.setMatrix(tmpmat);
		e3d.draw(0, 6);
		// バツ印
		tmpmat.copy(mat);
		if(ctrl.selectedChip == 8){
			tmpmat.mulTranslate(ctrl.mousex, ctrl.mousey, 0);
		}else{
			tmpmat.mulTranslate(256, 16, 0);
		}
		e3d.setMatrix(tmpmat);
		e3d.draw(6, 6);
		// 矢印
		e3d.setMatrix(mat);
		e3d.draw(12, 6);
		e3d.draw(18, 6);
		// スクロールゲージ
		e3d.draw(24 + ctrl.selectedLine * 6, 6);
	}
	
	this.draw2 = function(e3d, mat){
		e3d.bindVertBuf(this.vertBuffer2);
		e3d.bindClorBuf(this.clorBuffer2);
		e3d.bindFaceBuf(this.faceBuffer2);
		
		var fuga = 2;
		
		for(var i = 0; i < 8; i++){
			e3d.bindTexcBuf(this.texcBuffer2[i + ctrl.selectedLine * 8]);
			tmpmat.copy(mat);
			if(i == ctrl.selectedChip){
				if(ctrl.selectedx >= 0){continue;}
				tmpmat.mulTranslate(ctrl.mousex, ctrl.mousey, 0);
				tmpmat.mulScale(1.3, 1.3, 0);
			}else{
				tmpmat.mulTranslate(64 + i * 24, 16, 0);
				tmpmat.mulScale(1, 1, 0);
			}
			tmpmat.mulRotX(-ctrl.roth);
			tmpmat.mulRotY(ctrl.rotv + Math.PI);
			tmpmat.mulScale(-6, -6, -6);
			e3d.setMatrix(tmpmat);
			e3d.draw(0, 36);
		}
	}
	
	this.draw3 = function(e3d, mat){
		if(ctrl.selectedx < 0 || ctrl.selectedChip < 0 || 8 < ctrl.selectedChip){return;}
		var texid = 0;
		if(ctrl.selectedChip < 8){texid = ctrl.selectedLine * 8 + ctrl.selectedChip;}
		e3d.bindBuf(this.vertBuffer2, this.clorBuffer2, this.texcBuffer2[texid], this.faceBuffer2);
		tmpmat.copy(mat);
		tmpmat.mulTranslate(ctrl.selectedx + 0.5, ctrl.selectedy + 0.5, ctrl.selectedz + 0.5);
		if(ctrl.selectedChip < 8){
			tmpmat.mulScale(0.3, 0.3, 0.3);
		}else{
			tmpmat.mulScale(0.55, 0.55, 0.55);
		}
		e3d.setMatrix(tmpmat);
		e3d.draw(0, 36);
	}
}

// ここまでライブラリ部分
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// グローバル変数
var e3d = new Engine3d();
var map = new Map();
var character = new Character();
var shadow = new Shadow();
var player = new Player();
var menu = new Menu();

// テクスチャ
var mapTexture;
var ctrlTexture;
var utilTexture;
var playerTexture;
var shadowTexture;

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

window.onload = function(){
	// 初期化
	e3d.init(document.getElementById("screen"));
	ctrl.init(e3d, document.getElementById("screen"));
	character.init(e3d);
	shadow.init(e3d);
	menu.init(e3d);
	
	mapTexture = e3d.loadTexture("http://jsrun.it/assets/s/3/P/0/s3P04.png");
	ctrlTexture = e3d.loadTexture("http://jsrun.it/assets/h/4/Q/Q/h4QQL.png");
	utilTexture = e3d.loadTexture("http://jsrun.it/assets/1/G/6/u/1G6ua.png");
	playerTexture = e3d.loadTexture("http://jsrun.it/assets/6/n/Q/g/6nQgc.png");
	shadowTexture = e3d.loadTexture("http://jsrun.it/assets/y/u/C/2/yuC2U.png");
	
	map.init(e3d, [[
		[ 4,  4,  4,  4,  4],
		[ 4,  4,  4,  4,  4],
		[ 4,  4,  4,  4,  4],
		[ 4,  4,  4,  4,  4],
		[ 4,  4,  4,  4,  4],
	],[
		[ 0,  0,  0, 10, 10],
		[ 0, 13,  0,  0, 10],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
	],[
		[ 0, 14,  0,  0, 10],
		[14, 13, 14,  0,  0],
		[ 0, 14,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
	],[
		[ 0, 14,  0,  0,  0],
		[14, 13, 14,  0,  0],
		[ 0, 14,  0,  0,  0],
		[ 0,  0,  0, 17,  0],
		[ 0,  0,  0,  0,  0],
	],[
		[ 0,  0,  0,  0,  0],
		[ 0, 14,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
	],[
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
		[ 0,  0,  0,  0,  0],
	]]);
	
	ctrl.roth = Math.PI / 180 *  30;
	
	// 描画処理を毎秒 30 回呼び出す
	setInterval(redrawScene, 1000 / 30);
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// メインループ
function redrawScene(){
	// 計算
	player.calc();
	
	// 3D描画
	e3d.clear();
	e3d.setDepthMode(true);
	// カメラ
	var mat = new Matrix();
	ctrl.createWorldMatrix(mat, player.x, player.y, player.z);
	// マップ
	e3d.bindTex(mapTexture, 1);
	map.draw(e3d, mat, 0, 0, 0);
	menu.draw3(e3d, mat);
	// キャラクター
	e3d.bindTex(playerTexture, 0);
	player.draw(character, e3d, mat);
	// 影
	e3d.bindTex(shadowTexture, 0);
	shadow.draw(e3d, mat, player.x, player.y, player.z - player.altitude, player.radius * 2);
	
	// 2D描画
	e3d.setDepthMode(false);
	mat.ortho(0, 0, 320, 320);
	// メニュー
	e3d.bindTex(utilTexture, 1);
	menu.draw1(e3d, mat);
	e3d.bindTex(mapTexture, 1);
	menu.draw2(e3d, mat, map);
	// コントローラ
	e3d.bindTex(ctrlTexture, 0);
	ctrl.draw(e3d, mat);
	
	
	// ページに反映させる
	e3d.flush();
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------

// プレイヤークラス
function Player(){
	this.action = 0;
	this.rotate = Math.PI / 180 *  90;
	// あたり判定用キャラクタサイズ
	this.radius = 0.3;
	this.height = 1.0;
	// キャラクタ画像倍率
	this.size = 1.5;
	// 位置
	this.x = 2.5;
	this.y = 2.5; 
	this.z = 1;
	// 速度
	this.vx = 0;
	this.vy = 0; 
	this.vz = 0;
	// 地面との距離
	this.altitude = 0;
	
	// 計算
	this.calc = function(){
		this.action++;
		// 方向の計算
		if(ctrl.kup){
			if(ctrl.krt){this.rotate = Math.PI * 1.75 + ctrl.rotv;}
			else if(ctrl.klt){this.rotate = Math.PI * 1.25 + ctrl.rotv;}
			else{this.rotate = Math.PI * 1.50 + ctrl.rotv;}
		}else if(ctrl.kdn){
			if(ctrl.krt){this.rotate = Math.PI * 0.25 + ctrl.rotv;}
			else if(ctrl.klt){this.rotate = Math.PI * 0.75 + ctrl.rotv;}
			else{this.rotate = Math.PI * 0.50 + ctrl.rotv;}
		}else if(ctrl.krt){this.rotate = Math.PI * 0.00 + ctrl.rotv;
		}else if(ctrl.klt){this.rotate = Math.PI * 1.00 + ctrl.rotv;
		}else{this.action = 0;}
		// 水平軸方向速度の計算
		if(this.action > 0){
			var speed = 3 / 30;
			this.vx = speed * Math.cos(this.rotate);
			this.vy = speed * Math.sin(this.rotate);
		}else{
			this.vx = 0;
			this.vy = 0;
		}
		// 垂直軸方向速度の計算
		if(this.altitude > 0.1){
			// 地面との距離がある場合は空中
			this.action = 1;
			this.vz -= 1.2 / 30;
			if(ctrl.k_z && this.vz < 0){
			// 多段ジャンプ
				this.vz = 15 / 30;
			}
		}else if(ctrl.k_z){
			// ジャンプ
			this.vz = 15 / 30;
		}else if(ctrl.k_x){
			this.action = 1;
			this.vx = 0;
			this.vy = 0;
		}
		// あたり判定
		this.altitude = map.collision(this);
		// 位置の計算
		this.x += this.vx;
		this.y += this.vy;
		this.z += this.vz;
	}
	
	// 描画
	this.draw = function(character, e3d, mat){
		// 歩行アクション
		var type = 0;
		if(this.action > 0){
			switch(Math.floor(this.action / 4) % 4){
				case 0: type = 1; break;
				case 2: type = 3; break;
				default: type = 2; break;
			}
		}
		// 描画
		character.draw(e3d, mat, this.rotate, type, this.x, this.y, this.z, this.size);
	}
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer