LJ/www/trckr/js/libs/webgl-utils.js

333 lines
9.3 KiB
JavaScript

// This code is based on webgl-utils.js authored by Gregg Tavares, license below:
/*
* Copyright (c) 2011, Gregg Tavares
* 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 greggman.com 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 HOLDER 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.
*/
(function(){
var LOGGING_ENABLED = true;
/**
* Wrapped logging function.
* @param {string} msg The message to log.
*/
const log = function (msg) {
if (!LOGGING_ENABLED) { return; }
if (window.console && window.console.log) {
window.console.log(msg);
}
};
/**
* Wrapped logging function.
* @param {string} msg The message to log.
*/
const error = function (msg) {
if (!LOGGING_ENABLED) { return; }
if (window.console) {
if (window.console.error) {
window.console.error(msg);
} else if (window.console.log) {
window.console.log(msg);
}
}
throw msg;
};
/**
* Turn off all logging.
*/
const loggingOff = function () {
LOGGING_ENABLED = false;
};
/**
* Check if the page is embedded.
* @return {boolean} True of we are in an iframe
*/
const isInIFrame = function () {
return window !== window.top;
};
/**
* Converts a WebGL enum to a string
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} value The enum value.
* @return {string} The enum as a string.
*/
const glEnumToString = function (gl, value) {
for (var p in gl) {
if (gl[p] === value) {
return p;
}
}
return '0x' + value.toString(16);
};
/**
* Creates the HTLM for a failure message
* @param {string} canvasContainerId id of container of th
* canvas.
* @return {string} The html.
*/
const 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}
*/
// const 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}
*/
// const 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} optAttribs Any
* creation attributes you want to pass in.
* @return {WebGLRenderingContext} The created context.
*/
const setupWebGL = function (canvas, optAttribs) {
// const showLink = function (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, optAttribs);
if (!context) {
// showLink(OTHER_PROBLEM);
return null;
}
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.
*/
const create3DContext = function (canvas, optAttribs) {
var names = ['webgl', 'experimental-webgl'];
var context = null;
for (var ii = 0; ii < names.length; ++ii) {
try {
context = canvas.getContext(names[ii], optAttribs);
} catch (e) {}
if (context) {
break;
}
}
return context;
};
const updateCSSIfInIFrame = function () {
if (isInIFrame()) {
document.body.className = 'iframe';
}
};
/**
* Gets a WebGL context.
* makes its backing store the size it is displayed.
*/
const getWebGLContext = function (canvas) {
if (isInIFrame()) {
updateCSSIfInIFrame();
// make the canvas backing store the size it's displayed.
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
var gl = setupWebGL(canvas);
return gl;
};
/**
* Loads a shader.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {string} shaderSource The shader source.
* @param {number} shaderType The type of shader.
* @param {function(string): void) optErrorCallback callback for errors.
* @return {!WebGLShader} The created shader.
*/
const loadShader = function (gl, shaderSource, shaderType, optErrorCallback) {
var errFn = optErrorCallback || error;
// Create the shader object
var shader = gl.createShader(shaderType);
// Load the shader source
gl.shaderSource(shader, shaderSource);
// Compile the shader
gl.compileShader(shader);
// Check the compile status
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// Something went wrong during compilation; get the error
var lastError = gl.getShaderInfoLog(shader);
errFn("*** Error compiling shader '" + shader + "':" + lastError);
gl.deleteShader(shader);
return null;
}
return shader;
};
/**
* Creates a program, attaches shaders, binds attrib locations, links the
* program and calls useProgram.
* @param {!Array.<!WebGLShader>} shaders The shaders to attach
* @param {!Array.<string>} optAttribs The attribs names.
* @param {!Array.<number>} optLocations The locations for the attribs.
*/
const loadProgram = function (gl, shaders, optAttribs, optLocations) {
var program = gl.createProgram();
for (var i = 0; i < shaders.length; ++i) {
gl.attachShader(program, shaders[i]);
}
if (optAttribs) {
for (var i = 0; i < optAttribs.length; ++i) {
gl.bindAttribLocation(
program,
optLocations ? optLocations[i] : i,
optAttribs[i]);
}
}
gl.linkProgram(program);
// Check the link status
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
// something went wrong with the link
const lastError = gl.getProgramInfoLog(program);
error('Error in program linking:' + lastError);
gl.deleteProgram(program);
return null;
}
return program;
};
/**
* Loads a shader from a script tag.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {string} scriptId The id of the script tag.
* @param {number} optShaderType The type of shader. If not passed in it will
* be derived from the type of the script tag.
* @param {function(string): void) optErrorCallback callback for errors.
* @return {!WebGLShader} The created shader.
*/
const createShaderFromScript = function (
gl, scriptId, optShaderType, optErrorCallback
) {
var shaderSource = '';
var shaderType;
var shaderScript = document.getElementById(scriptId);
if (!shaderScript) {
throw new Error('*** Error: unknown script element' + scriptId);
}
shaderSource = shaderScript.text;
if (!optShaderType) {
if (shaderScript.type === 'x-shader/x-vertex') {
shaderType = gl.VERTEX_SHADER;
} else if (shaderScript.type === 'x-shader/x-fragment') {
shaderType = gl.FRAGMENT_SHADER;
} else if (
shaderType !== gl.VERTEX_SHADER &&
shaderType !== gl.FRAGMENT_SHADER
) {
throw new Error('*** Error: unknown shader type');
}
}
return loadShader(
gl,
shaderSource,
optShaderType || shaderType,
optErrorCallback
);
};
if (typeof exports === 'object' && typeof module !== 'undefined') {
module.exports = {
setupWebGL : setupWebGL,
createProgram : loadProgram,
createShaderFromScript : createShaderFromScript,
getWebGLContext : getWebGLContext,
loadShader : loadShader
}
} else {
// export to global
window.setupWebGL = setupWebGL;
window.createProgram = loadProgram;
window.createShaderFromScriptElement = createShaderFromScript;
window.getWebGLContext = getWebGLContext;
window.loadShader = loadShader;
}
}());