var VXSHADER = [
"attribute vec4 vPos;",
"attribute vec2 vTexCoord;",
"uniform   mat4 mProj;",
"varying   vec2 vPixelTexCoord;",
"void main(void) {",
" gl_Position = mProj * vec4(vPos.xyz, 1);",
" vPixelTexCoord = vTexCoord;",
"}"
].join("\n");

var PXSHADER = [
"varying vec2 vPixelTexCoord;",
"uniform sampler2D tex;",
"void main(void) {",
" gl_FragColor = texture2D(tex, vPixelTexCoord);",
"}"
].join("\n");

var PXSHADER_C = [
"uniform vec4 vConstColor;",
"void main(void) {",
" gl_FragColor = vConstColor;",
"}"
].join("\n");

var GLUtil = {
	createShader: function(gl, src, type) {
		var shader;
		if (type == 'vs') {
			shader = gl.createShader(gl.VERTEX_SHADER);
		} else {
			shader = gl.createShader(gl.FRAGMENT_SHADER);
		}

		gl.shaderSource(shader, src);
		gl.compileShader(shader);

		if (gl.getShaderParameter(shader, 0x8B81 /*gl.COMPILE_STATUS*/) != 1) {
			alert(gl.getShaderInfoLog(shader));
			return null;
		}

		return shader;
	},

	createTexture: function(gl, img) {
		var t = gl.genTextures(1)[0];
		gl.bindTexture(gl.TEXTURE_2D, t);
		gl.enable(gl.TEXTURE_2D);
		gl.texImage2DHTML(gl.TEXTURE_2D, 0, img);
		gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

		return t;
	},

	flattenM44: function(m) {
/*
		return [m._11, m._21, m._31, m._41, 
		        m._12, m._22, m._32, m._42,
		        m._13, m._23, m._33, m._43,
		        m._14, m._24, m._34, m._44
		       ];
*/
		return [m._11, m._12, m._13, m._14,
		        m._21, m._22, m._23, m._24,
		        m._31, m._32, m._33, m._34,
		        m._41, m._42, m._43, m._44,
		       ];

	}
};

GLUtil.Classic3D = function(g) {
	this.g = g;
	this.texture_name = 0;

	this.vxShader  = GLUtil.createShader(g, VXSHADER  , 'vs');
	this.pxShader  = GLUtil.createShader(g, PXSHADER  , 'ps');
	this.pxShaderC = GLUtil.createShader(g, PXSHADER_C, 'ps');

	this.shprog   = g.createProgram();
	this.shprog_c = g.createProgram();

	g.attachShader(this.shprog, this.vxShader);
	g.attachShader(this.shprog, this.pxShader);
	g.linkProgram(this.shprog);
	
	g.attachShader(this.shprog_c, this.vxShader );
	g.attachShader(this.shprog_c, this.pxShaderC);
	g.linkProgram(this.shprog_c);
}

GLUtil.Classic3D.prototype = {
	setProjection: function(m) {
		this.g.useProgram(this.shprog);
		var uProj = this.g.getUniformLocation(this.shprog, "mProj");
		this.g.uniformMatrix4fv(uProj, GLUtil.flattenM44(m));

		this.g.useProgram(this.shprog_c);
		uProj = this.g.getUniformLocation(this.shprog_c, "mProj");
		this.g.uniformMatrix4fv(uProj, GLUtil.flattenM44(m));
	},

	drawByIndexBuffer: function(pos_buf, ix_buf, tx_buf) {
		var color_polygon = !this.texture_name;

		var g = this.g;

		if (color_polygon) {
			g.useProgram(this.shprog_c);
			g.disable(g.TEXTURE_2D);

			var uConstColor = g.getUniformLocation(this.shprog_c, "vConstColor");
			g.uniform4fv(uConstColor, tx_buf[ix_buf[0]<<1]);
		} else {
			g.useProgram(this.shprog);

			g.bindTexture(g.TEXTURE_2D, this.texture_name);
			g.enable(g.TEXTURE_2D);

			var uTex = g.getUniformLocation(this.shprog, "tex");
			g.uniform1i(uTex, 0);
		}

		var aPos = g.getAttribLocation(this.shprog, "vPos");
		if (aPos == -1)
			throw "GLSL attrib 'vPos' not found";

		g.vertexAttribPointer(aPos, 4, g.FLOAT, false, 0, pos_buf);
		g.enableVertexAttribArray(aPos);

		var aTexCoord = g.getAttribLocation(this.shprog, "vTexCoord");
		if (aTexCoord != -1) {
			g.vertexAttribPointer(aTexCoord, 2, g.FLOAT, false, 0, tx_buf);
			g.enableVertexAttribArray(aTexCoord);
		}

		g.drawElements(g.TRIANGLES, ix_buf.length, g.UNSIGNED_SHORT, ix_buf);
	}
}
