* the source from.
* @param {!Array.<string>} opt_attribs The attribs names.
* @param {!Array.<number>} opt_locations The locations for the attribs.
+ * @param {boolean} opt_logShaders Whether to log shader source.
*/
-var setupProgram = function(gl, shaders, opt_attribs, opt_locations) {
+var setupProgram = function(
+ gl, shaders, opt_attribs, opt_locations, opt_logShaders) {
var realShaders = [];
var program = gl.createProgram();
var shaderCount = 0;
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);
+ shader = loadShaderFromScript(gl, shader, shaderType, undefined, opt_logShaders);
} else if (endsWith(shader, ".vert")) {
- shader = loadShaderFromFile(gl, shader, gl.VERTEX_SHADER);
+ shader = loadShaderFromFile(gl, shader, gl.VERTEX_SHADER, undefined, opt_logShaders);
} else if (endsWith(shader, ".frag")) {
- shader = loadShaderFromFile(gl, shader, gl.FRAGMENT_SHADER);
+ shader = loadShaderFromFile(gl, shader, gl.FRAGMENT_SHADER, undefined, opt_logShaders);
} else {
- shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER);
+ shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER, undefined, opt_logShaders);
}
+ } else if (opt_logShaders) {
+ throw 'Shader source logging requested but no shader source provided';
}
if (shader) {
++shaderCount;
};
/**
- * Returns the constructor for an ArrayBuffer that
- * corresponds to the given WebGL type.
+ * Returns the constructor for a typed array 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
+ * @return {!Constructor} The typed array constructor that
* corresponds to the given type.
*/
-var glTypeToArrayBufferType = function(gl, type) {
+var glTypeToTypedArrayType = function(gl, type) {
switch (type) {
case gl.BYTE:
return window.Int8Array;
};
/**
- * Returns the number of bytes per component for a given WebGL
- * 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.
+ * @param {GLenum} type The WebGL type (eg, gl.UNSIGNED_BYTE)
+ * @return {number} The number of bytes per component.
*/
var getBytesPerComponent = function(gl, type) {
switch (type) {
};
/**
+ * Returns the number of typed array elements per pixel for a given WebGL
+ * format/type combination. The corresponding typed array type can be determined
+ * by calling glTypeToTypedArrayType.
+ * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
+ * @param {GLenum} format The WebGL format (eg, gl.RGBA)
+ * @param {GLenum} type The WebGL type (eg, gl.UNSIGNED_BYTE)
+ * @return {number} The number of typed array elements per pixel.
+ */
+var getTypedArrayElementsPerPixel = function(gl, format, type) {
+ switch (type) {
+ case gl.UNSIGNED_SHORT_5_6_5:
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return 1;
+ case gl.UNSIGNED_BYTE:
+ break;
+ default:
+ throw 'not a gl type for color information ' + glEnumToString(gl, type);
+ }
+
+ switch (format) {
+ case gl.RGBA:
+ return 4;
+ case gl.RGB:
+ return 3;
+ case gl.LUMINANCE_ALPHA:
+ return 2;
+ case gl.LUMINANCE:
+ case gl.ALPHA:
+ return 1;
+ default:
+ throw 'unknown gl format ' + glEnumToString(gl, format);
+ }
+};
+
+/**
* Fills the given texture with a solid color.
* @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
* @param {!WebGLTexture} tex The texture to fill.
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);
+ var buf = new (glTypeToTypedArrayType(gl, opt_type))(size);
for (var yy = 0; yy < height; ++yy) {
var off = yy * paddedRowSize;
for (var xx = 0; xx < width; ++xx) {
};
/**
+ * Checks whether the bound texture has expected dimensions. One corner pixel
+ * of the texture will be changed as a side effect.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!WebGLTexture} texture The texture to check.
+ * @param {number} width Expected width.
+ * @param {number} height Expected height.
+ * @param {GLenum} opt_format The texture's format. Defaults to RGBA.
+ * @param {GLenum} opt_type The texture's type. Defaults to UNSIGNED_BYTE.
+ */
+var checkTextureSize = function(gl, width, height, opt_format, opt_type) {
+ opt_format = opt_format || gl.RGBA;
+ opt_type = opt_type || gl.UNSIGNED_BYTE;
+
+ var numElements = getTypedArrayElementsPerPixel(gl, opt_format, opt_type);
+ var buf = new (glTypeToTypedArrayType(gl, opt_type))(numElements);
+
+ var errors = 0;
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width - 1, height - 1, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() != gl.NO_ERROR) {
+ testFailed("Texture was smaller than the expected size " + width + "x" + height);
+ ++errors;
+ }
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width - 1, height, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() == gl.NO_ERROR) {
+ testFailed("Texture was taller than " + height);
+ ++errors;
+ }
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width, height - 1, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() == gl.NO_ERROR) {
+ testFailed("Texture was wider than " + width);
+ ++errors;
+ }
+ if (errors == 0) {
+ testPassed("Texture had the expected size " + width + "x" + height);
+ }
+};
+
+/**
* Makes a shallow copy of an object.
* @param {!Object) src Object to copy
* @return {!Object} The copy of src.
* @param {string} shaderSource The shader source.
* @param {number} shaderType The type of shader.
* @param {function(string): void) opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ * @param {string} opt_shaderLabel Label that identifies the shader source in
+ * the log.
+ * @param {string} opt_url URL from where the shader source was loaded from.
+ * If opt_logShaders is set, then a link to the source file will also be
+ * added.
* @return {!WebGLShader} The created shader.
*/
-var loadShader = function(gl, shaderSource, shaderType, opt_errorCallback) {
+var loadShader = function(
+ gl, shaderSource, shaderType, opt_errorCallback, opt_logShaders,
+ opt_shaderLabel, opt_url) {
var errFn = opt_errorCallback || error;
// Create the shader object
var shader = gl.createShader(shaderType);
// Compile the shader
gl.compileShader(shader);
+ if (opt_logShaders) {
+ var label = shaderType == gl.VERTEX_SHADER ? 'vertex shader' : 'fragment_shader';
+ if (opt_shaderLabel) {
+ label = opt_shaderLabel + ' ' + label;
+ }
+ addShaderSources(
+ gl, document.getElementById('console'), label, shader, shaderSource, opt_url);
+ }
+
// Check the compile status
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
* @param {file} file The URL of the shader source.
* @param {number} type The type of shader.
* @param {function(string): void) opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
* @return {!WebGLShader} The created shader.
*/
-var loadShaderFromFile = function(gl, file, type, opt_errorCallback) {
+var loadShaderFromFile = function(
+ gl, file, type, opt_errorCallback, opt_logShaders) {
var shaderSource = readFile(file);
- return loadShader(gl, shaderSource, type, opt_errorCallback);
+ return loadShader(gl, shaderSource, type, opt_errorCallback,
+ opt_logShaders, undefined, file);
};
/**
var getScript = function(scriptId) {
var shaderScript = document.getElementById(scriptId);
if (!shaderScript) {
- throw("*** Error: unknown script element" + scriptId);
+ throw("*** Error: unknown script element " + scriptId);
}
return shaderScript.text;
};
* @param {number} opt_shaderType The type of shader. If not passed in it will
* be derived from the type of the script tag.
* @param {function(string): void) opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
* @return {!WebGLShader} The created shader.
*/
var loadShaderFromScript = function(
- gl, scriptId, opt_shaderType, opt_errorCallback) {
+ gl, scriptId, opt_shaderType, opt_errorCallback, opt_logShaders) {
var shaderSource = "";
var shaderScript = document.getElementById(scriptId);
if (!shaderScript) {
}
}
- return loadShader(
- gl, shaderSource, opt_shaderType, opt_errorCallback);
+ return loadShader(gl, shaderSource, opt_shaderType, opt_errorCallback,
+ opt_logShaders);
};
var loadStandardProgram = function(gl) {
* @param {string} vertexShader The vertex shader source.
* @param {string} fragmentShader The fragment shader source.
* @param {function(string): void) opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
* @return {!WebGLProgram} The created program.
*/
var loadProgram = function(
- gl, vertexShader, fragmentShader, opt_errorCallback) {
+ gl, vertexShader, fragmentShader, opt_errorCallback, opt_logShaders) {
var program;
var vs = loadShader(
- gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback);
+ gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback, opt_logShaders);
var fs = loadShader(
- gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback);
+ gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback, opt_logShaders);
if (vs && fs) {
program = createProgram(gl, vs, fs, opt_errorCallback)
}
};
/**
- * Inserts a 'label' that when clicked expands to the pre
- * formatted text supplied by 'source'.
+ * Inserts a 'label' that when clicked expands to the pre formatted text
+ * supplied by 'source'.
* @param {!HTMLElement} element element to append label to.
* @param {string} label label for anchor.
* @param {string} source preformatted text to expand to.
- * @param {string} opt_url url of source. If provided a 2nd link
- * will be added.
+ * @param {string} opt_url URL of source. If provided a link to the source file
+ * will also be added.
*/
var addShaderSource = function(element, label, source, opt_url) {
var div = document.createElement("div");
element.appendChild(div);
};
+/**
+ * Inserts labels that when clicked expand to show the original source of the
+ * shader and also translated source of the shader, if that is available.
+ * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!HTMLElement} element element to append label to.
+ * @param {string} label label for anchor.
+ * @param {WebGLShader} shader Shader to show the sources for.
+ * @param {string} shaderSource Original shader source.
+ * @param {string} opt_url URL of source. If provided a link to the source file
+ * will also be added.
+ */
+var addShaderSources = function(
+ gl, element, label, shader, shaderSource, opt_url) {
+ addShaderSource(element, label, shaderSource, opt_url);
+
+ var debugShaders = gl.getExtension('WEBGL_debug_shaders');
+ if (debugShaders && shader) {
+ var translatedSource = debugShaders.getTranslatedShaderSource(shader);
+ if (translatedSource != '') {
+ addShaderSource(element, label + ' translated for driver', translatedSource);
+ }
+ }
+};
+
// Add your prefix here.
var browserPrefixes = [
"",
}
};
+/**
+ * Returns possible prefixed versions of an extension's name.
+ * @param {string} name Name of extension. May already include a prefix.
+ * @return {Array.<string>} Variations of the extension name with known
+ * browser prefixes.
+ */
+var getExtensionPrefixedNames = function(name) {
+ var unprefix = function(name) {
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ if (browserPrefixes[ii].length > 0 &&
+ name.substring(0, browserPrefixes[ii].length).toLowerCase() ===
+ browserPrefixes[ii].toLowerCase()) {
+ return name.substring(browserPrefixes[ii].length);
+ }
+ }
+ return name;
+ }
+
+ var unprefixed = unprefix(name);
+
+ var variations = [];
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ variations.push(browserPrefixes[ii] + unprefixed);
+ }
+
+ return variations;
+};
var replaceRE = /\$\((\w+)\)/g;
return {
addShaderSource: addShaderSource,
+ addShaderSources: addShaderSources,
cancelAnimFrame: cancelAnimFrame,
create3DContext: create3DContext,
create3DContextWithWrapperThatThrowsOnGLError:
checkCanvas: checkCanvas,
checkCanvasRect: checkCanvasRect,
checkCanvasRectColor: checkCanvasRectColor,
+ checkTextureSize: checkTextureSize,
clipToRange: clipToRange,
createColoredTexture: createColoredTexture,
createProgram: createProgram,
endsWith: endsWith,
fillTexture: fillTexture,
getBytesPerComponent: getBytesPerComponent,
+ getExtensionPrefixedNames: getExtensionPrefixedNames,
getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
getFileListAsync: getFileListAsync,
getLastError: getLastError,
getPrefixedProperty: getPrefixedProperty,
getScript: getScript,
getSupportedExtensionWithKnownPrefixes: getSupportedExtensionWithKnownPrefixes,
+ getTypedArrayElementsPerPixel: getTypedArrayElementsPerPixel,
getUrlArguments: getUrlArguments,
getUrlOptions: getUrlOptions,
getAttribMap: getAttribMap,
getUniformMap: getUniformMap,
glEnumToString: glEnumToString,
glErrorShouldBe: glErrorShouldBe,
- glTypeToArrayBufferType: glTypeToArrayBufferType,
+ glTypeToTypedArrayType: glTypeToTypedArrayType,
hasAttributeCaseInsensitive: hasAttributeCaseInsensitive,
insertImage: insertImage,
loadImageAsync: loadImageAsync,