Source code
Revision control
Copy as Markdown
Other Tools
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
WebGLTestUtils = (function() {
/**
* 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.
*/
var glEnumToString = function(gl, value) {
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;
};
// clang-format off
/**
* 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');
// clang-format on
/**
* Creates a simple texture vertex shader.
* @param {!WebGLContext} gl The WebGLContext to use.
* @return {!WebGLShader}
*/
var setupSimpleTextureVertexShader = function(gl) {
return loadShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
};
/**
* Creates a simple texture fragment shader.
* @param {!WebGLContext} gl The WebGLContext to use.
* @return {!WebGLShader}
*/
var setupSimpleTextureFragmentShader = function(gl) {
return loadShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_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>} 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();
for (var ii = 0; ii < shaders.length; ++ii) {
var shader = shaders[ii];
if (typeof shader == 'string') {
var element = document.getElementById(shader);
if (element) {
shader = loadShaderFromScript(gl, shader);
} else {
shader = loadShader(
gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER);
}
}
gl.attachShader(program, shader);
}
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) {
gl.deleteProgram(program);
return null;
}
gl.useProgram(program);
return program;
};
/**
* Creates a simple texture program.
* @param {!WebGLContext} gl The WebGLContext 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 buffers for a textured unit quad and attaches them to vertex
* attribs.
* @param {!WebGLContext} gl The WebGLContext 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) {
opt_positionLocation = opt_positionLocation || 0;
opt_texcoordLocation = opt_texcoordLocation || 1;
var objects = [];
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(
gl.ARRAY_BUFFER, new Float32Array([
1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0,
-1.0, 0.0, 1.0, -1.0, 0.0
]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(opt_positionLocation);
gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
objects.push(vertexObject);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(
[1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(opt_texcoordLocation);
gl.vertexAttribPointer(opt_texcoordLocation, 2, gl.FLOAT, false, 0, 0);
objects.push(vertexObject);
return objects;
};
/**
* Creates a program and buffers for rendering a textured quad.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} opt_positionLocation The attrib location for position.
* @param {number} opt_texcoordLocation The attrib location for texture
* coords.
* @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;
};
/**
* Draws a previously setup quad.
* @param {!WebGLContext} gl The WebGLContext 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 drawQuad = 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);
gl.drawArrays(gl.TRIANGLES, 0, 6);
};
/**
* Links a WebGL program, throws if there are errors.
* @param {!WebGLContext} gl The WebGLContext 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) {
// 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
gl.deleteProgram(program);
return false;
}
return true;
};
/**
* 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) opt_errorCallback callback for errors.
* @return {!WebGLShader} The created shader.
*/
var loadShader =
function(gl, shaderSource, shaderType, opt_errorCallback) {
var errFn = opt_errorCallback || (_ => {});
// Create the shader object
var shader = gl.createShader(shaderType);
if (shader == null) {
errFn('*** Error: unable to create shader \'' + shaderSource + '\'');
return null;
}
// Load the shader source
gl.shaderSource(shader, shaderSource);
var err = gl.getError();
if (err != gl.NO_ERROR) {
errFn(
'*** Error loading shader \'' + shader +
'\':' + glEnumToString(gl, err));
return null;
}
// 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
lastError = gl.getShaderInfoLog(shader);
errFn('*** Error compiling shader \'' + shader + '\':' + lastError);
gl.deleteShader(shader);
return null;
}
return shader;
}
/**
* Loads shaders from source, creates a program, attaches the shaders and
* links.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {string} vertexShader The vertex shader.
* @param {string} fragmentShader The fragment shader.
* @param {function(string): void) opt_errorCallback callback for errors.
* @return {!WebGLProgram} The created program.
*/
var loadProgram = function(
gl, vertexShader, fragmentShader, opt_errorCallback) {
var program = gl.createProgram();
gl.attachShader(
program,
loadShader(gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback));
gl.attachShader(
program,
loadShader(gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback));
return linkProgram(gl, program, opt_errorCallback) ? program : null;
};
return {
drawQuad: drawQuad,
getLastError: getLastError,
glEnumToString: glEnumToString,
loadProgram: loadProgram,
loadShader: loadShader,
setupProgram: setupProgram,
setupSimpleTextureFragmentShader: setupSimpleTextureFragmentShader,
setupSimpleTextureProgram: setupSimpleTextureProgram,
setupSimpleTextureVertexShader: setupSimpleTextureVertexShader,
setupTexturedQuad: setupTexturedQuad,
setupUnitQuad: setupUnitQuad,
};
}());