webgl-test-utils.js (10329B)
1 // Copyright 2011 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 WebGLTestUtils = (function() { 6 /** 7 * Converts a WebGL enum to a string 8 * @param {!WebGLContext} gl The WebGLContext to use. 9 * @param {number} value The enum value. 10 * @return {string} The enum as a string. 11 */ 12 var glEnumToString = function(gl, value) { 13 for (var p in gl) { 14 if (gl[p] == value) { 15 return p; 16 } 17 } 18 return '0x' + value.toString(16); 19 }; 20 21 var lastError = ''; 22 23 /** 24 * Returns the last compiler/linker error. 25 * @return {string} The last compiler/linker error. 26 */ 27 var getLastError = function() { 28 return lastError; 29 }; 30 31 // clang-format off 32 33 /** 34 * A vertex shader for a single texture. 35 * @type {string} 36 */ 37 var simpleTextureVertexShader = [ 38 'attribute vec4 vPosition;', // 39 'attribute vec2 texCoord0;', 40 'varying vec2 texCoord;', 41 'void main() {', 42 ' gl_Position = vPosition;', 43 ' texCoord = texCoord0;', 44 '}' 45 ].join('\n'); 46 47 /** 48 * A fragment shader for a single texture. 49 * @type {string} 50 */ 51 var simpleTextureFragmentShader = [ 52 'precision mediump float;', 53 'uniform sampler2D tex;', 54 'varying vec2 texCoord;', 55 'void main() {', 56 ' gl_FragData[0] = texture2D(tex, texCoord);', 57 '}' 58 ].join('\n'); 59 60 // clang-format on 61 62 /** 63 * Creates a simple texture vertex shader. 64 * @param {!WebGLContext} gl The WebGLContext to use. 65 * @return {!WebGLShader} 66 */ 67 var setupSimpleTextureVertexShader = function(gl) { 68 return loadShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER); 69 }; 70 71 /** 72 * Creates a simple texture fragment shader. 73 * @param {!WebGLContext} gl The WebGLContext to use. 74 * @return {!WebGLShader} 75 */ 76 var setupSimpleTextureFragmentShader = function(gl) { 77 return loadShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER); 78 }; 79 80 /** 81 * Creates a program, attaches shaders, binds attrib locations, links the 82 * program and calls useProgram. 83 * @param {!Array.<!WebGLShader>} shaders The shaders to attach . 84 * @param {!Array.<string>} opt_attribs The attribs names. 85 * @param {!Array.<number>} opt_locations The locations for the attribs. 86 */ 87 var setupProgram = function(gl, shaders, opt_attribs, opt_locations) { 88 var realShaders = []; 89 var program = gl.createProgram(); 90 for (var ii = 0; ii < shaders.length; ++ii) { 91 var shader = shaders[ii]; 92 if (typeof shader == 'string') { 93 var element = document.getElementById(shader); 94 if (element) { 95 shader = loadShaderFromScript(gl, shader); 96 } else { 97 shader = loadShader( 98 gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER); 99 } 100 } 101 gl.attachShader(program, shader); 102 } 103 if (opt_attribs) { 104 for (var ii = 0; ii < opt_attribs.length; ++ii) { 105 gl.bindAttribLocation( 106 program, opt_locations ? opt_locations[ii] : ii, opt_attribs[ii]); 107 } 108 } 109 gl.linkProgram(program); 110 111 // Check the link status 112 var linked = gl.getProgramParameter(program, gl.LINK_STATUS); 113 if (!linked) { 114 gl.deleteProgram(program); 115 return null; 116 } 117 118 gl.useProgram(program); 119 return program; 120 }; 121 122 /** 123 * Creates a simple texture program. 124 * @param {!WebGLContext} gl The WebGLContext to use. 125 * @param {number} opt_positionLocation The attrib location for position. 126 * @param {number} opt_texcoordLocation The attrib location for texture 127 * coords. 128 * @return {WebGLProgram} 129 */ 130 var setupSimpleTextureProgram = function( 131 gl, opt_positionLocation, opt_texcoordLocation) { 132 opt_positionLocation = opt_positionLocation || 0; 133 opt_texcoordLocation = opt_texcoordLocation || 1; 134 var vs = setupSimpleTextureVertexShader(gl); 135 var fs = setupSimpleTextureFragmentShader(gl); 136 if (!vs || !fs) { 137 return null; 138 } 139 var program = setupProgram( 140 gl, [vs, fs], ['vPosition', 'texCoord0'], 141 [opt_positionLocation, opt_texcoordLocation]); 142 if (!program) { 143 gl.deleteShader(fs); 144 gl.deleteShader(vs); 145 } 146 gl.useProgram(program); 147 return program; 148 }; 149 150 /** 151 * Creates buffers for a textured unit quad and attaches them to vertex 152 * attribs. 153 * @param {!WebGLContext} gl The WebGLContext to use. 154 * @param {number} opt_positionLocation The attrib location for position. 155 * @param {number} opt_texcoordLocation The attrib location for texture 156 * coords. 157 * @return {!Array.<WebGLBuffer>} The buffer objects that were 158 * created. 159 */ 160 var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) { 161 opt_positionLocation = opt_positionLocation || 0; 162 opt_texcoordLocation = opt_texcoordLocation || 1; 163 var objects = []; 164 165 var vertexObject = gl.createBuffer(); 166 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); 167 gl.bufferData( 168 gl.ARRAY_BUFFER, new Float32Array([ 169 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, 170 -1.0, 0.0, 1.0, -1.0, 0.0 171 ]), 172 gl.STATIC_DRAW); 173 gl.enableVertexAttribArray(opt_positionLocation); 174 gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0); 175 objects.push(vertexObject); 176 177 var vertexObject = gl.createBuffer(); 178 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject); 179 gl.bufferData( 180 gl.ARRAY_BUFFER, 181 new Float32Array( 182 [1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0]), 183 gl.STATIC_DRAW); 184 gl.enableVertexAttribArray(opt_texcoordLocation); 185 gl.vertexAttribPointer(opt_texcoordLocation, 2, gl.FLOAT, false, 0, 0); 186 objects.push(vertexObject); 187 return objects; 188 }; 189 190 /** 191 * Creates a program and buffers for rendering a textured quad. 192 * @param {!WebGLContext} gl The WebGLContext to use. 193 * @param {number} opt_positionLocation The attrib location for position. 194 * @param {number} opt_texcoordLocation The attrib location for texture 195 * coords. 196 * @return {!WebGLProgram} 197 */ 198 var setupTexturedQuad = function( 199 gl, opt_positionLocation, opt_texcoordLocation) { 200 var program = setupSimpleTextureProgram( 201 gl, opt_positionLocation, opt_texcoordLocation); 202 setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation); 203 return program; 204 }; 205 206 /** 207 * Draws a previously setup quad. 208 * @param {!WebGLContext} gl The WebGLContext to use. 209 * @param {!Array.<number>} opt_color The color to fill clear with before 210 * drawing. A 4 element array where each element is in the range 0 to 211 * 255. Default [255, 255, 255, 255] 212 */ 213 var drawQuad = function(gl, opt_color) { 214 opt_color = opt_color || [255, 255, 255, 255]; 215 gl.clearColor( 216 opt_color[0] / 255, opt_color[1] / 255, opt_color[2] / 255, 217 opt_color[3] / 255); 218 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 219 gl.drawArrays(gl.TRIANGLES, 0, 6); 220 }; 221 222 /** 223 * Links a WebGL program, throws if there are errors. 224 * @param {!WebGLContext} gl The WebGLContext to use. 225 * @param {!WebGLProgram} program The WebGLProgram to link. 226 * @param {function(string): void) opt_errorCallback callback for errors. 227 */ 228 var linkProgram = function(gl, program, opt_errorCallback) { 229 // Link the program 230 gl.linkProgram(program); 231 232 // Check the link status 233 var linked = gl.getProgramParameter(program, gl.LINK_STATUS); 234 if (!linked) { 235 // something went wrong with the link 236 gl.deleteProgram(program); 237 return false; 238 } 239 240 return true; 241 }; 242 243 /** 244 * Loads a shader. 245 * @param {!WebGLContext} gl The WebGLContext to use. 246 * @param {string} shaderSource The shader source. 247 * @param {number} shaderType The type of shader. 248 * @param {function(string): void) opt_errorCallback callback for errors. 249 * @return {!WebGLShader} The created shader. 250 */ 251 var loadShader = 252 function(gl, shaderSource, shaderType, opt_errorCallback) { 253 var errFn = opt_errorCallback || (_ => {}); 254 // Create the shader object 255 var shader = gl.createShader(shaderType); 256 if (shader == null) { 257 errFn('*** Error: unable to create shader \'' + shaderSource + '\''); 258 return null; 259 } 260 261 // Load the shader source 262 gl.shaderSource(shader, shaderSource); 263 var err = gl.getError(); 264 if (err != gl.NO_ERROR) { 265 errFn( 266 '*** Error loading shader \'' + shader + 267 '\':' + glEnumToString(gl, err)); 268 return null; 269 } 270 271 // Compile the shader 272 gl.compileShader(shader); 273 274 // Check the compile status 275 var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 276 if (!compiled) { 277 // Something went wrong during compilation; get the error 278 lastError = gl.getShaderInfoLog(shader); 279 errFn('*** Error compiling shader \'' + shader + '\':' + lastError); 280 gl.deleteShader(shader); 281 return null; 282 } 283 284 return shader; 285 } 286 287 /** 288 * Loads shaders from source, creates a program, attaches the shaders and 289 * links. 290 * @param {!WebGLContext} gl The WebGLContext to use. 291 * @param {string} vertexShader The vertex shader. 292 * @param {string} fragmentShader The fragment shader. 293 * @param {function(string): void) opt_errorCallback callback for errors. 294 * @return {!WebGLProgram} The created program. 295 */ 296 var loadProgram = function( 297 gl, vertexShader, fragmentShader, opt_errorCallback) { 298 var program = gl.createProgram(); 299 gl.attachShader( 300 program, 301 loadShader(gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback)); 302 gl.attachShader( 303 program, 304 loadShader(gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback)); 305 return linkProgram(gl, program, opt_errorCallback) ? program : null; 306 }; 307 308 return { 309 drawQuad: drawQuad, 310 getLastError: getLastError, 311 glEnumToString: glEnumToString, 312 loadProgram: loadProgram, 313 loadShader: loadShader, 314 setupProgram: setupProgram, 315 setupSimpleTextureFragmentShader: setupSimpleTextureFragmentShader, 316 setupSimpleTextureProgram: setupSimpleTextureProgram, 317 setupSimpleTextureVertexShader: setupSimpleTextureVertexShader, 318 setupTexturedQuad: setupTexturedQuad, 319 setupUnitQuad: setupUnitQuad, 320 }; 321 }());