Add graphics_WebGLManyPlanetsDeep test.
Also add the HTML and JavaScript source files (pulled from the public
khronos WebGL repository) to deps/webgl_mpd.
BUG=chromium:263300
TEST=test_that.py --fast <DUT IP> graphics_WebGLManyPlanetsDeep
Change-Id: Ia46664f89488cef6414c142e727e8e1e52522731
Reviewed-on: https://chromium-review.googlesource.com/57597
Reviewed-by: Ricky Liang <[email protected]>
Commit-Queue: Ricky Liang <[email protected]>
Tested-by: Ricky Liang <[email protected]>
diff --git a/client/deps/webgl_mpd/common.py b/client/deps/webgl_mpd/common.py
new file mode 100644
index 0000000..9c3d751
--- /dev/null
+++ b/client/deps/webgl_mpd/common.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+
+dirname = os.path.dirname(sys.modules[__name__].__file__)
+# Load setup_modules from client_dir (two level up from current dir).
+client_dir = os.path.abspath(os.path.join(dirname, "..", ".."))
+sys.path.insert(0, client_dir)
+import setup_modules
+sys.path.pop(0)
+setup_modules.setup(base_path=client_dir,
+ root_module_name="autotest_lib.client")
diff --git a/client/deps/webgl_mpd/control b/client/deps/webgl_mpd/control
new file mode 100644
index 0000000..6a78c41
--- /dev/null
+++ b/client/deps/webgl_mpd/control
@@ -0,0 +1,5 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+job.setup_dep(['webgl_mpd'])
diff --git a/client/deps/webgl_mpd/src/ManyPlanetsDeep.html b/client/deps/webgl_mpd/src/ManyPlanetsDeep.html
new file mode 100644
index 0000000..bc37e52
--- /dev/null
+++ b/client/deps/webgl_mpd/src/ManyPlanetsDeep.html
@@ -0,0 +1,280 @@
+<!DOCTYPE html>
+<!--
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ -->
+<html>
+ <head>
+ <title>Many Planets Deep</title>
+ <script type="text/javascript" src="common/webgl-utils.js"></script>
+ <script type="text/javascript" src="debug/webgl-debug.js"></script>
+ <script type="text/javascript" src="cros_fps.js"></script>
+ <script src="resources/J3DI.js"> </script>
+ <script src="resources/J3DIMath.js" type="text/javascript"> </script>
+
+ <script id="vshader" type="x-shader/x-vertex">
+ uniform mat4 u_modelViewProjMatrix;
+ uniform mat4 u_normalMatrix;
+ uniform vec3 lightDir;
+
+ attribute vec3 vNormal;
+ attribute vec4 vTexCoord;
+ attribute vec4 vPosition;
+
+ varying float v_Dot;
+ varying vec2 v_texCoord;
+
+ void main()
+ {
+ gl_Position = u_modelViewProjMatrix * vPosition;
+ v_texCoord = vTexCoord.st;
+ vec4 transNormal = u_normalMatrix * vec4(vNormal,1);
+ v_Dot = max(dot(transNormal.xyz, lightDir), 0.0);
+ }
+ </script>
+
+ <script id="fshader" type="x-shader/x-fragment">
+ precision mediump float;
+
+ uniform sampler2D sampler2d;
+
+ varying float v_Dot;
+ varying vec2 v_texCoord;
+
+ void main()
+ {
+ vec4 color = texture2D(sampler2d,v_texCoord);
+ color += vec4(0.1,0.1,0.1,1);
+ gl_FragColor = vec4(color.xyz * v_Dot, color.a);
+ }
+ </script>
+
+ <script>
+ const numRowCols = 4;
+ const numLayers = 3;
+ const layoutWidth = 10;
+ const layoutHeight = 8;
+ const globeSize = 25;
+ const minIncAngle = 0.2;
+ const maxIncAngle = 2;
+ var g = {}; // globals
+ var g_crosFpsCounter = new crosFpsCounter();
+ var then = 0.0;
+ var lastJSRenderTime = 0.0;
+
+ function init()
+ {
+ var gl = initWebGL("example");
+ if (!gl) {
+ return;
+ }
+ g.program = simpleSetup(gl, "vshader", "fshader",
+ [ "vPosition", "vTexCoord", "vNormal"],
+ [ 0, 0, 0, 1 ], 10000);
+ gl.uniform3f(gl.getUniformLocation(g.program, "lightDir"), 0, 0, 1);
+ gl.uniform1i(gl.getUniformLocation(g.program, "sampler2d"), 0);
+
+ if (g.program) {
+ g.u_normalMatrixLoc = gl.getUniformLocation(g.program, "u_normalMatrix");
+ g.u_modelViewProjMatrixLoc = gl.getUniformLocation(g.program, "u_modelViewProjMatrix");
+ }
+
+ g.sphere = makeSphere(gl, 1, 30, 30);
+
+ // get the images
+ earthTexture = loadImageTexture(gl, "resources/earthmap1k.jpg");
+ marsTexture = loadImageTexture(gl, "resources/mars500x250.png");
+
+ return gl;
+ }
+
+ width = -1;
+ height = -1;
+ var requestId;
+
+ function reshape(ctx)
+ {
+ var canvas = document.getElementById('example');
+ if (canvas.width == width && canvas.height == height)
+ return;
+
+ width = canvas.width;
+ height = canvas.height;
+
+ ctx.viewport(0, 0, width, height);
+
+ g.perspectiveMatrix = new J3DIMatrix4();
+ g.perspectiveMatrix.perspective(30, width/height, 1, 10000);
+ g.perspectiveMatrix.lookat(0,0,20, 0, 0, 0, 0, 1, 0);
+ }
+
+ function drawOne(ctx, angle, x, y, z, scale, texture)
+ {
+ // setup VBOs
+ ctx.enableVertexAttribArray(0);
+ ctx.enableVertexAttribArray(1);
+ ctx.enableVertexAttribArray(2);
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.vertexObject);
+ ctx.vertexAttribPointer(0, 3, ctx.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.normalObject);
+ ctx.vertexAttribPointer(2, 3, ctx.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, g.sphere.texCoordObject);
+ ctx.vertexAttribPointer(1, 2, ctx.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, g.sphere.indexObject);
+
+ // generate the model-view matrix
+ var mvMatrix = new J3DIMatrix4();
+ mvMatrix.translate(x,y,z);
+ mvMatrix.rotate(30, 1,0,0);
+ mvMatrix.rotate(angle, 0,1,0);
+ mvMatrix.scale(scale, scale, scale);
+
+ // construct the normal matrix from the model-view matrix
+ var normalMatrix = new J3DIMatrix4(mvMatrix);
+ normalMatrix.invert();
+ normalMatrix.transpose();
+ normalMatrix.setUniform(ctx, g.u_normalMatrixLoc, false);
+
+ // construct the model-view * projection matrix
+ var mvpMatrix = new J3DIMatrix4(g.perspectiveMatrix);
+ mvpMatrix.multiply(mvMatrix);
+ mvpMatrix.setUniform(ctx, g.u_modelViewProjMatrixLoc, false);
+
+ ctx.bindTexture(ctx.TEXTURE_2D, texture);
+ ctx.drawElements(ctx.TRIANGLES, g.sphere.numIndices, ctx.UNSIGNED_SHORT, 0);
+ }
+
+ function drawPicture(ctx)
+ {
+ var now = new Date().getTime();
+ if (then != 0.0) {
+ g_crosFpsCounter.update(then, now - then, lastJSRenderTime);
+ }
+ then = now;
+
+ reshape(ctx);
+ ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT);
+
+ var startX = -layoutWidth/2;
+ var startY = -layoutHeight/2;
+ var startZ = 0;
+ var incX = layoutWidth / (numRowCols-1);
+ var incY = layoutHeight / (numRowCols-1);
+ var incZ = -5;
+
+ for (i = 0; i < numLayers; ++i) {
+ for (j = 0; j < numRowCols; ++j) {
+ for (k = 0; k < numRowCols; ++k) {
+ var index = i * numLayers * numRowCols + j * numRowCols + k;
+
+ drawOne(ctx, currentAngles[index],
+ startX + incX * k,
+ startY + incY * j,
+ startZ + incZ * i,
+ showEarth[index] ? 1 : 0.6, showEarth[index] ? earthTexture : marsTexture);
+
+ currentAngles[index] += incAngles[index];
+ if (currentAngles[index] > 360)
+ currentAngles[index] -= 360;
+ }
+ }
+ }
+
+ ctx.bindTexture(ctx.TEXTURE_2D, null);
+
+ framerate.snapshot();
+ lastJSRenderTime = new Date().getTime() - then;
+ }
+
+ function start()
+ {
+ var c = document.getElementById("example");
+ var w = Math.floor(window.innerWidth * 0.9);
+ var h = Math.floor(window.innerHeight * 0.9);
+
+ //c = WebGLDebugUtils.makeLostContextSimulatingCanvas(c);
+ // tell the simulator when to lose context.
+ //c.loseContextInNCalls(1500);
+
+ c.addEventListener('webglcontextlost', handleContextLost, false);
+ c.addEventListener('webglcontextrestored', handleContextRestored, false);
+
+ c.width = w;
+ c.height = h;
+
+ var ctx = init();
+ if (!ctx) {
+ return;
+ }
+
+ currentAngles = [ ];
+ incAngles = [ ];
+ showEarth = [ ];
+
+ for (var i = 0; i < numRowCols * numRowCols * numLayers; ++i) {
+ currentAngles[i] = 0;
+ incAngles[i] = Math.random() * (maxIncAngle - minIncAngle) + minIncAngle;
+ showEarth[i] = Math.random() > 0.5;
+ }
+
+ framerate = new Framerate("framerate");
+ var f = function() {
+ drawPicture(ctx)
+ requestId = window.requestAnimFrame(f, c);
+ };
+ f();
+
+ function handleContextLost(e) {
+ e.preventDefault();
+ clearLoadingImages();
+ if (requestId !== undefined) {
+ window.cancelAnimFrame(requestId);
+ requestId = undefined;
+ }
+ }
+
+ function handleContextRestored() {
+ init();
+ f();
+ }
+ }
+ </script>
+ <style type="text/css">
+ canvas {
+ border: 2px solid black;
+ }
+ </style>
+ </head>
+ <body onload="start()">
+ <canvas id="example">
+ There is supposed to be an example drawing here, but it's not important.
+ </canvas>
+ <div id="framerate"></div>
+ </body>
+</html>
diff --git a/client/deps/webgl_mpd/src/common/webgl-utils.js b/client/deps/webgl_mpd/src/common/webgl-utils.js
new file mode 100644
index 0000000..4f14f7f
--- /dev/null
+++ b/client/deps/webgl_mpd/src/common/webgl-utils.js
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/**
+ * @fileoverview This file contains functions every webgl program will need
+ * a version of one way or another.
+ *
+ * Instead of setting up a context manually it is recommended to
+ * use. This will check for success or failure. On failure it
+ * will attempt to present an approriate message to the user.
+ *
+ * gl = WebGLUtils.setupWebGL(canvas);
+ *
+ * For animated WebGL apps use of setTimeout or setInterval are
+ * discouraged. It is recommended you structure your rendering
+ * loop like this.
+ *
+ * function render() {
+ * window.requestAnimFrame(render, canvas);
+ *
+ * // do rendering
+ * ...
+ * }
+ * render();
+ *
+ * This will call your rendering function up to the refresh rate
+ * of your display but will stop rendering if your app is not
+ * visible.
+ */
+
+WebGLUtils = function() {
+
+/**
+ * Creates the HTLM for a failure message
+ * @param {string} canvasContainerId id of container of th
+ * canvas.
+ * @return {string} The html.
+ */
+var makeFailHTML = function(msg) {
+ return '' +
+ '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
+ '<td align="center">' +
+ '<div style="display: table-cell; vertical-align: middle;">' +
+ '<div style="">' + msg + '</div>' +
+ '</div>' +
+ '</td></tr></table>';
+};
+
+/**
+ * Mesasge for getting a webgl browser
+ * @type {string}
+ */
+var GET_A_WEBGL_BROWSER = '' +
+ 'This page requires a browser that supports WebGL.<br/>' +
+ '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
+
+/**
+ * Mesasge for need better hardware
+ * @type {string}
+ */
+var OTHER_PROBLEM = '' +
+ "It doesn't appear your computer can support WebGL.<br/>" +
+ '<a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>';
+
+/**
+ * Creates a webgl context. If creation fails it will
+ * change the contents of the container of the <canvas>
+ * tag to an error message with the correct links for WebGL.
+ * @param {Element} canvas. The canvas element to create a
+ * context from.
+ * @param {WebGLContextCreationAttirbutes} opt_attribs Any
+ * creation attributes you want to pass in.
+ * @return {WebGLRenderingContext} The created context.
+ */
+var setupWebGL = function(canvas, opt_attribs) {
+ function showLink(str) {
+ var container = canvas.parentNode;
+ if (container) {
+ container.innerHTML = makeFailHTML(str);
+ }
+ };
+
+ if (!window.WebGLRenderingContext) {
+ showLink(GET_A_WEBGL_BROWSER);
+ return null;
+ }
+
+ var context = create3DContext(canvas, opt_attribs);
+ if (!context) {
+ showLink(OTHER_PROBLEM);
+ }
+ return context;
+};
+
+/**
+ * Creates a webgl context.
+ * @param {!Canvas} canvas The canvas tag to get context
+ * from. If one is not passed in one will be created.
+ * @return {!WebGLContext} The created context.
+ */
+var create3DContext = function(canvas, opt_attribs) {
+ var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
+ var context = null;
+ for (var ii = 0; ii < names.length; ++ii) {
+ try {
+ context = canvas.getContext(names[ii], opt_attribs);
+ } catch(e) {}
+ if (context) {
+ break;
+ }
+ }
+ return context;
+}
+
+return {
+ create3DContext: create3DContext,
+ setupWebGL: setupWebGL
+};
+}();
+
+/**
+ * Provides requestAnimationFrame in a cross browser way.
+ */
+window.requestAnimFrame = (function() {
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
+ return window.setTimeout(callback, 1000/60);
+ };
+})();
+
+/**
+ * Provides cancelAnimationFrame in a cross browser way.
+ */
+window.cancelAnimFrame = (function() {
+ return window.cancelAnimationFrame ||
+ window.webkitCancelAnimationFrame ||
+ window.mozCancelAnimationFrame ||
+ window.oCancelAnimationFrame ||
+ window.msCancelAnimationFrame ||
+ window.clearTimeout;
+})();
+
+
diff --git a/client/deps/webgl_mpd/src/cros_fps.js b/client/deps/webgl_mpd/src/cros_fps.js
new file mode 100644
index 0000000..33d50f7
--- /dev/null
+++ b/client/deps/webgl_mpd/src/cros_fps.js
@@ -0,0 +1,42 @@
+crosFrameData = function(seq, startTime, frameElapsedTime, jsElapsedTime) {
+ this.seq = seq;
+ this.startTime = startTime;
+ this.frameElapsedTime = frameElapsedTime;
+ this.jsElapsedTime = jsElapsedTime;
+}
+
+crosFpsCounter = function() {
+ this.totalElapsedTime = 0.0;
+ this.totalRenderTime = 0.0;
+ this.totalFrames = 0;
+ this.buffer_size = 120;
+ this.frameDataBuf = new Array();
+}
+
+crosFpsCounter.prototype.update = function(
+ startTime, frameElapsedTime, jsElapsedTime) {
+ this.totalFrameElapsedTime += frameElapsedTime;
+ this.totalJSElapsedTime += jsElapsedTime;
+ this.frameDataBuf[this.totalFrames % this.buffer_size] = new crosFrameData(
+ this.totalFrames, startTime, frameElapsedTime, jsElapsedTime);
+ this.totalFrames += 1;
+}
+
+crosFpsCounter.prototype.reset = function() {
+ this.totalFrameElapsedTime = 0.0;
+ this.totalJSElapsedTime = 0.0;
+ this.totalFrames = 0;
+ this.frameDataBuf = new Array();
+}
+
+crosFpsCounter.prototype.getAvgFps = function() {
+ return this.totalFrames / this.totalFrameElapsedTime;
+}
+
+crosFpsCounter.prototype.getAvgRenderTime = function() {
+ return this.totalJSElapsedTime / this.totalFrames;
+}
+
+crosFpsCounter.prototype.getFrameData = function() {
+ return this.frameDataBuf;
+}
diff --git a/client/deps/webgl_mpd/src/debug/webgl-debug.js b/client/deps/webgl_mpd/src/debug/webgl-debug.js
new file mode 100644
index 0000000..1e68146
--- /dev/null
+++ b/client/deps/webgl_mpd/src/debug/webgl-debug.js
@@ -0,0 +1,900 @@
+/*
+** Copyright (c) 2012 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+// Various functions for helping debug WebGL apps.
+
+WebGLDebugUtils = function() {
+
+/**
+ * Wrapped logging function.
+ * @param {string} msg Message to log.
+ */
+var log = function(msg) {
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+};
+
+/**
+ * Wrapped error logging function.
+ * @param {string} msg Message to log.
+ */
+var error = function(msg) {
+ if (window.console && window.console.error) {
+ window.console.error(msg);
+ } else {
+ log(msg);
+ }
+};
+
+
+/**
+ * Which arguments are enums based on the number of arguments to the function.
+ * So
+ * 'texImage2D': {
+ * 9: { 0:true, 2:true, 6:true, 7:true },
+ * 6: { 0:true, 2:true, 3:true, 4:true },
+ * },
+ *
+ * means if there are 9 arguments then 6 and 7 are enums, if there are 6
+ * arguments 3 and 4 are enums
+ *
+ * @type {!Object.<number, !Object.<number, string>}}
+ */
+var glValidEnumContexts = {
+ // Generic setters and getters
+
+ 'enable': {1: { 0:true }},
+ 'disable': {1: { 0:true }},
+ 'getParameter': {1: { 0:true }},
+
+ // Rendering
+
+ 'drawArrays': {3:{ 0:true }},
+ 'drawElements': {4:{ 0:true, 2:true }},
+
+ // Shaders
+
+ 'createShader': {1: { 0:true }},
+ 'getShaderParameter': {2: { 1:true }},
+ 'getProgramParameter': {2: { 1:true }},
+ 'getShaderPrecisionFormat': {2: { 0: true, 1:true }},
+
+ // Vertex attributes
+
+ 'getVertexAttrib': {2: { 1:true }},
+ 'vertexAttribPointer': {6: { 2:true }},
+
+ // Textures
+
+ 'bindTexture': {2: { 0:true }},
+ 'activeTexture': {1: { 0:true }},
+ 'getTexParameter': {2: { 0:true, 1:true }},
+ 'texParameterf': {3: { 0:true, 1:true }},
+ 'texParameteri': {3: { 0:true, 1:true, 2:true }},
+ 'texImage2D': {
+ 9: { 0:true, 2:true, 6:true, 7:true },
+ 6: { 0:true, 2:true, 3:true, 4:true },
+ },
+ 'texSubImage2D': {
+ 9: { 0:true, 6:true, 7:true },
+ 7: { 0:true, 4:true, 5:true },
+ },
+ 'copyTexImage2D': {8: { 0:true, 2:true }},
+ 'copyTexSubImage2D': {8: { 0:true }},
+ 'generateMipmap': {1: { 0:true }},
+ 'compressedTexImage2D': {7: { 0: true, 2:true }},
+ 'compressedTexSubImage2D': {8: { 0: true, 6:true }},
+
+ // Buffer objects
+
+ 'bindBuffer': {2: { 0:true }},
+ 'bufferData': {3: { 0:true, 2:true }},
+ 'bufferSubData': {3: { 0:true }},
+ 'getBufferParameter': {2: { 0:true, 1:true }},
+
+ // Renderbuffers and framebuffers
+
+ 'pixelStorei': {2: { 0:true, 1:true }},
+ 'readPixels': {7: { 4:true, 5:true }},
+ 'bindRenderbuffer': {2: { 0:true }},
+ 'bindFramebuffer': {2: { 0:true }},
+ 'checkFramebufferStatus': {1: { 0:true }},
+ 'framebufferRenderbuffer': {4: { 0:true, 1:true, 2:true }},
+ 'framebufferTexture2D': {5: { 0:true, 1:true, 2:true }},
+ 'getFramebufferAttachmentParameter': {3: { 0:true, 1:true, 2:true }},
+ 'getRenderbufferParameter': {2: { 0:true, 1:true }},
+ 'renderbufferStorage': {4: { 0:true, 1:true }},
+
+ // Frame buffer operations (clear, blend, depth test, stencil)
+
+ 'clear': {1: { 0:true }},
+ 'depthFunc': {1: { 0:true }},
+ 'blendFunc': {2: { 0:true, 1:true }},
+ 'blendFuncSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
+ 'blendEquation': {1: { 0:true }},
+ 'blendEquationSeparate': {2: { 0:true, 1:true }},
+ 'stencilFunc': {3: { 0:true }},
+ 'stencilFuncSeparate': {4: { 0:true, 1:true }},
+ 'stencilMaskSeparate': {2: { 0:true }},
+ 'stencilOp': {3: { 0:true, 1:true, 2:true }},
+ 'stencilOpSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
+
+ // Culling
+
+ 'cullFace': {1: { 0:true }},
+ 'frontFace': {1: { 0:true }},
+};
+
+/**
+ * Map of numbers to names.
+ * @type {Object}
+ */
+var glEnums = null;
+
+/**
+ * Initializes this module. Safe to call more than once.
+ * @param {!WebGLRenderingContext} ctx A WebGL context. If
+ * you have more than one context it doesn't matter which one
+ * you pass in, it is only used to pull out constants.
+ */
+function init(ctx) {
+ if (glEnums == null) {
+ glEnums = { };
+ for (var propertyName in ctx) {
+ if (typeof ctx[propertyName] == 'number') {
+ glEnums[ctx[propertyName]] = propertyName;
+ }
+ }
+ }
+}
+
+/**
+ * Checks the utils have been initialized.
+ */
+function checkInit() {
+ if (glEnums == null) {
+ throw 'WebGLDebugUtils.init(ctx) not called';
+ }
+}
+
+/**
+ * Returns true or false if value matches any WebGL enum
+ * @param {*} value Value to check if it might be an enum.
+ * @return {boolean} True if value matches one of the WebGL defined enums
+ */
+function mightBeEnum(value) {
+ checkInit();
+ return (glEnums[value] !== undefined);
+}
+
+/**
+ * Gets an string version of an WebGL enum.
+ *
+ * Example:
+ * var str = WebGLDebugUtil.glEnumToString(ctx.getError());
+ *
+ * @param {number} value Value to return an enum for
+ * @return {string} The string version of the enum.
+ */
+function glEnumToString(value) {
+ checkInit();
+ var name = glEnums[value];
+ return (name !== undefined) ? ("gl." + name) :
+ ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + "");
+}
+
+/**
+ * Returns the string version of a WebGL argument.
+ * Attempts to convert enum arguments to strings.
+ * @param {string} functionName the name of the WebGL function.
+ * @param {number} numArgs the number of arguments passed to the function.
+ * @param {number} argumentIndx the index of the argument.
+ * @param {*} value The value of the argument.
+ * @return {string} The value as a string.
+ */
+function glFunctionArgToString(functionName, numArgs, argumentIndex, value) {
+ var funcInfo = glValidEnumContexts[functionName];
+ if (funcInfo !== undefined) {
+ var funcInfo = funcInfo[numArgs];
+ if (funcInfo !== undefined) {
+ if (funcInfo[argumentIndex]) {
+ return glEnumToString(value);
+ }
+ }
+ }
+ if (value === null) {
+ return "null";
+ } else if (value === undefined) {
+ return "undefined";
+ } else {
+ return value.toString();
+ }
+}
+
+/**
+ * Converts the arguments of a WebGL function to a string.
+ * Attempts to convert enum arguments to strings.
+ *
+ * @param {string} functionName the name of the WebGL function.
+ * @param {number} args The arguments.
+ * @return {string} The arguments as a string.
+ */
+function glFunctionArgsToString(functionName, args) {
+ // apparently we can't do args.join(",");
+ var argStr = "";
+ var numArgs = args.length;
+ for (var ii = 0; ii < numArgs; ++ii) {
+ argStr += ((ii == 0) ? '' : ', ') +
+ glFunctionArgToString(functionName, numArgs, ii, args[ii]);
+ }
+ return argStr;
+};
+
+
+function makePropertyWrapper(wrapper, original, propertyName) {
+ //log("wrap prop: " + propertyName);
+ wrapper.__defineGetter__(propertyName, function() {
+ return original[propertyName];
+ });
+ // TODO(gmane): this needs to handle properties that take more than
+ // one value?
+ wrapper.__defineSetter__(propertyName, function(value) {
+ //log("set: " + propertyName);
+ original[propertyName] = value;
+ });
+}
+
+// Makes a function that calls a function on another object.
+function makeFunctionWrapper(original, functionName) {
+ //log("wrap fn: " + functionName);
+ var f = original[functionName];
+ return function() {
+ //log("call: " + functionName);
+ var result = f.apply(original, arguments);
+ return result;
+ };
+}
+
+/**
+ * Given a WebGL context returns a wrapped context that calls
+ * gl.getError after every command and calls a function if the
+ * result is not gl.NO_ERROR.
+ *
+ * @param {!WebGLRenderingContext} ctx The webgl context to
+ * wrap.
+ * @param {!function(err, funcName, args): void} opt_onErrorFunc
+ * The function to call when gl.getError returns an
+ * error. If not specified the default function calls
+ * console.log with a message.
+ * @param {!function(funcName, args): void} opt_onFunc The
+ * function to call when each webgl function is called.
+ * You can use this to log all calls for example.
+ */
+function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc) {
+ init(ctx);
+ opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
+ // apparently we can't do args.join(",");
+ var argStr = "";
+ var numArgs = args.length;
+ for (var ii = 0; ii < numArgs; ++ii) {
+ argStr += ((ii == 0) ? '' : ', ') +
+ glFunctionArgToString(functionName, numArgs, ii, args[ii]);
+ }
+ error("WebGL error "+ glEnumToString(err) + " in "+ functionName +
+ "(" + argStr + ")");
+ };
+
+ // Holds booleans for each GL error so after we get the error ourselves
+ // we can still return it to the client app.
+ var glErrorShadow = { };
+
+ // Makes a function that calls a WebGL function and then calls getError.
+ function makeErrorWrapper(ctx, functionName) {
+ return function() {
+ if (opt_onFunc) {
+ opt_onFunc(functionName, arguments);
+ }
+ var result = ctx[functionName].apply(ctx, arguments);
+ var err = ctx.getError();
+ if (err != 0) {
+ glErrorShadow[err] = true;
+ opt_onErrorFunc(err, functionName, arguments);
+ }
+ return result;
+ };
+ }
+
+ // Make a an object that has a copy of every property of the WebGL context
+ // but wraps all functions.
+ var wrapper = {};
+ for (var propertyName in ctx) {
+ if (typeof ctx[propertyName] == 'function') {
+ wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
+ } else {
+ makePropertyWrapper(wrapper, ctx, propertyName);
+ }
+ }
+
+ // Override the getError function with one that returns our saved results.
+ wrapper.getError = function() {
+ for (var err in glErrorShadow) {
+ if (glErrorShadow.hasOwnProperty(err)) {
+ if (glErrorShadow[err]) {
+ glErrorShadow[err] = false;
+ return err;
+ }
+ }
+ }
+ return ctx.NO_ERROR;
+ };
+
+ return wrapper;
+}
+
+function resetToInitialState(ctx) {
+ var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
+ var tmp = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp);
+ for (var ii = 0; ii < numAttribs; ++ii) {
+ ctx.disableVertexAttribArray(ii);
+ ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0);
+ ctx.vertexAttrib1f(ii, 0);
+ }
+ ctx.deleteBuffer(tmp);
+
+ var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
+ for (var ii = 0; ii < numTextureUnits; ++ii) {
+ ctx.activeTexture(ctx.TEXTURE0 + ii);
+ ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null);
+ ctx.bindTexture(ctx.TEXTURE_2D, null);
+ }
+
+ ctx.activeTexture(ctx.TEXTURE0);
+ ctx.useProgram(null);
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
+ ctx.bindFramebuffer(ctx.FRAMEBUFFER, null);
+ ctx.bindRenderbuffer(ctx.RENDERBUFFER, null);
+ ctx.disable(ctx.BLEND);
+ ctx.disable(ctx.CULL_FACE);
+ ctx.disable(ctx.DEPTH_TEST);
+ ctx.disable(ctx.DITHER);
+ ctx.disable(ctx.SCISSOR_TEST);
+ ctx.blendColor(0, 0, 0, 0);
+ ctx.blendEquation(ctx.FUNC_ADD);
+ ctx.blendFunc(ctx.ONE, ctx.ZERO);
+ ctx.clearColor(0, 0, 0, 0);
+ ctx.clearDepth(1);
+ ctx.clearStencil(-1);
+ ctx.colorMask(true, true, true, true);
+ ctx.cullFace(ctx.BACK);
+ ctx.depthFunc(ctx.LESS);
+ ctx.depthMask(true);
+ ctx.depthRange(0, 1);
+ ctx.frontFace(ctx.CCW);
+ ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE);
+ ctx.lineWidth(1);
+ ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4);
+ ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4);
+ ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false);
+ ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ // TODO: Delete this IF.
+ if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) {
+ ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL);
+ }
+ ctx.polygonOffset(0, 0);
+ ctx.sampleCoverage(1, false);
+ ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF);
+ ctx.stencilMask(0xFFFFFFFF);
+ ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP);
+ ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
+
+ // TODO: This should NOT be needed but Firefox fails with 'hint'
+ while(ctx.getError());
+}
+
+function makeLostContextSimulatingCanvas(canvas) {
+ var unwrappedContext_;
+ var wrappedContext_;
+ var onLost_ = [];
+ var onRestored_ = [];
+ var wrappedContext_ = {};
+ var contextId_ = 1;
+ var contextLost_ = false;
+ var resourceId_ = 0;
+ var resourceDb_ = [];
+ var numCallsToLoseContext_ = 0;
+ var numCalls_ = 0;
+ var canRestore_ = false;
+ var restoreTimeout_ = 0;
+
+ // Holds booleans for each GL error so can simulate errors.
+ var glErrorShadow_ = { };
+
+ canvas.getContext = function(f) {
+ return function() {
+ var ctx = f.apply(canvas, arguments);
+ // Did we get a context and is it a WebGL context?
+ if (ctx instanceof WebGLRenderingContext) {
+ if (ctx != unwrappedContext_) {
+ if (unwrappedContext_) {
+ throw "got different context"
+ }
+ unwrappedContext_ = ctx;
+ wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_);
+ }
+ return wrappedContext_;
+ }
+ return ctx;
+ }
+ }(canvas.getContext);
+
+ function wrapEvent(listener) {
+ if (typeof(listener) == "function") {
+ return listener;
+ } else {
+ return function(info) {
+ listener.handleEvent(info);
+ }
+ }
+ }
+
+ var addOnContextLostListener = function(listener) {
+ onLost_.push(wrapEvent(listener));
+ };
+
+ var addOnContextRestoredListener = function(listener) {
+ onRestored_.push(wrapEvent(listener));
+ };
+
+
+ function wrapAddEventListener(canvas) {
+ var f = canvas.addEventListener;
+ canvas.addEventListener = function(type, listener, bubble) {
+ switch (type) {
+ case 'webglcontextlost':
+ addOnContextLostListener(listener);
+ break;
+ case 'webglcontextrestored':
+ addOnContextRestoredListener(listener);
+ break;
+ default:
+ f.apply(canvas, arguments);
+ }
+ };
+ }
+
+ wrapAddEventListener(canvas);
+
+ canvas.loseContext = function() {
+ if (!contextLost_) {
+ contextLost_ = true;
+ numCallsToLoseContext_ = 0;
+ ++contextId_;
+ while (unwrappedContext_.getError());
+ clearErrors();
+ glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true;
+ var event = makeWebGLContextEvent("context lost");
+ var callbacks = onLost_.slice();
+ setTimeout(function() {
+ //log("numCallbacks:" + callbacks.length);
+ for (var ii = 0; ii < callbacks.length; ++ii) {
+ //log("calling callback:" + ii);
+ callbacks[ii](event);
+ }
+ if (restoreTimeout_ >= 0) {
+ setTimeout(function() {
+ canvas.restoreContext();
+ }, restoreTimeout_);
+ }
+ }, 0);
+ }
+ };
+
+ canvas.restoreContext = function() {
+ if (contextLost_) {
+ if (onRestored_.length) {
+ setTimeout(function() {
+ if (!canRestore_) {
+ throw "can not restore. webglcontestlost listener did not call event.preventDefault";
+ }
+ freeResources();
+ resetToInitialState(unwrappedContext_);
+ contextLost_ = false;
+ numCalls_ = 0;
+ canRestore_ = false;
+ var callbacks = onRestored_.slice();
+ var event = makeWebGLContextEvent("context restored");
+ for (var ii = 0; ii < callbacks.length; ++ii) {
+ callbacks[ii](event);
+ }
+ }, 0);
+ }
+ }
+ };
+
+ canvas.loseContextInNCalls = function(numCalls) {
+ if (contextLost_) {
+ throw "You can not ask a lost contet to be lost";
+ }
+ numCallsToLoseContext_ = numCalls_ + numCalls;
+ };
+
+ canvas.getNumCalls = function() {
+ return numCalls_;
+ };
+
+ canvas.setRestoreTimeout = function(timeout) {
+ restoreTimeout_ = timeout;
+ };
+
+ function isWebGLObject(obj) {
+ //return false;
+ return (obj instanceof WebGLBuffer ||
+ obj instanceof WebGLFramebuffer ||
+ obj instanceof WebGLProgram ||
+ obj instanceof WebGLRenderbuffer ||
+ obj instanceof WebGLShader ||
+ obj instanceof WebGLTexture);
+ }
+
+ function checkResources(args) {
+ for (var ii = 0; ii < args.length; ++ii) {
+ var arg = args[ii];
+ if (isWebGLObject(arg)) {
+ return arg.__webglDebugContextLostId__ == contextId_;
+ }
+ }
+ return true;
+ }
+
+ function clearErrors() {
+ var k = Object.keys(glErrorShadow_);
+ for (var ii = 0; ii < k.length; ++ii) {
+ delete glErrorShadow_[k];
+ }
+ }
+
+ function loseContextIfTime() {
+ ++numCalls_;
+ if (!contextLost_) {
+ if (numCallsToLoseContext_ == numCalls_) {
+ canvas.loseContext();
+ }
+ }
+ }
+
+ // Makes a function that simulates WebGL when out of context.
+ function makeLostContextFunctionWrapper(ctx, functionName) {
+ var f = ctx[functionName];
+ return function() {
+ // log("calling:" + functionName);
+ // Only call the functions if the context is not lost.
+ loseContextIfTime();
+ if (!contextLost_) {
+ //if (!checkResources(arguments)) {
+ // glErrorShadow_[wrappedContext_.INVALID_OPERATION] = true;
+ // return;
+ //}
+ var result = f.apply(ctx, arguments);
+ return result;
+ }
+ };
+ }
+
+ function freeResources() {
+ for (var ii = 0; ii < resourceDb_.length; ++ii) {
+ var resource = resourceDb_[ii];
+ if (resource instanceof WebGLBuffer) {
+ unwrappedContext_.deleteBuffer(resource);
+ } else if (resource instanceof WebGLFramebuffer) {
+ unwrappedContext_.deleteFramebuffer(resource);
+ } else if (resource instanceof WebGLProgram) {
+ unwrappedContext_.deleteProgram(resource);
+ } else if (resource instanceof WebGLRenderbuffer) {
+ unwrappedContext_.deleteRenderbuffer(resource);
+ } else if (resource instanceof WebGLShader) {
+ unwrappedContext_.deleteShader(resource);
+ } else if (resource instanceof WebGLTexture) {
+ unwrappedContext_.deleteTexture(resource);
+ }
+ }
+ }
+
+ function makeWebGLContextEvent(statusMessage) {
+ return {
+ statusMessage: statusMessage,
+ preventDefault: function() {
+ canRestore_ = true;
+ }
+ };
+ }
+
+ return canvas;
+
+ function makeLostContextSimulatingContext(ctx) {
+ // copy all functions and properties to wrapper
+ for (var propertyName in ctx) {
+ if (typeof ctx[propertyName] == 'function') {
+ wrappedContext_[propertyName] = makeLostContextFunctionWrapper(
+ ctx, propertyName);
+ } else {
+ makePropertyWrapper(wrappedContext_, ctx, propertyName);
+ }
+ }
+
+ // Wrap a few functions specially.
+ wrappedContext_.getError = function() {
+ loseContextIfTime();
+ if (!contextLost_) {
+ var err;
+ while (err = unwrappedContext_.getError()) {
+ glErrorShadow_[err] = true;
+ }
+ }
+ for (var err in glErrorShadow_) {
+ if (glErrorShadow_[err]) {
+ delete glErrorShadow_[err];
+ return err;
+ }
+ }
+ return wrappedContext_.NO_ERROR;
+ };
+
+ var creationFunctions = [
+ "createBuffer",
+ "createFramebuffer",
+ "createProgram",
+ "createRenderbuffer",
+ "createShader",
+ "createTexture"
+ ];
+ for (var ii = 0; ii < creationFunctions.length; ++ii) {
+ var functionName = creationFunctions[ii];
+ wrappedContext_[functionName] = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return null;
+ }
+ var obj = f.apply(ctx, arguments);
+ obj.__webglDebugContextLostId__ = contextId_;
+ resourceDb_.push(obj);
+ return obj;
+ };
+ }(ctx[functionName]);
+ }
+
+ var functionsThatShouldReturnNull = [
+ "getActiveAttrib",
+ "getActiveUniform",
+ "getBufferParameter",
+ "getContextAttributes",
+ "getAttachedShaders",
+ "getFramebufferAttachmentParameter",
+ "getParameter",
+ "getProgramParameter",
+ "getProgramInfoLog",
+ "getRenderbufferParameter",
+ "getShaderParameter",
+ "getShaderInfoLog",
+ "getShaderSource",
+ "getTexParameter",
+ "getUniform",
+ "getUniformLocation",
+ "getVertexAttrib"
+ ];
+ for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) {
+ var functionName = functionsThatShouldReturnNull[ii];
+ wrappedContext_[functionName] = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return null;
+ }
+ return f.apply(ctx, arguments);
+ }
+ }(wrappedContext_[functionName]);
+ }
+
+ var isFunctions = [
+ "isBuffer",
+ "isEnabled",
+ "isFramebuffer",
+ "isProgram",
+ "isRenderbuffer",
+ "isShader",
+ "isTexture"
+ ];
+ for (var ii = 0; ii < isFunctions.length; ++ii) {
+ var functionName = isFunctions[ii];
+ wrappedContext_[functionName] = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return false;
+ }
+ return f.apply(ctx, arguments);
+ }
+ }(wrappedContext_[functionName]);
+ }
+
+ wrappedContext_.checkFramebufferStatus = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return wrappedContext_.FRAMEBUFFER_UNSUPPORTED;
+ }
+ return f.apply(ctx, arguments);
+ };
+ }(wrappedContext_.checkFramebufferStatus);
+
+ wrappedContext_.getAttribLocation = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return -1;
+ }
+ return f.apply(ctx, arguments);
+ };
+ }(wrappedContext_.getAttribLocation);
+
+ wrappedContext_.getVertexAttribOffset = function(f) {
+ return function() {
+ loseContextIfTime();
+ if (contextLost_) {
+ return 0;
+ }
+ return f.apply(ctx, arguments);
+ };
+ }(wrappedContext_.getVertexAttribOffset);
+
+ wrappedContext_.isContextLost = function() {
+ return contextLost_;
+ };
+
+ return wrappedContext_;
+ }
+}
+
+return {
+ /**
+ * Initializes this module. Safe to call more than once.
+ * @param {!WebGLRenderingContext} ctx A WebGL context. If
+ }
+ * you have more than one context it doesn't matter which one
+ * you pass in, it is only used to pull out constants.
+ */
+ 'init': init,
+
+ /**
+ * Returns true or false if value matches any WebGL enum
+ * @param {*} value Value to check if it might be an enum.
+ * @return {boolean} True if value matches one of the WebGL defined enums
+ */
+ 'mightBeEnum': mightBeEnum,
+
+ /**
+ * Gets an string version of an WebGL enum.
+ *
+ * Example:
+ * WebGLDebugUtil.init(ctx);
+ * var str = WebGLDebugUtil.glEnumToString(ctx.getError());
+ *
+ * @param {number} value Value to return an enum for
+ * @return {string} The string version of the enum.
+ */
+ 'glEnumToString': glEnumToString,
+
+ /**
+ * Converts the argument of a WebGL function to a string.
+ * Attempts to convert enum arguments to strings.
+ *
+ * Example:
+ * WebGLDebugUtil.init(ctx);
+ * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 2, 0, gl.TEXTURE_2D);
+ *
+ * would return 'TEXTURE_2D'
+ *
+ * @param {string} functionName the name of the WebGL function.
+ * @param {number} numArgs The number of arguments
+ * @param {number} argumentIndx the index of the argument.
+ * @param {*} value The value of the argument.
+ * @return {string} The value as a string.
+ */
+ 'glFunctionArgToString': glFunctionArgToString,
+
+ /**
+ * Converts the arguments of a WebGL function to a string.
+ * Attempts to convert enum arguments to strings.
+ *
+ * @param {string} functionName the name of the WebGL function.
+ * @param {number} args The arguments.
+ * @return {string} The arguments as a string.
+ */
+ 'glFunctionArgsToString': glFunctionArgsToString,
+
+ /**
+ * Given a WebGL context returns a wrapped context that calls
+ * gl.getError after every command and calls a function if the
+ * result is not NO_ERROR.
+ *
+ * You can supply your own function if you want. For example, if you'd like
+ * an exception thrown on any GL error you could do this
+ *
+ * function throwOnGLError(err, funcName, args) {
+ * throw WebGLDebugUtils.glEnumToString(err) +
+ * " was caused by call to " + funcName;
+ * };
+ *
+ * ctx = WebGLDebugUtils.makeDebugContext(
+ * canvas.getContext("webgl"), throwOnGLError);
+ *
+ * @param {!WebGLRenderingContext} ctx The webgl context to wrap.
+ * @param {!function(err, funcName, args): void} opt_onErrorFunc The function
+ * to call when gl.getError returns an error. If not specified the default
+ * function calls console.log with a message.
+ * @param {!function(funcName, args): void} opt_onFunc The
+ * function to call when each webgl function is called. You
+ * can use this to log all calls for example.
+ */
+ 'makeDebugContext': makeDebugContext,
+
+ /**
+ * Given a canvas element returns a wrapped canvas element that will
+ * simulate lost context. The canvas returned adds the following functions.
+ *
+ * loseContext:
+ * simulates a lost context event.
+ *
+ * restoreContext:
+ * simulates the context being restored.
+ *
+ * lostContextInNCalls:
+ * loses the context after N gl calls.
+ *
+ * getNumCalls:
+ * tells you how many gl calls there have been so far.
+ *
+ * setRestoreTimeout:
+ * sets the number of milliseconds until the context is restored
+ * after it has been lost. Defaults to 0. Pass -1 to prevent
+ * automatic restoring.
+ *
+ * @param {!Canvas} canvas The canvas element to wrap.
+ */
+ 'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas,
+
+ /**
+ * Resets a context to the initial state.
+ * @param {!WebGLRenderingContext} ctx The webgl context to
+ * reset.
+ */
+ 'resetToInitialState': resetToInitialState
+};
+
+}();
+
diff --git a/client/deps/webgl_mpd/src/resources/J3DI.js b/client/deps/webgl_mpd/src/resources/J3DI.js
new file mode 100644
index 0000000..597417b
--- /dev/null
+++ b/client/deps/webgl_mpd/src/resources/J3DI.js
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// initWebGL
+//
+// Initialize the Canvas element with the passed name as a WebGL object and return the
+// WebGLRenderingContext.
+function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
+{
+ var canvas = document.getElementById(canvasName);
+ return gl = WebGLUtils.setupWebGL(canvas);
+}
+
+function log(msg) {
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+}
+
+// Load shaders with the passed names and create a program with them. Return this program
+// in the 'program' property of the returned context.
+//
+// For each string in the passed attribs array, bind an attrib with that name at that index.
+// Once the attribs are bound, link the program and then use it.
+//
+// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
+// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
+//
+// A console function is added to the context: console(string). This can be replaced
+// by the caller. By default, it maps to the window.console() function on WebKit and to
+// an empty function on other browsers.
+//
+function simpleSetup(gl, vshader, fshader, attribs, clearColor, clearDepth)
+{
+ // create our shaders
+ var vertexShader = loadShader(gl, vshader);
+ var fragmentShader = loadShader(gl, fshader);
+
+ // Create the program object
+ var program = gl.createProgram();
+
+ // Attach our two shaders to the program
+ gl.attachShader (program, vertexShader);
+ gl.attachShader (program, fragmentShader);
+
+ // Bind attributes
+ for (var i = 0; i < attribs.length; ++i)
+ gl.bindAttribLocation (program, i, attribs[i]);
+
+ // Link the program
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked && !gl.isContextLost()) {
+ // something went wrong with the link
+ var error = gl.getProgramInfoLog (program);
+ log("Error in program linking:"+error);
+
+ gl.deleteProgram(program);
+ gl.deleteProgram(fragmentShader);
+ gl.deleteProgram(vertexShader);
+
+ return null;
+ }
+
+ gl.useProgram(program);
+
+ gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
+ gl.clearDepth(clearDepth);
+
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ return program;
+}
+
+//
+// loadShader
+//
+// 'shaderId' is the id of a <script> element containing the shader source string.
+// Load this shader and return the WebGLShader object corresponding to it.
+//
+function loadShader(ctx, shaderId)
+{
+ var shaderScript = document.getElementById(shaderId);
+ if (!shaderScript) {
+ log("*** Error: shader script '"+shaderId+"' not found");
+ return null;
+ }
+
+ if (shaderScript.type == "x-shader/x-vertex")
+ var shaderType = ctx.VERTEX_SHADER;
+ else if (shaderScript.type == "x-shader/x-fragment")
+ var shaderType = ctx.FRAGMENT_SHADER;
+ else {
+ log("*** Error: shader script '"+shaderId+"' of undefined type '"+shaderScript.type+"'");
+ return null;
+ }
+
+ // Create the shader object
+ var shader = ctx.createShader(shaderType);
+
+ // Load the shader source
+ ctx.shaderSource(shader, shaderScript.text);
+
+ // Compile the shader
+ ctx.compileShader(shader);
+
+ // Check the compile status
+ var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
+ if (!compiled && !ctx.isContextLost()) {
+ // Something went wrong during compilation; get the error
+ var error = ctx.getShaderInfoLog(shader);
+ log("*** Error compiling shader '"+shaderId+"':"+error);
+ ctx.deleteShader(shader);
+ return null;
+ }
+
+ return shader;
+}
+
+//
+// makeBox
+//
+// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+// normalObject WebGLBuffer object for normals
+// texCoordObject WebGLBuffer object for texCoords
+// vertexObject WebGLBuffer object for vertices
+// indexObject WebGLBuffer object for indices
+// numIndices The number of indices in the indexObject
+//
+function makeBox(ctx)
+{
+ // box
+ // v6----- v5
+ // /| /|
+ // v1------v0|
+ // | | | |
+ // | |v7---|-|v4
+ // |/ |/
+ // v2------v3
+ //
+ // vertex coords array
+ var vertices = new Float32Array(
+ [ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0-v1-v2-v3 front
+ 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0-v3-v4-v5 right
+ 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0-v5-v6-v1 top
+ -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1-v6-v7-v2 left
+ -1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7-v4-v3-v2 bottom
+ 1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 ] // v4-v7-v6-v5 back
+ );
+
+ // normal array
+ var normals = new Float32Array(
+ [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front
+ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
+ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top
+ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left
+ 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3-v2 bottom
+ 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 ] // v4-v7-v6-v5 back
+ );
+
+
+ // texCoord array
+ var texCoords = new Float32Array(
+ [ 1, 1, 0, 1, 0, 0, 1, 0, // v0-v1-v2-v3 front
+ 0, 1, 0, 0, 1, 0, 1, 1, // v0-v3-v4-v5 right
+ 1, 0, 1, 1, 0, 1, 0, 0, // v0-v5-v6-v1 top
+ 1, 1, 0, 1, 0, 0, 1, 0, // v1-v6-v7-v2 left
+ 0, 0, 1, 0, 1, 1, 0, 1, // v7-v4-v3-v2 bottom
+ 0, 0, 1, 0, 1, 1, 0, 1 ] // v4-v7-v6-v5 back
+ );
+
+ // index array
+ var indices = new Uint8Array(
+ [ 0, 1, 2, 0, 2, 3, // front
+ 4, 5, 6, 4, 6, 7, // right
+ 8, 9,10, 8,10,11, // top
+ 12,13,14, 12,14,15, // left
+ 16,17,18, 16,18,19, // bottom
+ 20,21,22, 20,22,23 ] // back
+ );
+
+ var retval = { };
+
+ retval.normalObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
+
+ retval.texCoordObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
+
+ retval.vertexObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
+
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
+
+ retval.indexObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+ ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
+
+ retval.numIndices = indices.length;
+
+ return retval;
+}
+
+//
+// makeSphere
+//
+// Create a sphere with the passed number of latitude and longitude bands and the passed radius.
+// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
+// Return an object with the following properties:
+//
+// normalObject WebGLBuffer object for normals
+// texCoordObject WebGLBuffer object for texCoords
+// vertexObject WebGLBuffer object for vertices
+// indexObject WebGLBuffer object for indices
+// numIndices The number of indices in the indexObject
+//
+function makeSphere(ctx, radius, lats, longs)
+{
+ var geometryData = [ ];
+ var normalData = [ ];
+ var texCoordData = [ ];
+ var indexData = [ ];
+
+ for (var latNumber = 0; latNumber <= lats; ++latNumber) {
+ for (var longNumber = 0; longNumber <= longs; ++longNumber) {
+ var theta = latNumber * Math.PI / lats;
+ var phi = longNumber * 2 * Math.PI / longs;
+ var sinTheta = Math.sin(theta);
+ var sinPhi = Math.sin(phi);
+ var cosTheta = Math.cos(theta);
+ var cosPhi = Math.cos(phi);
+
+ var x = cosPhi * sinTheta;
+ var y = cosTheta;
+ var z = sinPhi * sinTheta;
+ var u = 1-(longNumber/longs);
+ var v = latNumber/lats;
+
+ normalData.push(x);
+ normalData.push(y);
+ normalData.push(z);
+ texCoordData.push(u);
+ texCoordData.push(v);
+ geometryData.push(radius * x);
+ geometryData.push(radius * y);
+ geometryData.push(radius * z);
+ }
+ }
+
+ for (var latNumber = 0; latNumber < lats; ++latNumber) {
+ for (var longNumber = 0; longNumber < longs; ++longNumber) {
+ var first = (latNumber * (longs+1)) + longNumber;
+ var second = first + longs + 1;
+ indexData.push(first);
+ indexData.push(second);
+ indexData.push(first+1);
+
+ indexData.push(second);
+ indexData.push(second+1);
+ indexData.push(first+1);
+ }
+ }
+
+ var retval = { };
+
+ retval.normalObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW);
+
+ retval.texCoordObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW);
+
+ retval.vertexObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
+ ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW);
+
+ retval.numIndices = indexData.length;
+ retval.indexObject = ctx.createBuffer();
+ ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
+ ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW);
+
+ return retval;
+}
+
+// Array of Objects curently loading
+var g_loadingObjects = [];
+
+// Clears all the Objects currently loading.
+// This is used to handle context lost events.
+function clearLoadingObjects() {
+ for (var ii = 0; ii < g_loadingObjects.length; ++ii) {
+ g_loadingObjects[ii].onreadystatechange = undefined;
+ }
+ g_loadingObjects = [];
+}
+
+//
+// loadObj
+//
+// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
+// When the object load is complete, the 'loaded' property becomes true and the following
+// properties are set:
+//
+// normalObject WebGLBuffer object for normals
+// texCoordObject WebGLBuffer object for texCoords
+// vertexObject WebGLBuffer object for vertices
+// indexObject WebGLBuffer object for indices
+// numIndices The number of indices in the indexObject
+//
+function loadObj(ctx, url)
+{
+ var obj = { loaded : false };
+ obj.ctx = ctx;
+ var req = new XMLHttpRequest();
+ req.obj = obj;
+ g_loadingObjects.push(req);
+ req.onreadystatechange = function () { processLoadObj(req) };
+ req.open("GET", url, true);
+ req.send(null);
+ return obj;
+}
+
+function processLoadObj(req)
+{
+ log("req="+req)
+ // only if req shows "complete"
+ if (req.readyState == 4) {
+ g_loadingObjects.splice(g_loadingObjects.indexOf(req), 1);
+ doLoadObj(req.obj, req.responseText);
+ }
+}
+
+function doLoadObj(obj, text)
+{
+ vertexArray = [ ];
+ normalArray = [ ];
+ textureArray = [ ];
+ indexArray = [ ];
+
+ var vertex = [ ];
+ var normal = [ ];
+ var texture = [ ];
+ var facemap = { };
+ var index = 0;
+
+ // This is a map which associates a range of indices with a name
+ // The name comes from the 'g' tag (of the form "g NAME"). Indices
+ // are part of one group until another 'g' tag is seen. If any indices
+ // come before a 'g' tag, it is given the group name "_unnamed"
+ // 'group' is an object whose property names are the group name and
+ // whose value is a 2 element array with [<first index>, <num indices>]
+ var groups = { };
+ var currentGroup = [-1, 0];
+ groups["_unnamed"] = currentGroup;
+
+ var lines = text.split("\n");
+ for (var lineIndex in lines) {
+ var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
+
+ // ignore comments
+ if (line[0] == "#")
+ continue;
+
+ var array = line.split(" ");
+ if (array[0] == "g") {
+ // new group
+ currentGroup = [indexArray.length, 0];
+ groups[array[1]] = currentGroup;
+ }
+ else if (array[0] == "v") {
+ // vertex
+ vertex.push(parseFloat(array[1]));
+ vertex.push(parseFloat(array[2]));
+ vertex.push(parseFloat(array[3]));
+ }
+ else if (array[0] == "vt") {
+ // normal
+ texture.push(parseFloat(array[1]));
+ texture.push(parseFloat(array[2]));
+ }
+ else if (array[0] == "vn") {
+ // normal
+ normal.push(parseFloat(array[1]));
+ normal.push(parseFloat(array[2]));
+ normal.push(parseFloat(array[3]));
+ }
+ else if (array[0] == "f") {
+ // face
+ if (array.length != 4) {
+ log("*** Error: face '"+line+"' not handled");
+ continue;
+ }
+
+ for (var i = 1; i < 4; ++i) {
+ if (!(array[i] in facemap)) {
+ // add a new entry to the map and arrays
+ var f = array[i].split("/");
+ var vtx, nor, tex;
+
+ if (f.length == 1) {
+ vtx = parseInt(f[0]) - 1;
+ nor = vtx;
+ tex = vtx;
+ }
+ else if (f.length = 3) {
+ vtx = parseInt(f[0]) - 1;
+ tex = parseInt(f[1]) - 1;
+ nor = parseInt(f[2]) - 1;
+ }
+ else {
+ obj.ctx.console.log("*** Error: did not understand face '"+array[i]+"'");
+ return null;
+ }
+
+ // do the vertices
+ var x = 0;
+ var y = 0;
+ var z = 0;
+ if (vtx * 3 + 2 < vertex.length) {
+ x = vertex[vtx*3];
+ y = vertex[vtx*3+1];
+ z = vertex[vtx*3+2];
+ }
+ vertexArray.push(x);
+ vertexArray.push(y);
+ vertexArray.push(z);
+
+ // do the textures
+ x = 0;
+ y = 0;
+ if (tex * 2 + 1 < texture.length) {
+ x = texture[tex*2];
+ y = texture[tex*2+1];
+ }
+ textureArray.push(x);
+ textureArray.push(y);
+
+ // do the normals
+ x = 0;
+ y = 0;
+ z = 1;
+ if (nor * 3 + 2 < normal.length) {
+ x = normal[nor*3];
+ y = normal[nor*3+1];
+ z = normal[nor*3+2];
+ }
+ normalArray.push(x);
+ normalArray.push(y);
+ normalArray.push(z);
+
+ facemap[array[i]] = index++;
+ }
+
+ indexArray.push(facemap[array[i]]);
+ currentGroup[1]++;
+ }
+ }
+ }
+
+ // set the VBOs
+ obj.normalObject = obj.ctx.createBuffer();
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW);
+
+ obj.texCoordObject = obj.ctx.createBuffer();
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW);
+
+ obj.vertexObject = obj.ctx.createBuffer();
+ obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
+ obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW);
+
+ obj.numIndices = indexArray.length;
+ obj.indexObject = obj.ctx.createBuffer();
+ obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
+ obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW);
+
+ obj.groups = groups;
+
+ obj.loaded = true;
+}
+
+// Array of images curently loading
+var g_loadingImages = [];
+
+// Clears all the images currently loading.
+// This is used to handle context lost events.
+function clearLoadingImages() {
+ for (var ii = 0; ii < g_loadingImages.length; ++ii) {
+ g_loadingImages[ii].onload = undefined;
+ }
+ g_loadingImages = [];
+}
+
+//
+// loadImageTexture
+//
+// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
+//
+function loadImageTexture(ctx, url)
+{
+ var texture = ctx.createTexture();
+ ctx.bindTexture(ctx.TEXTURE_2D, texture);
+ ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, 1, 1, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null);
+ var image = new Image();
+ g_loadingImages.push(image);
+ image.onload = function() { doLoadImageTexture(ctx, image, texture) }
+ image.src = url;
+ return texture;
+}
+
+function doLoadImageTexture(ctx, image, texture)
+{
+ g_loadingImages.splice(g_loadingImages.indexOf(image), 1);
+ ctx.bindTexture(ctx.TEXTURE_2D, texture);
+ ctx.texImage2D(
+ ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
+ ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
+ //ctx.generateMipmap(ctx.TEXTURE_2D)
+ ctx.bindTexture(ctx.TEXTURE_2D, null);
+}
+
+//
+// Framerate object
+//
+// This object keeps track of framerate and displays it as the innerHTML text of the
+// HTML element with the passed id. Once created you call snapshot at the end
+// of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
+//
+Framerate = function(id)
+{
+ this.numFramerates = 10;
+ this.framerateUpdateInterval = 500;
+ this.id = id;
+
+ this.renderTime = -1;
+ this.framerates = [ ];
+ self = this;
+ var fr = function() { self.updateFramerate() }
+ setInterval(fr, this.framerateUpdateInterval);
+}
+
+Framerate.prototype.updateFramerate = function()
+{
+ var tot = 0;
+ for (var i = 0; i < this.framerates.length; ++i)
+ tot += this.framerates[i];
+
+ var framerate = tot / this.framerates.length;
+ framerate = Math.round(framerate);
+ document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
+}
+
+Framerate.prototype.snapshot = function()
+{
+ if (this.renderTime < 0)
+ this.renderTime = new Date().getTime();
+ else {
+ var newTime = new Date().getTime();
+ var t = newTime - this.renderTime;
+ if (t == 0)
+ return;
+ var framerate = 1000/t;
+ this.framerates.push(framerate);
+ while (this.framerates.length > this.numFramerates)
+ this.framerates.shift();
+ this.renderTime = newTime;
+ }
+}
diff --git a/client/deps/webgl_mpd/src/resources/J3DIMath.js b/client/deps/webgl_mpd/src/resources/J3DIMath.js
new file mode 100644
index 0000000..b3e5b64
--- /dev/null
+++ b/client/deps/webgl_mpd/src/resources/J3DIMath.js
@@ -0,0 +1,1065 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ // J3DI (Jedi) - A support library for WebGL.
+
+/*
+ J3DI Math Classes. Currently includes:
+
+ J3DIMatrix4 - A 4x4 Matrix
+*/
+
+/*
+ J3DIMatrix4 class
+
+ This class implements a 4x4 matrix. It has functions which duplicate the
+ functionality of the OpenGL matrix stack and glut functions. On browsers
+ that support it, CSSMatrix is used to accelerate operations.
+
+ IDL:
+
+ [
+ Constructor(in J3DIMatrix4 matrix), // copy passed matrix into new J3DIMatrix4
+ Constructor(in sequence<float> array) // create new J3DIMatrix4 with 16 floats (row major)
+ Constructor() // create new J3DIMatrix4 with identity matrix
+ ]
+ interface J3DIMatrix4 {
+ void load(in J3DIMatrix4 matrix); // copy the values from the passed matrix
+ void load(in sequence<float> array); // copy 16 floats into the matrix
+ sequence<float> getAsArray(); // return the matrix as an array of 16 floats
+ Float32Array getAsFloat32Array(); // return the matrix as a Float32Array with 16 values
+ void setUniform(in WebGLRenderingContext ctx, // Send the matrix to the passed uniform location in the passed context
+ in WebGLUniformLocation loc,
+ in boolean transpose);
+ void makeIdentity(); // replace the matrix with identity
+ void transpose(); // replace the matrix with its transpose
+ void invert(); // replace the matrix with its inverse
+
+ void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right
+ void translate(in J3DVector3 v); // multiply the matrix by passed translation values on the right
+ void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right
+ void scale(in J3DVector3 v); // multiply the matrix by passed scale values on the right
+ void rotate(in float angle, // multiply the matrix by passed rotation values on the right
+ in float x, in float y, in float z); // (angle is in degrees)
+ void rotate(in float angle, in J3DVector3 v); // multiply the matrix by passed rotation values on the right
+ // (angle is in degrees)
+ void multiply(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right
+ void divide(in float divisor); // divide the matrix by the passed divisor
+ void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right
+ in float bottom, in float top,
+ in float near, in float far);
+ void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right
+ in float bottom, in float top,
+ in float near, in float far);
+ void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right
+ in float zNear, in float zFar);
+ void lookat(in J3DVector3 eye, // multiply the matrix by the passed lookat
+ in J3DVector3 center, in J3DVector3 up); // values on the right
+ bool decompose(in J3DVector3 translate, // decompose the matrix into the passed vector
+ in J3DVector3 rotate,
+ in J3DVector3 scale,
+ in J3DVector3 skew,
+ in sequence<float> perspective);
+ }
+
+ [
+ Constructor(in J3DVector3 vector), // copy passed vector into new J3DVector3
+ Constructor(in sequence<float> array) // create new J3DVector3 with 3 floats from array
+ Constructor(in float x, in float y, in float z) // create new J3DVector3 with 3 floats
+ Constructor() // create new J3DVector3 with (0,0,0)
+ ]
+ interface J3DVector3 {
+ void load(in J3DVector3 vector); // copy the values from the passed vector
+ void load(in sequence<float> array); // copy 3 floats into the vector from array
+ void load(in float x, in float y, in float z); // copy 3 floats into the vector
+ sequence<float> getAsArray(); // return the vector as an array of 3 floats
+ Float32Array getAsFloat32Array(); // return the matrix as a Float32Array with 16 values
+ void multMatrix(in J3DIMatrix4 matrix); // multiply the vector by the passed matrix (on the right)
+ float vectorLength(); // return the length of the vector
+ float dot(); // return the dot product of the vector
+ void cross(in J3DVector3 v); // replace the vector with vector x v
+ void divide(in float divisor); // divide the vector by the passed divisor
+ }
+*/
+
+J3DIHasCSSMatrix = false;
+J3DIHasCSSMatrixCopy = false;
+/*
+if ("WebKitCSSMatrix" in window && ("media" in window && window.media.matchMedium("(-webkit-transform-3d)")) ||
+ ("styleMedia" in window && window.styleMedia.matchMedium("(-webkit-transform-3d)"))) {
+ J3DIHasCSSMatrix = true;
+ if ("copy" in WebKitCSSMatrix.prototype)
+ J3DIHasCSSMatrixCopy = true;
+}
+*/
+
+// console.log("J3DIHasCSSMatrix="+J3DIHasCSSMatrix);
+// console.log("J3DIHasCSSMatrixCopy="+J3DIHasCSSMatrixCopy);
+
+//
+// J3DIMatrix4
+//
+J3DIMatrix4 = function(m)
+{
+ if (J3DIHasCSSMatrix)
+ this.$matrix = new WebKitCSSMatrix;
+ else
+ this.$matrix = new Object;
+
+ if (typeof m == 'object') {
+ if ("length" in m && m.length >= 16) {
+ this.load(m);
+ return;
+ }
+ else if (m instanceof J3DIMatrix4) {
+ this.load(m);
+ return;
+ }
+ }
+ this.makeIdentity();
+}
+
+J3DIMatrix4.prototype.load = function()
+{
+ if (arguments.length == 1 && typeof arguments[0] == 'object') {
+ var matrix;
+
+ if (arguments[0] instanceof J3DIMatrix4) {
+ matrix = arguments[0].$matrix;
+
+ this.$matrix.m11 = matrix.m11;
+ this.$matrix.m12 = matrix.m12;
+ this.$matrix.m13 = matrix.m13;
+ this.$matrix.m14 = matrix.m14;
+
+ this.$matrix.m21 = matrix.m21;
+ this.$matrix.m22 = matrix.m22;
+ this.$matrix.m23 = matrix.m23;
+ this.$matrix.m24 = matrix.m24;
+
+ this.$matrix.m31 = matrix.m31;
+ this.$matrix.m32 = matrix.m32;
+ this.$matrix.m33 = matrix.m33;
+ this.$matrix.m34 = matrix.m34;
+
+ this.$matrix.m41 = matrix.m41;
+ this.$matrix.m42 = matrix.m42;
+ this.$matrix.m43 = matrix.m43;
+ this.$matrix.m44 = matrix.m44;
+ return;
+ }
+ else
+ matrix = arguments[0];
+
+ if ("length" in matrix && matrix.length >= 16) {
+ this.$matrix.m11 = matrix[0];
+ this.$matrix.m12 = matrix[1];
+ this.$matrix.m13 = matrix[2];
+ this.$matrix.m14 = matrix[3];
+
+ this.$matrix.m21 = matrix[4];
+ this.$matrix.m22 = matrix[5];
+ this.$matrix.m23 = matrix[6];
+ this.$matrix.m24 = matrix[7];
+
+ this.$matrix.m31 = matrix[8];
+ this.$matrix.m32 = matrix[9];
+ this.$matrix.m33 = matrix[10];
+ this.$matrix.m34 = matrix[11];
+
+ this.$matrix.m41 = matrix[12];
+ this.$matrix.m42 = matrix[13];
+ this.$matrix.m43 = matrix[14];
+ this.$matrix.m44 = matrix[15];
+ return;
+ }
+ }
+
+ this.makeIdentity();
+}
+
+J3DIMatrix4.prototype.getAsArray = function()
+{
+ return [
+ this.$matrix.m11, this.$matrix.m12, this.$matrix.m13, this.$matrix.m14,
+ this.$matrix.m21, this.$matrix.m22, this.$matrix.m23, this.$matrix.m24,
+ this.$matrix.m31, this.$matrix.m32, this.$matrix.m33, this.$matrix.m34,
+ this.$matrix.m41, this.$matrix.m42, this.$matrix.m43, this.$matrix.m44
+ ];
+}
+
+J3DIMatrix4.prototype.getAsFloat32Array = function()
+{
+ if (J3DIHasCSSMatrixCopy) {
+ var array = new Float32Array(16);
+ this.$matrix.copy(array);
+ return array;
+ }
+ return new Float32Array(this.getAsArray());
+}
+
+J3DIMatrix4.prototype.setUniform = function(ctx, loc, transpose)
+{
+ if (J3DIMatrix4.setUniformArray == undefined) {
+ J3DIMatrix4.setUniformWebGLArray = new Float32Array(16);
+ J3DIMatrix4.setUniformArray = new Array(16);
+ }
+
+ if (J3DIHasCSSMatrixCopy)
+ this.$matrix.copy(J3DIMatrix4.setUniformWebGLArray);
+ else {
+ J3DIMatrix4.setUniformArray[0] = this.$matrix.m11;
+ J3DIMatrix4.setUniformArray[1] = this.$matrix.m12;
+ J3DIMatrix4.setUniformArray[2] = this.$matrix.m13;
+ J3DIMatrix4.setUniformArray[3] = this.$matrix.m14;
+ J3DIMatrix4.setUniformArray[4] = this.$matrix.m21;
+ J3DIMatrix4.setUniformArray[5] = this.$matrix.m22;
+ J3DIMatrix4.setUniformArray[6] = this.$matrix.m23;
+ J3DIMatrix4.setUniformArray[7] = this.$matrix.m24;
+ J3DIMatrix4.setUniformArray[8] = this.$matrix.m31;
+ J3DIMatrix4.setUniformArray[9] = this.$matrix.m32;
+ J3DIMatrix4.setUniformArray[10] = this.$matrix.m33;
+ J3DIMatrix4.setUniformArray[11] = this.$matrix.m34;
+ J3DIMatrix4.setUniformArray[12] = this.$matrix.m41;
+ J3DIMatrix4.setUniformArray[13] = this.$matrix.m42;
+ J3DIMatrix4.setUniformArray[14] = this.$matrix.m43;
+ J3DIMatrix4.setUniformArray[15] = this.$matrix.m44;
+
+ J3DIMatrix4.setUniformWebGLArray.set(J3DIMatrix4.setUniformArray);
+ }
+
+ ctx.uniformMatrix4fv(loc, transpose, J3DIMatrix4.setUniformWebGLArray);
+}
+
+J3DIMatrix4.prototype.makeIdentity = function()
+{
+ this.$matrix.m11 = 1;
+ this.$matrix.m12 = 0;
+ this.$matrix.m13 = 0;
+ this.$matrix.m14 = 0;
+
+ this.$matrix.m21 = 0;
+ this.$matrix.m22 = 1;
+ this.$matrix.m23 = 0;
+ this.$matrix.m24 = 0;
+
+ this.$matrix.m31 = 0;
+ this.$matrix.m32 = 0;
+ this.$matrix.m33 = 1;
+ this.$matrix.m34 = 0;
+
+ this.$matrix.m41 = 0;
+ this.$matrix.m42 = 0;
+ this.$matrix.m43 = 0;
+ this.$matrix.m44 = 1;
+}
+
+J3DIMatrix4.prototype.transpose = function()
+{
+ var tmp = this.$matrix.m12;
+ this.$matrix.m12 = this.$matrix.m21;
+ this.$matrix.m21 = tmp;
+
+ tmp = this.$matrix.m13;
+ this.$matrix.m13 = this.$matrix.m31;
+ this.$matrix.m31 = tmp;
+
+ tmp = this.$matrix.m14;
+ this.$matrix.m14 = this.$matrix.m41;
+ this.$matrix.m41 = tmp;
+
+ tmp = this.$matrix.m23;
+ this.$matrix.m23 = this.$matrix.m32;
+ this.$matrix.m32 = tmp;
+
+ tmp = this.$matrix.m24;
+ this.$matrix.m24 = this.$matrix.m42;
+ this.$matrix.m42 = tmp;
+
+ tmp = this.$matrix.m34;
+ this.$matrix.m34 = this.$matrix.m43;
+ this.$matrix.m43 = tmp;
+}
+
+J3DIMatrix4.prototype.invert = function()
+{
+ if (J3DIHasCSSMatrix) {
+ this.$matrix = this.$matrix.inverse();
+ return;
+ }
+
+ // Calculate the 4x4 determinant
+ // If the determinant is zero,
+ // then the inverse matrix is not unique.
+ var det = this._determinant4x4();
+
+ if (Math.abs(det) < 1e-8)
+ return null;
+
+ this._makeAdjoint();
+
+ // Scale the adjoint matrix to get the inverse
+ this.$matrix.m11 /= det;
+ this.$matrix.m12 /= det;
+ this.$matrix.m13 /= det;
+ this.$matrix.m14 /= det;
+
+ this.$matrix.m21 /= det;
+ this.$matrix.m22 /= det;
+ this.$matrix.m23 /= det;
+ this.$matrix.m24 /= det;
+
+ this.$matrix.m31 /= det;
+ this.$matrix.m32 /= det;
+ this.$matrix.m33 /= det;
+ this.$matrix.m34 /= det;
+
+ this.$matrix.m41 /= det;
+ this.$matrix.m42 /= det;
+ this.$matrix.m43 /= det;
+ this.$matrix.m44 /= det;
+}
+
+J3DIMatrix4.prototype.translate = function(x,y,z)
+{
+ if (typeof x == 'object' && "length" in x) {
+ var t = x;
+ x = t[0];
+ y = t[1];
+ z = t[2];
+ }
+ else {
+ if (x == undefined)
+ x = 0;
+ if (y == undefined)
+ y = 0;
+ if (z == undefined)
+ z = 0;
+ }
+
+ if (J3DIHasCSSMatrix) {
+ this.$matrix = this.$matrix.translate(x, y, z);
+ return;
+ }
+
+ var matrix = new J3DIMatrix4();
+ matrix.$matrix.m41 = x;
+ matrix.$matrix.m42 = y;
+ matrix.$matrix.m43 = z;
+
+ this.multiply(matrix);
+}
+
+J3DIMatrix4.prototype.scale = function(x,y,z)
+{
+ if (typeof x == 'object' && "length" in x) {
+ var t = x;
+ x = t[0];
+ y = t[1];
+ z = t[2];
+ }
+ else {
+ if (x == undefined)
+ x = 1;
+ if (z == undefined) {
+ if (y == undefined) {
+ y = x;
+ z = x;
+ }
+ else
+ z = 1;
+ }
+ else if (y == undefined)
+ y = x;
+ }
+
+ if (J3DIHasCSSMatrix) {
+ this.$matrix = this.$matrix.scale(x, y, z);
+ return;
+ }
+
+ var matrix = new J3DIMatrix4();
+ matrix.$matrix.m11 = x;
+ matrix.$matrix.m22 = y;
+ matrix.$matrix.m33 = z;
+
+ this.multiply(matrix);
+}
+
+J3DIMatrix4.prototype.rotate = function(angle,x,y,z)
+{
+ // Forms are (angle, x,y,z), (angle,vector), (angleX, angleY, angleZ), (angle)
+ if (typeof x == 'object' && "length" in x) {
+ var t = x;
+ x = t[0];
+ y = t[1];
+ z = t[2];
+ }
+ else {
+ if (arguments.length == 1) {
+ x = 0;
+ y = 0;
+ z = 1;
+ }
+ else if (arguments.length == 3) {
+ this.rotate(angle, 1,0,0); // about X axis
+ this.rotate(x, 0,1,0); // about Y axis
+ this.rotate(y, 0,0,1); // about Z axis
+ return;
+ }
+ }
+
+ if (J3DIHasCSSMatrix) {
+ this.$matrix = this.$matrix.rotateAxisAngle(x, y, z, angle);
+ return;
+ }
+
+ // angles are in degrees. Switch to radians
+ angle = angle / 180 * Math.PI;
+
+ angle /= 2;
+ var sinA = Math.sin(angle);
+ var cosA = Math.cos(angle);
+ var sinA2 = sinA * sinA;
+
+ // normalize
+ var len = Math.sqrt(x * x + y * y + z * z);
+ if (len == 0) {
+ // bad vector, just use something reasonable
+ x = 0;
+ y = 0;
+ z = 1;
+ } else if (len != 1) {
+ x /= len;
+ y /= len;
+ z /= len;
+ }
+
+ var mat = new J3DIMatrix4();
+
+ // optimize case where axis is along major axis
+ if (x == 1 && y == 0 && z == 0) {
+ mat.$matrix.m11 = 1;
+ mat.$matrix.m12 = 0;
+ mat.$matrix.m13 = 0;
+ mat.$matrix.m21 = 0;
+ mat.$matrix.m22 = 1 - 2 * sinA2;
+ mat.$matrix.m23 = 2 * sinA * cosA;
+ mat.$matrix.m31 = 0;
+ mat.$matrix.m32 = -2 * sinA * cosA;
+ mat.$matrix.m33 = 1 - 2 * sinA2;
+ mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
+ mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
+ mat.$matrix.m44 = 1;
+ } else if (x == 0 && y == 1 && z == 0) {
+ mat.$matrix.m11 = 1 - 2 * sinA2;
+ mat.$matrix.m12 = 0;
+ mat.$matrix.m13 = -2 * sinA * cosA;
+ mat.$matrix.m21 = 0;
+ mat.$matrix.m22 = 1;
+ mat.$matrix.m23 = 0;
+ mat.$matrix.m31 = 2 * sinA * cosA;
+ mat.$matrix.m32 = 0;
+ mat.$matrix.m33 = 1 - 2 * sinA2;
+ mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
+ mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
+ mat.$matrix.m44 = 1;
+ } else if (x == 0 && y == 0 && z == 1) {
+ mat.$matrix.m11 = 1 - 2 * sinA2;
+ mat.$matrix.m12 = 2 * sinA * cosA;
+ mat.$matrix.m13 = 0;
+ mat.$matrix.m21 = -2 * sinA * cosA;
+ mat.$matrix.m22 = 1 - 2 * sinA2;
+ mat.$matrix.m23 = 0;
+ mat.$matrix.m31 = 0;
+ mat.$matrix.m32 = 0;
+ mat.$matrix.m33 = 1;
+ mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
+ mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
+ mat.$matrix.m44 = 1;
+ } else {
+ var x2 = x*x;
+ var y2 = y*y;
+ var z2 = z*z;
+
+ mat.$matrix.m11 = 1 - 2 * (y2 + z2) * sinA2;
+ mat.$matrix.m12 = 2 * (x * y * sinA2 + z * sinA * cosA);
+ mat.$matrix.m13 = 2 * (x * z * sinA2 - y * sinA * cosA);
+ mat.$matrix.m21 = 2 * (y * x * sinA2 - z * sinA * cosA);
+ mat.$matrix.m22 = 1 - 2 * (z2 + x2) * sinA2;
+ mat.$matrix.m23 = 2 * (y * z * sinA2 + x * sinA * cosA);
+ mat.$matrix.m31 = 2 * (z * x * sinA2 + y * sinA * cosA);
+ mat.$matrix.m32 = 2 * (z * y * sinA2 - x * sinA * cosA);
+ mat.$matrix.m33 = 1 - 2 * (x2 + y2) * sinA2;
+ mat.$matrix.m14 = mat.$matrix.m24 = mat.$matrix.m34 = 0;
+ mat.$matrix.m41 = mat.$matrix.m42 = mat.$matrix.m43 = 0;
+ mat.$matrix.m44 = 1;
+ }
+ this.multiply(mat);
+}
+
+J3DIMatrix4.prototype.multiply = function(mat)
+{
+ if (J3DIHasCSSMatrix) {
+ this.$matrix = this.$matrix.multiply(mat.$matrix);
+ return;
+ }
+
+ var m11 = (mat.$matrix.m11 * this.$matrix.m11 + mat.$matrix.m12 * this.$matrix.m21
+ + mat.$matrix.m13 * this.$matrix.m31 + mat.$matrix.m14 * this.$matrix.m41);
+ var m12 = (mat.$matrix.m11 * this.$matrix.m12 + mat.$matrix.m12 * this.$matrix.m22
+ + mat.$matrix.m13 * this.$matrix.m32 + mat.$matrix.m14 * this.$matrix.m42);
+ var m13 = (mat.$matrix.m11 * this.$matrix.m13 + mat.$matrix.m12 * this.$matrix.m23
+ + mat.$matrix.m13 * this.$matrix.m33 + mat.$matrix.m14 * this.$matrix.m43);
+ var m14 = (mat.$matrix.m11 * this.$matrix.m14 + mat.$matrix.m12 * this.$matrix.m24
+ + mat.$matrix.m13 * this.$matrix.m34 + mat.$matrix.m14 * this.$matrix.m44);
+
+ var m21 = (mat.$matrix.m21 * this.$matrix.m11 + mat.$matrix.m22 * this.$matrix.m21
+ + mat.$matrix.m23 * this.$matrix.m31 + mat.$matrix.m24 * this.$matrix.m41);
+ var m22 = (mat.$matrix.m21 * this.$matrix.m12 + mat.$matrix.m22 * this.$matrix.m22
+ + mat.$matrix.m23 * this.$matrix.m32 + mat.$matrix.m24 * this.$matrix.m42);
+ var m23 = (mat.$matrix.m21 * this.$matrix.m13 + mat.$matrix.m22 * this.$matrix.m23
+ + mat.$matrix.m23 * this.$matrix.m33 + mat.$matrix.m24 * this.$matrix.m43);
+ var m24 = (mat.$matrix.m21 * this.$matrix.m14 + mat.$matrix.m22 * this.$matrix.m24
+ + mat.$matrix.m23 * this.$matrix.m34 + mat.$matrix.m24 * this.$matrix.m44);
+
+ var m31 = (mat.$matrix.m31 * this.$matrix.m11 + mat.$matrix.m32 * this.$matrix.m21
+ + mat.$matrix.m33 * this.$matrix.m31 + mat.$matrix.m34 * this.$matrix.m41);
+ var m32 = (mat.$matrix.m31 * this.$matrix.m12 + mat.$matrix.m32 * this.$matrix.m22
+ + mat.$matrix.m33 * this.$matrix.m32 + mat.$matrix.m34 * this.$matrix.m42);
+ var m33 = (mat.$matrix.m31 * this.$matrix.m13 + mat.$matrix.m32 * this.$matrix.m23
+ + mat.$matrix.m33 * this.$matrix.m33 + mat.$matrix.m34 * this.$matrix.m43);
+ var m34 = (mat.$matrix.m31 * this.$matrix.m14 + mat.$matrix.m32 * this.$matrix.m24
+ + mat.$matrix.m33 * this.$matrix.m34 + mat.$matrix.m34 * this.$matrix.m44);
+
+ var m41 = (mat.$matrix.m41 * this.$matrix.m11 + mat.$matrix.m42 * this.$matrix.m21
+ + mat.$matrix.m43 * this.$matrix.m31 + mat.$matrix.m44 * this.$matrix.m41);
+ var m42 = (mat.$matrix.m41 * this.$matrix.m12 + mat.$matrix.m42 * this.$matrix.m22
+ + mat.$matrix.m43 * this.$matrix.m32 + mat.$matrix.m44 * this.$matrix.m42);
+ var m43 = (mat.$matrix.m41 * this.$matrix.m13 + mat.$matrix.m42 * this.$matrix.m23
+ + mat.$matrix.m43 * this.$matrix.m33 + mat.$matrix.m44 * this.$matrix.m43);
+ var m44 = (mat.$matrix.m41 * this.$matrix.m14 + mat.$matrix.m42 * this.$matrix.m24
+ + mat.$matrix.m43 * this.$matrix.m34 + mat.$matrix.m44 * this.$matrix.m44);
+
+ this.$matrix.m11 = m11;
+ this.$matrix.m12 = m12;
+ this.$matrix.m13 = m13;
+ this.$matrix.m14 = m14;
+
+ this.$matrix.m21 = m21;
+ this.$matrix.m22 = m22;
+ this.$matrix.m23 = m23;
+ this.$matrix.m24 = m24;
+
+ this.$matrix.m31 = m31;
+ this.$matrix.m32 = m32;
+ this.$matrix.m33 = m33;
+ this.$matrix.m34 = m34;
+
+ this.$matrix.m41 = m41;
+ this.$matrix.m42 = m42;
+ this.$matrix.m43 = m43;
+ this.$matrix.m44 = m44;
+}
+
+J3DIMatrix4.prototype.divide = function(divisor)
+{
+ this.$matrix.m11 /= divisor;
+ this.$matrix.m12 /= divisor;
+ this.$matrix.m13 /= divisor;
+ this.$matrix.m14 /= divisor;
+
+ this.$matrix.m21 /= divisor;
+ this.$matrix.m22 /= divisor;
+ this.$matrix.m23 /= divisor;
+ this.$matrix.m24 /= divisor;
+
+ this.$matrix.m31 /= divisor;
+ this.$matrix.m32 /= divisor;
+ this.$matrix.m33 /= divisor;
+ this.$matrix.m34 /= divisor;
+
+ this.$matrix.m41 /= divisor;
+ this.$matrix.m42 /= divisor;
+ this.$matrix.m43 /= divisor;
+ this.$matrix.m44 /= divisor;
+
+}
+
+J3DIMatrix4.prototype.ortho = function(left, right, bottom, top, near, far)
+{
+ var tx = (left + right) / (left - right);
+ var ty = (top + bottom) / (top - bottom);
+ var tz = (far + near) / (far - near);
+
+ var matrix = new J3DIMatrix4();
+ matrix.$matrix.m11 = 2 / (left - right);
+ matrix.$matrix.m12 = 0;
+ matrix.$matrix.m13 = 0;
+ matrix.$matrix.m14 = 0;
+ matrix.$matrix.m21 = 0;
+ matrix.$matrix.m22 = 2 / (top - bottom);
+ matrix.$matrix.m23 = 0;
+ matrix.$matrix.m24 = 0;
+ matrix.$matrix.m31 = 0;
+ matrix.$matrix.m32 = 0;
+ matrix.$matrix.m33 = -2 / (far - near);
+ matrix.$matrix.m34 = 0;
+ matrix.$matrix.m41 = tx;
+ matrix.$matrix.m42 = ty;
+ matrix.$matrix.m43 = tz;
+ matrix.$matrix.m44 = 1;
+
+ this.multiply(matrix);
+}
+
+J3DIMatrix4.prototype.frustum = function(left, right, bottom, top, near, far)
+{
+ var matrix = new J3DIMatrix4();
+ var A = (right + left) / (right - left);
+ var B = (top + bottom) / (top - bottom);
+ var C = -(far + near) / (far - near);
+ var D = -(2 * far * near) / (far - near);
+
+ matrix.$matrix.m11 = (2 * near) / (right - left);
+ matrix.$matrix.m12 = 0;
+ matrix.$matrix.m13 = 0;
+ matrix.$matrix.m14 = 0;
+
+ matrix.$matrix.m21 = 0;
+ matrix.$matrix.m22 = 2 * near / (top - bottom);
+ matrix.$matrix.m23 = 0;
+ matrix.$matrix.m24 = 0;
+
+ matrix.$matrix.m31 = A;
+ matrix.$matrix.m32 = B;
+ matrix.$matrix.m33 = C;
+ matrix.$matrix.m34 = -1;
+
+ matrix.$matrix.m41 = 0;
+ matrix.$matrix.m42 = 0;
+ matrix.$matrix.m43 = D;
+ matrix.$matrix.m44 = 0;
+
+ this.multiply(matrix);
+}
+
+J3DIMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
+{
+ var top = Math.tan(fovy * Math.PI / 360) * zNear;
+ var bottom = -top;
+ var left = aspect * bottom;
+ var right = aspect * top;
+ this.frustum(left, right, bottom, top, zNear, zFar);
+}
+
+J3DIMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
+{
+ if (typeof eyez == 'object' && "length" in eyez) {
+ var t = eyez;
+ upx = t[0];
+ upy = t[1];
+ upz = t[2];
+
+ t = eyey;
+ centerx = t[0];
+ centery = t[1];
+ centerz = t[2];
+
+ t = eyex;
+ eyex = t[0];
+ eyey = t[1];
+ eyez = t[2];
+ }
+
+ var matrix = new J3DIMatrix4();
+
+ // Make rotation matrix
+
+ // Z vector
+ var zx = eyex - centerx;
+ var zy = eyey - centery;
+ var zz = eyez - centerz;
+ var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
+ if (mag) {
+ zx /= mag;
+ zy /= mag;
+ zz /= mag;
+ }
+
+ // Y vector
+ var yx = upx;
+ var yy = upy;
+ var yz = upz;
+
+ // X vector = Y cross Z
+ xx = yy * zz - yz * zy;
+ xy = -yx * zz + yz * zx;
+ xz = yx * zy - yy * zx;
+
+ // Recompute Y = Z cross X
+ yx = zy * xz - zz * xy;
+ yy = -zx * xz + zz * xx;
+ yx = zx * xy - zy * xx;
+
+ // cross product gives area of parallelogram, which is < 1.0 for
+ // non-perpendicular unit-length vectors; so normalize x, y here
+
+ mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
+ if (mag) {
+ xx /= mag;
+ xy /= mag;
+ xz /= mag;
+ }
+
+ mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
+ if (mag) {
+ yx /= mag;
+ yy /= mag;
+ yz /= mag;
+ }
+
+ matrix.$matrix.m11 = xx;
+ matrix.$matrix.m12 = xy;
+ matrix.$matrix.m13 = xz;
+ matrix.$matrix.m14 = 0;
+
+ matrix.$matrix.m21 = yx;
+ matrix.$matrix.m22 = yy;
+ matrix.$matrix.m23 = yz;
+ matrix.$matrix.m24 = 0;
+
+ matrix.$matrix.m31 = zx;
+ matrix.$matrix.m32 = zy;
+ matrix.$matrix.m33 = zz;
+ matrix.$matrix.m34 = 0;
+
+ matrix.$matrix.m41 = 0;
+ matrix.$matrix.m42 = 0;
+ matrix.$matrix.m43 = 0;
+ matrix.$matrix.m44 = 1;
+ matrix.translate(-eyex, -eyey, -eyez);
+
+ this.multiply(matrix);
+}
+
+// Returns true on success, false otherwise. All params are Array objects
+J3DIMatrix4.prototype.decompose = function(_translate, _rotate, _scale, _skew, _perspective)
+{
+ // Normalize the matrix.
+ if (this.$matrix.m44 == 0)
+ return false;
+
+ // Gather the params
+ var translate, rotate, scale, skew, perspective;
+
+ var translate = (_translate == undefined || !("length" in _translate)) ? new J3DIVector3 : _translate;
+ var rotate = (_rotate == undefined || !("length" in _rotate)) ? new J3DIVector3 : _rotate;
+ var scale = (_scale == undefined || !("length" in _scale)) ? new J3DIVector3 : _scale;
+ var skew = (_skew == undefined || !("length" in _skew)) ? new J3DIVector3 : _skew;
+ var perspective = (_perspective == undefined || !("length" in _perspective)) ? new Array(4) : _perspective;
+
+ var matrix = new J3DIMatrix4(this);
+
+ matrix.divide(matrix.$matrix.m44);
+
+ // perspectiveMatrix is used to solve for perspective, but it also provides
+ // an easy way to test for singularity of the upper 3x3 component.
+ var perspectiveMatrix = new J3DIMatrix4(matrix);
+
+ perspectiveMatrix.$matrix.m14 = 0;
+ perspectiveMatrix.$matrix.m24 = 0;
+ perspectiveMatrix.$matrix.m34 = 0;
+ perspectiveMatrix.$matrix.m44 = 1;
+
+ if (perspectiveMatrix._determinant4x4() == 0)
+ return false;
+
+ // First, isolate perspective.
+ if (matrix.$matrix.m14 != 0 || matrix.$matrix.m24 != 0 || matrix.$matrix.m34 != 0) {
+ // rightHandSide is the right hand side of the equation.
+ var rightHandSide = [ matrix.$matrix.m14, matrix.$matrix.m24, matrix.$matrix.m34, matrix.$matrix.m44 ];
+
+ // Solve the equation by inverting perspectiveMatrix and multiplying
+ // rightHandSide by the inverse.
+ var inversePerspectiveMatrix = new J3DIMatrix4(perspectiveMatrix);
+ inversePerspectiveMatrix.invert();
+ var transposedInversePerspectiveMatrix = new J3DIMatrix4(inversePerspectiveMatrix);
+ transposedInversePerspectiveMatrix.transpose();
+ transposedInversePerspectiveMatrix.multVecMatrix(perspective, rightHandSide);
+
+ // Clear the perspective partition
+ matrix.$matrix.m14 = matrix.$matrix.m24 = matrix.$matrix.m34 = 0
+ matrix.$matrix.m44 = 1;
+ }
+ else {
+ // No perspective.
+ perspective[0] = perspective[1] = perspective[2] = 0;
+ perspective[3] = 1;
+ }
+
+ // Next take care of translation
+ translate[0] = matrix.$matrix.m41
+ matrix.$matrix.m41 = 0
+ translate[1] = matrix.$matrix.m42
+ matrix.$matrix.m42 = 0
+ translate[2] = matrix.$matrix.m43
+ matrix.$matrix.m43 = 0
+
+ // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
+ var row0 = new J3DIVector3(matrix.$matrix.m11, matrix.$matrix.m12, matrix.$matrix.m13);
+ var row1 = new J3DIVector3(matrix.$matrix.m21, matrix.$matrix.m22, matrix.$matrix.m23);
+ var row2 = new J3DIVector3(matrix.$matrix.m31, matrix.$matrix.m32, matrix.$matrix.m33);
+
+ // Compute X scale factor and normalize first row.
+ scale[0] = row0.vectorLength();
+ row0.divide(scale[0]);
+
+ // Compute XY shear factor and make 2nd row orthogonal to 1st.
+ skew[0] = row0.dot(row1);
+ row1.combine(row0, 1.0, -skew[0]);
+
+ // Now, compute Y scale and normalize 2nd row.
+ scale[1] = row1.vectorLength();
+ row1.divide(scale[1]);
+ skew[0] /= scale[1];
+
+ // Compute XZ and YZ shears, orthogonalize 3rd row
+ skew[1] = row1.dot(row2);
+ row2.combine(row0, 1.0, -skew[1]);
+ skew[2] = row1.dot(row2);
+ row2.combine(row1, 1.0, -skew[2]);
+
+ // Next, get Z scale and normalize 3rd row.
+ scale[2] = row2.vectorLength();
+ row2.divide(scale[2]);
+ skew[1] /= scale[2];
+ skew[2] /= scale[2];
+
+ // At this point, the matrix (in rows) is orthonormal.
+ // Check for a coordinate system flip. If the determinant
+ // is -1, then negate the matrix and the scaling factors.
+ var pdum3 = new J3DIVector3(row1);
+ pdum3.cross(row2);
+ if (row0.dot(pdum3) < 0) {
+ for (i = 0; i < 3; i++) {
+ scale[i] *= -1;
+ row[0][i] *= -1;
+ row[1][i] *= -1;
+ row[2][i] *= -1;
+ }
+ }
+
+ // Now, get the rotations out
+ rotate[1] = Math.asin(-row0[2]);
+ if (Math.cos(rotate[1]) != 0) {
+ rotate[0] = Math.atan2(row1[2], row2[2]);
+ rotate[2] = Math.atan2(row0[1], row0[0]);
+ }
+ else {
+ rotate[0] = Math.atan2(-row2[0], row1[1]);
+ rotate[2] = 0;
+ }
+
+ // Convert rotations to degrees
+ var rad2deg = 180 / Math.PI;
+ rotate[0] *= rad2deg;
+ rotate[1] *= rad2deg;
+ rotate[2] *= rad2deg;
+
+ return true;
+}
+
+J3DIMatrix4.prototype._determinant2x2 = function(a, b, c, d)
+{
+ return a * d - b * c;
+}
+
+J3DIMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
+{
+ return a1 * this._determinant2x2(b2, b3, c2, c3)
+ - b1 * this._determinant2x2(a2, a3, c2, c3)
+ + c1 * this._determinant2x2(a2, a3, b2, b3);
+}
+
+J3DIMatrix4.prototype._determinant4x4 = function()
+{
+ var a1 = this.$matrix.m11;
+ var b1 = this.$matrix.m12;
+ var c1 = this.$matrix.m13;
+ var d1 = this.$matrix.m14;
+
+ var a2 = this.$matrix.m21;
+ var b2 = this.$matrix.m22;
+ var c2 = this.$matrix.m23;
+ var d2 = this.$matrix.m24;
+
+ var a3 = this.$matrix.m31;
+ var b3 = this.$matrix.m32;
+ var c3 = this.$matrix.m33;
+ var d3 = this.$matrix.m34;
+
+ var a4 = this.$matrix.m41;
+ var b4 = this.$matrix.m42;
+ var c4 = this.$matrix.m43;
+ var d4 = this.$matrix.m44;
+
+ return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
+ - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
+ + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
+ - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+}
+
+J3DIMatrix4.prototype._makeAdjoint = function()
+{
+ var a1 = this.$matrix.m11;
+ var b1 = this.$matrix.m12;
+ var c1 = this.$matrix.m13;
+ var d1 = this.$matrix.m14;
+
+ var a2 = this.$matrix.m21;
+ var b2 = this.$matrix.m22;
+ var c2 = this.$matrix.m23;
+ var d2 = this.$matrix.m24;
+
+ var a3 = this.$matrix.m31;
+ var b3 = this.$matrix.m32;
+ var c3 = this.$matrix.m33;
+ var d3 = this.$matrix.m34;
+
+ var a4 = this.$matrix.m41;
+ var b4 = this.$matrix.m42;
+ var c4 = this.$matrix.m43;
+ var d4 = this.$matrix.m44;
+
+ // Row column labeling reversed since we transpose rows & columns
+ this.$matrix.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ this.$matrix.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ this.$matrix.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ this.$matrix.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ this.$matrix.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ this.$matrix.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ this.$matrix.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ this.$matrix.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
+
+ this.$matrix.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ this.$matrix.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ this.$matrix.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ this.$matrix.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
+
+ this.$matrix.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ this.$matrix.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ this.$matrix.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ this.$matrix.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+//
+// J3DIVector3
+//
+J3DIVector3 = function(x,y,z)
+{
+ this.load(x,y,z);
+}
+
+J3DIVector3.prototype.load = function(x,y,z)
+{
+ if (typeof x == 'object' && "length" in x) {
+ this[0] = x[0];
+ this[1] = x[1];
+ this[2] = x[2];
+ }
+ else if (typeof x == 'number') {
+ this[0] = x;
+ this[1] = y;
+ this[2] = z;
+ }
+ else {
+ this[0] = 0;
+ this[1] = 0;
+ this[2] = 0;
+ }
+}
+
+J3DIVector3.prototype.getAsArray = function()
+{
+ return [ this[0], this[1], this[2] ];
+}
+
+J3DIVector3.prototype.getAsFloat32Array = function()
+{
+ return new Float32Array(this.getAsArray());
+}
+
+J3DIVector3.prototype.vectorLength = function()
+{
+ return Math.sqrt(this[0] * this[0] + this[1] * this[1] + this[2] * this[2]);
+}
+
+J3DIVector3.prototype.divide = function(divisor)
+{
+ this[0] /= divisor; this[1] /= divisor; this[2] /= divisor;
+}
+
+J3DIVector3.prototype.cross = function(v)
+{
+ this[0] = this[1] * v[2] - this[2] * v[1];
+ this[1] = -this[0] * v[2] + this[2] * v[0];
+ this[2] = this[0] * v[1] - this[1] * v[0];
+}
+
+J3DIVector3.prototype.dot = function(v)
+{
+ return this[0] * v[0] + this[1] * v[1] + this[2] * v[2];
+}
+
+J3DIVector3.prototype.combine = function(v, ascl, bscl)
+{
+ this[0] = (ascl * this[0]) + (bscl * v[0]);
+ this[1] = (ascl * this[1]) + (bscl * v[1]);
+ this[2] = (ascl * this[2]) + (bscl * v[2]);
+}
+
+J3DIVector3.prototype.multVecMatrix = function(matrix)
+{
+ var x = this[0];
+ var y = this[1];
+ var z = this[2];
+
+ this[0] = matrix.$matrix.m41 + x * matrix.$matrix.m11 + y * matrix.$matrix.m21 + z * matrix.$matrix.m31;
+ this[1] = matrix.$matrix.m42 + x * matrix.$matrix.m12 + y * matrix.$matrix.m22 + z * matrix.$matrix.m32;
+ this[2] = matrix.$matrix.m43 + x * matrix.$matrix.m13 + y * matrix.$matrix.m23 + z * matrix.$matrix.m33;
+ var w = matrix.$matrix.m44 + x * matrix.$matrix.m14 + y * matrix.$matrix.m24 + z * matrix.$matrix.m34;
+ if (w != 1 && w != 0) {
+ this[0] /= w;
+ this[1] /= w;
+ this[2] /= w;
+ }
+}
+
+J3DIVector3.prototype.toString = function()
+{
+ return "["+this[0]+","+this[1]+","+this[2]+"]";
+}
diff --git a/client/deps/webgl_mpd/src/resources/earthmap1k.jpg b/client/deps/webgl_mpd/src/resources/earthmap1k.jpg
new file mode 100644
index 0000000..7dcab8a
--- /dev/null
+++ b/client/deps/webgl_mpd/src/resources/earthmap1k.jpg
Binary files differ
diff --git a/client/deps/webgl_mpd/src/resources/mars500x250.png b/client/deps/webgl_mpd/src/resources/mars500x250.png
new file mode 100644
index 0000000..f38ef09
--- /dev/null
+++ b/client/deps/webgl_mpd/src/resources/mars500x250.png
Binary files differ
diff --git a/client/deps/webgl_mpd/webgl_mpd.py b/client/deps/webgl_mpd/webgl_mpd.py
new file mode 100755
index 0000000..05fdc2d
--- /dev/null
+++ b/client/deps/webgl_mpd/webgl_mpd.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import common, os
+from autotest_lib.client.bin import utils
+
+version = 1
+
+def setup():
+ """Nothing needs to be done here."""
+ pass
+
+pwd = os.getcwd()
+utils.update_version(pwd + '/src', True, version, setup)