Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / fast / canvas / webgl / resources / webgl-test.js
blob03f7fcf9421fd4918473fff6f480f03f0798c10c
1 //----------------------------------------------------------------------
2 // Differences with respect to Khronos version of webgl-test.js
3 if (window.testRunner)
4 testRunner.overridePreference("WebKitWebGLEnabled", "1");
6 function assertMsg(assertion, msg) {
7 if (assertion) {
8 testPassed(msg);
9 } else {
10 testFailed(msg);
14 function initNonKhronosFramework(waitUntilDone) {
15 if (window.testRunner) {
16 testRunner.overridePreference("WebKitWebGLEnabled", "1");
17 testRunner.dumpAsText();
18 if (waitUntilDone) {
19 window.jsTestIsAsync = true;
20 testRunner.waitUntilDone();
25 function nonKhronosFrameworkNotifyDone() {
26 if (window.testRunner) {
27 testRunner.notifyDone();
31 function finishTest() {
32 finishJSTest();
36 //----------------------------------------------------------------------
38 function webglTestLog(msg) {
39 if (window.console && window.console.log) {
40 window.console.log(msg);
42 if (document.getElementById("console")) {
43 var log = document.getElementById("console");
44 log.innerHTML += msg + "<br>";
49 // create3DContext
51 // Returns the WebGLRenderingContext for any known implementation.
53 function create3DContext(canvas, attributes)
55 if (!canvas)
56 canvas = document.createElement("canvas");
57 var context = null;
58 try {
59 context = canvas.getContext("webgl", attributes);
60 } catch(e) {}
61 if (!context) {
62 try {
63 context = canvas.getContext("webkit-3d", attributes);
64 } catch(e) {}
66 if (!context) {
67 try {
68 context = canvas.getContext("moz-webgl", attributes);
69 } catch(e) {}
71 if (!context) {
72 throw "Unable to fetch WebGL rendering context for Canvas";
74 return context;
77 function createGLErrorWrapper(context, fname) {
78 return function() {
79 var rv = context[fname].apply(context, arguments);
80 var err = context.getError();
81 if (err != 0)
82 throw "GL error " + err + " in " + fname;
83 return rv;
87 function create3DContextWithWrapperThatThrowsOnGLError(canvas, attributes) {
88 var context = create3DContext(canvas, attributes);
89 // Thanks to Ilmari Heikkinen for the idea on how to implement this so elegantly.
90 var wrap = {};
91 for (var i in context) {
92 try {
93 if (typeof context[i] == 'function') {
94 wrap[i] = createGLErrorWrapper(context, i);
95 } else {
96 wrap[i] = context[i];
98 } catch (e) {
99 webglTestLog("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
102 wrap.getError = function() {
103 return context.getError();
105 return wrap;
108 function getGLErrorAsString(ctx, err) {
109 if (err === ctx.NO_ERROR) {
110 return "NO_ERROR";
112 for (var name in ctx) {
113 if (ctx[name] === err) {
114 return name;
117 return "0x" + err.toString(16);
120 // Pass undefined for glError to test that it at least throws some error
121 function shouldGenerateGLError(ctx, glErrors, evalStr) {
122 if (!glErrors.length) {
123 glErrors = [glErrors];
125 var exception;
126 try {
127 eval(evalStr);
128 } catch (e) {
129 exception = e;
131 if (exception) {
132 testFailed(evalStr + " threw exception " + exception);
133 } else {
134 var err = ctx.getError();
135 var errStrs = [];
136 for (var ii = 0; ii < glErrors.length; ++ii) {
137 errStrs.push(getGLErrorAsString(ctx, glErrors[ii]));
139 var expected = errStrs.join(" or ");
140 if (glErrors.indexOf(err) < 0) {
141 testFailed(evalStr + " expected: " + expected + ". Was " + getGLErrorAsString(ctx, err) + ".");
142 } else {
143 var msg = (glErrors.length == 1) ? " generated expected GL error: " :
144 " generated one of expected GL errors: ";
145 testPassed(evalStr + msg + expected + ".");
151 * Tests that the first error GL returns is the specified error.
152 * @param {!WebGLContext} gl The WebGLContext to use.
153 * @param {number|!Array.<number>} glError The expected gl
154 * error. Multiple errors can be passed in using an
155 * array.
156 * @param {string} opt_msg Optional additional message.
158 function glErrorShouldBe(gl, glErrors, opt_msg) {
159 if (!glErrors.length) {
160 glErrors = [glErrors];
162 opt_msg = opt_msg || "";
163 var err = gl.getError();
164 var ndx = glErrors.indexOf(err);
165 var errStrs = [];
166 for (var ii = 0; ii < glErrors.length; ++ii) {
167 errStrs.push(getGLErrorAsString(gl, glErrors[ii]));
169 var expected = errStrs.join(" or ");
170 if (ndx < 0) {
171 var msg = "getError expected" + ((glErrors.length > 1) ? " one of: " : ": ");
172 testFailed(msg + expected + ". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
173 } else {
174 var msg = "getError was " + ((glErrors.length > 1) ? "one of: " : "expected value: ");
175 testPassed(msg + expected + " : " + opt_msg);
180 // createProgram
182 // Create and return a program object, attaching each of the given shaders.
184 // If attribs are given, bind an attrib with that name at that index.
186 function createProgram(gl, vshaders, fshaders, attribs)
188 if (typeof(vshaders) == "string")
189 vshaders = [vshaders];
190 if (typeof(fshaders) == "string")
191 fshaders = [fshaders];
193 var shaders = [];
194 var i;
196 for (i = 0; i < vshaders.length; ++i) {
197 var shader = loadShader(gl, vshaders[i], gl.VERTEX_SHADER);
198 if (!shader)
199 return null;
200 shaders.push(shader);
203 for (i = 0; i < fshaders.length; ++i) {
204 var shader = loadShader(gl, fshaders[i], gl.FRAGMENT_SHADER);
205 if (!shader)
206 return null;
207 shaders.push(shader);
210 var prog = gl.createProgram();
211 for (i = 0; i < shaders.length; ++i) {
212 gl.attachShader(prog, shaders[i]);
215 if (attribs) {
216 for (var i in attribs) {
217 gl.bindAttribLocation (prog, parseInt(i), attribs[i]);
221 gl.linkProgram(prog);
223 // Check the link status
224 var linked = gl.getProgramParameter(prog, gl.LINK_STATUS);
225 if (!linked) {
226 // something went wrong with the link
227 var error = gl.getProgramInfoLog(prog);
228 webglTestLog("Error in program linking:" + error);
230 gl.deleteProgram(prog);
231 for (i = 0; i < shaders.length; ++i)
232 gl.deleteShader(shaders[i]);
233 return null;
236 return prog;
240 // initWebGL
242 // Initialize the Canvas element with the passed name as a WebGL object and return the
243 // WebGLRenderingContext.
245 // Load shaders with the passed names and create a program with them. Return this program
246 // in the 'program' property of the returned context.
248 // For each string in the passed attribs array, bind an attrib with that name at that index.
249 // Once the attribs are bound, link the program and then use it.
251 // Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
252 // Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
254 function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth, contextAttribs)
256 var canvas = document.getElementById(canvasName);
257 var gl = create3DContext(canvas, contextAttribs);
258 if (!gl) {
259 alert("No WebGL context found");
260 return null;
263 // Create the program object
264 gl.program = createProgram(gl, vshader, fshader, attribs);
265 if (!gl.program)
266 return null;
268 gl.useProgram(gl.program);
270 gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
271 gl.clearDepth(clearDepth);
273 gl.enable(gl.DEPTH_TEST);
274 gl.enable(gl.BLEND);
275 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
277 return gl;
281 // getShaderSource
283 // Load the source from the passed shader file.
285 function getShaderSource(file)
287 var xhr = new XMLHttpRequest();
288 xhr.open("GET", file, false);
289 xhr.send();
290 return xhr.responseText;
295 // loadShader
297 // 'shader' is either the id of a <script> element containing the shader source
298 // string, the shader string itself, or the URL of a file containing the shader
299 // source. Load this shader and return the WebGLShader object corresponding to
300 // it.
302 function loadShader(ctx, shaderId, shaderType, isFile)
304 var shaderSource = "";
306 if (isFile)
307 shaderSource = getShaderSource(shaderId);
308 else {
309 var shaderScript = document.getElementById(shaderId);
310 if (!shaderScript) {
311 shaderSource = shaderId;
312 } else {
313 if (shaderScript.type == "x-shader/x-vertex") {
314 shaderType = ctx.VERTEX_SHADER;
315 } else if (shaderScript.type == "x-shader/x-fragment") {
316 shaderType = ctx.FRAGMENT_SHADER;
317 } else if (shaderType != ctx.VERTEX_SHADER && shaderType != ctx.FRAGMENT_SHADER) {
318 webglTestLog("*** Error: unknown shader type");
319 return null;
322 shaderSource = shaderScript.text;
326 // Create the shader object
327 var shader = ctx.createShader(shaderType);
328 if (shader == null) {
329 webglTestLog("*** Error: unable to create shader '"+shaderId+"'");
330 return null;
333 // Load the shader source
334 ctx.shaderSource(shader, shaderSource);
336 // Compile the shader
337 ctx.compileShader(shader);
339 // Check the compile status
340 var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
341 if (!compiled) {
342 // Something went wrong during compilation; get the error
343 var error = ctx.getShaderInfoLog(shader);
344 webglTestLog("*** Error compiling shader '"+shader+"':"+error);
345 ctx.deleteShader(shader);
346 return null;
349 return shader;
352 function loadShaderFromFile(ctx, file, type)
354 return loadShader(ctx, file, type, true);
357 function loadShaderFromScript(ctx, script)
359 return loadShader(ctx, script, 0, false);
362 function loadStandardProgram(context) {
363 var program = context.createProgram();
364 context.attachShader(program, loadStandardVertexShader(context));
365 context.attachShader(program, loadStandardFragmentShader(context));
366 context.linkProgram(program);
367 return program;
370 function loadProgram(context, vertexShaderPath, fragmentShaderPath, isFile) {
371 isFile = (isFile === undefined) ? true : isFile;
372 var program = context.createProgram();
373 context.attachShader(program, loadShader(context, vertexShaderPath, context.VERTEX_SHADER, isFile));
374 context.attachShader(program, loadShader(context, fragmentShaderPath, context.FRAGMENT_SHADER, isFile));
375 context.linkProgram(program);
376 return program;
379 function loadStandardVertexShader(context) {
380 return loadShader(context, "resources/vertexShader.vert", context.VERTEX_SHADER, true);
383 function loadStandardFragmentShader(context) {
384 return loadShader(context, "resources/fragmentShader.frag", context.FRAGMENT_SHADER, true);
388 // makeBox
390 // Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
391 // Return an object with the following properties:
393 // normalObject WebGLBuffer object for normals
394 // texCoordObject WebGLBuffer object for texCoords
395 // vertexObject WebGLBuffer object for vertices
396 // indexObject WebGLBuffer object for indices
397 // numIndices The number of indices in the indexObject
399 function makeBox(ctx)
401 // box
402 // v6----- v5
403 // /| /|
404 // v1------v0|
405 // | | | |
406 // | |v7---|-|v4
407 // |/ |/
408 // v2------v3
410 // vertex coords array
411 var vertices = new Float32Array(
412 [ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0-v1-v2-v3 front
413 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0-v3-v4-v5 right
414 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0-v5-v6-v1 top
415 -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1-v6-v7-v2 left
416 -1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7-v4-v3-v2 bottom
417 1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 ] // v4-v7-v6-v5 back
420 // normal array
421 var normals = new Float32Array(
422 [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front
423 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
424 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top
425 -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left
426 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3-v2 bottom
427 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 ] // v4-v7-v6-v5 back
431 // texCoord array
432 var texCoords = new Float32Array(
433 [ 1, 1, 0, 1, 0, 0, 1, 0, // v0-v1-v2-v3 front
434 0, 1, 0, 0, 1, 0, 1, 1, // v0-v3-v4-v5 right
435 1, 0, 1, 1, 0, 1, 0, 0, // v0-v5-v6-v1 top
436 1, 1, 0, 1, 0, 0, 1, 0, // v1-v6-v7-v2 left
437 0, 0, 1, 0, 1, 1, 0, 1, // v7-v4-v3-v2 bottom
438 0, 0, 1, 0, 1, 1, 0, 1 ] // v4-v7-v6-v5 back
441 // index array
442 var indices = new Uint8Array(
443 [ 0, 1, 2, 0, 2, 3, // front
444 4, 5, 6, 4, 6, 7, // right
445 8, 9,10, 8,10,11, // top
446 12,13,14, 12,14,15, // left
447 16,17,18, 16,18,19, // bottom
448 20,21,22, 20,22,23 ] // back
451 var retval = { };
453 retval.normalObject = ctx.createBuffer();
454 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
455 ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
457 retval.texCoordObject = ctx.createBuffer();
458 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
459 ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
461 retval.vertexObject = ctx.createBuffer();
462 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
463 ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
465 ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
467 retval.indexObject = ctx.createBuffer();
468 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
469 ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
470 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
472 retval.numIndices = indices.length;
474 return retval;
478 // makeSphere
480 // Create a sphere with the passed number of latitude and longitude bands and the passed radius.
481 // Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
482 // Return an object with the following properties:
484 // normalObject WebGLBuffer object for normals
485 // texCoordObject WebGLBuffer object for texCoords
486 // vertexObject WebGLBuffer object for vertices
487 // indexObject WebGLBuffer object for indices
488 // numIndices The number of indices in the indexObject
490 function makeSphere(ctx, radius, lats, longs)
492 var geometryData = [ ];
493 var normalData = [ ];
494 var texCoordData = [ ];
495 var indexData = [ ];
497 for (var latNumber = 0; latNumber <= lats; ++latNumber) {
498 for (var longNumber = 0; longNumber <= longs; ++longNumber) {
499 var theta = latNumber * Math.PI / lats;
500 var phi = longNumber * 2 * Math.PI / longs;
501 var sinTheta = Math.sin(theta);
502 var sinPhi = Math.sin(phi);
503 var cosTheta = Math.cos(theta);
504 var cosPhi = Math.cos(phi);
506 var x = cosPhi * sinTheta;
507 var y = cosTheta;
508 var z = sinPhi * sinTheta;
509 var u = 1-(longNumber/longs);
510 var v = latNumber/lats;
512 normalData.push(x);
513 normalData.push(y);
514 normalData.push(z);
515 texCoordData.push(u);
516 texCoordData.push(v);
517 geometryData.push(radius * x);
518 geometryData.push(radius * y);
519 geometryData.push(radius * z);
523 longs += 1;
524 for (var latNumber = 0; latNumber < lats; ++latNumber) {
525 for (var longNumber = 0; longNumber < longs; ++longNumber) {
526 var first = (latNumber * longs) + (longNumber % longs);
527 var second = first + longs;
528 indexData.push(first);
529 indexData.push(second);
530 indexData.push(first+1);
532 indexData.push(second);
533 indexData.push(second+1);
534 indexData.push(first+1);
538 var retval = { };
540 retval.normalObject = ctx.createBuffer();
541 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
542 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW);
544 retval.texCoordObject = ctx.createBuffer();
545 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
546 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW);
548 retval.vertexObject = ctx.createBuffer();
549 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
550 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW);
552 retval.numIndices = indexData.length;
553 retval.indexObject = ctx.createBuffer();
554 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
555 ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW);
557 return retval;
561 // loadObj
563 // Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
564 // When the object load is complete, the 'loaded' property becomes true and the following
565 // properties are set:
567 // normalObject WebGLBuffer object for normals
568 // texCoordObject WebGLBuffer object for texCoords
569 // vertexObject WebGLBuffer object for vertices
570 // indexObject WebGLBuffer object for indices
571 // numIndices The number of indices in the indexObject
573 function loadObj(ctx, url)
575 var obj = { loaded : false };
576 obj.ctx = ctx;
577 var req = new XMLHttpRequest();
578 req.obj = obj;
579 req.onreadystatechange = function () { processLoadObj(req) };
580 req.open("GET", url, true);
581 req.send(null);
582 return obj;
585 function processLoadObj(req)
587 webglTestLog("req="+req)
588 // only if req shows "complete"
589 if (req.readyState == 4) {
590 doLoadObj(req.obj, req.responseText);
594 function doLoadObj(obj, text)
596 vertexArray = [ ];
597 normalArray = [ ];
598 textureArray = [ ];
599 indexArray = [ ];
601 var vertex = [ ];
602 var normal = [ ];
603 var texture = [ ];
604 var facemap = { };
605 var index = 0;
607 var lines = text.split("\n");
608 for (var lineIndex in lines) {
609 var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
611 // ignore comments
612 if (line[0] == "#")
613 continue;
615 var array = line.split(" ");
616 if (array[0] == "v") {
617 // vertex
618 vertex.push(parseFloat(array[1]));
619 vertex.push(parseFloat(array[2]));
620 vertex.push(parseFloat(array[3]));
622 else if (array[0] == "vt") {
623 // normal
624 texture.push(parseFloat(array[1]));
625 texture.push(parseFloat(array[2]));
627 else if (array[0] == "vn") {
628 // normal
629 normal.push(parseFloat(array[1]));
630 normal.push(parseFloat(array[2]));
631 normal.push(parseFloat(array[3]));
633 else if (array[0] == "f") {
634 // face
635 if (array.length != 4) {
636 webglTestLog("*** Error: face '"+line+"' not handled");
637 continue;
640 for (var i = 1; i < 4; ++i) {
641 if (!(array[i] in facemap)) {
642 // add a new entry to the map and arrays
643 var f = array[i].split("/");
644 var vtx, nor, tex;
646 if (f.length == 1) {
647 vtx = parseInt(f[0]) - 1;
648 nor = vtx;
649 tex = vtx;
651 else if (f.length = 3) {
652 vtx = parseInt(f[0]) - 1;
653 tex = parseInt(f[1]) - 1;
654 nor = parseInt(f[2]) - 1;
656 else {
657 webglTestLog("*** Error: did not understand face '"+array[i]+"'");
658 return null;
661 // do the vertices
662 var x = 0;
663 var y = 0;
664 var z = 0;
665 if (vtx * 3 + 2 < vertex.length) {
666 x = vertex[vtx*3];
667 y = vertex[vtx*3+1];
668 z = vertex[vtx*3+2];
670 vertexArray.push(x);
671 vertexArray.push(y);
672 vertexArray.push(z);
674 // do the textures
675 x = 0;
676 y = 0;
677 if (tex * 2 + 1 < texture.length) {
678 x = texture[tex*2];
679 y = texture[tex*2+1];
681 textureArray.push(x);
682 textureArray.push(y);
684 // do the normals
685 x = 0;
686 y = 0;
687 z = 1;
688 if (nor * 3 + 2 < normal.length) {
689 x = normal[nor*3];
690 y = normal[nor*3+1];
691 z = normal[nor*3+2];
693 normalArray.push(x);
694 normalArray.push(y);
695 normalArray.push(z);
697 facemap[array[i]] = index++;
700 indexArray.push(facemap[array[i]]);
705 // set the VBOs
706 obj.normalObject = obj.ctx.createBuffer();
707 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
708 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW);
710 obj.texCoordObject = obj.ctx.createBuffer();
711 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
712 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW);
714 obj.vertexObject = obj.ctx.createBuffer();
715 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
716 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW);
718 obj.numIndices = indexArray.length;
719 obj.indexObject = obj.ctx.createBuffer();
720 obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
721 obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW);
723 obj.loaded = true;
727 // loadImageTexture
729 // Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
731 function loadImageTexture(ctx, url)
733 var texture = ctx.createTexture();
734 texture.image = new Image();
735 texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
736 texture.image.src = url;
737 return texture;
740 function doLoadImageTexture(ctx, image, texture)
742 ctx.enable(ctx.TEXTURE_2D);
743 ctx.bindTexture(ctx.TEXTURE_2D, texture);
744 ctx.texImage2D(ctx.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
745 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
746 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR);
747 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
748 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
749 ctx.generateMipmap(ctx.TEXTURE_2D)
750 ctx.bindTexture(ctx.TEXTURE_2D, 0);
754 // Framerate object
756 // This object keeps track of framerate and displays it as the innerHTML text of the
757 // HTML element with the passed id. Once created you call snapshot at the end
758 // of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
760 Framerate = function(id)
762 this.numFramerates = 10;
763 this.framerateUpdateInterval = 500;
764 this.id = id;
766 this.renderTime = -1;
767 this.framerates = [ ];
768 self = this;
769 var fr = function() { self.updateFramerate() }
770 setInterval(fr, this.framerateUpdateInterval);
773 Framerate.prototype.updateFramerate = function()
775 var tot = 0;
776 for (var i = 0; i < this.framerates.length; ++i)
777 tot += this.framerates[i];
779 var framerate = tot / this.framerates.length;
780 framerate = Math.round(framerate);
781 document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
784 Framerate.prototype.snapshot = function()
786 if (this.renderTime < 0)
787 this.renderTime = new Date().getTime();
788 else {
789 var newTime = new Date().getTime();
790 var t = newTime - this.renderTime;
791 var framerate = 1000/t;
792 this.framerates.push(framerate);
793 while (this.framerates.length > this.numFramerates)
794 this.framerates.shift();
795 this.renderTime = newTime;