API Docs for:
Show:

File: ../src/shader.js


/**
* @namespace GL
*/

/**
* Shader class to upload programs to the GPU
* @class Shader
* @constructor
* @param {String} vertexSource (it also allows to pass a compiled vertex shader)
* @param {String} fragmentSource (it also allows to pass a compiled fragment shader)
* @param {Object} macros (optional) precompiler macros to be applied when compiling
*/
global.Shader = GL.Shader = function Shader( vertexSource, fragmentSource, macros )
{
	if(GL.debug)
		console.log("GL.Shader created");

	if( !vertexSource || !fragmentSource )
		throw("GL.Shader source code parameter missing");

	//used to avoid problems with resources moving between different webgl context
	this._context_id = global.gl.context_id; 
	var gl = this.gl = global.gl;

	//expand macros
	var extra_code = Shader.expandMacros( macros );

	var final_vertexSource = vertexSource.constructor === String ? Shader.injectCode( extra_code, vertexSource, gl ) : vertexSource;
	var final_fragmentSource = fragmentSource.constructor === String ? Shader.injectCode( extra_code, fragmentSource, gl ) : fragmentSource;

	this.program = gl.createProgram();

	var vs = vertexSource.constructor === String ? GL.Shader.compileSource( gl.VERTEX_SHADER, final_vertexSource ) : vertexSource;
	var fs = fragmentSource.constructor === String ? GL.Shader.compileSource( gl.FRAGMENT_SHADER, final_fragmentSource ) : fragmentSource;

	gl.attachShader( this.program, vs, gl );
	gl.attachShader( this.program, fs, gl );
	gl.linkProgram(this.program);
	if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
		throw 'link error: ' + gl.getProgramInfoLog(this.program);
	}

	this.vs_shader = vs;
	this.fs_shader = fs;

	//Extract info from the shader
	this.attributes = {}; 
	this.uniformInfo = {};
	this.samplers = {};

	//extract info about the shader to speed up future processes
	this.extractShaderInfo();
}

Shader.expandMacros = function(macros)
{
	var extra_code = ""; //add here preprocessor directives that should be above everything
	if(macros)
		for(var i in macros)
			extra_code += "#define " + i + " " + (macros[i] ? macros[i] : "") + "\n";
	return extra_code;
}

//this is done to avoid problems with the #version which must be in the first line
Shader.injectCode = function( inject_code, code, gl )
{
	var index = code.indexOf("\n");
	var version = ( gl ? "#define WEBGL" + gl.webgl_version + "\n" : "");
	var first_line = code.substr(0,index).trim();
	if( first_line.indexOf("#version") == -1 )
		return version + inject_code + code;
	return first_line + "\n" + version + inject_code + code.substr(index);
}


/**
* Compiles one single shader source (could be gl.VERTEX_SHADER or gl.FRAGMENT_SHADER) and returns the webgl shader handler 
* Used internaly to compile the vertex and fragment shader.
* It throws an exception if there is any error in the code
* @method Shader.compileSource
* @param {Number} type could be gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
* @param {String} source the source file to compile
* @return {WebGLShader} the handler from webgl
*/
Shader.compileSource = function( type, source, gl, shader )
{
	gl = gl || global.gl;
	shader = shader || gl.createShader(type);
	gl.shaderSource(shader, source);
	gl.compileShader(shader);
	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		throw (type == gl.VERTEX_SHADER ? "Vertex" : "Fragment") + ' shader compile error: ' + gl.getShaderInfoLog(shader);
	}
	return shader;
}

Shader.parseError = function( error_str, vs_code, fs_code )
{
	if(!error_str)
		return null;

	var t = error_str.split(" ");
	var nums = t[5].split(":");

	return {
		type: t[0],
		line_number: parseInt( nums[1] ),
		line_pos: parseInt( nums[0] ),
		line_code: ( t[0] == "Fragment" ? fs_code : vs_code ).split("\n")[ parseInt( nums[1] ) ],
		err: error_str
	};
}

/**
* It updates the code inside one shader
* @method updateShader
* @param {String} vertexSource 
* @param {String} fragmentSource 
* @param {Object} macros [optional]
*/
Shader.prototype.updateShader = function( vertexSource, fragmentSource, macros )
{
	var gl = this.gl || global.gl;

	//expand macros
	var extra_code = Shader.expandMacros( macros );

	if(this.program)
		this.program = gl.createProgram();

	var extra_code = Shader.expandMacros( macros );

	var final_vertexSource = vertexSource.constructor === String ? Shader.injectCode( extra_code, vertexSource, gl ) : vertexSource;
	var final_fragmentSource = fragmentSource.constructor === String ? Shader.injectCode( extra_code, fragmentSource, gl ) : fragmentSource;

	var vs = vertexSource.constructor === String ? GL.Shader.compileSource( gl.VERTEX_SHADER, final_vertexSource ) : vertexSource;
	var fs = fragmentSource.constructor === String ? GL.Shader.compileSource( gl.FRAGMENT_SHADER, final_fragmentSource ) : fragmentSource;

	gl.attachShader( this.program, vs, gl );
	gl.attachShader( this.program, fs, gl );
	gl.linkProgram( this.program );
	if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
		throw 'link error: ' + gl.getProgramInfoLog( this.program );
	}

	//store shaders separated
	this.vs_shader = vs;
	this.fs_shader = fs;

	//Extract info from the shader
	this.attributes = {}; 
	this.uniformInfo = {};
	this.samplers = {};

	//extract info about the shader to speed up future processes
	this.extractShaderInfo();
}

/**
* It extract all the info about the compiled shader program, all the info about uniforms and attributes.
* This info is stored so it works faster during rendering.
* @method extractShaderInfo
*/
Shader.prototype.extractShaderInfo = function()
{
	var gl = this.gl;
	
	var l = gl.getProgramParameter( this.program, gl.ACTIVE_UNIFORMS );

	//extract uniforms info
	for(var i = 0; i < l; ++i)
	{
		var data = gl.getActiveUniform( this.program, i);
		if(!data) break;

		var uniformName = data.name;

		//arrays have uniformName[0], strip the [] (also data.size tells you if it is an array)
		var pos = uniformName.indexOf("["); 
		if(pos != -1)
		{
			var pos2 = uniformName.indexOf("]."); //leave array of structs though
			if(pos2 == -1)
				uniformName = uniformName.substr(0,pos);
		}

		//store texture samplers
		if(data.type == gl.SAMPLER_2D || data.type == gl.SAMPLER_CUBE)
			this.samplers[ uniformName ] = data.type;
		
		//get which function to call when uploading this uniform
		var func = Shader.getUniformFunc(data);
		var is_matrix = false;
		if(data.type == gl.FLOAT_MAT2 || data.type == gl.FLOAT_MAT3 || data.type == gl.FLOAT_MAT4)
			is_matrix = true;


		//save the info so the user doesnt have to specify types when uploading data to the shader
		this.uniformInfo[ uniformName ] = { type: data.type, func: func, size: data.size, is_matrix: is_matrix, loc: gl.getUniformLocation(this.program, uniformName) };
	}

	//extract attributes info
	for(var i = 0, l = gl.getProgramParameter(this.program, gl.ACTIVE_ATTRIBUTES); i < l; ++i)
	{
		var data = gl.getActiveAttrib( this.program, i);
		if(!data) break;
		var func = Shader.getUniformFunc(data);
		this.uniformInfo[ data.name ] = { 
			type: data.type,
			func: func,
			size: data.size,
			loc: null 
		}; //gl.getAttribLocation( this.program, data.name )
		this.attributes[ data.name ] = gl.getAttribLocation(this.program, data.name );	
	}
}

/**
* Returns if this shader has a uniform with the given name
* @method hasUniform
* @param {String} name name of the uniform
* @return {Boolean}
*/
Shader.prototype.hasUniform = function(name)
{
	return this.uniformInfo[name];
}

/**
* Returns if this shader has an attribute with the given name
* @method hasAttribute
* @param {String} name name of the attribute
* @return {Boolean}
*/
Shader.prototype.hasAttribute = function(name)
{
	return this.attributes[name];
}


/**
* Tells you which function to call when uploading a uniform according to the data type in the shader
* Used internally from extractShaderInfo to optimize calls 
* @method Shader.getUniformFunc
* @param {Object} data info about the uniform
* @return {Function}
*/
Shader.getUniformFunc = function( data )
{
	var func = null;
	switch (data.type)
	{
		case GL.FLOAT: 		
			if(data.size == 1)
				func = gl.uniform1f; 
			else
				func = gl.uniform1fv; 
			break;
		case GL.FLOAT_MAT2: func = gl.uniformMatrix2fv; break;
		case GL.FLOAT_MAT3:	func = gl.uniformMatrix3fv; break;
		case GL.FLOAT_MAT4:	func = gl.uniformMatrix4fv; break;
		case GL.FLOAT_VEC2: func = gl.uniform2fv; break;
		case GL.FLOAT_VEC3: func = gl.uniform3fv; break;
		case GL.FLOAT_VEC4: func = gl.uniform4fv; break;

		case GL.UNSIGNED_INT: 
		case GL.INT: 	  
			if(data.size == 1)
				func = gl.uniform1i; 
			else
				func = gl.uniform1iv; 
			break;
		case GL.INT_VEC2: func = gl.uniform2iv; break;
		case GL.INT_VEC3: func = gl.uniform3iv; break;
		case GL.INT_VEC4: func = gl.uniform4iv; break;

		case GL.SAMPLER_2D:
		case GL.SAMPLER_3D:
		case GL.SAMPLER_CUBE:
			func = gl.uniform1i; break;
		default: func = gl.uniform1f; break;
	}	
	return func;
}

/**
* Create a shader from two urls. While the system is fetching the two urls, the shader contains a dummy shader that renders black.
* @method Shader.fromURL
* @param {String} vs_path the url to the vertex shader
* @param {String} fs_path the url to the fragment shader
* @param {Function} on_complete [Optional] a callback to call once the shader is ready.
* @return {Shader}
*/
Shader.fromURL = function( vs_path, fs_path, on_complete )
{
	//create simple shader first
	var vs_code = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			attribute mat4 u_mvp;\n\
			void main() { \n\
				gl_Position = u_mvp * vec4(a_vertex,1.0); \n\
			}\n\
		";
	var fs_code = "\n\
			precision highp float;\n\
			void main() {\n\
				gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n\
			}\n\
			";
	
	var shader = new GL.Shader(vs_code, fs_code);
	shader.ready = false;

	var true_vs = null;
	var true_fs = null;

	HttpRequest( vs_path, null, function(vs_code) {
		true_vs = vs_code;
		if(true_fs)
			compileShader();
	});

	HttpRequest( fs_path, null, function(fs_code) {
		true_fs = fs_code;
		if(true_vs)
			compileShader();
	});

	function compileShader()
	{
		var true_shader = new GL.Shader(true_vs, true_fs);
		for(var i in true_shader)
			shader[i] = true_shader[i];
		shader.ready = true;
	}

	return shader;
}

/**
* enables the shader (calls useProgram)
* @method bind
*/
Shader.prototype.bind = function()
{
	var gl = this.gl;
	gl.useProgram( this.program );
	gl._current_shader = this;
}

/**
* Returns the location of a uniform or attribute
* @method getLocation
* @param {String} name
* @return {WebGLUniformLocation} location
*/
Shader.prototype.getLocation = function( name )
{
	var info = this.uniformInfo[name];
	if(info)
		return this.uniformInfo[name].loc;
	return null;
}

/**
* Uploads a set of uniforms to the Shader. You dont need to specify types, they are infered from the shader info.
* @method uniforms
* @param {Object} uniforms
*/
Shader._temp_uniform = new Float32Array(16);

Shader.prototype.uniforms = function(uniforms) {
	var gl = this.gl;
	gl.useProgram(this.program);
	gl._current_shader = this;

	for (var name in uniforms)
	{
		var info = this.uniformInfo[ name ];
		if (!info)
			continue;
		this._setUniform( name, uniforms[name] );
		//this.setUniform( name, uniforms[name] );
		//this._assing_uniform(uniforms, name, gl );
	}

	return this;
}//uniforms

Shader.prototype.uniformsArray = function(array) {
	var gl = this.gl;
	gl.useProgram( this.program );
	gl._current_shader = this;

	for(var i = 0, l = array.length; i < l; ++i)
	{
		var uniforms = array[i];
		for (var name in uniforms)
			this._setUniform( name, uniforms[name] );
			//this._assing_uniform(uniforms, name, gl );
	}

	return this;
}

/**
* Uploads a uniform to the Shader. You dont need to specify types, they are infered from the shader info. Shader must be binded!
* @method setUniform
* @param {string} name
* @param {*} value
*/
Shader.prototype.setUniform = (function(){
	var temps = [];
	for(var i = 2; i <= 16; ++i)
		temps[i] = new Float32Array(i);

	return (function(name, value)
	{
		if(	this.gl._current_shader != this )
			this.bind();

		var info = this.uniformInfo[name];
		if (!info)
			return;

		if(info.loc === null)
			return;

		if(value == null) //strict?
			return;

		if(value.constructor === Array)
		{
			var v = temps[ value.length ]; //reuse same container
			if(v)
			{
				v.set(value);
				value = v;
			}
			else
				value = new Float32Array( value );  //garbage generated...
		}

		if(info.is_matrix)
			info.func.call( this.gl, info.loc, false, value );
		else
			info.func.call( this.gl, info.loc, value );
	});
})();

//skips enabling shader
Shader.prototype._setUniform = (function(){
	var temps = [];
	for(var i = 2; i <= 16; ++i)
		temps[i] = new Float32Array(i);

	return (function(name, value)
	{
		var info = this.uniformInfo[ name ];
		if (!info)
			return;

		if(info.loc === null)
			return;

		//if(info.loc.constructor !== Function)
		//	return;

		if(value == null) 
			return;

		if(value.constructor === Array)
		{
			var v = temps[ value.length ]; //reuse same container
			if(v)
			{
				v.set(value);
				value = v;
			}
			else
				value = new Float32Array( value );  //garbage generated...
		}

		if(info.is_matrix)
			info.func.call( this.gl, info.loc, false, value );
		else
			info.func.call( this.gl, info.loc, value );
	});
})();

/**
* Renders a mesh using this shader, remember to use the function uniforms before to enable the shader
* @method draw
* @param {Mesh} mesh
* @param {number} mode could be gl.LINES, gl.POINTS, gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN
* @param {String} index_buffer_name the name of the index buffer, if not provided triangles will be assumed
*/
Shader.prototype.draw = function(mesh, mode, index_buffer_name ) {
	index_buffer_name = index_buffer_name === undefined ? (mode == gl.LINES ? 'lines' : 'triangles') : index_buffer_name;
	this.drawBuffers(mesh.vertexBuffers,
	  index_buffer_name ? mesh.indexBuffers[ index_buffer_name ] : null,
	  arguments.length < 2 ? gl.TRIANGLES : mode);
}

/**
* Renders a range of a mesh using this shader
* @method drawRange
* @param {Mesh} mesh
* @param {number} mode could be gl.LINES, gl.POINTS, gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN
* @param {number} start first primitive to render
* @param {number} length number of primitives to render
* @param {String} index_buffer_name the name of the index buffer, if not provided triangles will be assumed
*/
Shader.prototype.drawRange = function(mesh, mode, start, length, index_buffer_name )
{
	index_buffer_name = index_buffer_name === undefined ? (mode == gl.LINES ? 'lines' : 'triangles') : index_buffer_name;

	this.drawBuffers(mesh.vertexBuffers,
	  index_buffer_name ? mesh.indexBuffers[ index_buffer_name ] : null,
	  mode, start, length);
}

/**
* render several buffers with a given index buffer
* @method drawBuffers
* @param {Object} vertexBuffers an object containing all the buffers
* @param {IndexBuffer} indexBuffer
* @param {number} mode could be gl.LINES, gl.POINTS, gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN
* @param {number} range_start first primitive to render
* @param {number} range_length number of primitives to render
*/

//this two variables are a hack to avoid memory allocation on drawCalls
var temp_attribs_array = new Uint8Array(16);
var temp_attribs_array_zero = new Uint8Array(16); //should be filled with zeros always

Shader.prototype.drawBuffers = function( vertexBuffers, indexBuffer, mode, range_start, range_length )
{
	if(range_length == 0)
		return;

	var gl = this.gl;

	gl.useProgram(this.program); //this could be removed assuming every shader is called with some uniforms 

	// enable attributes as necessary.
	var length = 0;
	var attribs_in_use = temp_attribs_array; //hack to avoid garbage
	attribs_in_use.set( temp_attribs_array_zero ); //reset

	for (var name in vertexBuffers)
	{
		var buffer = vertexBuffers[name];
		var attribute = buffer.attribute || name;
		//precompute attribute locations in shader
		var location = this.attributes[attribute];// || gl.getAttribLocation(this.program, attribute);

		if (location == null || !buffer.buffer) //-1 changed for null
			continue; //ignore this buffer

		attribs_in_use[location] = 1; //mark it as used

		//this.attributes[attribute] = location;
		gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
		gl.enableVertexAttribArray(location);

		gl.vertexAttribPointer(location, buffer.buffer.spacing, buffer.buffer.gl_type, false, 0, 0);
		length = buffer.buffer.length / buffer.buffer.spacing;
	}

	//range rendering
	var offset = 0; //in bytes
	if(range_start > 0) //render a polygon range
		offset = range_start; //in bytes (Uint16 == 2 bytes)

	if (indexBuffer)
		length = indexBuffer.buffer.length - offset;

	if(range_length > 0 && range_length < length) //to avoid problems
		length = range_length;

	var BYTES_PER_ELEMENT = (indexBuffer && indexBuffer.data) ? indexBuffer.data.constructor.BYTES_PER_ELEMENT : 1;
	offset *= BYTES_PER_ELEMENT;

	// Force to disable buffers in this shader that are not in this mesh
	for (var attribute in this.attributes)
	{
		var location = this.attributes[attribute];
		if (!(attribs_in_use[location])) {
			gl.disableVertexAttribArray(this.attributes[attribute]);
		}
	}

	// Draw the geometry.
	if (length && (!indexBuffer || indexBuffer.buffer)) {
	  if (indexBuffer) {
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer.buffer);
		gl.drawElements( mode, length, indexBuffer.buffer.gl_type, offset); //gl.UNSIGNED_SHORT
		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
	  } else {
		gl.drawArrays(mode, offset, length);
	  }
	}

	return this;
}

Shader._instancing_arrays = [];

Shader.prototype.drawInstanced = function( mesh, primitive, indices, instanced_uniforms, gl )
{
	//bind buffers
	var gl = this.gl;

	if( gl.webgl_version == 1 && !gl.extensions.ANGLE_instanced_arrays )
		throw("instancing not supported");

	gl.useProgram(this.program); //this could be removed assuming every shader is called with some uniforms 

	// enable attributes as necessary.
	var length = 0;
	var attribs_in_use = temp_attribs_array; //hack to avoid garbage
	attribs_in_use.set( temp_attribs_array_zero ); //reset

	var vertexBuffers = mesh.vertexBuffers;

	for (var name in vertexBuffers)
	{
		var buffer = vertexBuffers[name];
		var attribute = buffer.attribute || name;
		//precompute attribute locations in shader
		var location = this.attributes[attribute];// || gl.getAttribLocation(this.program, attribute);

		if (location == null || !buffer.buffer) //-1 changed for null
			continue; //ignore this buffer

		attribs_in_use[location] = 1; //mark it as used

		//this.attributes[attribute] = location;
		gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
		gl.enableVertexAttribArray(location);

		gl.vertexAttribPointer(location, buffer.buffer.spacing, buffer.buffer.gl_type, false, 0, 0);
		length = buffer.buffer.length / buffer.buffer.spacing;
	}

	var indexBuffer = indices ? mesh.getIndexBuffer( indices ) : null;

	//range rendering
	var offset = 0; //in bytes
	if (indexBuffer)
		length = indexBuffer.buffer.length - offset;

	var BYTES_PER_ELEMENT = (indexBuffer && indexBuffer.data) ? indexBuffer.data.constructor.BYTES_PER_ELEMENT : 1;
	offset *= BYTES_PER_ELEMENT;

	// Force to disable buffers in this shader that are not in this mesh
	for (var attribute in this.attributes)
	{
		var location = this.attributes[attribute];
		if (!(attribs_in_use[location])) {
			gl.disableVertexAttribArray(this.attributes[attribute]);
		}
	}

	var ext = gl.extensions.ANGLE_instanced_arrays;
	var batch_length = 0;

	//pack the instanced uniforms
	var index = 0;
	for(var uniform in instanced_uniforms)
	{
		var values = instanced_uniforms[ uniform ];
		batch_length = values.length;
		var uniformLocation = this.attributes[ uniform ];
		if( uniformLocation == null )
			return; //not found
		var size = values[0].constructor === Number ? 1 : values[0].length;
		var data_array = Shader._instancing_arrays[ index ];
		if( !data_array || data_array.data.length < (values.length * size) )
			data_array = Shader._instancing_arrays[ index ] = { data: new Float32Array( values.length * size ), buffer: gl.createBuffer() };
		data_array.uniform = uniform;
		data_array.size = size;
		for(var j = 0; j < values.length; ++j)
			data_array.data.set( values[j], j*size ); //copy
		gl.bindBuffer( gl.ARRAY_BUFFER, data_array.buffer );
		gl.bufferData( gl.ARRAY_BUFFER, data_array.data, gl.STREAM_DRAW );

		if(size == 16) //mat4
		{
			for(var k = 0; k < 4; ++k)
			{
				gl.enableVertexAttribArray( uniformLocation+k );
				gl.vertexAttribPointer( uniformLocation+k, 4, gl.FLOAT , false, 16*4, k*4*4 );
				if( ext ) //webgl 1
					ext.vertexAttribDivisorANGLE( uniformLocation+k, 1 ); // This makes it instanced!
				else
					gl.vertexAttribDivisor( uniformLocation+k, 1 ); // This makes it instanced!
			}
		}
		else //others
		{
			gl.enableVertexAttribArray( uniformLocation );
			gl.vertexAttribPointer( uniformLocation, size, gl.FLOAT , false, size*4, size*4 );
			if( ext ) //webgl 1
				ext.vertexAttribDivisorANGLE( uniformLocation, 1 ); // This makes it instanced!
			else
				gl.vertexAttribDivisor( uniformLocation, 1 ); // This makes it instanced!
		}
		index+=1;
	}

	if( ext ) //webgl 1.0
	{
		if(indexBuffer)
			ext.drawElementsInstancedANGLE( primitive, length, indexBuffer.buffer.gl_type, 0, batch_length);
		else
			ext.drawArraysInstancedANGLE( primitive, 0, length, batch_length);
	}
	else
	{
		if(indexBuffer)
			gl.drawElementsInstanced( primitive, length, indexBuffer.buffer.gl_type, 0, batch_length);
		else
			gl.drawArraysInstanced( primitive, 0, length, batch_length);
	}

	//disable instancing buffers
	for(var i = 0; i < index; ++i)
	{
		var info = Shader._instancing_arrays[ i ];
		var uniformLocation = this.attributes[ info.uniform ];
		var size = info.size;
		if( ext ) //webgl 1
			ext.vertexAttribDivisorANGLE( uniformLocation, 1 ); // This makes it instanced!
		else
			gl.vertexAttribDivisor( uniformLocation, 1 ); // This makes it instanced!
		if( size == 16) //mat4
		{
			for(var k = 0; k < 4; ++k)
			{
				gl.disableVertexAttribArray( uniformLocation+k );
				if( ext ) //webgl 1
					ext.vertexAttribDivisorANGLE( uniformLocation+k, 0 );
				else
					gl.vertexAttribDivisor( uniformLocation+k, 0 ); 
			}
		}
		else //others
		{
			gl.enableVertexAttribArray( uniformLocation );
			if( ext ) //webgl 1
				ext.vertexAttribDivisorANGLE( uniformLocation, 0 );
			else
				gl.vertexAttribDivisor( uniformLocation, 0 );
		}
	}

	return this;
}



/**
* Given a source code with the directive #import it expands it inserting the code using Shader.files to fetch for import files.
* Warning: Imports are evaluated only the first inclusion, the rest are ignored to avoid double inclusion of functions
*          Also, imports cannot have other imports inside.
* @method Shader.expandImports
* @param {String} code the source code
* @param {Object} files [Optional] object with files to import from (otherwise Shader.files is used)
* @return {String} the code with the lines #import removed and replaced by the code
*/
Shader.expandImports = function(code, files)
{
	files = files || Shader.files;

	var already_imported = {}; //avoid to import two times the same code
	if( !files )
		throw("Shader.files not initialized, assign files there");

	var replace_import = function(v)
	{
		var token = v.split("\"");
		var id = token[1];
		if( already_imported[id] )
			return "//already imported: " + id + "\n";
		var file = files[id];
		already_imported[ id ] = true;
		if(file)
			return file + "\n";
		return "//import code not found: " + id + "\n";
	}

	//return code.replace(/#import\s+\"(\w+)\"\s*\n/g, replace_import );
	return code.replace(/#import\s+\"([a-zA-Z0-9_\.]+)\"\s*\n/g, replace_import );
}

Shader.dumpErrorToConsole = function(err, vscode, fscode)
{
	console.error(err);
	var msg = err.msg;
	var code = null;
	if(err.indexOf("Fragment") != -1)
		code = fscode;
	else
		code = vscode;

	var lines = code.split("\n");
	for(var i in lines)
		lines[i] = i + "| " + lines[i];

	console.groupCollapsed("Shader code");
	console.log( lines.join("\n") );
	console.groupEnd();
}

Shader.convertTo100 = function(code,type)
{
	//in VERTEX
		//change in for attribute
		//change out for varying
		//add #extension GL_OES_standard_derivatives
	//in FRAGMENT
		//change in for varying 
		//remove out vec4 _gl_FragColor
		//rename _gl_FragColor for gl_FragColor
	//in both
		//change #version 300 es for #version 100
		//replace 'texture(' for 'texture2D('
}


Shader.convertTo300 = function(code,type)
{
	//in VERTEX
		//change attribute for in
		//change varying for out
		//remove #extension GL_OES_standard_derivatives
	//in FRAGMENT
		//change varying for in
		//rename gl_FragColor for _gl_FragColor
		//rename gl_FragData[0] for _gl_FragColor
		//add out vec4 _gl_FragColor
	//in both
		//replace texture2D for texture
}

//helps to check if a variable value is valid to an specific uniform in a shader
Shader.validateValue = function( value, uniform_info )
{
	if(value === null || value === undefined)
		return false;

	switch (uniform_info.type)
	{
		//used to validate shaders
		case GL.INT: 
		case GL.FLOAT: 
		case GL.SAMPLER_2D: 
		case GL.SAMPLER_CUBE: 
			return isNumber(value);
		case GL.INT_VEC2: 
		case GL.FLOAT_VEC2:
			return value.length === 2;
		case GL.INT_VEC3: 
		case GL.FLOAT_VEC3:
			return value.length === 3;
		case GL.INT_VEC4: 
		case GL.FLOAT_VEC4:
		case GL.FLOAT_MAT2:
			 return value.length === 4;
		case GL.FLOAT_MAT3:
			 return value.length === 8;
		case GL.FLOAT_MAT4:
			 return value.length === 16;
	}
	return true;
}

//**************** SHADERS ***********************************

Shader.DEFAULT_VERTEX_SHADER = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			attribute vec3 a_normal;\n\
			attribute vec2 a_coord;\n\
			varying vec3 v_position;\n\
			varying vec3 v_normal;\n\
			varying vec2 v_coord;\n\
			uniform mat4 u_model;\n\
			uniform mat4 u_mvp;\n\
			void main() {\n\
				v_position = (u_model * vec4(a_vertex,1.0)).xyz;\n\
				v_normal = (u_model * vec4(a_normal,0.0)).xyz;\n\
				v_coord = a_coord;\n\
				gl_Position = u_mvp * vec4(a_vertex,1.0);\n\
			}\n\
			";

Shader.SCREEN_VERTEX_SHADER = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			attribute vec2 a_coord;\n\
			varying vec2 v_coord;\n\
			void main() { \n\
				v_coord = a_coord; \n\
				gl_Position = vec4(a_coord * 2.0 - 1.0, 0.0, 1.0); \n\
			}\n\
			";

Shader.SCREEN_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			varying vec2 v_coord;\n\
			void main() {\n\
				gl_FragColor = texture2D(u_texture, v_coord);\n\
			}\n\
			";

//used in createFX
Shader.SCREEN_FRAGMENT_FX = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			varying vec2 v_coord;\n\
			#ifdef FX_UNIFORMS\n\
				FX_UNIFORMS\n\
			#endif\n\
			void main() {\n\
				vec2 uv = v_coord;\n\
				vec4 color = texture2D(u_texture, uv);\n\
				#ifdef FX_CODE\n\
					FX_CODE ;\n\
				#endif\n\
				gl_FragColor = color;\n\
			}\n\
			";

Shader.SCREEN_COLORED_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			uniform vec4 u_color;\n\
			varying vec2 v_coord;\n\
			void main() {\n\
				gl_FragColor = u_color * texture2D(u_texture, v_coord);\n\
			}\n\
			";

Shader.BLEND_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			uniform sampler2D u_texture2;\n\
			uniform float u_factor;\n\
			varying vec2 v_coord;\n\
			void main() {\n\
				gl_FragColor = mix( texture2D(u_texture, v_coord), texture2D(u_texture2, v_coord), u_factor);\n\
			}\n\
			";

Shader.SCREEN_FLAT_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform vec4 u_color;\n\
			void main() {\n\
				gl_FragColor = u_color;\n\
			}\n\
			";

//used to paint quads
Shader.QUAD_VERTEX_SHADER = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			attribute vec2 a_coord;\n\
			varying vec2 v_coord;\n\
			uniform vec2 u_position;\n\
			uniform vec2 u_size;\n\
			uniform vec2 u_viewport;\n\
			uniform mat3 u_transform;\n\
			void main() { \n\
				vec3 pos = vec3(u_position + vec2(a_coord.x,1.0 - a_coord.y)  * u_size, 1.0);\n\
				v_coord = a_coord; \n\
				pos = u_transform * pos;\n\
				pos.z = 0.0;\n\
				//normalize\n\
				pos.x = (2.0 * pos.x / u_viewport.x) - 1.0;\n\
				pos.y = -((2.0 * pos.y / u_viewport.y) - 1.0);\n\
				gl_Position = vec4(pos, 1.0); \n\
			}\n\
			";

Shader.QUAD_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			uniform vec4 u_color;\n\
			varying vec2 v_coord;\n\
			void main() {\n\
				gl_FragColor = u_color * texture2D(u_texture, v_coord);\n\
			}\n\
			";

//used to render partially a texture
Shader.QUAD2_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform sampler2D u_texture;\n\
			uniform vec4 u_color;\n\
			uniform vec4 u_texture_area;\n\
			varying vec2 v_coord;\n\
			void main() {\n\
			    vec2 uv = vec2( mix(u_texture_area.x, u_texture_area.z, v_coord.x), 1.0 - mix(u_texture_area.w, u_texture_area.y, v_coord.y) );\n\
				gl_FragColor = u_color * texture2D(u_texture, uv);\n\
			}\n\
			";

Shader.PRIMITIVE2D_VERTEX_SHADER = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			uniform vec2 u_viewport;\n\
			uniform mat3 u_transform;\n\
			void main() { \n\
				vec3 pos = a_vertex;\n\
				pos = u_transform * pos;\n\
				pos.z = 0.0;\n\
				//normalize\n\
				pos.x = (2.0 * pos.x / u_viewport.x) - 1.0;\n\
				pos.y = -((2.0 * pos.y / u_viewport.y) - 1.0);\n\
				gl_Position = vec4(pos, 1.0); \n\
			}\n\
			";

Shader.FLAT_VERTEX_SHADER = "\n\
			precision highp float;\n\
			attribute vec3 a_vertex;\n\
			uniform mat4 u_mvp;\n\
			void main() { \n\
				gl_Position = u_mvp * vec4(a_vertex,1.0); \n\
			}\n\
			";

Shader.FLAT_FRAGMENT_SHADER = "\n\
			precision highp float;\n\
			uniform vec4 u_color;\n\
			void main() {\n\
				gl_FragColor = u_color;\n\
			}\n\
			";

/**
* Allows to create a simple shader meant to be used to process a texture, instead of having to define the generic Vertex & Fragment Shader code
* @method Shader.createFX
* @param {string} code string containg code, like "color = color * 2.0;"
* @param {string} [uniforms=null] string containg extra uniforms, like "uniform vec3 u_pos;"
*/
Shader.createFX = function(code, uniforms, shader)
{
	//remove comments
	code = GL.Shader.removeComments( code, true ); //remove comments and breaklines to avoid problems with the macros
	var macros = {
		FX_CODE: code,
		FX_UNIFORMS: uniforms || ""
	}
	if(!shader)
		return new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, GL.Shader.SCREEN_FRAGMENT_FX, macros );
	shader.updateShader( GL.Shader.SCREEN_VERTEX_SHADER, GL.Shader.SCREEN_FRAGMENT_FX, macros );
	return shader;
}

Shader.removeComments = function(code, one_line)
{
	if(!code)
		return "";

	var rx = /(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(\/\/.*)/g;
	var code = code.replace( rx ,"");
	var lines = code.split("\n");
	var result = [];
	for(var i = 0; i < lines.length; ++i)
	{
		var line = lines[i]; 
		var pos = line.indexOf("//");
		if(pos != -1)
			line = lines[i].substr(0,pos);
		line = line.trim();
		if(line.length)
			result.push(line);
	}
	return result.join( one_line ? "" : "\n" );
}

/**
* Renders a fullscreen quad with this shader applied
* @method toViewport
* @param {object} uniforms
*/
Shader.prototype.toViewport = function(uniforms)
{
	var mesh = GL.Mesh.getScreenQuad();
	if(uniforms)
		this.uniforms(uniforms);
	this.draw( mesh );
}

//Now some common shaders everybody needs

/**
* Returns a shader ready to render a textured quad in fullscreen, use with Mesh.getScreenQuad() mesh
* shader params sampler2D u_texture
* @method Shader.getScreenShader
*/
Shader.getScreenShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":screen"];
	if(shader)
		return shader;
	shader = gl.shaders[":screen"] = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, Shader.SCREEN_FRAGMENT_SHADER );
	return shader.uniforms({u_texture:0}); //do it the first time so I dont have to do it every time
}

/**
* Returns a shader ready to render a colored textured quad in fullscreen, use with Mesh.getScreenQuad() mesh
* shader params vec4 u_color and sampler2D u_texture
* @method Shader.getColoredScreenShader
*/
Shader.getColoredScreenShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":colored_screen"];
	if(shader)
		return shader;
	shader = gl.shaders[":colored_screen"] = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, Shader.SCREEN_COLORED_FRAGMENT_SHADER );
	return shader.uniforms({u_texture:0, u_color: vec4.fromValues(1,1,1,1) }); //do it the first time so I dont have to do it every time
}

/**
* Returns a shader ready to render a quad with transform, use with Mesh.getScreenQuad() mesh
* shader must have: u_position, u_size, u_viewport, u_transform (mat3)
* @method Shader.getQuadShader
*/
Shader.getQuadShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":quad"];
	if(shader)
		return shader;
	return gl.shaders[":quad"] = new GL.Shader( Shader.QUAD_VERTEX_SHADER, Shader.QUAD_FRAGMENT_SHADER );
}

/**
* Returns a shader ready to render part of a texture into the viewport
* shader must have: u_position, u_size, u_viewport, u_transform, u_texture_area (vec4)
* @method Shader.getPartialQuadShader
*/
Shader.getPartialQuadShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":quad2"];
	if(shader)
		return shader;
	return gl.shaders[":quad2"] = new GL.Shader( Shader.QUAD_VERTEX_SHADER, Shader.QUAD2_FRAGMENT_SHADER );
}

/**
* Returns a shader that blends two textures
* shader must have: u_factor, u_texture, u_texture2
* @method Shader.getBlendShader
*/
Shader.getBlendShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":blend"];
	if(shader)
		return shader;
	return gl.shaders[":blend"] = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, Shader.BLEND_FRAGMENT_SHADER );
}

/**
* Returns a shader used to apply gaussian blur to one texture in one axis (you should use it twice to get a gaussian blur)
* shader params are: vec2 u_offset, float u_intensity
* @method Shader.getBlurShader
*/
Shader.getBlurShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":blur"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER,"\n\
			precision highp float;\n\
			varying vec2 v_coord;\n\
			uniform sampler2D u_texture;\n\
			uniform vec2 u_offset;\n\
			uniform float u_intensity;\n\
			void main() {\n\
			   vec4 sum = vec4(0.0);\n\
			   sum += texture2D(u_texture, v_coord + u_offset * -4.0) * 0.05/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * -3.0) * 0.09/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * -2.0) * 0.12/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * -1.0) * 0.15/0.98;\n\
			   sum += texture2D(u_texture, v_coord) * 0.16/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * 4.0) * 0.05/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * 3.0) * 0.09/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * 2.0) * 0.12/0.98;\n\
			   sum += texture2D(u_texture, v_coord + u_offset * 1.0) * 0.15/0.98;\n\
			   gl_FragColor = u_intensity * sum;\n\
			}\n\
			");
	return gl.shaders[":blur"] = shader;
}

//shader to copy a depth texture into another one
Shader.getCopyDepthShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":copy_depth"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER,"\n\
			#extension GL_EXT_frag_depth : enable\n\
			precision highp float;\n\
			varying vec2 v_coord;\n\
			uniform sampler2D u_texture;\n\
			void main() {\n\
			   gl_FragDepthEXT = texture2D( u_texture, v_coord ).x;\n\
			   gl_FragColor = vec4(1.0);\n\
			}\n\
			");
	return gl.shaders[":copy_depth"] = shader;
}

Shader.getCubemapShowShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":show_cubemap"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.DEFAULT_VERTEX_SHADER,"\n\
			precision highp float;\n\
			varying vec3 v_normal;\n\
			uniform samplerCube u_texture;\n\
			void main() {\n\
			   gl_FragColor = textureCube( u_texture, v_normal );\n\
			}\n\
			");
	shader.uniforms({u_texture:0});
	return gl.shaders[":show_cubemap"] = shader;
}

//shader to copy a cubemap into another 
Shader.getCubemapCopyShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":copy_cubemap"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER,"\n\
			precision highp float;\n\
			varying vec2 v_coord;\n\
			uniform samplerCube u_texture;\n\
			uniform mat3 u_rotation;\n\
			void main() {\n\
				vec2 uv = vec2( v_coord.x, 1.0 - v_coord.y );\n\
				vec3 dir = vec3( uv - vec2(0.5), 0.5 );\n\
				dir = u_rotation * dir;\n\
			   gl_FragColor = textureCube( u_texture, dir );\n\
			}\n\
			");
	return gl.shaders[":copy_cubemap"] = shader;
}

//shader to blur a cubemap
Shader.getCubemapBlurShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":blur_cubemap"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER,"\n\
			#ifndef NUM_SAMPLES\n\
				#define NUM_SAMPLES 4\n\
			#endif\n\
			\n\
			precision highp float;\n\
			varying vec2 v_coord;\n\
			uniform samplerCube u_texture;\n\
			uniform mat3 u_rotation;\n\
			uniform vec2 u_offset;\n\
			uniform float u_intensity;\n\
			void main() {\n\
				vec4 sum = vec4(0.0);\n\
				vec2 uv = vec2( v_coord.x, 1.0 - v_coord.y ) - vec2(0.5);\n\
				vec3 dir = vec3(0.0);\n\
				vec4 color = vec4(0.0);\n\
				for( int x = -2; x <= 2; x++ )\n\
				{\n\
					for( int y = -2; y <= 2; y++ )\n\
					{\n\
						dir.xy = uv + vec2( u_offset.x * float(x), u_offset.y * float(y)) * 0.5;\n\
						dir.z = 0.5;\n\
						dir = u_rotation * dir;\n\
						color = textureCube( u_texture, dir );\n\
						color.xyz = color.xyz * color.xyz;/*linearize*/\n\
						sum += color;\n\
					}\n\
				}\n\
				sum /= 25.0;\n\
			   gl_FragColor = vec4( sqrt( sum.xyz ), sum.w ) ;\n\
			}\n\
			");
	return gl.shaders[":blur_cubemap"] = shader;
}

//shader to do FXAA (antialiasing)
Shader.FXAA_FUNC = "\n\
	uniform vec2 u_viewportSize;\n\
	uniform vec2 u_iViewportSize;\n\
	#define FXAA_REDUCE_MIN   (1.0/ 128.0)\n\
	#define FXAA_REDUCE_MUL   (1.0 / 8.0)\n\
	#define FXAA_SPAN_MAX     8.0\n\
	\n\
	/* from mitsuhiko/webgl-meincraft based on the code on geeks3d.com */\n\
	vec4 applyFXAA(sampler2D tex, vec2 fragCoord)\n\
	{\n\
		vec4 color = vec4(0.0);\n\
		/*vec2 u_iViewportSize = vec2(1.0 / u_viewportSize.x, 1.0 / u_viewportSize.y);*/\n\
		vec3 rgbNW = texture2D(tex, (fragCoord + vec2(-1.0, -1.0)) * u_iViewportSize).xyz;\n\
		vec3 rgbNE = texture2D(tex, (fragCoord + vec2(1.0, -1.0)) * u_iViewportSize).xyz;\n\
		vec3 rgbSW = texture2D(tex, (fragCoord + vec2(-1.0, 1.0)) * u_iViewportSize).xyz;\n\
		vec3 rgbSE = texture2D(tex, (fragCoord + vec2(1.0, 1.0)) * u_iViewportSize).xyz;\n\
		vec3 rgbM  = texture2D(tex, fragCoord  * u_iViewportSize).xyz;\n\
		vec3 luma = vec3(0.299, 0.587, 0.114);\n\
		float lumaNW = dot(rgbNW, luma);\n\
		float lumaNE = dot(rgbNE, luma);\n\
		float lumaSW = dot(rgbSW, luma);\n\
		float lumaSE = dot(rgbSE, luma);\n\
		float lumaM  = dot(rgbM,  luma);\n\
		float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n\
		float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\
		\n\
		vec2 dir;\n\
		dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n\
		dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\
		\n\
		float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\
		\n\
		float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n\
		dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * u_iViewportSize;\n\
		\n\
		vec3 rgbA = 0.5 * (texture2D(tex, fragCoord * u_iViewportSize + dir * (1.0 / 3.0 - 0.5)).xyz + \n\
			texture2D(tex, fragCoord * u_iViewportSize + dir * (2.0 / 3.0 - 0.5)).xyz);\n\
		vec3 rgbB = rgbA * 0.5 + 0.25 * (texture2D(tex, fragCoord * u_iViewportSize + dir * -0.5).xyz + \n\
			texture2D(tex, fragCoord * u_iViewportSize + dir * 0.5).xyz);\n\
		\n\
		return vec4(rgbA,1.0);\n\
		float lumaB = dot(rgbB, luma);\n\
		if ((lumaB < lumaMin) || (lumaB > lumaMax))\n\
			color = vec4(rgbA, 1.0);\n\
		else\n\
			color = vec4(rgbB, 1.0);\n\
		return color;\n\
	}\n\
";

/**
* Returns a shader to apply FXAA antialiasing
* params are vec2 u_viewportSize, vec2 u_iViewportSize or you can call shader.setup()
* @method Shader.getFXAAShader
*/
Shader.getFXAAShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":fxaa"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER,"\n\
			precision highp float;\n\
			varying vec2 v_coord;\n\
			uniform sampler2D u_texture;\n\
			" + Shader.FXAA_FUNC + "\n\
			\n\
			void main() {\n\
			   gl_FragColor = applyFXAA( u_texture, v_coord * u_viewportSize) ;\n\
			}\n\
			");

	var viewport = vec2.fromValues( gl.viewport_data[2], gl.viewport_data[3] );
	var iviewport = vec2.fromValues( 1/gl.viewport_data[2], 1/gl.viewport_data[3] );

	shader.setup = function() {
		viewport[0] = gl.viewport_data[2];
		viewport[1] = gl.viewport_data[3];
		iviewport[0] = 1/gl.viewport_data[2];
		iviewport[1] = 1/gl.viewport_data[3];
		this.uniforms({ u_viewportSize: viewport, u_iViewportSize: iviewport });	
	}
	return gl.shaders[":fxaa"] = shader;
}

/**
* Returns a flat shader (useful to render lines)
* @method Shader.getFlatShader
*/
Shader.getFlatShader = function(gl)
{
	gl = gl || global.gl;
	var shader = gl.shaders[":flat"];
	if(shader)
		return shader;

	var shader = new GL.Shader( Shader.FLAT_VERTEX_SHADER,Shader.FLAT_FRAGMENT_SHADER);
	shader.uniforms({u_color:[1,1,1,1]});
	return gl.shaders[":flat"] = shader;
}