diff --git a/Makefile b/Makefile index d934d5af..2e5358cb 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,13 @@ www: mkdir -p /var/www/css cp web/css/*.css /var/www/css mkdir -p /var/www/js - cp web/js/*.js /var/www/js + cp web/js/main.js /var/www/js + cp web/js/addtohomescreen.min.js /var/www/js + cp web/js/j3di-all.min.js /var/www/js mkdir -p /var/www/img cp web/img/logo*.png /var/www/img cp web/img/screen*.png /var/www/img + cp web/img/world.png /var/www/img mkdir -p /var/www/maui mkdir -p /var/www/maui/js cp web/maui/js/angular-ui-router.min.js /var/www/maui/js diff --git a/web/css/main.css b/web/css/main.css index 3b9c5a59..135b85ad 100755 --- a/web/css/main.css +++ b/web/css/main.css @@ -6,16 +6,48 @@ .weather-page {} +.gps_page {} + +.map-container { + position: relative; +} + +.world-map { + background-image: url(../img/world.png); + background-position: 1186px 591px; + margin-bottom: 4px; + /* this will be set dynamically to center map at gps location */ + /* + width: 100%; + height: 300px; +*/ +} + +.mark-position { + position: absolute; + top: 0; + left: 0; + font-size: 18px; +} + +.washout { + background-color: rgba(255, 255, 255, 0.65); + display: inline-block; + width: 100%; + text-align: center; + padding: 4px; +} + .section_invisible { display: none; } .text-normal { - font-weight:100; + font-weight: 100; } .reset-flow { - clear:both; + clear: both; } .separator { @@ -86,20 +118,23 @@ } .flight_condition_VFR { - background-color:forestgreen; - color:white; + background-color: forestgreen; + color: white; } + .flight_condition_MVFR { - background-color:blue; - color:white; + background-color: blue; + color: white; } + .flight_condition_IFR { - background-color:crimson; - color:white; + background-color: crimson; + color: white; } + .flight_condition_LIFR { - background-color:darkorchid; - color:white; + background-color: darkorchid; + color: white; } .traffic-style1 { @@ -129,16 +164,18 @@ } .bar_container { - display:inline-block; - border:1px solid #cccccc; + display: inline-block; + border: 1px solid #cccccc; width: 100%; - border-radius: 2px; - font-size: 0.75em; + border-radius: 2px; + font-size: 0.75em; } + .bar_display { padding: 1px 2px 1px 3px; } + /* *************************************************************************** everything below this comment represents tweeks to the mobile-angular-uis CSS *************************************************************************** */ diff --git a/web/img/map-world-medium.png b/web/img/map-world-medium.png new file mode 100755 index 00000000..47a1004c Binary files /dev/null and b/web/img/map-world-medium.png differ diff --git a/web/img/world.png b/web/img/world.png new file mode 100755 index 00000000..3ead9b72 Binary files /dev/null and b/web/img/world.png differ diff --git a/web/index.html b/web/index.html index a867e77c..9d022712 100755 --- a/web/index.html +++ b/web/index.html @@ -39,9 +39,7 @@ @@ -57,12 +55,14 @@ - + + + diff --git a/web/js/j3di-all.js b/web/js/j3di-all.js new file mode 100755 index 00000000..dd476d13 --- /dev/null +++ b/web/js/j3di-all.js @@ -0,0 +1,3344 @@ +/* + * 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 '' + + '' + + '
' + + '
' + + '
' + msg + '
' + + '
' + + '
'; + }; + + /** + * Mesasge for getting a webgl browser + * @type {string} + */ + var GET_A_WEBGL_BROWSER = '' + + 'This page requires a browser that supports WebGL.
' + + 'Click here to upgrade your browser.'; + + /** + * Mesasge for need better hardware + * @type {string} + */ + var OTHER_PROBLEM = '' + + "It doesn't appear your computer can support WebGL.
" + + 'Click here for more information.'; + + /** + * Creates a webgl context. If creation fails it will + * change the contents of the container of the + * 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; +})(); + + +/* + ** 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.} + */ + 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: { + 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] + } + } + }, + '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 + } + }, + + // ANGLE_instanced_arrays extension + + 'drawArraysInstancedANGLE': { + 4: { + 0: true + } + }, + 'drawElementsInstancedANGLE': { + 5: { + 0: true, + 2: true + } + }, + + // EXT_blend_minmax extension + + 'blendEquationEXT': { + 1: { + 0: true + } + } + }; + + /** + * Map of numbers to names. + * @type {Object} + */ + var glEnums = null; + + /** + * Map of names to numbers. + * @type {Object} + */ + var enumStringToValue = 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 = {}; + enumStringToValue = {}; + for (var propertyName in ctx) { + if (typeof ctx[propertyName] == 'number') { + glEnums[ctx[propertyName]] = propertyName; + enumStringToValue[propertyName] = ctx[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]) { + if (typeof funcInfo[argumentIndex] === 'object' && + funcInfo[argumentIndex]['enumBitwiseOr'] !== undefined) { + var enums = funcInfo[argumentIndex]['enumBitwiseOr']; + var orResult = 0; + var orEnums = []; + for (var i = 0; i < enums.length; ++i) { + var enumValue = enumStringToValue[enums[i]]; + if ((value & enumValue) !== 0) { + orResult |= enumValue; + orEnums.push(glEnumToString(enumValue)); + } + } + if (orResult === value) { + return orEnums.join(' | '); + } else { + return glEnumToString(value); + } + } else { + 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. + * @param {!WebGLRenderingContext} opt_err_ctx The webgl context + * to call getError on if different than ctx. + */ + function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc, opt_err_ctx) { + opt_err_ctx = opt_err_ctx || ctx; + 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 = opt_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') { + if (propertyName != 'getExtension') { + wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); + } else { + var wrapped = makeErrorWrapper(ctx, propertyName); + wrapper[propertyName] = function () { + var result = wrapped.apply(ctx, arguments); + return makeDebugContext(result, opt_onErrorFunc, opt_onFunc, opt_err_ctx); + }; + } + } 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 + }; + +}(); + + +/* + * 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