/sdk/tests/conformance/resources/webgl-test-utils.js
JavaScript | 2429 lines | 1498 code | 164 blank | 767 comment | 246 complexity | 4916ccfcca581dd97e9a73b2f6bab1a5 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- ** 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.
- */
- var WebGLTestUtils = (function() {
- "use strict";
- /**
- * Wrapped logging function.
- * @param {string} msg The message to log.
- */
- var log = function(msg) {
- if (window.console && window.console.log) {
- window.console.log(msg);
- }
- };
- /**
- * Wrapped logging function.
- * @param {string} msg The message to log.
- */
- var error = function(msg) {
- if (window.console) {
- if (window.console.error) {
- window.console.error(msg);
- }
- else if (window.console.log) {
- window.console.log(msg);
- }
- }
- };
- /**
- * Turn off all logging.
- */
- var loggingOff = function() {
- log = function() {};
- error = function() {};
- };
- /**
- * Converts a WebGL enum to a string.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} value The enum value.
- * @return {string} The enum as a string.
- */
- var glEnumToString = function(gl, value) {
- // Optimization for the most common enum:
- if (value === gl.NO_ERROR) {
- return "NO_ERROR";
- }
- for (var p in gl) {
- if (gl[p] == value) {
- return p;
- }
- }
- return "0x" + value.toString(16);
- };
- var lastError = "";
- /**
- * Returns the last compiler/linker error.
- * @return {string} The last compiler/linker error.
- */
- var getLastError = function() {
- return lastError;
- };
- /**
- * Whether a haystack ends with a needle.
- * @param {string} haystack String to search
- * @param {string} needle String to search for.
- * @param {boolean} True if haystack ends with needle.
- */
- var endsWith = function(haystack, needle) {
- return haystack.substr(haystack.length - needle.length) === needle;
- };
- /**
- * Whether a haystack starts with a needle.
- * @param {string} haystack String to search
- * @param {string} needle String to search for.
- * @param {boolean} True if haystack starts with needle.
- */
- var startsWith = function(haystack, needle) {
- return haystack.substr(0, needle.length) === needle;
- };
- /**
- * A vertex shader for a single texture.
- * @type {string}
- */
- var simpleTextureVertexShader = [
- 'attribute vec4 vPosition;',
- 'attribute vec2 texCoord0;',
- 'varying vec2 texCoord;',
- 'void main() {',
- ' gl_Position = vPosition;',
- ' texCoord = texCoord0;',
- '}'].join('\n');
- /**
- * A fragment shader for a single texture.
- * @type {string}
- */
- var simpleTextureFragmentShader = [
- 'precision mediump float;',
- 'uniform sampler2D tex;',
- 'varying vec2 texCoord;',
- 'void main() {',
- ' gl_FragData[0] = texture2D(tex, texCoord);',
- '}'].join('\n');
- /**
- * A vertex shader for a single texture.
- * @type {string}
- */
- var noTexCoordTextureVertexShader = [
- 'attribute vec4 vPosition;',
- 'varying vec2 texCoord;',
- 'void main() {',
- ' gl_Position = vPosition;',
- ' texCoord = vPosition.xy * 0.5 + 0.5;',
- '}'].join('\n');
- /**
- * A vertex shader for a uniform color.
- * @type {string}
- */
- var simpleColorVertexShader = [
- 'attribute vec4 vPosition;',
- 'void main() {',
- ' gl_Position = vPosition;',
- '}'].join('\n');
- /**
- * A fragment shader for a uniform color.
- * @type {string}
- */
- var simpleColorFragmentShader = [
- 'precision mediump float;',
- 'uniform vec4 u_color;',
- 'void main() {',
- ' gl_FragData[0] = u_color;',
- '}'].join('\n');
- /**
- * A vertex shader for vertex colors.
- * @type {string}
- */
- var simpleVertexColorVertexShader = [
- 'attribute vec4 vPosition;',
- 'attribute vec4 a_color;',
- 'varying vec4 v_color;',
- 'void main() {',
- ' gl_Position = vPosition;',
- ' v_color = a_color;',
- '}'].join('\n');
- /**
- * A fragment shader for vertex colors.
- * @type {string}
- */
- var simpleVertexColorFragmentShader = [
- 'precision mediump float;',
- 'varying vec4 v_color;',
- 'void main() {',
- ' gl_FragData[0] = v_color;',
- '}'].join('\n');
- /**
- * Creates a simple texture vertex shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleTextureVertexShader = function(gl) {
- return loadShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
- };
- /**
- * Creates a simple texture fragment shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleTextureFragmentShader = function(gl) {
- return loadShader(
- gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER);
- };
- /**
- * Creates a texture vertex shader that doesn't need texcoords.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupNoTexCoordTextureVertexShader = function(gl) {
- return loadShader(gl, noTexCoordTextureVertexShader, gl.VERTEX_SHADER);
- };
- /**
- * Creates a simple vertex color vertex shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleVertexColorVertexShader = function(gl) {
- return loadShader(gl, simpleVertexColorVertexShader, gl.VERTEX_SHADER);
- };
- /**
- * Creates a simple vertex color fragment shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleVertexColorFragmentShader = function(gl) {
- return loadShader(
- gl, simpleVertexColorFragmentShader, gl.FRAGMENT_SHADER);
- };
- /**
- * Creates a simple color vertex shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleColorVertexShader = function(gl) {
- return loadShader(gl, simpleColorVertexShader, gl.VERTEX_SHADER);
- };
- /**
- * Creates a simple color fragment shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {!WebGLShader}
- */
- var setupSimpleColorFragmentShader = function(gl) {
- return loadShader(
- gl, simpleColorFragmentShader, gl.FRAGMENT_SHADER);
- };
- /**
- * Creates a program, attaches shaders, binds attrib locations, links the
- * program and calls useProgram.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<!WebGLShader|string>} shaders The shaders to
- * attach, or the source, or the id of a script to get
- * the source from.
- * @param {!Array.<string>} opt_attribs The attribs names.
- * @param {!Array.<number>} opt_locations The locations for the attribs.
- */
- var setupProgram = function(gl, shaders, opt_attribs, opt_locations) {
- var realShaders = [];
- var program = gl.createProgram();
- var shaderCount = 0;
- for (var ii = 0; ii < shaders.length; ++ii) {
- var shader = shaders[ii];
- var shaderType = undefined;
- if (typeof shader == 'string') {
- var element = document.getElementById(shader);
- if (element) {
- if (element.type != "x-shader/x-vertex" && element.type != "x-shader/x-fragment")
- shaderType = ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER;
- shader = loadShaderFromScript(gl, shader, shaderType);
- } else if (endsWith(shader, ".vert")) {
- shader = loadShaderFromFile(gl, shader, gl.VERTEX_SHADER);
- } else if (endsWith(shader, ".frag")) {
- shader = loadShaderFromFile(gl, shader, gl.FRAGMENT_SHADER);
- } else {
- shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER);
- }
- }
- if (shader) {
- ++shaderCount;
- gl.attachShader(program, shader);
- }
- }
- if (shaderCount != 2) {
- error("Error in compiling shader");
- return null;
- }
- if (opt_attribs) {
- for (var ii = 0; ii < opt_attribs.length; ++ii) {
- gl.bindAttribLocation(
- program,
- opt_locations ? opt_locations[ii] : ii,
- opt_attribs[ii]);
- }
- }
- gl.linkProgram(program);
- // Check the link status
- var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
- if (!linked) {
- // something went wrong with the link
- lastError = gl.getProgramInfoLog (program);
- error("Error in program linking:" + lastError);
- gl.deleteProgram(program);
- return null;
- }
- gl.useProgram(program);
- return program;
- };
- /**
- * Creates a simple texture program.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @return {WebGLProgram}
- */
- var setupNoTexCoordTextureProgram = function(gl) {
- var vs = setupNoTexCoordTextureVertexShader(gl);
- var fs = setupSimpleTextureFragmentShader(gl);
- if (!vs || !fs) {
- return null;
- }
- var program = setupProgram(
- gl,
- [vs, fs],
- ['vPosition'],
- [0]);
- if (!program) {
- gl.deleteShader(fs);
- gl.deleteShader(vs);
- }
- gl.useProgram(program);
- return program;
- };
- /**
- * Creates a simple texture program.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for position.
- * @param {number} opt_texcoordLocation The attrib location for texture coords.
- * @return {WebGLProgram}
- */
- var setupSimpleTextureProgram = function(
- gl, opt_positionLocation, opt_texcoordLocation) {
- opt_positionLocation = opt_positionLocation || 0;
- opt_texcoordLocation = opt_texcoordLocation || 1;
- var vs = setupSimpleTextureVertexShader(gl);
- var fs = setupSimpleTextureFragmentShader(gl);
- if (!vs || !fs) {
- return null;
- }
- var program = setupProgram(
- gl,
- [vs, fs],
- ['vPosition', 'texCoord0'],
- [opt_positionLocation, opt_texcoordLocation]);
- if (!program) {
- gl.deleteShader(fs);
- gl.deleteShader(vs);
- }
- gl.useProgram(program);
- return program;
- };
- /**
- * Creates a simple vertex color program.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for position.
- * @param {number} opt_vertexColorLocation The attrib location
- * for vertex colors.
- * @return {WebGLProgram}
- */
- var setupSimpleVertexColorProgram = function(
- gl, opt_positionLocation, opt_vertexColorLocation) {
- opt_positionLocation = opt_positionLocation || 0;
- opt_vertexColorLocation = opt_vertexColorLocation || 1;
- var vs = setupSimpleVertexColorVertexShader(gl);
- var fs = setupSimpleVertexColorFragmentShader(gl);
- if (!vs || !fs) {
- return null;
- }
- var program = setupProgram(
- gl,
- [vs, fs],
- ['vPosition', 'a_color'],
- [opt_positionLocation, opt_vertexColorLocation]);
- if (!program) {
- gl.deleteShader(fs);
- gl.deleteShader(vs);
- }
- gl.useProgram(program);
- return program;
- };
- /**
- * Creates a simple color program.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for position.
- * @return {WebGLProgram}
- */
- var setupSimpleColorProgram = function(gl, opt_positionLocation) {
- opt_positionLocation = opt_positionLocation || 0;
- var vs = setupSimpleColorVertexShader(gl);
- var fs = setupSimpleColorFragmentShader(gl);
- if (!vs || !fs) {
- return null;
- }
- var program = setupProgram(
- gl,
- [vs, fs],
- ['vPosition'],
- [opt_positionLocation]);
- if (!program) {
- gl.deleteShader(fs);
- gl.deleteShader(vs);
- }
- gl.useProgram(program);
- return program;
- };
- /**
- * Creates buffers for a textured unit quad and attaches them to vertex attribs.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for position.
- * @param {number} opt_texcoordLocation The attrib location for texture coords.
- * @return {!Array.<WebGLBuffer>} The buffer objects that were
- * created.
- */
- var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) {
- return setupUnitQuadWithTexCoords(gl, [ 0.0, 0.0 ], [ 1.0, 1.0 ],
- opt_positionLocation, opt_texcoordLocation);
- };
- /**
- * Creates buffers for a textured unit quad with specified lower left
- * and upper right texture coordinates, and attaches them to vertex
- * attribs.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the lower left corner.
- * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
- * @param {number} opt_positionLocation The attrib location for position.
- * @param {number} opt_texcoordLocation The attrib location for texture coords.
- * @return {!Array.<WebGLBuffer>} The buffer objects that were
- * created.
- */
- var setupUnitQuadWithTexCoords = function(
- gl, lowerLeftTexCoords, upperRightTexCoords,
- opt_positionLocation, opt_texcoordLocation) {
- return setupQuad(gl, {
- positionLocation: opt_positionLocation || 0,
- texcoordLocation: opt_texcoordLocation || 1,
- lowerLeftTexCoords: lowerLeftTexCoords,
- upperRightTexCoords: upperRightTexCoords,
- });
- };
- /**
- * Makes a quad with various options.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Object} options.
- *
- * scale: scale to multiple unit quad values by. default 1.0.
- * positionLocation: attribute location for position.
- * texcoordLocation: attribute location for texcoords.
- * If this does not exist no texture coords are created.
- * lowerLeftTexCoords: an array of 2 values for the
- * lowerLeftTexCoords.
- * upperRightTexCoords: an array of 2 values for the
- * upperRightTexCoords.
- */
- var setupQuad = function(gl, options) {
- var positionLocation = options.positionLocation || 0;
- var scale = options.scale || 1;
- var objects = [];
- var vertexObject = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
- 1.0 * scale , 1.0 * scale,
- -1.0 * scale , 1.0 * scale,
- -1.0 * scale , -1.0 * scale,
- 1.0 * scale , 1.0 * scale,
- -1.0 * scale , -1.0 * scale,
- 1.0 * scale , -1.0 * scale,]), gl.STATIC_DRAW);
- gl.enableVertexAttribArray(positionLocation);
- gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
- objects.push(vertexObject);
- if (options.texcoordLocation !== undefined) {
- var llx = options.lowerLeftTexCoords[0];
- var lly = options.lowerLeftTexCoords[1];
- var urx = options.upperRightTexCoords[0];
- var ury = options.upperRightTexCoords[1];
- var vertexObject = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
- urx, ury,
- llx, ury,
- llx, lly,
- urx, ury,
- llx, lly,
- urx, lly]), gl.STATIC_DRAW);
- gl.enableVertexAttribArray(options.texcoordLocation);
- gl.vertexAttribPointer(options.texcoordLocation, 2, gl.FLOAT, false, 0, 0);
- objects.push(vertexObject);
- }
- return objects;
- };
- /**
- * Creates a program and buffers for rendering a textured quad.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for
- * position. Default = 0.
- * @param {number} opt_texcoordLocation The attrib location for
- * texture coords. Default = 1.
- * @return {!WebGLProgram}
- */
- var setupTexturedQuad = function(
- gl, opt_positionLocation, opt_texcoordLocation) {
- var program = setupSimpleTextureProgram(
- gl, opt_positionLocation, opt_texcoordLocation);
- setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation);
- return program;
- };
- /**
- * Creates a program and buffers for rendering a color quad.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} opt_positionLocation The attrib location for position.
- * @return {!WebGLProgram}
- */
- var setupColorQuad = function(gl, opt_positionLocation) {
- opt_positionLocation = opt_positionLocation || 0;
- var program = setupSimpleColorProgram(gl);
- setupUnitQuad(gl, opt_positionLocation);
- return program;
- };
- /**
- * Creates a program and buffers for rendering a textured quad with
- * specified lower left and upper right texture coordinates.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the lower left corner.
- * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
- * @param {number} opt_positionLocation The attrib location for position.
- * @param {number} opt_texcoordLocation The attrib location for texture coords.
- * @return {!WebGLProgram}
- */
- var setupTexturedQuadWithTexCoords = function(
- gl, lowerLeftTexCoords, upperRightTexCoords,
- opt_positionLocation, opt_texcoordLocation) {
- var program = setupSimpleTextureProgram(
- gl, opt_positionLocation, opt_texcoordLocation);
- setupUnitQuadWithTexCoords(gl, lowerLeftTexCoords, upperRightTexCoords,
- opt_positionLocation, opt_texcoordLocation);
- return program;
- };
- /**
- * Creates a unit quad with only positions of a given resolution.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} gridRes The resolution of the mesh grid,
- * expressed in the number of quads across and down.
- * @param {number} opt_positionLocation The attrib location for position.
- */
- var setupIndexedQuad = function (
- gl, gridRes, opt_positionLocation, opt_flipOddTriangles) {
- return setupIndexedQuadWithOptions(gl,
- { gridRes: gridRes,
- positionLocation: opt_positionLocation,
- flipOddTriangles: opt_flipOddTriangles
- });
- };
- /**
- * Creates a quad with various options.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Object) options The options. See below.
- * @return {!Array.<WebGLBuffer>} The created buffers.
- * [positions, <colors>, indices]
- *
- * Options:
- * gridRes: number of quads across and down grid.
- * positionLocation: attrib location for position
- * flipOddTriangles: reverse order of vertices of every other
- * triangle
- * positionOffset: offset added to each vertex
- * positionMult: multipier for each vertex
- * colorLocation: attrib location for vertex colors. If
- * undefined no vertex colors will be created.
- */
- var setupIndexedQuadWithOptions = function (gl, options) {
- var positionLocation = options.positionLocation || 0;
- var objects = [];
- var gridRes = options.gridRes || 1;
- var positionOffset = options.positionOffset || 0;
- var positionMult = options.positionMult || 1;
- var vertsAcross = gridRes + 1;
- var numVerts = vertsAcross * vertsAcross;
- var positions = new Float32Array(numVerts * 3);
- var indices = new Uint16Array(6 * gridRes * gridRes);
- var poffset = 0;
- for (var yy = 0; yy <= gridRes; ++yy) {
- for (var xx = 0; xx <= gridRes; ++xx) {
- positions[poffset + 0] = (-1 + 2 * xx / gridRes) * positionMult + positionOffset;
- positions[poffset + 1] = (-1 + 2 * yy / gridRes) * positionMult + positionOffset;
- positions[poffset + 2] = 0;
- poffset += 3;
- }
- }
- var buf = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
- gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
- gl.enableVertexAttribArray(positionLocation);
- gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
- objects.push(buf);
- if (options.colorLocation !== undefined) {
- var colors = new Float32Array(numVerts * 4);
- for (var yy = 0; yy <= gridRes; ++yy) {
- for (var xx = 0; xx <= gridRes; ++xx) {
- if (options.color !== undefined) {
- colors[poffset + 0] = options.color[0];
- colors[poffset + 1] = options.color[1];
- colors[poffset + 2] = options.color[2];
- colors[poffset + 3] = options.color[3];
- } else {
- colors[poffset + 0] = xx / gridRes;
- colors[poffset + 1] = yy / gridRes;
- colors[poffset + 2] = (xx / gridRes) * (yy / gridRes);
- colors[poffset + 3] = (yy % 2) * 0.5 + 0.5;
- }
- poffset += 4;
- }
- }
- var buf = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
- gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
- gl.enableVertexAttribArray(options.colorLocation);
- gl.vertexAttribPointer(options.colorLocation, 4, gl.FLOAT, false, 0, 0);
- objects.push(buf);
- }
- var tbase = 0;
- for (var yy = 0; yy < gridRes; ++yy) {
- var index = yy * vertsAcross;
- for (var xx = 0; xx < gridRes; ++xx) {
- indices[tbase + 0] = index + 0;
- indices[tbase + 1] = index + 1;
- indices[tbase + 2] = index + vertsAcross;
- indices[tbase + 3] = index + vertsAcross;
- indices[tbase + 4] = index + 1;
- indices[tbase + 5] = index + vertsAcross + 1;
- if (options.flipOddTriangles) {
- indices[tbase + 4] = index + vertsAcross + 1;
- indices[tbase + 5] = index + 1;
- }
- index += 1;
- tbase += 6;
- }
- }
- var buf = gl.createBuffer();
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
- objects.push(buf);
- return objects;
- };
- /**
- * Returns the constructor for an ArrayBuffer that
- * corresponds to the given WebGL type.
- * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
- * @param {number} type The WebGL type (eg, gl.UNSIGNED_BYTE)
- * @return {!Constructor} The ArrayBuffer constructor that
- * corresponds to the given type.
- */
- var glTypeToArrayBufferType = function(gl, type) {
- switch (type) {
- case gl.BYTE:
- return window.Int8Array;
- case gl.UNSIGNED_BYTE:
- return window.Uint8Array;
- case gl.SHORT:
- return window.Int16Array;
- case gl.UNSIGNED_SHORT:
- case gl.UNSIGNED_SHORT_5_6_5:
- case gl.UNSIGNED_SHORT_4_4_4_4:
- case gl.UNSIGNED_SHORT_5_5_5_1:
- return window.Uint16Array;
- case gl.INT:
- return window.Int32Array;
- case gl.UNSIGNED_INT:
- return window.Uint32Array;
- default:
- throw 'unknown gl type ' + glEnumToString(gl, type);
- }
- };
- /**
- * Returns the number of bytes per component for a given WebGL
- * type.
- * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
- * @param {number} type The WebGL type (eg, gl.UNSIGNED_BYTE)
- * @return {!Constructor} The ArrayBuffer constructor that
- * corresponds to the given type.
- */
- var getBytesPerComponent = function(gl, type) {
- switch (type) {
- case gl.BYTE:
- case gl.UNSIGNED_BYTE:
- return 1;
- case gl.SHORT:
- case gl.UNSIGNED_SHORT:
- case gl.UNSIGNED_SHORT_5_6_5:
- case gl.UNSIGNED_SHORT_4_4_4_4:
- case gl.UNSIGNED_SHORT_5_5_5_1:
- return 2;
- case gl.INT:
- case gl.UNSIGNED_INT:
- return 4;
- default:
- throw 'unknown gl type ' + glEnumToString(gl, type);
- }
- };
- /**
- * Fills the given texture with a solid color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!WebGLTexture} tex The texture to fill.
- * @param {number} width The width of the texture to create.
- * @param {number} height The height of the texture to create.
- * @param {!Array.<number>} color The color to fill with.
- * where each element is in the range 0 to 255.
- * @param {number} opt_level The level of the texture to fill. Default = 0.
- * @param {number} opt_format The format for the texture.
- */
- var fillTexture = function(gl, tex, width, height, color, opt_level, opt_format, opt_type) {
- opt_level = opt_level || 0;
- opt_format = opt_format || gl.RGBA;
- opt_type = opt_type || gl.UNSIGNED_BYTE;
- var pack = gl.getParameter(gl.UNPACK_ALIGNMENT);
- var numComponents = color.length;
- var bytesPerComponent = getBytesPerComponent(gl, opt_type);
- var rowSize = numComponents * width * bytesPerComponent;
- var paddedRowSize = Math.floor((rowSize + pack - 1) / pack) * pack;
- var size = rowSize + (height - 1) * paddedRowSize;
- size = Math.floor((size + bytesPerComponent - 1) / bytesPerComponent) * bytesPerComponent;
- var buf = new (glTypeToArrayBufferType(gl, opt_type))(size);
- for (var yy = 0; yy < height; ++yy) {
- var off = yy * paddedRowSize;
- for (var xx = 0; xx < width; ++xx) {
- for (var jj = 0; jj < numComponents; ++jj) {
- buf[off++] = color[jj];
- }
- }
- }
- gl.bindTexture(gl.TEXTURE_2D, tex);
- gl.texImage2D(
- gl.TEXTURE_2D, opt_level, opt_format, width, height, 0,
- opt_format, opt_type, buf);
- };
- /**
- * Creates a texture and fills it with a solid color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} width The width of the texture to create.
- * @param {number} height The height of the texture to create.
- * @param {!Array.<number>} color The color to fill with. A 4 element array
- * where each element is in the range 0 to 255.
- * @return {!WebGLTexture}
- */
- var createColoredTexture = function(gl, width, height, color) {
- var tex = gl.createTexture();
- fillTexture(gl, tex, width, height, color);
- return tex;
- };
- var ubyteToFloat = function(c) {
- return c / 255;
- };
- var ubyteColorToFloatColor = function(color) {
- var floatColor = [];
- for (var ii = 0; ii < color.length; ++ii) {
- floatColor[ii] = ubyteToFloat(color[ii]);
- }
- return floatColor;
- };
- /**
- * Sets the "u_color" uniform of the current program to color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number> color 4 element array of 0-1 color
- * components.
- */
- var setFloatDrawColor = function(gl, color) {
- var program = gl.getParameter(gl.CURRENT_PROGRAM);
- var colorLocation = gl.getUniformLocation(program, "u_color");
- gl.uniform4fv(colorLocation, color);
- };
- /**
- * Sets the "u_color" uniform of the current program to color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number> color 4 element array of 0-255 color
- * components.
- */
- var setUByteDrawColor = function(gl, color) {
- setFloatDrawColor(gl, ubyteColorToFloatColor(color));
- };
- /**
- * Draws a previously setup quad in the given color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number>} color The color to draw with. A 4
- * element array where each element is in the range 0 to
- * 1.
- */
- var drawFloatColorQuad = function(gl, color) {
- var program = gl.getParameter(gl.CURRENT_PROGRAM);
- var colorLocation = gl.getUniformLocation(program, "u_color");
- gl.uniform4fv(colorLocation, color);
- gl.drawArrays(gl.TRIANGLES, 0, 6);
- };
- /**
- * Draws a previously setup quad in the given color.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number>} color The color to draw with. A 4
- * element array where each element is in the range 0 to
- * 255.
- */
- var drawUByteColorQuad = function(gl, color) {
- drawFloatColorQuad(gl, ubyteColorToFloatColor(color));
- };
- /**
- * Draws a previously setupUnitQuad.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- */
- var drawUnitQuad = function(gl) {
- gl.drawArrays(gl.TRIANGLES, 0, 6);
- };
- /**
- * Clears then Draws a previously setupUnitQuad.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!Array.<number>} opt_color The color to fill clear with before
- * drawing. A 4 element array where each element is in the range 0 to
- * 255. Default [255, 255, 255, 255]
- */
- var clearAndDrawUnitQuad = function(gl, opt_color) {
- opt_color = opt_color || [255, 255, 255, 255];
- gl.clearColor(
- opt_color[0] / 255,
- opt_color[1] / 255,
- opt_color[2] / 255,
- opt_color[3] / 255);
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- drawUnitQuad(gl);
- };
- /**
- * Draws a quad previously setup with setupIndexedQuad.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} gridRes Resolution of grid.
- */
- var drawIndexedQuad = function(gl, gridRes) {
- gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0);
- };
- /**
- * Draws a previously setupIndexedQuad
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number} gridRes Resolution of grid.
- * @param {!Array.<number>} opt_color The color to fill clear with before
- * drawing. A 4 element array where each element is in the range 0 to
- * 255. Default [255, 255, 255, 255]
- */
- var clearAndDrawIndexedQuad = function(gl, gridRes, opt_color) {
- opt_color = opt_color || [255, 255, 255, 255];
- gl.clearColor(
- opt_color[0] / 255,
- opt_color[1] / 255,
- opt_color[2] / 255,
- opt_color[3] / 255);
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- drawIndexedQuad(gl, gridRes);
- };
- /**
- * Clips a range to min, max
- * (Eg. clipToRange(-5,7,0,20) would return {value:0,extent:2}
- * @param {number} value start of range
- * @param {number} extent extent of range
- * @param {number} min min.
- * @param {number} max max.
- * @return {!{value:number,extent:number} The clipped value.
- */
- var clipToRange = function(value, extent, min, max) {
- if (value < min) {
- extent -= min - value;
- value = min;
- }
- var end = value + extent;
- if (end > max) {
- extent -= end - max;
- }
- if (extent < 0) {
- value = max;
- extent = 0;
- }
- return {value:value, extent: extent};
- };
- /**
- * Determines if the passed context is an instance of a WebGLRenderingContext
- * or later variant (like WebGL2RenderingContext)
- * @param {CanvasRenderingContext} ctx The context to check.
- */
- var isWebGLContext = function(ctx) {
- if (ctx instanceof WebGLRenderingContext)
- return true;
- if ('WebGL2RenderingContext' in window && ctx instanceof WebGL2RenderingContext)
- return true;
- return false;
- };
- /**
- * Checks that a portion of a canvas is 1 color.
- * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
- * WebGLRenderingContext or 2D context to use.
- * @param {number} x left corner of region to check.
- * @param {number} y bottom corner of region to check in case of checking from
- * a GL context or top corner in case of checking from a 2D context.
- * @param {number} width width of region to check.
- * @param {number} height width of region to check.
- * @param {!Array.<number>} color The color expected. A 4 element array where
- * each element is in the range 0 to 255.
- * @param {number} opt_errorRange Optional. Acceptable error in
- * color checking. 0 by default.
- * @param {!function()} sameFn Function to call if all pixels
- * are the same as color.
- * @param {!function()} differentFn Function to call if a pixel
- * is different than color
- * @param {!function()} logFn Function to call for logging.
- */
- var checkCanvasRectColor = function(gl, x, y, width, height, color, opt_errorRange, sameFn, differentFn, logFn) {
- if (isWebGLContext(gl) && !gl.getParameter(gl.FRAMEBUFFER_BINDING)) {
- // We're reading the backbuffer so clip.
- var xr = clipToRange(x, width, 0, gl.canvas.width);
- var yr = clipToRange(y, height, 0, gl.canvas.height);
- if (!xr.extent || !yr.extent) {
- logFn("checking rect: effective width or heigh is zero");
- sameFn();
- return;
- }
- x = xr.value;
- y = yr.value;
- width = xr.extent;
- height = yr.extent;
- }
- var errorRange = opt_errorRange || 0;
- if (!errorRange.length) {
- errorRange = [errorRange, errorRange, errorRange, errorRange]
- }
- var buf;
- if (isWebGLContext(gl)) {
- buf = new Uint8Array(width * height * 4);
- gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
- } else {
- buf = gl.getImageData(x, y, width, height).data;
- }
- for (var i = 0; i < width * height; ++i) {
- var offset = i * 4;
- for (var j = 0; j < color.length; ++j) {
- if (Math.abs(buf[offset + j] - color[j]) > errorRange[j]) {
- differentFn();
- var was = buf[offset + 0].toString();
- for (j = 1; j < color.length; ++j) {
- was += "," + buf[offset + j];
- }
- logFn('at (' + (x + (i % width)) + ', ' + (y + Math.floor(i / width)) +
- ') expected: ' + color + ' was ' + was);
- return;
- }
- }
- }
- sameFn();
- };
- /**
- * Checks that a portion of a canvas is 1 color.
- * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
- * WebGLRenderingContext or 2D context to use.
- * @param {number} x left corner of region to check.
- * @param {number} y bottom corner of region to check in case of checking from
- * a GL context or top corner in case of checking from a 2D context.
- * @param {number} width width of region to check.
- * @param {number} height width of region to check.
- * @param {!Array.<number>} color The color expected. A 4 element array where
- * each element is in the range 0 to 255.
- * @param {string} opt_msg Message to associate with success. Eg
- * ("should be red").
- * @param {number} opt_errorRange Optional. Acceptable error in
- * color checking. 0 by default.
- */
- var checkCanvasRect = function(gl, x, y, width, height, color, opt_msg, opt_errorRange) {
- var msg = opt_msg;
- if (msg === undefined) {
- msg = "should be " + color.toString();
- }
- checkCanvasRectColor(
- gl, x, y, width, height, color, opt_errorRange,
- function() {
- testPassed(msg);
- },
- function() {
- testFailed(msg);
- },
- debug);
- };
- /**
- * Checks that an entire canvas is 1 color.
- * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
- * WebGLRenderingContext or 2D context to use.
- * @param {!Array.<number>} color The color expected. A 4 element array where
- * each element is in the range 0 to 255.
- * @param {string} msg Message to associate with success. Eg ("should be red").
- * @param {number} errorRange Optional. Acceptable error in
- * color checking. 0 by default.
- */
- var checkCanvas = function(gl, color, msg, errorRange) {
- checkCanvasRect(gl, 0, 0, gl.canvas.width, gl.canvas.height, color, msg, errorRange);
- };
- /**
- * Checks a rectangular area both inside the area and outside
- * the area.
- * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
- * WebGLRenderingContext or 2D context to use.
- * @param {number} x left corner of region to check.
- * @param {number} y bottom corner of region to check in case of checking from
- * a GL context or top corner in case of checking from a 2D context.
- * @param {number} width width of region to check.
- * @param {number} height width of region to check.
- * @param {!Array.<number>} innerColor The color expected inside
- * the area. A 4 element array where each element is in the
- * range 0 to 255.
- * @param {!Array.<number>} outerColor The color expected
- * outside. A 4 element array where each element is in the
- * range 0 to 255.
- * @param {!number} opt_edgeSize: The number of pixels to skip
- * around the edges of the area. Defaut 0.
- * @param {!{width:number, height:number}} opt_outerDimensions
- * The outer dimensions. Default the size of gl.canvas.
- */
- var checkAreaInAndOut = function(gl, x, y, width, height, innerColor, outerColor, opt_edgeSize, opt_outerDimensions) {
- var outerDimensions = opt_outerDimensions || { width: gl.canvas.width, height: gl.canvas.height };
- var edgeSize = opt_edgeSize || 0;
- checkCanvasRect(gl, x + edgeSize, y + edgeSize, width - edgeSize * 2, height - edgeSize * 2, innerColor);
- checkCanvasRect(gl, 0, 0, x - edgeSize, outerDimensions.height, outerColor);
- checkCanvasRect(gl, x + width + edgeSize, 0, outerDimensions.width - x - width - edgeSize, outerDimensions.height, outerColor);
- checkCanvasRect(gl, 0, 0, outerDimensions.width, y - edgeSize, outerColor);
- checkCanvasRect(gl, 0, y + height + edgeSize, outerDimensions.width, outerDimensions.height - y - height - edgeSize, outerColor);
- };
- /**
- * Loads a texture, calls callback when finished.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {string} url URL of image to load
- * @param {function(!Image): void} callback Function that gets called after
- * image has loaded
- * @return {!WebGLTexture} The created texture.
- */
- var loadTexture = function(gl, url, callback) {
- var texture = gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- var image = new Image();
- image.onload = function() {
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
- callback(image);
- };
- image.src = url;
- return texture;
- };
- /**
- * Makes a shallow copy of an object.
- * @param {!Object) src Object to copy
- * @return {!Object} The copy of src.
- */
- var shallowCopyObject = function(src) {
- var dst = {};
- for (var attr in src) {
- if (src.hasOwnProperty(attr)) {
- dst[attr] = src[attr];
- }
- }
- return dst;
- };
- /**
- * Checks if an attribute exists on an object case insensitive.
- * @param {!Object) obj Object to check
- * @param {string} attr Name of attribute to look for.
- * @return {string?} The name of the attribute if it exists,
- * undefined if not.
- */
- var hasAttributeCaseInsensitive = function(obj, attr) {
- var lower = attr.toLowerCase();
- for (var key in obj) {
- if (obj.hasOwnProperty(key) && key.toLowerCase() == lower) {
- return key;
- }
- }
- };
- /**
- * Returns a map of URL querystring options
- * @return {Object?} Object containing all the values in the URL querystring
- */
- var getUrlOptions = function() {
- var options = {};
- var s = window.location.href;
- var q = s.indexOf("?");
- var e = s.indexOf("#");
- if (e < 0) {
- e = s.length;
- }
- var query = s.substring(q + 1, e);
- var pairs = query.split("&");
- for (var ii = 0; ii < pairs.length; ++ii) {
- var keyValue = pairs[ii].split("=");
- var key = keyValue[0];
- var value = decodeURIComponent(keyValue[1]);
- options[key] = value;
- }
- return options;
- };
- /**
- * Creates a webgl context.
- * @param {!Canvas|string} opt_canvas The canvas tag to get
- * context from. If one is not passed in one will be
- * created. If it's a string it's assumed to be the id of a
- * canvas.
- * @param {Object} opt_attributes Context attributes.
- * @param {!number} opt_version Version of WebGL context to create
- * @return {!WebGLRenderingContext} The created context.
- */
- var create3DContext = function(opt_canvas, opt_attributes, opt_version) {
- if (window.initTestingHarness) {
- window.initTestingHarness();
- }
- var attributes = shallowCopyObject(opt_attributes || {});
- if (!hasAttributeCaseInsensitive(attributes, "antialias")) {
- attributes.antialias = false;
- }
- if (!opt_version) {
- opt_version = parseInt(getUrlOptions().webglVersion, 10) || 1;
- }
- opt_canvas = opt_canvas || document.createElement("canvas");
- if (typeof opt_canvas == 'string') {
- opt_canvas = document.getElementById(opt_canvas);
- }
- var context = null;
- var names;
- switch (opt_version) {
- case 2:
- names = ["webgl2", "experimental-webgl2"]; break;
- default:
- names = ["webgl", "experimental-webgl"]; break;
- }
- for (var i = 0; i < names.length; ++i) {
- try {
- context = opt_canvas.getContext(names[i], attributes);
- } catch (e) {
- }
- if (context) {
- break;
- }
- }
- if (!context) {
- testFailed("Unable to fetch WebGL rendering context for Canvas");
- }
- return context;
- }
- /**
- * Wraps a WebGL function with a function that throws an exception if there is
- * an error.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {string} fname Name of function to wrap.
- * @return {function} The wrapped function.
- */
- var createGLErrorWrapper = function(context, fname) {
- return function() {
- var rv = context[fname].apply(context, arguments);
- var err = context.getError();
- if (err != context.NO_ERROR)
- throw "GL error " + glEnumToString(context, err) + " in " + fname;
- return rv;
- };
- };
- /**
- * Creates a WebGL context where all functions are wrapped to throw an exception
- * if there is an error.
- * @param {!Canvas} canvas The HTML canvas to get a context from.
- * @return {!Object} The wrapped context.
- */
- function create3DContextWithWrapperThatThrowsOnGLError(canvas) {
- var context = create3DContext(canvas);
- var wrap = {};
- for (var i in context) {
- try {
- if (typeof context[i] == 'function') {
- wrap[i] = createGLErrorWrapper(context, i);
- } else {
- wrap[i] = context[i];
- }
- } catch (e) {
- error("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
- }
- }
- wrap.getError = function() {
- return context.getError();
- };
- return wrap;
- };
- /**
- * Tests that an evaluated expression generates a specific GL error.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number|Array.<number>} glErrors The expected gl error or an array of expected errors.
- * @param {string} evalStr The string to evaluate.
- */
- var shouldGenerateGLError = function(gl, glErrors, evalStr) {
- var exception;
- try {
- eval(evalStr);
- } catch (e) {
- exception = e;
- }
- if (exception) {
- testFailed(evalStr + " threw exception " + exception);
- } else {
- glErrorShouldBe(gl, glErrors, "after evaluating: " + evalStr);
- }
- };
- /**
- * Tests that the first error GL returns is the specified error.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {number|Array.<number>} glErrors The expected gl error or an array of expected errors.
- * @param {string} opt_msg Optional additional message.
- */
- var glErrorShouldBe = function(gl, glErrors, opt_msg) {
- if (!glErrors.length) {
- glErrors = [glErrors];
- }
- opt_msg = opt_msg || "";
- var err = gl.getError();
- var ndx = glErrors.indexOf(err);
- var errStrs = [];
- for (var ii = 0; ii < glErrors.length; ++ii) {
- errStrs.push(glEnumToString(gl, glErrors[ii]));
- }
- var expected = errStrs.join(" or ");
- if (ndx < 0) {
- var msg = "getError expected" + ((glErrors.length > 1) ? " one of: " : ": ");
- testFailed(msg + expected + ". Was " + glEnumToString(gl, err) + " : " + opt_msg);
- } else {
- var msg = "getError was " + ((glErrors.length > 1) ? "one of: " : "expected value: ");
- testPassed(msg + expected + " : " + opt_msg);
- }
- };
- /**
- * Links a WebGL program, throws if there are errors.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {!WebGLProgram} program The WebGLProgram to link.
- * @param {function(string): void) opt_errorCallback callback for errors.
- */
- var linkProgram = function(gl, program, opt_errorCallback) {
- var errFn = opt_errorCallback || testFailed;
- // Link the program
- gl.linkProgram(program);
- // Check the link status
- var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
- if (!linked) {
- // something went wrong with the link
- var error = gl.getProgramInfoLog (program);
- errFn("Error in program linking:" + error);
- gl.deleteProgram(program);
- }
- };
- /**
- * Loads text from an external file. This function is synchronous.
- * @param {string} url The url of the external file.
- * @param {!function(bool, string): void} callback that is sent a bool for
- * success and the string.
- */
- var loadTextFileAsync = function(url, callback) {
- log ("loading: " + url);
- var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
- var request;
- if (window.XMLHttpRequest) {
- request = new XMLHttpRequest();
- if (request.overrideMimeType) {
- request.overrideMimeType('text/plain');
- }
- } else {
- throw 'XMLHttpRequest is disabled';
- }
- try {
- request.open('GET', url, true);
- request.onreadystatechange = function() {
- if (request.readyState == 4) {
- var text = '';
- // HTTP reports success with a 200 status. The file protocol reports
- // success with zero. HTTP does not use zero as a status code (they
- // start at 100).
- // https://developer.mozilla.org/En/Using_XMLHttpRequest
- var success = request.status == 200 || request.status == 0;
- if (success) {
- text = request.responseText;
- }
- log("loaded: " + url);
- callback(success, text);
- }
- };
- request.send(null);
- } catch (e) {
- log("failed to load: " + url);
- callback(false, '');
- }
- };
- /**
- * Recursively loads a file as a list. Each line is parsed for a relative
- * path. If the file ends in .txt the contents of that file is inserted in
- * the list.
- *
- * @param {string} url The url of the external file.
- * @param {!function(bool, Array<string>): void} callback that is sent a bool
- * for success and the array of strings.
- */
- var getFileListAsync = function(url, callback) {
- var files = [];
- var getFileListImpl = function(url, callback) {
- var files = [];
- if (url.substr(url.length - 4) == '.txt') {
- loadTextFileAsync(url, function() {
- return function(success, text) {
- if (!success) {
- callback(false, '');
- return;
- }
- var lines = text.split('\n');
- var prefix = '';
- var lastSlash = url.lastIndexOf('/');
- if (lastSlash >= 0) {
- prefix = url.substr(0, lastSlash + 1);
- }
- var fail = false;
- var count = 1;
- var index = 0;
- for (var ii = 0; ii < lines.length; ++ii) {
- var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- if (str.length > 4 &&
- str[0] != '#' &&
- str[0] != ";" &&
- str.substr(0, 2) != "//") {
- var names = str.split(/ +/);
- new_url = prefix + str;
- if (names.length == 1) {
- new_url = prefix + str;
- ++count;
- getFileListImpl(new_url, function(index) {
- return function(success, new_files) {
- log("got files: " + new_files.length);
- if (success) {
- files[index] = new_files;
- }
- finish(success);
- };
- }(index++));
- } else {
- var s = "";
- var p = "";
- for (var jj = 0; jj < names.length; ++jj) {
- s += p + prefix + names[jj];
- p = " ";
- }
- files[index++] = s;
- }
- }
- }
- finish(true);
- function finish(success) {
- if (!success) {
- fail = true;
- }
- --count;
- log("count: " + count);
- if (!count) {
- callback(!fail, files);
- }
- }
- }
- }());
- } else {
- files.push(url);
- callback(true, files);
- }
- };
- getFileListImpl(url, function(success, files) {
- // flatten
- var flat = [];
- flatten(files);
- function flatten(files) {
- for (var ii = 0; ii < files.length; ++ii) {
- var value = files[ii];
- if (typeof(value) == "string") {
- flat.push(value);
- } else {
- flatten(value);
- }
- }
- }
- callback(success, flat);
- });
- };
- /**
- * Gets a file from a file/URL.
- * @param {string} file the URL of the file to get.
- * @return {string} The contents of the file.
- */
- var readFile = function(file) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", file, false);
- xhr.send();
- return xhr.responseText.replace(/\r/g, "");
- };
- var readFileList = function(url) {
- var files = [];
- if (url.substr(url.length - 4) == '.txt') {
- var lines = readFile(url).split('\n');
- var prefix = '';
- var lastSlash = url.lastIndexOf('/');
- if (lastSlash >= 0) {
- prefix = url.substr(0, lastSlash + 1);
- }
- for (var ii = 0; ii < lines.length; ++ii) {
- var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- if (str.length > 4 &&
- str[0] != '#' &&
- str[0] != ";" &&
- str.substr(0, 2) != "//") {
- var names = str.split(/ +/);
- if (names.length == 1) {
- new_url = prefix + str;
- files = files.concat(readFileList(new_url));
- } else {
- var s = "";
- var p = "";
- for (var jj = 0; jj < names.length; ++jj) {
- s += p + prefix + names[jj];
- p = " ";
- }
- files.push(s);
- }
- }
- }
- } else {
- files.push(url);
- }
- return files;
- };
- /**
- * Loads a shader.
- * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
- * @param {string} shaderSource The shader source.
- * @param {number} shaderType The type of shader.
- * @param {function(string): void) opt_errorCallback callback for errors.
- * @return {!WebGLShader} The created shader.
- */
- var loadShader = function(gl, shaderSource, shaderType, opt_errorCallback) {
- var errFn = opt_errorCallback || error;
- // Create the shader object
- var shader = gl.createShader(shaderTyp…
Large files files are truncated, but you can click here to view the full file