Index: /issm/trunk-jpl/src/m/plot/applyoptions.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/applyoptions.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/applyoptions.js	(revision 21205)
@@ -360,5 +360,5 @@
 		if (options.getfieldvalue('render',[]).indexOf('sky')!=-1) {	
 			//atmosphere
-			var node = Node(gl,options);
+			var node = Node(gl);
 			canvas.nodes[canvas.nodes.length] = node;
 			node["name"] = "atmosphere";
@@ -369,5 +369,5 @@
 			node["mesh"] = GL.Mesh.icosahedron({size:6371000*atmosphereScale,subdivisions:6});
 			node["useIndexBuffer"] = false;
-			node["rotation"] = [0, 0, 0]
+			node["rotation"] = [0, 0, 0];
 			node["translation"] = translation;
 			node["center"] = [0, 0, 0];
@@ -376,5 +376,5 @@
 		if (options.getfieldvalue('render',[]).indexOf('space')!=-1) {	
 			//skysphere
-			node = Node(gl,options);
+			node = Node(gl);
 			canvas.nodes[canvas.nodes.length] = node;
 			node["name"] = "skysphere";
@@ -386,5 +386,5 @@
 			node["texture"] = initTexture(gl,'../../../js/textures/TychoSkymapII_t4_2k.jpg');
 			node["useIndexBuffer"] = false;
-			node["rotation"] = [0, 0, 0]
+			node["rotation"] = [0, 0, 0];
 			node["translation"] = translation;
 			node["center"] = [0, 0, 0];
Index: /issm/trunk-jpl/src/m/plot/plot_mesh.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_mesh.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/plot_mesh.js	(revision 21205)
@@ -59,5 +59,6 @@
 	//Compute gl variables:
 	var gl = canvas.gl;
-	var node = Node(gl,options);
+	gl.makeCurrent();
+	var node = Node(gl);
 	canvas.nodes[canvas.nodes.length] = node;
 	node["name"] = "mesh";
@@ -135,4 +136,4 @@
 	}
 	//}}}
-	node["mesh"] = GL.Mesh.load({vertices:vertices, colors:colors, indices:indices});
+	node["mesh"] = GL.Mesh.load({vertices:vertices, colors:colors, indices:indices}, null, null, gl);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_overlay.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_overlay.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/plot_overlay.js	(revision 21205)
@@ -59,5 +59,5 @@
 	//Compute gl variables:
 	var gl = canvas.gl;
-	var node = Node(gl,options);
+	var node = Node(gl);
 	canvas.nodes[canvas.nodes.length] = node;
 	node["name"] = "overlay";
@@ -159,4 +159,4 @@
 		indices[indices.length] = element[2];
 	}
-	node["mesh"] = GL.Mesh.load({vertices:vertices, coords:texcoords, indices:indices});
+	node["mesh"] = GL.Mesh.load({vertices:vertices, coords:texcoords, indices:indices}, null, null, gl);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_quiver.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_quiver.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/plot_quiver.js	(revision 21205)
@@ -61,5 +61,5 @@
 	//Compute gl variables:
 	var gl = canvas.gl;
-	var node = Node(gl,options);
+	var node = Node(gl);
 	canvas.nodes[canvas.nodes.length] = node;
 	node["name"] = "quiver";
@@ -134,4 +134,4 @@
 	}
 	//}}}
-	node["mesh"] = GL.Mesh.load({vertices:vertices, colors:colors});
+	node["mesh"] = GL.Mesh.load({vertices:vertices, colors:colors}, null, null, gl);
 }
Index: /issm/trunk-jpl/src/m/plot/plot_unit.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/plot_unit.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/plot_unit.js	(revision 21205)
@@ -61,5 +61,5 @@
 	//Compute gl variables:
 	var gl = canvas.gl;
-	var node = Node(gl,options);
+	var node = Node(gl);
 	canvas.nodes[canvas.nodes.length] = node;
 	node["name"] = "unit";
@@ -117,8 +117,9 @@
 						vertices[vindex++] = vertex[2];
 						
-						texcoords[tindex++] = 0.0;
+						texcoords[tindex++] = 0.5;
 						texcoords[tindex++] = 0.0;
 						continue;
 					}
+
 					//Scale vertices
 					xyz = vec3.fromValues(x[i], y[i], z[i]);
@@ -131,5 +132,6 @@
 
 					texcoords[tindex++] = 0.5;
-					texcoords[tindex++] = (data[i] - datamin) / datadelta;
+					texcoords[tindex++] = clamp((data[i] - datamin) / datadelta, 0.0, 1.0);
+					
 				}
 
@@ -205,5 +207,5 @@
 					for(var j = 0, index = 0; j < x.length; j++){
 						texcoords[i][index++] = 0.5;
-						texcoords[i][index++] = (data[i][j] - datamin) / datadelta;
+						texcoords[i][index++] = clamp((data[i][j] - datamin) / datadelta, 0.0, 1.0);
 					}
 				}
@@ -248,5 +250,5 @@
 				}
 			}
-			node["mesh"] = GL.Mesh.load({vertices:vertices, coords:texcoords[0], indices:indices});
+			node["mesh"] = GL.Mesh.load({vertices:vertices, coords:texcoords[0], indices:indices}, null, null, gl);
 			break;
 		//}}}
Index: /issm/trunk-jpl/src/m/plot/webgl.js
===================================================================
--- /issm/trunk-jpl/src/m/plot/webgl.js	(revision 21204)
+++ /issm/trunk-jpl/src/m/plot/webgl.js	(revision 21205)
@@ -1,4 +1,4 @@
 /*This is where we have all our webgl relevant functionality for the plotting routines: */
-	
+
 //{{{ Canvas Initialization
 function initCanvas(options) {
@@ -7,4 +7,5 @@
 	//var canvas = document.getElementById(options.getfieldvalue('canvasid'));
 	if (!canvas.initialized) {
+		typedArraySliceSupport();
 		canvas.gl = initWebGL(canvas,options);
 		canvas.nodes = [];
@@ -18,6 +19,10 @@
 	var gl;
 	try {
-		if (!canvas.gl) gl = GL.create({canvas:canvas});
-		else gl = canvas.gl;
+		if (!canvas.gl) {
+			gl = GL.create({canvas:canvas});
+		}
+		else {
+			gl = canvas.gl;
+		}
 	}
 	catch(e) {
@@ -25,5 +30,5 @@
 		return;
 	}
-
+	
 	// Enable depth testing
 	gl.enable(gl.DEPTH_TEST);
@@ -45,8 +50,9 @@
 	canvas.zoom = clamp(options.getfieldvalue('zoom',1.0), canvas.zoomBounds[0], canvas.zoomBounds[1]);
 	canvas.zoomLast = canvas.zoom;
+	canvas.cameraPosition = vec3.create();
 	canvas.cameraMatrix = mat4.create();
 	canvas.vInverseMatrix = mat4.create();
-	canvas.translation = options.getfieldvalue('origin',[0,0,0.0]);
-	canvas.viewPanning = options.getfieldvalue('viewpanning','off') == 'on';
+	canvas.translation = options.getfieldvalue('origin',[0,0,0]);
+	canvas.viewPanning = options.getfieldvalue('enablepanning','off') == 'on';
 	canvas.view = options.getfieldvalue('view',[0,90]); //0 azimuth - up is north, 90 elevation - looking straight down
 	canvas.rotation = canvas.view;
@@ -68,9 +74,10 @@
 	var mc = new Hammer.Manager(canvas);
 	
+	mc.add(new Hammer.Tap());
     mc.add(new Hammer.Pan({threshold:0, pointers:0}));
     mc.add(new Hammer.Pinch({threshold:0})).recognizeWith(mc.get('pan'));
+	mc.on("tap", function (ev) {onTap(ev,canvas);});
     mc.on("panstart panmove", function (ev) {onPan(ev,canvas,displayview);});
     mc.on("pinchstart pinchmove", function (ev) {onPinch(ev,canvas,displayview);});
-	//mc.on("mousewheel DOMMouseScroll", function (ev) {onZoom(ev,canvas,options);});
 	
 	canvas.addEventListener("mousewheel", function (ev) {onZoom(ev,canvas,displayzoom)}, false);
@@ -80,45 +87,44 @@
 } //}}}
 function initTexture(gl,imageSource) { //{{{
-	return GL.Texture.fromURL(imageSource, {minFilter:gl.LINEAR_MIPMAP_LINEAR, magFilter:gl.LINEAR});
-} //}}}
-function Node(gl,options) { //{{{
+	return GL.Texture.fromURL(imageSource, {minFilter:gl.LINEAR_MIPMAP_LINEAR, magFilter:gl.LINEAR}, null, gl);
+} //}}}
+function Node(gl) { //{{{
 	//Returns a Node object that contains default display states for webgl object. center represents pivot point of rotation.
 	return {
+		alpha:1.0,
 		buffers:[],
+		cullFace:gl.FRONT,
+		disableDepthTest:false, 
+		drawMode:gl.TRIANGLES,
+		drawOrder:0,
+		enabled:true,
+		enableCullFace:false,
+		hideOcean:false,
+		lineWidth:1.0,
+		maskEnabled:false,
+		maskHeight:150.0,
+		maskColor:vec4.fromValues(0.0, 0.0, 1.0, 1.0),
+		mesh:null,
 		name:"node",
+		shaderName:"Colored",
 		shader:gl.shaders["Colored"],
-		draw:null,
-		hideOcean:false,
-		level:0,
+		texture:null,
 		useIndexBuffer:true,
-		alpha:1.0,
-		lineWidth:1.0,
-		disableDepthTest:false, 
-		enableCullFace:false,
-		cullFace:gl.FRONT,
-		drawMode:gl.TRIANGLES,
-		texture:null,
+		center:vec3.create(), 
 		scale:vec3.fromValues(1, 1, 1),
 		rotation:vec3.create(),
 		translation:vec3.create(),
-		center:vec3.create(), 
-		modelMatrix:mat4.create(),
-		shaderName:"Colored",
-		drawOrder:0,
-		maskEnabled:false,
-		maskHeight:150.0,
-		maskColor:vec4.fromValues(0.0, 0.0, 1.0, 1.0),
-		enabled:true
+		modelMatrix:mat4.create()
 	};
 } //}}}
-function displayNodes() {
-	var nodes = $('.sim-canvas')[0].nodes;
-	console.log("Nodes:");
+function debugNodes(canvasid) {
+	var nodes = $(canvasid)[0].nodes;
+	console.log(canvasid, "Nodes:");
 	for (var node in nodes) {
 		console.log("name", nodes[node]["name"], "translation", nodes[node]["translation"], "center", nodes[node]["center"], "rotation", nodes[node]["rotation"]);
 	}
+	return nodes;
 }
 function recalculateModelMatrix(node) { //{{{
-	//TODO: move to 0,0,0, rotate,move back to normal space, then apply transform
 	var modelMatrix = mat4.create();
 
@@ -145,8 +151,4 @@
 	mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
 	
-	// mat4.identity(translationMatrix);
-	// mat4.translate(translationMatrix, translationMatrix, [-node["translation"][0],-node["translation"][1],-node["translation"][2]]); //absolute translation
-	// mat4.multiply(modelMatrix, translationMatrix, modelMatrix);
-	
 	mat4.identity(translationMatrix);
 	mat4.translate(translationMatrix, translationMatrix, node["translation"]); //absolute translation
@@ -154,4 +156,15 @@
 	return modelMatrix;
 } //}}}
+function raycast(canvas,mesh,x,y) { //{{{
+	var raytracer = new GL.Raytracer(canvas.cameraMatrix);
+	var ray = raytracer.getRayForPixel(x, y);
+	if(!mesh || mesh.ready == false) return;
+	if(!mesh.octree) mesh.octree = new GL.Octree(mesh);
+
+	var hit = mesh.octree.testRay(canvas.cameraPosition, ray, 1e2, 1e10);
+	
+	if(!hit) return;
+	return hit.pos;
+}
 function radians (degrees) { //{{{
   return degrees * Math.PI / 180;
@@ -170,15 +183,65 @@
 	return defaultvalue;
 } //}}}
+function typedArraySliceSupport() { //{{{
+	//TypedArray compatibility for Safari/IE
+	if (typeof Int8Array !== 'undefined') {
+		if (!Int8Array.prototype.fill) Int8Array.prototype.fill = Array.prototype.fill;
+		if (!Int8Array.prototype.slice) Int8Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Uint8Array !== 'undefined') {
+		if (!Uint8Array.prototype.fill) Uint8Array.prototype.fill = Array.prototype.fill;
+		if (!Uint8Array.prototype.slice) Uint8Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Uint8ClampedArray !== 'undefined') {
+		if (!Uint8ClampedArray.prototype.fill) Uint8ClampedArray.prototype.fill = Array.prototype.fill;
+		if (!Uint8ClampedArray.prototype.slice) Uint8ClampedArray.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Int16Array !== 'undefined') {
+		if (!Int16Array.prototype.fill) Int16Array.prototype.fill = Array.prototype.fill;
+		if (!Int16Array.prototype.slice) Int16Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Uint16Array !== 'undefined') {
+		if (!Uint16Array.prototype.fill) Uint16Array.prototype.fill = Array.prototype.fill;
+		if (!Uint16Array.prototype.slice) Uint16Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Int32Array !== 'undefined') {
+		if (!Int32Array.prototype.fill) Int32Array.prototype.fill = Array.prototype.fill;
+		if (!Int32Array.prototype.slice) Int32Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Uint32Array !== 'undefined') {
+		if (!Uint32Array.prototype.fill) Uint32Array.prototype.fill = Array.prototype.fill;
+		if (!Uint32Array.prototype.slice) Uint32Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Float32Array !== 'undefined') {
+		if (!Float32Array.prototype.fill) Float32Array.prototype.fill = Array.prototype.fill;
+		if (!Float32Array.prototype.slice) Float32Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof Float64Array !== 'undefined') {
+		if (!Float64Array.prototype.fill) Float64Array.prototype.fill = Array.prototype.fill;
+		if (!Float64Array.prototype.slice) Float64Array.prototype.slice = Array.prototype.slice;
+	}
+	if (typeof TypedArray !== 'undefined') {
+		if (!TypedArray.prototype.fill) TypedArray.prototype.fill = Array.prototype.fill;
+		if (!TypedArray.prototype.slice) TypedArray.prototype.slice = Array.prototype.slice;
+	}
+} //}}}
 //}}}
 //{{{ Shader Loading
 function loadShaders(gl) { //{{{
-	shaders = {};
-	shaders["Colored"] = new Shader.fromURL("../../../js/shaders/Colored.vsh", "../../../js/shaders/Colored.fsh");
-	shaders["Textured"] = new Shader.fromURL("../../../js/shaders/Textured.vsh", "../../../js/shaders/Textured.fsh");
-	shaders["SkyFromSpace"] = new Shader.fromURL("../../../js/shaders/SkyFromSpace.vert", "../../../js/shaders/SkyFromSpace.frag");
-	shaders["GroundFromSpace"] = new Shader.fromURL("../../../js/shaders/GroundFromSpace.vert", "../../../js/shaders/GroundFromSpace.frag");
+	var shaders = {};
+	shaders["Colored"] = new GL.Shader.fromURL("../../../js/shaders/Colored.vsh", "../../../js/shaders/Colored.fsh", null, gl);
+	shaders["Textured"] = new GL.Shader.fromURL("../../../js/shaders/Textured.vsh", "../../../js/shaders/Textured.fsh", null, gl);
+	shaders["SkyFromSpace"] = new GL.Shader.fromURL("../../../js/shaders/SkyFromSpace.vert", "../../../js/shaders/SkyFromSpace.frag", null, gl);
+	shaders["GroundFromSpace"] = new GL.Shader.fromURL("../../../js/shaders/GroundFromSpace.vert", "../../../js/shaders/GroundFromSpace.frag", null, gl);
 	return shaders;
 } //}}}
 //{{{ Interface Functions
+function onTap(ev,canvas) { //{{{
+	ev.preventDefault();
+	if (ev.type == 'panstart') {
+		canvas.lastDeltaX = 0;
+		canvas.lastDeltaY = 0;
+	}
+}
 function onPan(ev,canvas,displaylog) { //{{{
 	ev.preventDefault();
@@ -189,6 +252,6 @@
 	if (ev.srcEvent.shiftKey || ev.pointers.length == 2) {
 		if (!canvas.viewPanning) return;
-		var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.zoom * -2 * canvas.controlSensitivity * 6371000.0;
-		var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.zoom * -2 * canvas.controlSensitivity * 6371000.0;
+		var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.zoom * 2 * canvas.controlSensitivity * 6.371e6;
+		var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.zoom * 2 * canvas.controlSensitivity * 6.371e6;
 		
 		if (canvas.twod) {
@@ -229,5 +292,5 @@
 function onZoom(ev,canvas,displaylog) { //{{{
 	ev.preventDefault();
-	var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.zoom / 10;
+	var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.zoom / 20;
 	modifyZoom(canvas.zoom + delta, canvas, displaylog);
 } //}}}
@@ -247,10 +310,11 @@
 	var elevationRotationMatrix = mat4.create();
 	var aspectRatio = canvas.clientWidth / canvas.clientHeight;
+	var cameraPosition = vec3.create();
 
 	if (canvas.twod) {
-		mat4.ortho(pMatrix, -aspectRatio*6371000.0/canvas.zoom, aspectRatio*6371000.0/canvas.zoom, -6371000.0/canvas.zoom, 6371000.0/canvas.zoom, -1.0, 10000000000.0);
+		mat4.ortho(pMatrix, -aspectRatio*6.371e6/canvas.zoom, aspectRatio*6.371e6/canvas.zoom, -6.371e6/canvas.zoom, 6.371e6/canvas.zoom, -1.0, 1e10);
 	}
 	else {
-		mat4.perspective(pMatrix, 60 * Math.PI / 180, aspectRatio, 100, 1000000000.0);
+		mat4.perspective(pMatrix, 60 * Math.PI / 180, aspectRatio, 1e2, 1e10);
 	}
 	
@@ -276,9 +340,10 @@
 	//Apply screenspace translation
 	mat4.identity(translateMatrix);
-	mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6371000.0/canvas.zoom]);
+	mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/canvas.zoom]);
 	mat4.multiply(vMatrix, translateMatrix, vMatrix);
 	
-	//Calculate inverse matrices for lighting
+	//Calculate fields for lighting and raycasts
 	mat4.invert(canvas.vInverseMatrix, vMatrix);
+	vec3.transformMat4(canvas.cameraPosition, cameraPosition, canvas.vInverseMatrix);
 
 	//Apply projection matrix to get camera matrix
@@ -287,4 +352,7 @@
 function drawSceneGraphNode(canvas,node) { //{{{
 	if (!node["enabled"]) return;
+
+	var gl = canvas.gl;
+	gl.makeCurrent();
 	
 	var mvpMatrix = mat4.create();
@@ -302,9 +370,9 @@
 	var origin = vec3.fromValues(0, 0, 0);
 	var lightOrigin = vec3.fromValues(0, 0, 0);
-	var cameraPosition = vec3.create();
+	var cameraPositionRelative = vec3.create();
 	vec3.transformMat4(origin, origin, canvas.vInverseMatrix);
 	vec3.normalize(lightOrigin, lightOrigin);
-	vec3.sub(cameraPosition, origin, node["translation"]);
-	cameraHeight = vec3.length(cameraPosition);
+	vec3.sub(cameraPositionRelative, origin, node["translation"]);
+	cameraHeight = vec3.length(cameraPositionRelative);
 	
 	var atm = { 							//Default Values
@@ -328,5 +396,5 @@
 			
 	var inv_wavelength4 = [1.0 / Math.pow(atm.wavelength_r, 4), 1.0 / Math.pow(atm.wavelength_g, 4), 1.0 / Math.pow(atm.wavelength_b, 4)];
-	var innerRadius = 6371000.0;
+	var innerRadius = 6.371e6;
 	var outerRadius = innerRadius*atm.scale;
 	var scale = 1.0 / (outerRadius - innerRadius);
@@ -374,4 +442,5 @@
 } //}}}
 function draw(canvas,options) { //{{{
+
 	// Ensure canvas and gl viewport sizes are the same
 	if (canvas.width  != canvas.clientWidth || canvas.height != canvas.clientHeight) {
@@ -389,5 +458,5 @@
 	}
 	for (var node in nodes) {
-		if (nodes[node]["texture"] && nodes[node]["texture"]["ready"] == false) {
+		if (nodes[node]["texture"] && nodes[node]["texture"]["ready"] == false || nodes[node]["shader"]["ready"] == false) {
 			canvas.drawHandler = window.requestAnimationFrame(function(time) {draw(canvas,options)});
 			return;
@@ -398,4 +467,5 @@
 	gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]);
 	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+	gl.makeCurrent();
 	
 	updateCameraMatrix(canvas);
@@ -407,4 +477,5 @@
 		}
 	}
+
 	canvas.drawHandler = window.requestAnimationFrame(function(time) {draw(canvas,options)});
 } //}}}
