Index: issm/trunk-jpl/src/m/plot/webgl.js
===================================================================
--- issm/trunk-jpl/src/m/plot/webgl.js	(revision 19839)
+++ issm/trunk-jpl/src/m/plot/webgl.js	(revision 19853)
@@ -66,4 +66,36 @@
 	return bufferArray;
 } //}}}
+function createSolidTexture(gl, r, g, b, a) {
+    var data = new Uint8Array([r, g, b, a]);
+    var texture = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, texture);
+    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+	gl.bindTexture(gl.TEXTURE_2D, null);
+    return texture;
+}
+function initTexture(gl,imageSource) { //{{{
+	var texture = gl.createTexture();
+	texture.image = new Image();
+	texture.image.onload = function () {
+		handleLoadedTexture(gl,texture);
+	}
+	texture.image.src = imageSource;
+	texture.isLoaded = true;
+	return texture;
+} //}}}
+function handleLoadedTexture(gl,texture) { //{{{
+	gl.activeTexture(gl.TEXTURE0);
+	gl.bindTexture(gl.TEXTURE_2D, texture);
+	gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
+	gl.generateMipmap(gl.TEXTURE_2D);
+	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
+	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.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);
+	gl.bindTexture(gl.TEXTURE_2D, null);
+} //}}}
 function Node(gl,options) { //{{{
 	
@@ -71,5 +103,5 @@
 
 	node= {buffers:[],
-		shader:gl.shaders["colored"]["program"],
+		shader:gl.shaders["unlit_textured"]["program"],
 		draw:null,
 		hideOcean:false,
@@ -87,5 +119,5 @@
 		scale:vec3.fromValues(1, 1, 1),
 		modelMatrix:mat4.create(),
-		shaderName:"colored",
+		shaderName:"unlit_textured",
 	};
 	
@@ -120,5 +152,5 @@
 	var normalizedValue;
 					
-	colorbar=colorbars[cmap];
+	var colorbar=colorbars[cmap];
 
 	value = clamp(value, min, max);
@@ -135,8 +167,7 @@
 //{{{ Shader Loading
 function loadShaders(gl) { //{{{
-	// TODO: Subsitute shaders["colored"] with shaderColored
-	shaderName = "colored";
+	var shaderNames = ["colored", "unlit_textured"];
 	shaders = {};
-	shaders[shaderName] = {loaded:false, vsh:{}, fsh:{}};
+	shaders["colored"] = {loaded:false, vsh:{}, fsh:{}};
 	shaders["colored"]["vsh"]["string"] = 
 		['attribute vec3 aVertexPosition;',
@@ -160,46 +191,70 @@
 		'	gl_FragColor = vColor;',
 		'}'].join('\n');
-
-	shaders[shaderName]["vsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["vsh"]["string"], "vsh");
-	shaders[shaderName]["fsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["fsh"]["string"], "fsh");
-
-	shaders[shaderName]["program"] = gl.createProgram();
-	gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["vsh"]["shader"]);
-	gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["fsh"]["shader"]);
-	gl.linkProgram(shaders[shaderName]["program"]);
-
-	if (!gl.getProgramParameter(shaders[shaderName]["program"], gl.LINK_STATUS)) {
-		alert("Could not initialise shaders");
-	}
-
-	var vshStringArray = shaders[shaderName]["vsh"]["string"].split("\n");
-	var fshStringArray = shaders[shaderName]["fsh"]["string"].split("\n");
-	var line = "";
-	var property = "";
-	for (var i = 0; i < vshStringArray.length; i++) {
-		line = vshStringArray[i];
-		if (line.search("attribute") != -1) {
-			property = nameFromLine(line);
-			shaders[shaderName]["program"][property] = gl.getAttribLocation(shaders[shaderName]["program"], property);
-		}
-		else if (line.search("uniform") != -1) {
-			property = nameFromLine(line);
-			shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property);
-		}
-		else if (line.search("void main") != -1) {
-			break;
-		}
-	}
-	for (var i = 0; i < fshStringArray.length; i++) {
-		line = fshStringArray[i];
-		if (line.search("uniform") != -1) {
-			property = nameFromLine(line);
-			shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property);
-		}
-		else if (line.search("void main") != -1) {
-			break;
-		}
-	}
-	shaders[shaderName]["loaded"] = true;
+	shaders["unlit_textured"] = {loaded:false, vsh:{}, fsh:{}};
+	shaders["unlit_textured"]["vsh"]["string"] = 
+		['attribute vec3 aVertexPosition;',
+		'attribute vec2 aTextureCoord;',
+		'',
+		'uniform mat4 uMVPMatrix;',
+		'',
+		'varying vec2 vTextureCoord;',
+		'',
+		'void main(void) {',
+		'	gl_Position = uMVPMatrix * vec4(aVertexPosition.xyz, 1.0);',
+		'	vTextureCoord = aTextureCoord;',
+		'}'].join('\n');
+	shaders["unlit_textured"]["fsh"]["string"] =
+		['precision mediump float;',
+		'',
+		'varying vec2 vTextureCoord;',
+		'',
+		'uniform sampler2D uColorSampler;',
+		'',
+		'void main(void) {',
+		'	gl_FragColor = texture2D(uColorSampler, vec2(vTextureCoord.s, vTextureCoord.t));',
+		'}'].join('\n');
+	shaderNames.forEach(function(shaderName){
+		shaders[shaderName]["vsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["vsh"]["string"], "vsh");
+		shaders[shaderName]["fsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["fsh"]["string"], "fsh");
+
+		shaders[shaderName]["program"] = gl.createProgram();
+		gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["vsh"]["shader"]);
+		gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["fsh"]["shader"]);
+		gl.linkProgram(shaders[shaderName]["program"]);
+
+		if (!gl.getProgramParameter(shaders[shaderName]["program"], gl.LINK_STATUS)) {
+			alert("Could not initialise shaders");
+		}
+
+		var vshStringArray = shaders[shaderName]["vsh"]["string"].split("\n");
+		var fshStringArray = shaders[shaderName]["fsh"]["string"].split("\n");
+		var line = "";
+		var property = "";
+		for (var i = 0; i < vshStringArray.length; i++) {
+			line = vshStringArray[i];
+			if (line.search("attribute") != -1) {
+				property = nameFromLine(line);
+				shaders[shaderName]["program"][property] = gl.getAttribLocation(shaders[shaderName]["program"], property);
+			}
+			else if (line.search("uniform") != -1) {
+				property = nameFromLine(line);
+				shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property);
+			}
+			else if (line.search("void main") != -1) {
+				break;
+			}
+		}
+		for (var i = 0; i < fshStringArray.length; i++) {
+			line = fshStringArray[i];
+			if (line.search("uniform") != -1) {
+				property = nameFromLine(line);
+				shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property);
+			}
+			else if (line.search("void main") != -1) {
+				break;
+			}
+		}
+		shaders[shaderName]["loaded"] = true;
+	});
 	return shaders;
 } //}}}
@@ -269,4 +324,9 @@
 	gl.uniformMatrix4fv(node["shader"]["uMVPMatrix"], false, mvpMatrix);
 	gl.uniform1f(node["shader"]["uAlpha"], node["transparency"]);
+	if (node["texture"]) {
+		gl.activeTexture(gl.TEXTURE0);
+		gl.bindTexture(gl.TEXTURE_2D, node["texture"]);
+		gl.uniform1i(node["shader"]["uColorSampler"], 0);	
+	}
 	if  (node["useIndexBuffer"]) {
 		gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, node["buffers"][node["buffers"].length - 1]);
@@ -304,6 +364,6 @@
 	window.requestAnimationFrame(function(time) {draw(gl,options,canvas,node)});
 	updateCameraMatrix(canvas);
+
 	drawSceneGraphNode(gl, canvas, node);
-
 } //}}}
 //}}}
