Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: third_party/webgl/sdk/tests/conformance/resources/webgl-test-utils.js

Issue 10399113: Roll webgl conformance tests to r17874: part 2, adding r17874 (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 /*
2 ** Copyright (c) 2012 The Khronos Group Inc.
3 **
4 ** Permission is hereby granted, free of charge, to any person obtaining a
5 ** copy of this software and/or associated documentation files (the
6 ** "Materials"), to deal in the Materials without restriction, including
7 ** without limitation the rights to use, copy, modify, merge, publish,
8 ** distribute, sublicense, and/or sell copies of the Materials, and to
9 ** permit persons to whom the Materials are furnished to do so, subject to
10 ** the following conditions:
11 **
12 ** The above copyright notice and this permission notice shall be included
13 ** in all copies or substantial portions of the Materials.
14 **
15 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
22 */
23
24 WebGLTestUtils = (function() {
25
26 /**
27 * Wrapped logging function.
28 * @param {string} msg The message to log.
29 */
30 var log = function(msg) {
31 if (window.console && window.console.log) {
32 window.console.log(msg);
33 }
34 };
35
36 /**
37 * Wrapped logging function.
38 * @param {string} msg The message to log.
39 */
40 var error = function(msg) {
41 if (window.console) {
42 if (window.console.error) {
43 window.console.error(msg);
44 }
45 else if (window.console.log) {
46 window.console.log(msg);
47 }
48 }
49 };
50
51 /**
52 * Turn off all logging.
53 */
54 var loggingOff = function() {
55 log = function() {};
56 error = function() {};
57 };
58
59 /**
60 * Converts a WebGL enum to a string
61 * @param {!WebGLContext} gl The WebGLContext to use.
62 * @param {number} value The enum value.
63 * @return {string} The enum as a string.
64 */
65 var glEnumToString = function(gl, value) {
66 for (var p in gl) {
67 if (gl[p] == value) {
68 return p;
69 }
70 }
71 return "0x" + value.toString(16);
72 };
73
74 var lastError = "";
75
76 /**
77 * Returns the last compiler/linker error.
78 * @return {string} The last compiler/linker error.
79 */
80 var getLastError = function() {
81 return lastError;
82 };
83
84 /**
85 * Whether a haystack ends with a needle.
86 * @param {string} haystack String to search
87 * @param {string} needle String to search for.
88 * @param {boolean} True if haystack ends with needle.
89 */
90 var endsWith = function(haystack, needle) {
91 return haystack.substr(haystack.length - needle.length) === needle;
92 };
93
94 /**
95 * Whether a haystack starts with a needle.
96 * @param {string} haystack String to search
97 * @param {string} needle String to search for.
98 * @param {boolean} True if haystack starts with needle.
99 */
100 var startsWith = function(haystack, needle) {
101 return haystack.substr(0, needle.length) === needle;
102 };
103
104 /**
105 * A vertex shader for a single texture.
106 * @type {string}
107 */
108 var simpleTextureVertexShader = [
109 'attribute vec4 vPosition;',
110 'attribute vec2 texCoord0;',
111 'varying vec2 texCoord;',
112 'void main() {',
113 ' gl_Position = vPosition;',
114 ' texCoord = texCoord0;',
115 '}'].join('\n');
116
117 /**
118 * A fragment shader for a single texture.
119 * @type {string}
120 */
121 var simpleTextureFragmentShader = [
122 'precision mediump float;',
123 'uniform sampler2D tex;',
124 'varying vec2 texCoord;',
125 'void main() {',
126 ' gl_FragData[0] = texture2D(tex, texCoord);',
127 '}'].join('\n');
128
129 /**
130 * A vertex shader for a single texture.
131 * @type {string}
132 */
133 var noTexCoordTextureVertexShader = [
134 'attribute vec4 vPosition;',
135 'varying vec2 texCoord;',
136 'void main() {',
137 ' gl_Position = vPosition;',
138 ' texCoord = vPosition.xy * 0.5 + 0.5;',
139 '}'].join('\n');
140
141 /**
142 * A vertex shader for a single texture.
143 * @type {string}
144 */
145 var simpleColorVertexShader = [
146 'attribute vec4 vPosition;',
147 'void main() {',
148 ' gl_Position = vPosition;',
149 '}'].join('\n');
150
151 /**
152 * A fragment shader for a color.
153 * @type {string}
154 */
155 var simpleColorFragmentShader = [
156 'precision mediump float;',
157 'uniform vec4 u_color;',
158 'void main() {',
159 ' gl_FragData[0] = u_color;',
160 '}'].join('\n');
161
162 /**
163 * Creates a simple texture vertex shader.
164 * @param {!WebGLContext} gl The WebGLContext to use.
165 * @return {!WebGLShader}
166 */
167 var setupSimpleTextureVertexShader = function(gl) {
168 return loadShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
169 };
170
171 /**
172 * Creates a simple texture fragment shader.
173 * @param {!WebGLContext} gl The WebGLContext to use.
174 * @return {!WebGLShader}
175 */
176 var setupSimpleTextureFragmentShader = function(gl) {
177 return loadShader(
178 gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER);
179 };
180
181 /**
182 * Creates a texture vertex shader that doesn't need texcoords.
183 * @param {!WebGLContext} gl The WebGLContext to use.
184 * @return {!WebGLShader}
185 */
186 var setupNoTexCoordTextureVertexShader = function(gl) {
187 return loadShader(gl, noTexCoordTextureVertexShader, gl.VERTEX_SHADER);
188 };
189
190 /**
191 * Creates a program, attaches shaders, binds attrib locations, links the
192 * program and calls useProgram.
193 * @param {!Array.<!WebGLShader|string>} shaders The shaders to
194 * attach, or the source, or the id of a script to get
195 * the source from.
196 * @param {!Array.<string>} opt_attribs The attribs names.
197 * @param {!Array.<number>} opt_locations The locations for the attribs.
198 */
199 var setupProgram = function(gl, shaders, opt_attribs, opt_locations) {
200 var realShaders = [];
201 var program = gl.createProgram();
202 for (var ii = 0; ii < shaders.length; ++ii) {
203 var shader = shaders[ii];
204 if (typeof shader == 'string') {
205 var element = document.getElementById(shader);
206 if (element) {
207 shader = loadShaderFromScript(gl, shader);
208 } else {
209 shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHAD ER);
210 }
211 }
212 gl.attachShader(program, shader);
213 }
214 if (opt_attribs) {
215 for (var ii = 0; ii < opt_attribs.length; ++ii) {
216 gl.bindAttribLocation(
217 program,
218 opt_locations ? opt_locations[ii] : ii,
219 opt_attribs[ii]);
220 }
221 }
222 gl.linkProgram(program);
223
224 // Check the link status
225 var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
226 if (!linked) {
227 // something went wrong with the link
228 lastError = gl.getProgramInfoLog (program);
229 error("Error in program linking:" + lastError);
230
231 gl.deleteProgram(program);
232 return null;
233 }
234
235 gl.useProgram(program);
236 return program;
237 };
238
239 /**
240 * Creates a simple texture program.
241 * @param {!WebGLContext} gl The WebGLContext to use.
242 * @param {number} opt_positionLocation The attrib location for position.
243 * @param {number} opt_texcoordLocation The attrib location for texture coords.
244 * @return {WebGLProgram}
245 */
246 var setupSimpleTextureProgram = function(
247 gl, opt_positionLocation, opt_texcoordLocation) {
248 opt_positionLocation = opt_positionLocation || 0;
249 opt_texcoordLocation = opt_texcoordLocation || 1;
250 var vs = setupSimpleTextureVertexShader(gl);
251 var fs = setupSimpleTextureFragmentShader(gl);
252 if (!vs || !fs) {
253 return null;
254 }
255 var program = setupProgram(
256 gl,
257 [vs, fs],
258 ['vPosition', 'texCoord0'],
259 [opt_positionLocation, opt_texcoordLocation]);
260 if (!program) {
261 gl.deleteShader(fs);
262 gl.deleteShader(vs);
263 }
264 gl.useProgram(program);
265 return program;
266 };
267
268 /**
269 * Creates a simple texture program.
270 * @param {!WebGLContext} gl The WebGLContext to use.
271 * @return {WebGLProgram}
272 */
273 var setupNoTexCoordTextureProgram = function(gl) {
274 var vs = setupNoTexCoordTextureVertexShader(gl);
275 var fs = setupSimpleTextureFragmentShader(gl);
276 if (!vs || !fs) {
277 return null;
278 }
279 var program = setupProgram(
280 gl,
281 [vs, fs],
282 ['vPosition'],
283 [0]);
284 if (!program) {
285 gl.deleteShader(fs);
286 gl.deleteShader(vs);
287 }
288 gl.useProgram(program);
289 return program;
290 };
291
292 /**
293 * Creates a simple texture program.
294 * @param {!WebGLContext} gl The WebGLContext to use.
295 * @param {number} opt_positionLocation The attrib location for position.
296 * @param {number} opt_texcoordLocation The attrib location for texture coords.
297 * @return {WebGLProgram}
298 */
299 var setupSimpleTextureProgram = function(
300 gl, opt_positionLocation, opt_texcoordLocation) {
301 opt_positionLocation = opt_positionLocation || 0;
302 opt_texcoordLocation = opt_texcoordLocation || 1;
303 var vs = setupSimpleTextureVertexShader(gl);
304 var fs = setupSimpleTextureFragmentShader(gl);
305 if (!vs || !fs) {
306 return null;
307 }
308 var program = setupProgram(
309 gl,
310 [vs, fs],
311 ['vPosition', 'texCoord0'],
312 [opt_positionLocation, opt_texcoordLocation]);
313 if (!program) {
314 gl.deleteShader(fs);
315 gl.deleteShader(vs);
316 }
317 gl.useProgram(program);
318 return program;
319 };
320
321 /**
322 * Creates buffers for a textured unit quad and attaches them to vertex attribs.
323 * @param {!WebGLContext} gl The WebGLContext to use.
324 * @param {number} opt_positionLocation The attrib location for position.
325 * @param {number} opt_texcoordLocation The attrib location for texture coords.
326 * @return {!Array.<WebGLBuffer>} The buffer objects that were
327 * created.
328 */
329 var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation) {
330 return setupUnitQuadWithTexCoords(gl, [ 0.0, 0.0 ], [ 1.0, 1.0 ],
331 opt_positionLocation, opt_texcoordLocation);
332 };
333
334 /**
335 * Creates buffers for a textured unit quad with specified lower left
336 * and upper right texture coordinates, and attaches them to vertex
337 * attribs.
338 * @param {!WebGLContext} gl The WebGLContext to use.
339 * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the l ower left corner.
340 * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
341 * @param {number} opt_positionLocation The attrib location for position.
342 * @param {number} opt_texcoordLocation The attrib location for texture coords.
343 * @return {!Array.<WebGLBuffer>} The buffer objects that were
344 * created.
345 */
346 var setupUnitQuadWithTexCoords = function(
347 gl, lowerLeftTexCoords, upperRightTexCoords,
348 opt_positionLocation, opt_texcoordLocation) {
349 opt_positionLocation = opt_positionLocation || 0;
350 opt_texcoordLocation = opt_texcoordLocation || 1;
351 var objects = [];
352
353 var vertexObject = gl.createBuffer();
354 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
355 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
356 1.0, 1.0, 0.0,
357 -1.0, 1.0, 0.0,
358 -1.0, -1.0, 0.0,
359 1.0, 1.0, 0.0,
360 -1.0, -1.0, 0.0,
361 1.0, -1.0, 0.0]), gl.STATIC_DRAW);
362 gl.enableVertexAttribArray(opt_positionLocation);
363 gl.vertexAttribPointer(opt_positionLocation, 3, gl.FLOAT, false, 0, 0);
364 objects.push(vertexObject);
365
366 var llx = lowerLeftTexCoords[0];
367 var lly = lowerLeftTexCoords[1];
368 var urx = upperRightTexCoords[0];
369 var ury = upperRightTexCoords[1];
370
371 var vertexObject = gl.createBuffer();
372 gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
373 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
374 urx, ury,
375 llx, ury,
376 llx, lly,
377 urx, ury,
378 llx, lly,
379 urx, lly]), gl.STATIC_DRAW);
380 gl.enableVertexAttribArray(opt_texcoordLocation);
381 gl.vertexAttribPointer(opt_texcoordLocation, 2, gl.FLOAT, false, 0, 0);
382 objects.push(vertexObject);
383 return objects;
384 };
385
386 /**
387 * Creates a program and buffers for rendering a textured quad.
388 * @param {!WebGLContext} gl The WebGLContext to use.
389 * @param {number} opt_positionLocation The attrib location for position.
390 * @param {number} opt_texcoordLocation The attrib location for texture coords.
391 * @return {!WebGLProgram}
392 */
393 var setupTexturedQuad = function(
394 gl, opt_positionLocation, opt_texcoordLocation) {
395 var program = setupSimpleTextureProgram(
396 gl, opt_positionLocation, opt_texcoordLocation);
397 setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation);
398 return program;
399 };
400
401 /**
402 * Creates a program and buffers for rendering a color quad.
403 * @param {!WebGLContext} gl The WebGLContext to use.
404 * @param {number} opt_positionLocation The attrib location for position.
405 * @return {!WebGLProgram}
406 */
407 var setupColorQuad = function(gl, opt_positionLocation) {
408 opt_positionLocation = opt_positionLocation || 0;
409 var program = wtu.setupProgram(
410 gl,
411 [simpleColorVertexShader, simpleColorFragmentShader],
412 ['vPosition'],
413 [opt_positionLocation]);
414 setupUnitQuad(gl, opt_positionLocation);
415 return program;
416 };
417
418 /**
419 * Creates a program and buffers for rendering a textured quad with
420 * specified lower left and upper right texture coordinates.
421 * @param {!WebGLContext} gl The WebGLContext to use.
422 * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the l ower left corner.
423 * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
424 * @param {number} opt_positionLocation The attrib location for position.
425 * @param {number} opt_texcoordLocation The attrib location for texture coords.
426 * @return {!WebGLProgram}
427 */
428 var setupTexturedQuadWithTexCoords = function(
429 gl, lowerLeftTexCoords, upperRightTexCoords,
430 opt_positionLocation, opt_texcoordLocation) {
431 var program = setupSimpleTextureProgram(
432 gl, opt_positionLocation, opt_texcoordLocation);
433 setupUnitQuadWithTexCoords(gl, lowerLeftTexCoords, upperRightTexCoords,
434 opt_positionLocation, opt_texcoordLocation);
435 return program;
436 };
437
438 /**
439 * Creates a unit quad with only positions of a given resolution.
440 * @param {!WebGLContext} gl The WebGLContext to use.
441 * @param {number} gridRes The resolution of the mesh grid,
442 * expressed in the number of quads across and down.
443 * @param {number} opt_positionLocation The attrib location for position.
444 */
445 var setupQuad = function (
446 gl, gridRes, opt_positionLocation, opt_flipOddTriangles) {
447 setupQuadWithOptions(gl,
448 { gridRes: gridRes,
449 positionLocation: opt_positionLocation,
450 flipOddTriangles: opt_flipOddTriangles
451 });
452 };
453
454 /**
455 * Creates a quad with various options.
456 * @param {!WebGLContext} gl The WebGLContext to use.
457 *
458 * Options:
459 * gridRes: number of quads across and down grid.
460 * positionLocation: attrib location for position
461 * flipOddTriangles: reverse order of vertices of every other
462 * triangle
463 * positionOffset: offset added to each vertex
464 * positionMult: multipier for each vertex
465 * colorLocation: attrib location for vertex colors. If
466 * undefined no vertex colors will be created.
467 */
468 var setupQuadWithOptions = function (gl, options) {
469 var positionLocation = options.positionLocation || 0;
470 var objects = [];
471
472 var gridRes = options.gridRes || 1;
473 var positionOffset = options.positionOffset || 0;
474 var positionMult = options.positionMult || 1;
475 var vertsAcross = gridRes + 1;
476 var numVerts = vertsAcross * vertsAcross;
477 var positions = new Float32Array(numVerts * 3);
478 var indices = new Uint16Array(6 * gridRes * gridRes);
479 var poffset = 0;
480
481 for (var yy = 0; yy <= gridRes; ++yy) {
482 for (var xx = 0; xx <= gridRes; ++xx) {
483 positions[poffset + 0] = (-1 + 2 * xx / gridRes) * positionMult + position Offset;
484 positions[poffset + 1] = (-1 + 2 * yy / gridRes) * positionMult + position Offset;
485 positions[poffset + 2] = 0;
486
487 poffset += 3;
488 }
489 }
490
491 var buf = gl.createBuffer();
492 gl.bindBuffer(gl.ARRAY_BUFFER, buf);
493 gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
494 gl.enableVertexAttribArray(positionLocation);
495 gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
496 objects.push(buf);
497
498 if (options.colorLocation !== undefined) {
499 var colors = new Float32Array(numVerts * 4);
500 for (var yy = 0; yy <= gridRes; ++yy) {
501 for (var xx = 0; xx <= gridRes; ++xx) {
502 if (options.color !== undefined) {
503 colors[poffset + 0] = options.color[0];
504 colors[poffset + 1] = options.color[1];
505 colors[poffset + 2] = options.color[2];
506 colors[poffset + 3] = options.color[3];
507 } else {
508 colors[poffset + 0] = xx / gridRes;
509 colors[poffset + 1] = yy / gridRes;
510 colors[poffset + 2] = (xx / gridRes) * (yy / gridRes);
511 colors[poffset + 3] = (yy % 2) * 0.5 + 0.5;
512 }
513 poffset += 4;
514 }
515 }
516
517 var buf = gl.createBuffer();
518 gl.bindBuffer(gl.ARRAY_BUFFER, buf);
519 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
520 gl.enableVertexAttribArray(options.colorLocation);
521 gl.vertexAttribPointer(options.colorLocation, 4, gl.FLOAT, false, 0, 0);
522 objects.push(buf);
523 }
524
525 var tbase = 0;
526 for (var yy = 0; yy < gridRes; ++yy) {
527 var index = yy * vertsAcross;
528 for (var xx = 0; xx < gridRes; ++xx) {
529 indices[tbase + 0] = index + 0;
530 indices[tbase + 1] = index + 1;
531 indices[tbase + 2] = index + vertsAcross;
532 indices[tbase + 3] = index + vertsAcross;
533 indices[tbase + 4] = index + 1;
534 indices[tbase + 5] = index + vertsAcross + 1;
535
536 if (options.flipOddTriangles) {
537 indices[tbase + 4] = index + vertsAcross + 1;
538 indices[tbase + 5] = index + 1;
539 }
540
541 index += 1;
542 tbase += 6;
543 }
544 }
545
546 var buf = gl.createBuffer();
547 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
548 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
549 objects.push(buf);
550
551 return objects;
552 };
553
554 /**
555 * Fills the given texture with a solid color
556 * @param {!WebGLContext} gl The WebGLContext to use.
557 * @param {!WebGLTexture} tex The texture to fill.
558 * @param {number} width The width of the texture to create.
559 * @param {number} height The height of the texture to create.
560 * @param {!Array.<number>} color The color to fill with. A 4 element array
561 * where each element is in the range 0 to 255.
562 * @param {number} opt_level The level of the texture to fill. Default = 0.
563 */
564 var fillTexture = function(gl, tex, width, height, color, opt_level) {
565 opt_level = opt_level || 0;
566 var numPixels = width * height;
567 var size = numPixels * 4;
568 var buf = new Uint8Array(size);
569 for (var ii = 0; ii < numPixels; ++ii) {
570 var off = ii * 4;
571 buf[off + 0] = color[0];
572 buf[off + 1] = color[1];
573 buf[off + 2] = color[2];
574 buf[off + 3] = color[3];
575 }
576 gl.bindTexture(gl.TEXTURE_2D, tex);
577 gl.texImage2D(
578 gl.TEXTURE_2D, opt_level, gl.RGBA, width, height, 0,
579 gl.RGBA, gl.UNSIGNED_BYTE, buf);
580 };
581
582 /**
583 * Creates a textures and fills it with a solid color
584 * @param {!WebGLContext} gl The WebGLContext to use.
585 * @param {number} width The width of the texture to create.
586 * @param {number} height The height of the texture to create.
587 * @param {!Array.<number>} color The color to fill with. A 4 element array
588 * where each element is in the range 0 to 255.
589 * @return {!WebGLTexture}
590 */
591 var createColoredTexture = function(gl, width, height, color) {
592 var tex = gl.createTexture();
593 fillTexture(gl, tex, width, height, color);
594 return tex;
595 };
596
597 /**
598 * Draws a previously setup quad.
599 * @param {!WebGLContext} gl The WebGLContext to use.
600 * @param {!Array.<number>} opt_color The color to fill clear with before
601 * drawing. A 4 element array where each element is in the range 0 to
602 * 255. Default [255, 255, 255, 255]
603 */
604 var drawQuad = function(gl, opt_color) {
605 opt_color = opt_color || [255, 255, 255, 255];
606 gl.clearColor(
607 opt_color[0] / 255,
608 opt_color[1] / 255,
609 opt_color[2] / 255,
610 opt_color[3] / 255);
611 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
612 gl.drawArrays(gl.TRIANGLES, 0, 6);
613 };
614
615 /**
616 * Draws a previously setup quad.
617 * @param {!WebGLContext} gl The WebGLContext to use.
618 * @param {number} gridRes Resolution of grid.
619 * @param {!Array.<number>} opt_color The color to fill clear with before
620 * drawing. A 4 element array where each element is in the range 0 to
621 * 255. Default [255, 255, 255, 255]
622 */
623 var drawIndexedQuad = function(gl, gridRes, opt_color) {
624 opt_color = opt_color || [255, 255, 255, 255];
625 gl.clearColor(
626 opt_color[0] / 255,
627 opt_color[1] / 255,
628 opt_color[2] / 255,
629 opt_color[3] / 255);
630 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
631 gl.drawElements(gl.TRIANGLES, gridRes * 6, gl.UNSIGNED_SHORT, 0);
632 };
633
634 /**
635 * Checks that a portion of a canvas is 1 color.
636 * @param {!WebGLContext} gl The WebGLContext to use.
637 * @param {number} x left corner of region to check.
638 * @param {number} y bottom corner of region to check.
639 * @param {number} width width of region to check.
640 * @param {number} height width of region to check.
641 * @param {!Array.<number>} color The color to fill clear with before drawing. A
642 * 4 element array where each element is in the range 0 to 255.
643 * @param {string} msg Message to associate with success. Eg ("should be red").
644 * @param {number} errorRange Optional. Acceptable error in
645 * color checking. 0 by default.
646 */
647 var checkCanvasRect = function(gl, x, y, width, height, color, msg, errorRange) {
648 errorRange = errorRange || 0;
649 if (!errorRange.length) {
650 errorRange = [errorRange, errorRange, errorRange, errorRange]
651 }
652 var buf = new Uint8Array(width * height * 4);
653 gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
654 for (var i = 0; i < width * height; ++i) {
655 var offset = i * 4;
656 for (var j = 0; j < color.length; ++j) {
657 if (Math.abs(buf[offset + j] - color[j]) > errorRange[j]) {
658 testFailed(msg);
659 var was = buf[offset + 0].toString();
660 for (j = 1; j < color.length; ++j) {
661 was += "," + buf[offset + j];
662 }
663 debug('at (' + (i % width) + ', ' + Math.floor(i / width) +
664 ') expected: ' + color + ' was ' + was);
665 return;
666 }
667 }
668 }
669 testPassed(msg);
670 };
671
672 /**
673 * Checks that an entire canvas is 1 color.
674 * @param {!WebGLContext} gl The WebGLContext to use.
675 * @param {!Array.<number>} color The color to fill clear with before drawing. A
676 * 4 element array where each element is in the range 0 to 255.
677 * @param {string} msg Message to associate with success. Eg ("should be red").
678 * @param {number} errorRange Optional. Acceptable error in
679 * color checking. 0 by default.
680 */
681 var checkCanvas = function(gl, color, msg, errorRange) {
682 checkCanvasRect(gl, 0, 0, gl.canvas.width, gl.canvas.height, color, msg, error Range);
683 };
684
685 /**
686 * Loads a texture, calls callback when finished.
687 * @param {!WebGLContext} gl The WebGLContext to use.
688 * @param {string} url URL of image to load
689 * @param {function(!Image): void} callback Function that gets called after
690 * image has loaded
691 * @return {!WebGLTexture} The created texture.
692 */
693 var loadTexture = function(gl, url, callback) {
694 var texture = gl.createTexture();
695 gl.bindTexture(gl.TEXTURE_2D, texture);
696 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
697 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
698 var image = new Image();
699 image.onload = function() {
700 gl.bindTexture(gl.TEXTURE_2D, texture);
701 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
702 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imag e);
703 callback(image);
704 };
705 image.src = url;
706 return texture;
707 };
708
709 /**
710 * Creates a webgl context.
711 * @param {!Canvas|string} opt_canvas The canvas tag to get
712 * context from. If one is not passed in one will be
713 * created. If it's a string it's assumed to be the id of a
714 * canvas.
715 * @return {!WebGLContext} The created context.
716 */
717 var create3DContext = function(opt_canvas, opt_attributes) {
718 opt_canvas = opt_canvas || document.createElement("canvas");
719 if (typeof opt_canvas == 'string') {
720 opt_canvas = document.getElementById(opt_canvas);
721 }
722 var context = null;
723 var names = ["webgl", "experimental-webgl"];
724 for (var i = 0; i < names.length; ++i) {
725 try {
726 context = opt_canvas.getContext(names[i], opt_attributes);
727 } catch (e) {
728 }
729 if (context) {
730 break;
731 }
732 }
733 if (!context) {
734 testFailed("Unable to fetch WebGL rendering context for Canvas");
735 }
736 return context;
737 }
738
739 /**
740 * Gets a GLError value as a string.
741 * @param {!WebGLContext} gl The WebGLContext to use.
742 * @param {number} err The webgl error as retrieved from gl.getError().
743 * @return {string} the error as a string.
744 */
745 var getGLErrorAsString = function(gl, err) {
746 if (err === gl.NO_ERROR) {
747 return "NO_ERROR";
748 }
749 for (var name in gl) {
750 if (gl[name] === err) {
751 return name;
752 }
753 }
754 return err.toString();
755 };
756
757 /**
758 * Wraps a WebGL function with a function that throws an exception if there is
759 * an error.
760 * @param {!WebGLContext} gl The WebGLContext to use.
761 * @param {string} fname Name of function to wrap.
762 * @return {function} The wrapped function.
763 */
764 var createGLErrorWrapper = function(context, fname) {
765 return function() {
766 var rv = context[fname].apply(context, arguments);
767 var err = context.getError();
768 if (err != context.NO_ERROR)
769 throw "GL error " + getGLErrorAsString(context, err) + " in " + fname;
770 return rv;
771 };
772 };
773
774 /**
775 * Creates a WebGL context where all functions are wrapped to throw an exception
776 * if there is an error.
777 * @param {!Canvas} canvas The HTML canvas to get a context from.
778 * @return {!Object} The wrapped context.
779 */
780 function create3DContextWithWrapperThatThrowsOnGLError(canvas) {
781 var context = create3DContext(canvas);
782 var wrap = {};
783 for (var i in context) {
784 try {
785 if (typeof context[i] == 'function') {
786 wrap[i] = createGLErrorWrapper(context, i);
787 } else {
788 wrap[i] = context[i];
789 }
790 } catch (e) {
791 error("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
792 }
793 }
794 wrap.getError = function() {
795 return context.getError();
796 };
797 return wrap;
798 };
799
800 /**
801 * Tests that an evaluated expression generates a specific GL error.
802 * @param {!WebGLContext} gl The WebGLContext to use.
803 * @param {number} glError The expected gl error.
804 * @param {string} evalSTr The string to evaluate.
805 */
806 var shouldGenerateGLError = function(gl, glError, evalStr) {
807 var exception;
808 try {
809 eval(evalStr);
810 } catch (e) {
811 exception = e;
812 }
813 if (exception) {
814 testFailed(evalStr + " threw exception " + exception);
815 } else {
816 var err = gl.getError();
817 if (err != glError) {
818 testFailed(evalStr + " expected: " + getGLErrorAsString(gl, glError) + ". Was " + getGLErrorAsString(gl, err) + ".");
819 } else {
820 testPassed(evalStr + " was expected value: " + getGLErrorAsString(gl, glEr ror) + ".");
821 }
822 }
823 };
824
825 /**
826 * Tests that the first error GL returns is the specified error.
827 * @param {!WebGLContext} gl The WebGLContext to use.
828 * @param {number} glError The expected gl error.
829 * @param {string} opt_msg
830 */
831 var glErrorShouldBe = function(gl, glError, opt_msg) {
832 opt_msg = opt_msg || "";
833 var err = gl.getError();
834 if (err != glError) {
835 testFailed("getError expected: " + getGLErrorAsString(gl, glError) +
836 ". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
837 } else {
838 testPassed("getError was expected value: " +
839 getGLErrorAsString(gl, glError) + " : " + opt_msg);
840 }
841 };
842
843 /**
844 * Links a WebGL program, throws if there are errors.
845 * @param {!WebGLContext} gl The WebGLContext to use.
846 * @param {!WebGLProgram} program The WebGLProgram to link.
847 * @param {function(string): void) opt_errorCallback callback for errors.
848 */
849 var linkProgram = function(gl, program, opt_errorCallback) {
850 errFn = opt_errorCallback || testFailed;
851 // Link the program
852 gl.linkProgram(program);
853
854 // Check the link status
855 var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
856 if (!linked) {
857 // something went wrong with the link
858 var error = gl.getProgramInfoLog (program);
859
860 errFn("Error in program linking:" + error);
861
862 gl.deleteProgram(program);
863 }
864 };
865
866 /**
867 * Loads text from an external file. This function is synchronous.
868 * @param {string} url The url of the external file.
869 * @param {!function(bool, string): void} callback that is sent a bool for
870 * success and the string.
871 */
872 var loadTextFileAsync = function(url, callback) {
873 log ("loading: " + url);
874 var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
875 var request;
876 if (window.XMLHttpRequest) {
877 request = new XMLHttpRequest();
878 if (request.overrideMimeType) {
879 request.overrideMimeType('text/plain');
880 }
881 } else {
882 throw 'XMLHttpRequest is disabled';
883 }
884 try {
885 request.open('GET', url, true);
886 request.onreadystatechange = function() {
887 if (request.readyState == 4) {
888 var text = '';
889 // HTTP reports success with a 200 status. The file protocol reports
890 // success with zero. HTTP does not use zero as a status code (they
891 // start at 100).
892 // https://developer.mozilla.org/En/Using_XMLHttpRequest
893 var success = request.status == 200 || request.status == 0;
894 if (success) {
895 text = request.responseText;
896 }
897 log("loaded: " + url);
898 callback(success, text);
899 }
900 };
901 request.send(null);
902 } catch (e) {
903 log("failed to load: " + url);
904 callback(false, '');
905 }
906 };
907
908 /**
909 * Recursively loads a file as a list. Each line is parsed for a relative
910 * path. If the file ends in .txt the contents of that file is inserted in
911 * the list.
912 *
913 * @param {string} url The url of the external file.
914 * @param {!function(bool, Array<string>): void} callback that is sent a bool
915 * for success and the array of strings.
916 */
917 var getFileListAsync = function(url, callback) {
918 var files = [];
919
920 var getFileListImpl = function(url, callback) {
921 var files = [];
922 if (url.substr(url.length - 4) == '.txt') {
923 loadTextFileAsync(url, function() {
924 return function(success, text) {
925 if (!success) {
926 callback(false, '');
927 return;
928 }
929 var lines = text.split('\n');
930 var prefix = '';
931 var lastSlash = url.lastIndexOf('/');
932 if (lastSlash >= 0) {
933 prefix = url.substr(0, lastSlash + 1);
934 }
935 var fail = false;
936 var count = 1;
937 var index = 0;
938 for (var ii = 0; ii < lines.length; ++ii) {
939 var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
940 if (str.length > 4 &&
941 str[0] != '#' &&
942 str[0] != ";" &&
943 str.substr(0, 2) != "//") {
944 var names = str.split(/ +/);
945 new_url = prefix + str;
946 if (names.length == 1) {
947 new_url = prefix + str;
948 ++count;
949 getFileListImpl(new_url, function(index) {
950 return function(success, new_files) {
951 log("got files: " + new_files.length);
952 if (success) {
953 files[index] = new_files;
954 }
955 finish(success);
956 };
957 }(index++));
958 } else {
959 var s = "";
960 var p = "";
961 for (var jj = 0; jj < names.length; ++jj) {
962 s += p + prefix + names[jj];
963 p = " ";
964 }
965 files[index++] = s;
966 }
967 }
968 }
969 finish(true);
970
971 function finish(success) {
972 if (!success) {
973 fail = true;
974 }
975 --count;
976 log("count: " + count);
977 if (!count) {
978 callback(!fail, files);
979 }
980 }
981 }
982 }());
983
984 } else {
985 files.push(url);
986 callback(true, files);
987 }
988 };
989
990 getFileListImpl(url, function(success, files) {
991 // flatten
992 var flat = [];
993 flatten(files);
994 function flatten(files) {
995 for (var ii = 0; ii < files.length; ++ii) {
996 var value = files[ii];
997 if (typeof(value) == "string") {
998 flat.push(value);
999 } else {
1000 flatten(value);
1001 }
1002 }
1003 }
1004 callback(success, flat);
1005 });
1006 };
1007
1008 /**
1009 * Gets a file from a file/URL
1010 * @param {string} file the URL of the file to get.
1011 * @return {string} The contents of the file.
1012 */
1013 var readFile = function(file) {
1014 var xhr = new XMLHttpRequest();
1015 xhr.open("GET", file, false);
1016 xhr.send();
1017 return xhr.responseText.replace(/\r/g, "");
1018 };
1019
1020 var readFileList = function(url) {
1021 var files = [];
1022 if (url.substr(url.length - 4) == '.txt') {
1023 var lines = readFile(url).split('\n');
1024 var prefix = '';
1025 var lastSlash = url.lastIndexOf('/');
1026 if (lastSlash >= 0) {
1027 prefix = url.substr(0, lastSlash + 1);
1028 }
1029 for (var ii = 0; ii < lines.length; ++ii) {
1030 var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
1031 if (str.length > 4 &&
1032 str[0] != '#' &&
1033 str[0] != ";" &&
1034 str.substr(0, 2) != "//") {
1035 var names = str.split(/ +/);
1036 if (names.length == 1) {
1037 new_url = prefix + str;
1038 files = files.concat(readFileList(new_url));
1039 } else {
1040 var s = "";
1041 var p = "";
1042 for (var jj = 0; jj < names.length; ++jj) {
1043 s += p + prefix + names[jj];
1044 p = " ";
1045 }
1046 files.push(s);
1047 }
1048 }
1049 }
1050 } else {
1051 files.push(url);
1052 }
1053 return files;
1054 };
1055
1056 /**
1057 * Loads a shader.
1058 * @param {!WebGLContext} gl The WebGLContext to use.
1059 * @param {string} shaderSource The shader source.
1060 * @param {number} shaderType The type of shader.
1061 * @param {function(string): void) opt_errorCallback callback for errors.
1062 * @return {!WebGLShader} The created shader.
1063 */
1064 var loadShader = function(gl, shaderSource, shaderType, opt_errorCallback) {
1065 var errFn = opt_errorCallback || error;
1066 // Create the shader object
1067 var shader = gl.createShader(shaderType);
1068 if (shader == null) {
1069 errFn("*** Error: unable to create shader '"+shaderSource+"'");
1070 return null;
1071 }
1072
1073 // Load the shader source
1074 gl.shaderSource(shader, shaderSource);
1075 var err = gl.getError();
1076 if (err != gl.NO_ERROR) {
1077 errFn("*** Error loading shader '" + shader + "':" + glEnumToString(gl, err) );
1078 return null;
1079 }
1080
1081 // Compile the shader
1082 gl.compileShader(shader);
1083
1084 // Check the compile status
1085 var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
1086 if (!compiled) {
1087 // Something went wrong during compilation; get the error
1088 lastError = gl.getShaderInfoLog(shader);
1089 errFn("*** Error compiling shader '" + shader + "':" + lastError);
1090 gl.deleteShader(shader);
1091 return null;
1092 }
1093
1094 return shader;
1095 }
1096
1097 /**
1098 * Loads a shader from a URL.
1099 * @param {!WebGLContext} gl The WebGLContext to use.
1100 * @param {file} file The URL of the shader source.
1101 * @param {number} type The type of shader.
1102 * @param {function(string): void) opt_errorCallback callback for errors.
1103 * @return {!WebGLShader} The created shader.
1104 */
1105 var loadShaderFromFile = function(gl, file, type, opt_errorCallback) {
1106 var shaderSource = readFile(file);
1107 return loadShader(gl, shaderSource, type, opt_errorCallback);
1108 };
1109
1110 /**
1111 * Gets the content of script.
1112 */
1113 var getScript = function(scriptId) {
1114 var shaderScript = document.getElementById(scriptId);
1115 if (!shaderScript) {
1116 throw("*** Error: unknown script element" + scriptId);
1117 }
1118 return shaderScript.text;
1119 };
1120
1121 /**
1122 * Loads a shader from a script tag.
1123 * @param {!WebGLContext} gl The WebGLContext to use.
1124 * @param {string} scriptId The id of the script tag.
1125 * @param {number} opt_shaderType The type of shader. If not passed in it will
1126 * be derived from the type of the script tag.
1127 * @param {function(string): void) opt_errorCallback callback for errors.
1128 * @return {!WebGLShader} The created shader.
1129 */
1130 var loadShaderFromScript = function(
1131 gl, scriptId, opt_shaderType, opt_errorCallback) {
1132 var shaderSource = "";
1133 var shaderType;
1134 var shaderScript = document.getElementById(scriptId);
1135 if (!shaderScript) {
1136 throw("*** Error: unknown script element " + scriptId);
1137 }
1138 shaderSource = shaderScript.text;
1139
1140 if (!opt_shaderType) {
1141 if (shaderScript.type == "x-shader/x-vertex") {
1142 shaderType = gl.VERTEX_SHADER;
1143 } else if (shaderScript.type == "x-shader/x-fragment") {
1144 shaderType = gl.FRAGMENT_SHADER;
1145 } else if (shaderType != gl.VERTEX_SHADER && shaderType != gl.FRAGMENT_SHADE R) {
1146 throw("*** Error: unknown shader type");
1147 return null;
1148 }
1149 }
1150
1151 return loadShader(
1152 gl, shaderSource, opt_shaderType ? opt_shaderType : shaderType,
1153 opt_errorCallback);
1154 };
1155
1156 var loadStandardProgram = function(gl) {
1157 var program = gl.createProgram();
1158 gl.attachShader(program, loadStandardVertexShader(gl));
1159 gl.attachShader(program, loadStandardFragmentShader(gl));
1160 linkProgram(gl, program);
1161 return program;
1162 };
1163
1164 /**
1165 * Loads shaders from files, creates a program, attaches the shaders and links.
1166 * @param {!WebGLContext} gl The WebGLContext to use.
1167 * @param {string} vertexShaderPath The URL of the vertex shader.
1168 * @param {string} fragmentShaderPath The URL of the fragment shader.
1169 * @param {function(string): void) opt_errorCallback callback for errors.
1170 * @return {!WebGLProgram} The created program.
1171 */
1172 var loadProgramFromFile = function(
1173 gl, vertexShaderPath, fragmentShaderPath, opt_errorCallback) {
1174 var program = gl.createProgram();
1175 var vs = loadShaderFromFile(
1176 gl, vertexShaderPath, gl.VERTEX_SHADER, opt_errorCallback);
1177 var fs = loadShaderFromFile(
1178 gl, fragmentShaderPath, gl.FRAGMENT_SHADER, opt_errorCallback);
1179 if (vs && fs) {
1180 gl.attachShader(program, vs);
1181 gl.attachShader(program, fs);
1182 linkProgram(gl, program, opt_errorCallback);
1183 }
1184 if (vs) {
1185 gl.deleteShader(vs);
1186 }
1187 if (fs) {
1188 gl.deleteShader(fs);
1189 }
1190 return program;
1191 };
1192
1193 /**
1194 * Loads shaders from script tags, creates a program, attaches the shaders and
1195 * links.
1196 * @param {!WebGLContext} gl The WebGLContext to use.
1197 * @param {string} vertexScriptId The id of the script tag that contains the
1198 * vertex shader.
1199 * @param {string} fragmentScriptId The id of the script tag that contains the
1200 * fragment shader.
1201 * @param {function(string): void) opt_errorCallback callback for errors.
1202 * @return {!WebGLProgram} The created program.
1203 */
1204 var loadProgramFromScript = function loadProgramFromScript(
1205 gl, vertexScriptId, fragmentScriptId, opt_errorCallback) {
1206 var program = gl.createProgram();
1207 gl.attachShader(
1208 program,
1209 loadShaderFromScript(
1210 gl, vertexScriptId, gl.VERTEX_SHADER, opt_errorCallback));
1211 gl.attachShader(
1212 program,
1213 loadShaderFromScript(
1214 gl, fragmentScriptId, gl.FRAGMENT_SHADER, opt_errorCallback));
1215 linkProgram(gl, program, opt_errorCallback);
1216 return program;
1217 };
1218
1219 /**
1220 * Loads shaders from source, creates a program, attaches the shaders and
1221 * links.
1222 * @param {!WebGLContext} gl The WebGLContext to use.
1223 * @param {!WebGLShader} vertexShader The vertex shader.
1224 * @param {!WebGLShader} fragmentShader The fragment shader.
1225 * @param {function(string): void) opt_errorCallback callback for errors.
1226 * @return {!WebGLProgram} The created program.
1227 */
1228 var createProgram = function(gl, vertexShader, fragmentShader, opt_errorCallback ) {
1229 var program = gl.createProgram();
1230 gl.attachShader(program, vertexShader);
1231 gl.attachShader(program, fragmentShader);
1232 linkProgram(gl, program, opt_errorCallback);
1233 return program;
1234 };
1235
1236 /**
1237 * Loads shaders from source, creates a program, attaches the shaders and
1238 * links.
1239 * @param {!WebGLContext} gl The WebGLContext to use.
1240 * @param {string} vertexShader The vertex shader source.
1241 * @param {string} fragmentShader The fragment shader source.
1242 * @param {function(string): void) opt_errorCallback callback for errors.
1243 * @return {!WebGLProgram} The created program.
1244 */
1245 var loadProgram = function(
1246 gl, vertexShader, fragmentShader, opt_errorCallback) {
1247 var program;
1248 var vs = loadShader(
1249 gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback);
1250 var fs = loadShader(
1251 gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback);
1252 if (vs && fs) {
1253 program = createProgram(gl, vs, fs, opt_errorCallback)
1254 }
1255 if (vs) {
1256 gl.deleteShader(vs);
1257 }
1258 if (fs) {
1259 gl.deleteShader(fs);
1260 }
1261 return program;
1262 };
1263
1264 /**
1265 * Loads shaders from source, creates a program, attaches the shaders and
1266 * links but expects error.
1267 *
1268 * GLSL 1.0.17 10.27 effectively says that compileShader can
1269 * always succeed as long as linkProgram fails so we can't
1270 * rely on compileShader failing. This function expects
1271 * one of the shader to fail OR linking to fail.
1272 *
1273 * @param {!WebGLContext} gl The WebGLContext to use.
1274 * @param {string} vertexShaderScriptId The vertex shader.
1275 * @param {string} fragmentShaderScriptId The fragment shader.
1276 * @return {WebGLProgram} The created program.
1277 */
1278 var loadProgramFromScriptExpectError = function(
1279 gl, vertexShaderScriptId, fragmentShaderScriptId) {
1280 var vertexShader = loadShaderFromScript(gl, vertexShaderScriptId);
1281 if (!vertexShader) {
1282 return null;
1283 }
1284 var fragmentShader = loadShaderFromScript(gl, fragmentShaderScriptId);
1285 if (!fragmentShader) {
1286 return null;
1287 }
1288 var linkSuccess = true;
1289 var program = gl.createProgram();
1290 gl.attachShader(program, vertexShader);
1291 gl.attachShader(program, fragmentShader);
1292 linkSuccess = true;
1293 linkProgram(gl, program, function() {
1294 linkSuccess = false;
1295 });
1296 return linkSuccess ? program : null;
1297 };
1298
1299 var basePath;
1300 var getBasePath = function() {
1301 if (!basePath) {
1302 var expectedBase = "webgl-test-utils.js";
1303 var scripts = document.getElementsByTagName('script');
1304 for (var script, i = 0; script = scripts[i]; i++) {
1305 var src = script.src;
1306 var l = src.length;
1307 if (src.substr(l - expectedBase.length) == expectedBase) {
1308 basePath = src.substr(0, l - expectedBase.length);
1309 }
1310 }
1311 }
1312 return basePath;
1313 };
1314
1315 var loadStandardVertexShader = function(gl) {
1316 return loadShaderFromFile(
1317 gl, getBasePath() + "vertexShader.vert", gl.VERTEX_SHADER);
1318 };
1319
1320 var loadStandardFragmentShader = function(gl) {
1321 return loadShaderFromFile(
1322 gl, getBasePath() + "fragmentShader.frag", gl.FRAGMENT_SHADER);
1323 };
1324
1325 /**
1326 * Loads an image asynchronously.
1327 * @param {string} url URL of image to load.
1328 * @param {!function(!Element): void} callback Function to call
1329 * with loaded image.
1330 */
1331 var loadImageAsync = function(url, callback) {
1332 var img = document.createElement('img');
1333 img.onload = function() {
1334 callback(img);
1335 };
1336 img.src = url;
1337 };
1338
1339 /**
1340 * Loads an array of images.
1341 * @param {!Array.<string>} urls URLs of images to load.
1342 * @param {!function(!{string, img}): void} callback. Callback
1343 * that gets passed map of urls to img tags.
1344 */
1345 var loadImagesAsync = function(urls, callback) {
1346 var count = 1;
1347 var images = { };
1348 function countDown() {
1349 --count;
1350 if (count == 0) {
1351 callback(images);
1352 }
1353 }
1354 function imageLoaded(url) {
1355 return function(img) {
1356 images[url] = img;
1357 countDown();
1358 }
1359 }
1360 for (var ii = 0; ii < urls.length; ++ii) {
1361 ++count;
1362 loadImageAsync(urls[ii], imageLoaded(urls[ii]));
1363 }
1364 countDown();
1365 };
1366
1367 var getUrlArguments = function() {
1368 var args = {};
1369 try {
1370 var s = window.location.href;
1371 var q = s.indexOf("?");
1372 var e = s.indexOf("#");
1373 if (e < 0) {
1374 e = s.length;
1375 }
1376 var query = s.substring(q + 1, e);
1377 var pairs = query.split("&");
1378 for (var ii = 0; ii < pairs.length; ++ii) {
1379 var keyValue = pairs[ii].split("=");
1380 var key = keyValue[0];
1381 var value = decodeURIComponent(keyValue[1]);
1382 args[key] = value;
1383 }
1384 } catch (e) {
1385 throw "could not parse url";
1386 }
1387 return args;
1388 };
1389
1390 var makeImage = function(canvas) {
1391 var img = document.createElement('img');
1392 img.src = canvas.toDataURL();
1393 return img;
1394 };
1395
1396 var insertImage = function(element, caption, img) {
1397 var div = document.createElement("div");
1398 div.appendChild(img);
1399 var label = document.createElement("div");
1400 label.appendChild(document.createTextNode(caption));
1401 div.appendChild(label);
1402 element.appendChild(div);
1403 };
1404
1405 var addShaderSource = function(element, label, source, opt_url) {
1406 var div = document.createElement("div");
1407 var s = document.createElement("pre");
1408 s.className = "shader-source";
1409 s.style.display = "none";
1410 var ol = document.createElement("ol");
1411 //s.appendChild(document.createTextNode(source));
1412 var lines = source.split("\n");
1413 for (var ii = 0; ii < lines.length; ++ii) {
1414 var line = lines[ii];
1415 var li = document.createElement("li");
1416 li.appendChild(document.createTextNode(line));
1417 ol.appendChild(li);
1418 }
1419 s.appendChild(ol);
1420 var l = document.createElement("a");
1421 l.href = "show-shader-source";
1422 l.appendChild(document.createTextNode(label));
1423 l.addEventListener('click', function(event) {
1424 if (event.preventDefault) {
1425 event.preventDefault();
1426 }
1427 s.style.display = (s.style.display == 'none') ? 'block' : 'none';
1428 return false;
1429 }, false);
1430 div.appendChild(l);
1431 if (opt_url) {
1432 var u = document.createElement("a");
1433 u.href = opt_url;
1434 div.appendChild(document.createTextNode(" "));
1435 u.appendChild(document.createTextNode("(" + opt_url + ")"));
1436 div.appendChild(u);
1437 }
1438 div.appendChild(s);
1439 element.appendChild(div);
1440 };
1441
1442 // Add your prefix here.
1443 var browserPrefixes = [
1444 "",
1445 "MOZ_",
1446 "OP_",
1447 "WEBKIT_"
1448 ];
1449
1450 /**
1451 * Given an extension name like WEBGL_compressed_texture_s3tc
1452 * returns the name of the supported version extension, like
1453 * WEBKIT_WEBGL_compressed_teture_s3tc
1454 * @param {string} name Name of extension to look for
1455 * @return {string} name of extension found or undefined if not
1456 * found.
1457 */
1458 var getSupportedExtensionWithKnownPrefixes = function(gl, name) {
1459 var supported = gl.getSupportedExtensions();
1460 for (var ii = 0; ii < browserPrefixes.length; ++ii) {
1461 var prefixedName = browserPrefixes[ii] + name;
1462 if (supported.indexOf(prefixedName) >= 0) {
1463 return prefixedName;
1464 }
1465 }
1466 };
1467
1468 /**
1469 * Given an extension name like WEBGL_compressed_texture_s3tc
1470 * returns the supported version extension, like
1471 * WEBKIT_WEBGL_compressed_teture_s3tc
1472 * @param {string} name Name of extension to look for
1473 * @return {WebGLExtension} The extension or undefined if not
1474 * found.
1475 */
1476 var getExtensionWithKnownPrefixes = function(gl, name) {
1477 for (var ii = 0; ii < browserPrefixes.length; ++ii) {
1478 var prefixedName = browserPrefixes[ii] + name;
1479 var ext = gl.getExtension(prefixedName);
1480 if (ext) {
1481 return ext;
1482 }
1483 }
1484 };
1485
1486
1487 var replaceRE = /\$\((\w+)\)/g;
1488
1489 /**
1490 * Replaces strings with property values.
1491 * Given a string like "hello $(first) $(last)" and an object
1492 * like {first:"John", last:"Smith"} will return
1493 * "hello John Smith".
1494 * @param {string} str String to do replacements in
1495 * @param {...} 1 or more objects conaining properties.
1496 */
1497 var replaceParams = function(str) {
1498 var args = arguments;
1499 return str.replace(replaceRE, function(str, p1, offset, s) {
1500 for (var ii = 1; ii < args.length; ++ii) {
1501 if (args[ii][p1] !== undefined) {
1502 return args[ii][p1];
1503 }
1504 }
1505 throw "unknown string param '" + p1 + "'";
1506 });
1507 };
1508
1509
1510 /**
1511 * Provides requestAnimationFrame in a cross browser way.
1512 */
1513 var requestAnimFrameImpl_;
1514
1515 var requestAnimFrame = function(callback, element) {
1516 if (!requestAnimFrameImpl_) {
1517 requestAnimFrameImpl_ = function() {
1518 var functionNames = [
1519 "requestAnimationFrame",
1520 "webkitRequestAnimationFrame",
1521 "mozRequestAnimationFrame",
1522 "oRequestAnimationFrame",
1523 "msRequestAnimationFrame"
1524 ];
1525 for (var jj = 0; jj < functionNames.length; ++jj) {
1526 var functionName = functionNames[jj];
1527 if (window[functionName]) {
1528 return function(name) {
1529 return function(callback, element) {
1530 return window[name].call(window, callback, element);
1531 };
1532 }(functionName);
1533 }
1534 }
1535 return function(callback, element) {
1536 return window.setTimeout(callback, 1000 / 70);
1537 };
1538 }();
1539 }
1540
1541 return requestAnimFrameImpl_(callback, element);
1542 };
1543
1544 /**
1545 * Provides cancelAnimationFrame in a cross browser way.
1546 */
1547 var cancelAnimFrame = (function() {
1548 return window.cancelAnimationFrame ||
1549 window.webkitCancelAnimationFrame ||
1550 window.mozCancelAnimationFrame ||
1551 window.oCancelAnimationFrame ||
1552 window.msCancelAnimationFrame ||
1553 window.clearTimeout;
1554 })();
1555
1556 var waitFrames = function(frames, callback) {
1557 var countDown = function() {
1558 if (frames == 0) {
1559 callback();
1560 } else {
1561 --frames;
1562 requestAnimFrame(countDown);
1563 }
1564 };
1565 countDown();
1566 };
1567
1568 return {
1569 addShaderSource: addShaderSource,
1570 cancelAnimFrame: cancelAnimFrame,
1571 create3DContext: create3DContext,
1572 create3DContextWithWrapperThatThrowsOnGLError:
1573 create3DContextWithWrapperThatThrowsOnGLError,
1574 checkCanvas: checkCanvas,
1575 checkCanvasRect: checkCanvasRect,
1576 createColoredTexture: createColoredTexture,
1577 createProgram: createProgram,
1578 drawQuad: drawQuad,
1579 drawIndexedQuad: drawIndexedQuad,
1580 endsWith: endsWith,
1581 getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
1582 getFileListAsync: getFileListAsync,
1583 getLastError: getLastError,
1584 getScript: getScript,
1585 getSupportedExtensionWithKnownPrefixes: getSupportedExtensionWithKnownPrefixes ,
1586 getUrlArguments: getUrlArguments,
1587 glEnumToString: glEnumToString,
1588 glErrorShouldBe: glErrorShouldBe,
1589 fillTexture: fillTexture,
1590 insertImage: insertImage,
1591 loadImageAsync: loadImageAsync,
1592 loadImagesAsync: loadImagesAsync,
1593 loadProgram: loadProgram,
1594 loadProgramFromFile: loadProgramFromFile,
1595 loadProgramFromScript: loadProgramFromScript,
1596 loadProgramFromScriptExpectError: loadProgramFromScriptExpectError,
1597 loadShader: loadShader,
1598 loadShaderFromFile: loadShaderFromFile,
1599 loadShaderFromScript: loadShaderFromScript,
1600 loadStandardProgram: loadStandardProgram,
1601 loadStandardVertexShader: loadStandardVertexShader,
1602 loadStandardFragmentShader: loadStandardFragmentShader,
1603 loadTextFileAsync: loadTextFileAsync,
1604 loadTexture: loadTexture,
1605 log: log,
1606 loggingOff: loggingOff,
1607 makeImage: makeImage,
1608 error: error,
1609 setupColorQuad: setupColorQuad,
1610 setupProgram: setupProgram,
1611 setupQuad: setupQuad,
1612 setupQuadWithOptions: setupQuadWithOptions,
1613 setupSimpleTextureFragmentShader: setupSimpleTextureFragmentShader,
1614 setupSimpleTextureProgram: setupSimpleTextureProgram,
1615 setupSimpleTextureVertexShader: setupSimpleTextureVertexShader,
1616 setupNoTexCoordTextureProgram: setupNoTexCoordTextureProgram,
1617 setupNoTexCoordTextureVertexShader: setupNoTexCoordTextureVertexShader,
1618 setupTexturedQuad: setupTexturedQuad,
1619 setupTexturedQuadWithTexCoords: setupTexturedQuadWithTexCoords,
1620 setupUnitQuad: setupUnitQuad,
1621 setupUnitQuadWithTexCoords: setupUnitQuadWithTexCoords,
1622 startsWith: startsWith,
1623 shouldGenerateGLError: shouldGenerateGLError,
1624 readFile: readFile,
1625 readFileList: readFileList,
1626 replaceParams: replaceParams,
1627 requestAnimFrame: requestAnimFrame,
1628 waitFrames: waitFrames,
1629
1630 none: false
1631 };
1632
1633 }());
1634
1635
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698