content/canvas/test/webgl-conformance/conformance/more/util.js

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

michael@0 1 /*
michael@0 2 Utilities for the OpenGL ES 2.0 HTML Canvas context
michael@0 3
michael@0 4 Copyright (C) 2011 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
michael@0 5
michael@0 6 Permission is hereby granted, free of charge, to any person
michael@0 7 obtaining a copy of this software and associated documentation
michael@0 8 files (the "Software"), to deal in the Software without
michael@0 9 restriction, including without limitation the rights to use,
michael@0 10 copy, modify, merge, publish, distribute, sublicense, and/or sell
michael@0 11 copies of the Software, and to permit persons to whom the
michael@0 12 Software is furnished to do so, subject to the following
michael@0 13 conditions:
michael@0 14
michael@0 15 The above copyright notice and this permission notice shall be
michael@0 16 included in all copies or substantial portions of the Software.
michael@0 17
michael@0 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
michael@0 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
michael@0 20 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
michael@0 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
michael@0 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
michael@0 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
michael@0 24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
michael@0 25 OTHER DEALINGS IN THE SOFTWARE.
michael@0 26 */
michael@0 27
michael@0 28 function loadTexture(gl, elem, mipmaps) {
michael@0 29 var tex = gl.createTexture();
michael@0 30 gl.bindTexture(gl.TEXTURE_2D, tex);
michael@0 31 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elem);
michael@0 32 if (mipmaps != false)
michael@0 33 gl.generateMipmap(gl.TEXTURE_2D);
michael@0 34 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
michael@0 35 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
michael@0 36 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
michael@0 37 if (mipmaps)
michael@0 38 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
michael@0 39 else
michael@0 40 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
michael@0 41 return tex;
michael@0 42 }
michael@0 43
michael@0 44 function getShader(gl, id) {
michael@0 45 var shaderScript = document.getElementById(id);
michael@0 46 if (!shaderScript) {
michael@0 47 throw(new Error("No shader element with id: "+id));
michael@0 48 }
michael@0 49
michael@0 50 var str = "";
michael@0 51 var k = shaderScript.firstChild;
michael@0 52 while (k) {
michael@0 53 if (k.nodeType == 3)
michael@0 54 str += k.textContent;
michael@0 55 k = k.nextSibling;
michael@0 56 }
michael@0 57
michael@0 58 var shader;
michael@0 59 if (shaderScript.type == "x-shader/x-fragment") {
michael@0 60 shader = gl.createShader(gl.FRAGMENT_SHADER);
michael@0 61 } else if (shaderScript.type == "x-shader/x-vertex") {
michael@0 62 shader = gl.createShader(gl.VERTEX_SHADER);
michael@0 63 } else {
michael@0 64 throw(new Error("Unknown shader type "+shaderScript.type));
michael@0 65 }
michael@0 66
michael@0 67 gl.shaderSource(shader, str);
michael@0 68 gl.compileShader(shader);
michael@0 69
michael@0 70 if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) != 1) {
michael@0 71 var ilog = gl.getShaderInfoLog(shader);
michael@0 72 gl.deleteShader(shader);
michael@0 73 throw(new Error("Failed to compile shader "+shaderScript.id + ", Shader info log: " + ilog));
michael@0 74 }
michael@0 75 return shader;
michael@0 76 }
michael@0 77
michael@0 78 function loadShaderArray(gl, shaders) {
michael@0 79 var id = gl.createProgram();
michael@0 80 var shaderObjs = [];
michael@0 81 for (var i=0; i<shaders.length; ++i) {
michael@0 82 try {
michael@0 83 var sh = getShader(gl, shaders[i]);
michael@0 84 shaderObjs.push(sh);
michael@0 85 gl.attachShader(id, sh);
michael@0 86 } catch (e) {
michael@0 87 var pr = {program: id, shaders: shaderObjs};
michael@0 88 deleteShader(gl, pr);
michael@0 89 throw (e);
michael@0 90 }
michael@0 91 }
michael@0 92 var prog = {program: id, shaders: shaderObjs};
michael@0 93 gl.linkProgram(id);
michael@0 94 gl.validateProgram(id);
michael@0 95 if (gl.getProgramParameter(id, gl.LINK_STATUS) != 1) {
michael@0 96 deleteShader(gl,prog);
michael@0 97 throw(new Error("Failed to link shader"));
michael@0 98 }
michael@0 99 if (gl.getProgramParameter(id, gl.VALIDATE_STATUS) != 1) {
michael@0 100 deleteShader(gl,prog);
michael@0 101 throw(new Error("Failed to validate shader"));
michael@0 102 }
michael@0 103 return prog;
michael@0 104 }
michael@0 105 function loadShader(gl) {
michael@0 106 var sh = [];
michael@0 107 for (var i=1; i<arguments.length; ++i)
michael@0 108 sh.push(arguments[i]);
michael@0 109 return loadShaderArray(gl, sh);
michael@0 110 }
michael@0 111
michael@0 112 function deleteShader(gl, sh) {
michael@0 113 gl.useProgram(null);
michael@0 114 sh.shaders.forEach(function(s){
michael@0 115 gl.detachShader(sh.program, s);
michael@0 116 gl.deleteShader(s);
michael@0 117 });
michael@0 118 gl.deleteProgram(sh.program);
michael@0 119 }
michael@0 120
michael@0 121 function getGLErrorAsString(ctx, err) {
michael@0 122 if (err === ctx.NO_ERROR) {
michael@0 123 return "NO_ERROR";
michael@0 124 }
michael@0 125 for (var name in ctx) {
michael@0 126 if (ctx[name] === err) {
michael@0 127 return name;
michael@0 128 }
michael@0 129 }
michael@0 130 return err.toString();
michael@0 131 }
michael@0 132
michael@0 133 function checkError(gl, msg) {
michael@0 134 var e = gl.getError();
michael@0 135 if (e != gl.NO_ERROR) {
michael@0 136 log("Error " + getGLErrorAsString(gl, e) + " at " + msg);
michael@0 137 }
michael@0 138 return e;
michael@0 139 }
michael@0 140
michael@0 141 function throwError(gl, msg) {
michael@0 142 var e = gl.getError();
michael@0 143 if (e != 0) {
michael@0 144 throw(new Error("Error " + getGLErrorAsString(gl, e) + " at " + msg));
michael@0 145 }
michael@0 146 }
michael@0 147
michael@0 148 Math.cot = function(z) { return 1.0 / Math.tan(z); }
michael@0 149
michael@0 150 /*
michael@0 151 Matrix utilities, using the OpenGL element order where
michael@0 152 the last 4 elements are the translation column.
michael@0 153
michael@0 154 Uses flat arrays as matrices for performance.
michael@0 155
michael@0 156 Most operations have in-place variants to avoid allocating temporary matrices.
michael@0 157
michael@0 158 Naming logic:
michael@0 159 Matrix.method operates on a 4x4 Matrix and returns a new Matrix.
michael@0 160 Matrix.method3x3 operates on a 3x3 Matrix and returns a new Matrix. Not all operations have a 3x3 version (as 3x3 is usually only used for the normal matrix: Matrix.transpose3x3(Matrix.inverseTo3x3(mat4x4)))
michael@0 161 Matrix.method[3x3]InPlace(args, target) stores its result in the target matrix.
michael@0 162
michael@0 163 Matrix.scale([sx, sy, sz]) -- non-uniform scale by vector
michael@0 164 Matrix.scale1(s) -- uniform scale by scalar
michael@0 165 Matrix.scale3(sx, sy, sz) -- non-uniform scale by scalars
michael@0 166
michael@0 167 Ditto for translate.
michael@0 168 */
michael@0 169 Matrix = {
michael@0 170 identity : [
michael@0 171 1.0, 0.0, 0.0, 0.0,
michael@0 172 0.0, 1.0, 0.0, 0.0,
michael@0 173 0.0, 0.0, 1.0, 0.0,
michael@0 174 0.0, 0.0, 0.0, 1.0
michael@0 175 ],
michael@0 176
michael@0 177 newIdentity : function() {
michael@0 178 return [
michael@0 179 1.0, 0.0, 0.0, 0.0,
michael@0 180 0.0, 1.0, 0.0, 0.0,
michael@0 181 0.0, 0.0, 1.0, 0.0,
michael@0 182 0.0, 0.0, 0.0, 1.0
michael@0 183 ];
michael@0 184 },
michael@0 185
michael@0 186 newIdentity3x3 : function() {
michael@0 187 return [
michael@0 188 1.0, 0.0, 0.0,
michael@0 189 0.0, 1.0, 0.0,
michael@0 190 0.0, 0.0, 1.0
michael@0 191 ];
michael@0 192 },
michael@0 193
michael@0 194 copyMatrix : function(src, dst) {
michael@0 195 for (var i=0; i<16; i++) dst[i] = src[i];
michael@0 196 return dst;
michael@0 197 },
michael@0 198
michael@0 199 to3x3 : function(m) {
michael@0 200 return [
michael@0 201 m[0], m[1], m[2],
michael@0 202 m[4], m[5], m[6],
michael@0 203 m[8], m[9], m[10]
michael@0 204 ];
michael@0 205 },
michael@0 206
michael@0 207 // orthonormal matrix inverse
michael@0 208 inverseON : function(m) {
michael@0 209 var n = this.transpose4x4(m);
michael@0 210 var t = [m[12], m[13], m[14]];
michael@0 211 n[3] = n[7] = n[11] = 0;
michael@0 212 n[12] = -Vec3.dot([n[0], n[4], n[8]], t);
michael@0 213 n[13] = -Vec3.dot([n[1], n[5], n[9]], t);
michael@0 214 n[14] = -Vec3.dot([n[2], n[6], n[10]], t);
michael@0 215 return n;
michael@0 216 },
michael@0 217
michael@0 218 inverseTo3x3 : function(m) {
michael@0 219 return this.inverse4x4to3x3InPlace(m, this.newIdentity3x3());
michael@0 220 },
michael@0 221
michael@0 222 inverseTo3x3InPlace : function(m,n) {
michael@0 223 var a11 = m[10]*m[5]-m[6]*m[9],
michael@0 224 a21 = -m[10]*m[1]+m[2]*m[9],
michael@0 225 a31 = m[6]*m[1]-m[2]*m[5],
michael@0 226 a12 = -m[10]*m[4]+m[6]*m[8],
michael@0 227 a22 = m[10]*m[0]-m[2]*m[8],
michael@0 228 a32 = -m[6]*m[0]+m[2]*m[4],
michael@0 229 a13 = m[9]*m[4]-m[5]*m[8],
michael@0 230 a23 = -m[9]*m[0]+m[1]*m[8],
michael@0 231 a33 = m[5]*m[0]-m[1]*m[4];
michael@0 232 var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13);
michael@0 233 if (det == 0) // no inverse
michael@0 234 return [1,0,0,0,1,0,0,0,1];
michael@0 235 var idet = 1 / det;
michael@0 236 n[0] = idet*a11;
michael@0 237 n[1] = idet*a21;
michael@0 238 n[2] = idet*a31;
michael@0 239 n[3] = idet*a12;
michael@0 240 n[4] = idet*a22;
michael@0 241 n[5] = idet*a32;
michael@0 242 n[6] = idet*a13;
michael@0 243 n[7] = idet*a23;
michael@0 244 n[8] = idet*a33;
michael@0 245 return n;
michael@0 246 },
michael@0 247
michael@0 248 inverse3x3 : function(m) {
michael@0 249 return this.inverse3x3InPlace(m, this.newIdentity3x3());
michael@0 250 },
michael@0 251
michael@0 252 inverse3x3InPlace : function(m,n) {
michael@0 253 var a11 = m[8]*m[4]-m[5]*m[7],
michael@0 254 a21 = -m[8]*m[1]+m[2]*m[7],
michael@0 255 a31 = m[5]*m[1]-m[2]*m[4],
michael@0 256 a12 = -m[8]*m[3]+m[5]*m[6],
michael@0 257 a22 = m[8]*m[0]-m[2]*m[6],
michael@0 258 a32 = -m[5]*m[0]+m[2]*m[3],
michael@0 259 a13 = m[7]*m[4]-m[4]*m[8],
michael@0 260 a23 = -m[7]*m[0]+m[1]*m[6],
michael@0 261 a33 = m[4]*m[0]-m[1]*m[3];
michael@0 262 var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13);
michael@0 263 if (det == 0) // no inverse
michael@0 264 return [1,0,0,0,1,0,0,0,1];
michael@0 265 var idet = 1 / det;
michael@0 266 n[0] = idet*a11;
michael@0 267 n[1] = idet*a21;
michael@0 268 n[2] = idet*a31;
michael@0 269 n[3] = idet*a12;
michael@0 270 n[4] = idet*a22;
michael@0 271 n[5] = idet*a32;
michael@0 272 n[6] = idet*a13;
michael@0 273 n[7] = idet*a23;
michael@0 274 n[8] = idet*a33;
michael@0 275 return n;
michael@0 276 },
michael@0 277
michael@0 278 frustum : function (left, right, bottom, top, znear, zfar) {
michael@0 279 var X = 2*znear/(right-left);
michael@0 280 var Y = 2*znear/(top-bottom);
michael@0 281 var A = (right+left)/(right-left);
michael@0 282 var B = (top+bottom)/(top-bottom);
michael@0 283 var C = -(zfar+znear)/(zfar-znear);
michael@0 284 var D = -2*zfar*znear/(zfar-znear);
michael@0 285
michael@0 286 return [
michael@0 287 X, 0, 0, 0,
michael@0 288 0, Y, 0, 0,
michael@0 289 A, B, C, -1,
michael@0 290 0, 0, D, 0
michael@0 291 ];
michael@0 292 },
michael@0 293
michael@0 294 perspective : function (fovy, aspect, znear, zfar) {
michael@0 295 var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
michael@0 296 var ymin = -ymax;
michael@0 297 var xmin = ymin * aspect;
michael@0 298 var xmax = ymax * aspect;
michael@0 299
michael@0 300 return this.frustum(xmin, xmax, ymin, ymax, znear, zfar);
michael@0 301 },
michael@0 302
michael@0 303 mul4x4 : function (a,b) {
michael@0 304 return this.mul4x4InPlace(a,b,this.newIdentity());
michael@0 305 },
michael@0 306
michael@0 307 mul4x4InPlace : function (a, b, c) {
michael@0 308 c[0] = b[0] * a[0] +
michael@0 309 b[0+1] * a[4] +
michael@0 310 b[0+2] * a[8] +
michael@0 311 b[0+3] * a[12];
michael@0 312 c[0+1] = b[0] * a[1] +
michael@0 313 b[0+1] * a[5] +
michael@0 314 b[0+2] * a[9] +
michael@0 315 b[0+3] * a[13];
michael@0 316 c[0+2] = b[0] * a[2] +
michael@0 317 b[0+1] * a[6] +
michael@0 318 b[0+2] * a[10] +
michael@0 319 b[0+3] * a[14];
michael@0 320 c[0+3] = b[0] * a[3] +
michael@0 321 b[0+1] * a[7] +
michael@0 322 b[0+2] * a[11] +
michael@0 323 b[0+3] * a[15];
michael@0 324 c[4] = b[4] * a[0] +
michael@0 325 b[4+1] * a[4] +
michael@0 326 b[4+2] * a[8] +
michael@0 327 b[4+3] * a[12];
michael@0 328 c[4+1] = b[4] * a[1] +
michael@0 329 b[4+1] * a[5] +
michael@0 330 b[4+2] * a[9] +
michael@0 331 b[4+3] * a[13];
michael@0 332 c[4+2] = b[4] * a[2] +
michael@0 333 b[4+1] * a[6] +
michael@0 334 b[4+2] * a[10] +
michael@0 335 b[4+3] * a[14];
michael@0 336 c[4+3] = b[4] * a[3] +
michael@0 337 b[4+1] * a[7] +
michael@0 338 b[4+2] * a[11] +
michael@0 339 b[4+3] * a[15];
michael@0 340 c[8] = b[8] * a[0] +
michael@0 341 b[8+1] * a[4] +
michael@0 342 b[8+2] * a[8] +
michael@0 343 b[8+3] * a[12];
michael@0 344 c[8+1] = b[8] * a[1] +
michael@0 345 b[8+1] * a[5] +
michael@0 346 b[8+2] * a[9] +
michael@0 347 b[8+3] * a[13];
michael@0 348 c[8+2] = b[8] * a[2] +
michael@0 349 b[8+1] * a[6] +
michael@0 350 b[8+2] * a[10] +
michael@0 351 b[8+3] * a[14];
michael@0 352 c[8+3] = b[8] * a[3] +
michael@0 353 b[8+1] * a[7] +
michael@0 354 b[8+2] * a[11] +
michael@0 355 b[8+3] * a[15];
michael@0 356 c[12] = b[12] * a[0] +
michael@0 357 b[12+1] * a[4] +
michael@0 358 b[12+2] * a[8] +
michael@0 359 b[12+3] * a[12];
michael@0 360 c[12+1] = b[12] * a[1] +
michael@0 361 b[12+1] * a[5] +
michael@0 362 b[12+2] * a[9] +
michael@0 363 b[12+3] * a[13];
michael@0 364 c[12+2] = b[12] * a[2] +
michael@0 365 b[12+1] * a[6] +
michael@0 366 b[12+2] * a[10] +
michael@0 367 b[12+3] * a[14];
michael@0 368 c[12+3] = b[12] * a[3] +
michael@0 369 b[12+1] * a[7] +
michael@0 370 b[12+2] * a[11] +
michael@0 371 b[12+3] * a[15];
michael@0 372 return c;
michael@0 373 },
michael@0 374
michael@0 375 mulv4 : function (a, v) {
michael@0 376 c = new Array(4);
michael@0 377 for (var i=0; i<4; ++i) {
michael@0 378 var x = 0;
michael@0 379 for (var k=0; k<4; ++k)
michael@0 380 x += v[k] * a[k*4+i];
michael@0 381 c[i] = x;
michael@0 382 }
michael@0 383 return c;
michael@0 384 },
michael@0 385
michael@0 386 rotate : function (angle, axis) {
michael@0 387 axis = Vec3.normalize(axis);
michael@0 388 var x=axis[0], y=axis[1], z=axis[2];
michael@0 389 var c = Math.cos(angle);
michael@0 390 var c1 = 1-c;
michael@0 391 var s = Math.sin(angle);
michael@0 392 return [
michael@0 393 x*x*c1+c, y*x*c1+z*s, z*x*c1-y*s, 0,
michael@0 394 x*y*c1-z*s, y*y*c1+c, y*z*c1+x*s, 0,
michael@0 395 x*z*c1+y*s, y*z*c1-x*s, z*z*c1+c, 0,
michael@0 396 0,0,0,1
michael@0 397 ];
michael@0 398 },
michael@0 399 rotateInPlace : function(angle, axis, m) {
michael@0 400 axis = Vec3.normalize(axis);
michael@0 401 var x=axis[0], y=axis[1], z=axis[2];
michael@0 402 var c = Math.cos(angle);
michael@0 403 var c1 = 1-c;
michael@0 404 var s = Math.sin(angle);
michael@0 405 var tmpMatrix = this.tmpMatrix;
michael@0 406 var tmpMatrix2 = this.tmpMatrix2;
michael@0 407 tmpMatrix[0] = x*x*c1+c; tmpMatrix[1] = y*x*c1+z*s; tmpMatrix[2] = z*x*c1-y*s; tmpMatrix[3] = 0;
michael@0 408 tmpMatrix[4] = x*y*c1-z*s; tmpMatrix[5] = y*y*c1+c; tmpMatrix[6] = y*z*c1+x*s; tmpMatrix[7] = 0;
michael@0 409 tmpMatrix[8] = x*z*c1+y*s; tmpMatrix[9] = y*z*c1-x*s; tmpMatrix[10] = z*z*c1+c; tmpMatrix[11] = 0;
michael@0 410 tmpMatrix[12] = 0; tmpMatrix[13] = 0; tmpMatrix[14] = 0; tmpMatrix[15] = 1;
michael@0 411 this.copyMatrix(m, tmpMatrix2);
michael@0 412 return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
michael@0 413 },
michael@0 414
michael@0 415 scale : function(v) {
michael@0 416 return [
michael@0 417 v[0], 0, 0, 0,
michael@0 418 0, v[1], 0, 0,
michael@0 419 0, 0, v[2], 0,
michael@0 420 0, 0, 0, 1
michael@0 421 ];
michael@0 422 },
michael@0 423 scale3 : function(x,y,z) {
michael@0 424 return [
michael@0 425 x, 0, 0, 0,
michael@0 426 0, y, 0, 0,
michael@0 427 0, 0, z, 0,
michael@0 428 0, 0, 0, 1
michael@0 429 ];
michael@0 430 },
michael@0 431 scale1 : function(s) {
michael@0 432 return [
michael@0 433 s, 0, 0, 0,
michael@0 434 0, s, 0, 0,
michael@0 435 0, 0, s, 0,
michael@0 436 0, 0, 0, 1
michael@0 437 ];
michael@0 438 },
michael@0 439 scale3InPlace : function(x, y, z, m) {
michael@0 440 var tmpMatrix = this.tmpMatrix;
michael@0 441 var tmpMatrix2 = this.tmpMatrix2;
michael@0 442 tmpMatrix[0] = x; tmpMatrix[1] = 0; tmpMatrix[2] = 0; tmpMatrix[3] = 0;
michael@0 443 tmpMatrix[4] = 0; tmpMatrix[5] = y; tmpMatrix[6] = 0; tmpMatrix[7] = 0;
michael@0 444 tmpMatrix[8] = 0; tmpMatrix[9] = 0; tmpMatrix[10] = z; tmpMatrix[11] = 0;
michael@0 445 tmpMatrix[12] = 0; tmpMatrix[13] = 0; tmpMatrix[14] = 0; tmpMatrix[15] = 1;
michael@0 446 this.copyMatrix(m, tmpMatrix2);
michael@0 447 return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
michael@0 448 },
michael@0 449 scale1InPlace : function(s, m) { return this.scale3InPlace(s, s, s, m); },
michael@0 450 scaleInPlace : function(s, m) { return this.scale3InPlace(s[0],s[1],s[2],m); },
michael@0 451
michael@0 452 translate3 : function(x,y,z) {
michael@0 453 return [
michael@0 454 1, 0, 0, 0,
michael@0 455 0, 1, 0, 0,
michael@0 456 0, 0, 1, 0,
michael@0 457 x, y, z, 1
michael@0 458 ];
michael@0 459 },
michael@0 460
michael@0 461 translate : function(v) {
michael@0 462 return this.translate3(v[0], v[1], v[2]);
michael@0 463 },
michael@0 464 tmpMatrix : [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0],
michael@0 465 tmpMatrix2 : [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0],
michael@0 466 translate3InPlace : function(x,y,z,m) {
michael@0 467 var tmpMatrix = this.tmpMatrix;
michael@0 468 var tmpMatrix2 = this.tmpMatrix2;
michael@0 469 tmpMatrix[0] = 1; tmpMatrix[1] = 0; tmpMatrix[2] = 0; tmpMatrix[3] = 0;
michael@0 470 tmpMatrix[4] = 0; tmpMatrix[5] = 1; tmpMatrix[6] = 0; tmpMatrix[7] = 0;
michael@0 471 tmpMatrix[8] = 0; tmpMatrix[9] = 0; tmpMatrix[10] = 1; tmpMatrix[11] = 0;
michael@0 472 tmpMatrix[12] = x; tmpMatrix[13] = y; tmpMatrix[14] = z; tmpMatrix[15] = 1;
michael@0 473 this.copyMatrix(m, tmpMatrix2);
michael@0 474 return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
michael@0 475 },
michael@0 476 translateInPlace : function(v,m){ return this.translate3InPlace(v[0], v[1], v[2], m); },
michael@0 477
michael@0 478 lookAt : function (eye, center, up) {
michael@0 479 var z = Vec3.direction(eye, center);
michael@0 480 var x = Vec3.normalizeInPlace(Vec3.cross(up, z));
michael@0 481 var y = Vec3.normalizeInPlace(Vec3.cross(z, x));
michael@0 482
michael@0 483 var m = [
michael@0 484 x[0], y[0], z[0], 0,
michael@0 485 x[1], y[1], z[1], 0,
michael@0 486 x[2], y[2], z[2], 0,
michael@0 487 0, 0, 0, 1
michael@0 488 ];
michael@0 489
michael@0 490 var t = [
michael@0 491 1, 0, 0, 0,
michael@0 492 0, 1, 0, 0,
michael@0 493 0, 0, 1, 0,
michael@0 494 -eye[0], -eye[1], -eye[2], 1
michael@0 495 ];
michael@0 496
michael@0 497 return this.mul4x4(m,t);
michael@0 498 },
michael@0 499
michael@0 500 transpose4x4 : function(m) {
michael@0 501 return [
michael@0 502 m[0], m[4], m[8], m[12],
michael@0 503 m[1], m[5], m[9], m[13],
michael@0 504 m[2], m[6], m[10], m[14],
michael@0 505 m[3], m[7], m[11], m[15]
michael@0 506 ];
michael@0 507 },
michael@0 508
michael@0 509 transpose4x4InPlace : function(m) {
michael@0 510 var tmp = 0.0;
michael@0 511 tmp = m[1]; m[1] = m[4]; m[4] = tmp;
michael@0 512 tmp = m[2]; m[2] = m[8]; m[8] = tmp;
michael@0 513 tmp = m[3]; m[3] = m[12]; m[12] = tmp;
michael@0 514 tmp = m[6]; m[6] = m[9]; m[9] = tmp;
michael@0 515 tmp = m[7]; m[7] = m[13]; m[13] = tmp;
michael@0 516 tmp = m[11]; m[11] = m[14]; m[14] = tmp;
michael@0 517 return m;
michael@0 518 },
michael@0 519
michael@0 520 transpose3x3 : function(m) {
michael@0 521 return [
michael@0 522 m[0], m[3], m[6],
michael@0 523 m[1], m[4], m[7],
michael@0 524 m[2], m[5], m[8]
michael@0 525 ];
michael@0 526 },
michael@0 527
michael@0 528 transpose3x3InPlace : function(m) {
michael@0 529 var tmp = 0.0;
michael@0 530 tmp = m[1]; m[1] = m[3]; m[3] = tmp;
michael@0 531 tmp = m[2]; m[2] = m[6]; m[6] = tmp;
michael@0 532 tmp = m[5]; m[5] = m[7]; m[7] = tmp;
michael@0 533 return m;
michael@0 534 },
michael@0 535 }
michael@0 536
michael@0 537 Vec3 = {
michael@0 538 make : function() { return [0,0,0]; },
michael@0 539 copy : function(v) { return [v[0],v[1],v[2]]; },
michael@0 540
michael@0 541 add : function (u,v) {
michael@0 542 return [u[0]+v[0], u[1]+v[1], u[2]+v[2]];
michael@0 543 },
michael@0 544
michael@0 545 sub : function (u,v) {
michael@0 546 return [u[0]-v[0], u[1]-v[1], u[2]-v[2]];
michael@0 547 },
michael@0 548
michael@0 549 negate : function (u) {
michael@0 550 return [-u[0], -u[1], -u[2]];
michael@0 551 },
michael@0 552
michael@0 553 direction : function (u,v) {
michael@0 554 return this.normalizeInPlace(this.sub(u,v));
michael@0 555 },
michael@0 556
michael@0 557 normalizeInPlace : function(v) {
michael@0 558 var imag = 1.0 / Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
michael@0 559 v[0] *= imag; v[1] *= imag; v[2] *= imag;
michael@0 560 return v;
michael@0 561 },
michael@0 562
michael@0 563 normalize : function(v) {
michael@0 564 return this.normalizeInPlace(this.copy(v));
michael@0 565 },
michael@0 566
michael@0 567 scale : function(f, v) {
michael@0 568 return [f*v[0], f*v[1], f*v[2]];
michael@0 569 },
michael@0 570
michael@0 571 dot : function(u,v) {
michael@0 572 return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
michael@0 573 },
michael@0 574
michael@0 575 inner : function(u,v) {
michael@0 576 return [u[0]*v[0], u[1]*v[1], u[2]*v[2]];
michael@0 577 },
michael@0 578
michael@0 579 cross : function(u,v) {
michael@0 580 return [
michael@0 581 u[1]*v[2] - u[2]*v[1],
michael@0 582 u[2]*v[0] - u[0]*v[2],
michael@0 583 u[0]*v[1] - u[1]*v[0]
michael@0 584 ];
michael@0 585 }
michael@0 586 }
michael@0 587
michael@0 588 Shader = function(gl){
michael@0 589 this.gl = gl;
michael@0 590 this.shaders = [];
michael@0 591 this.uniformLocations = {};
michael@0 592 this.attribLocations = {};
michael@0 593 for (var i=1; i<arguments.length; i++) {
michael@0 594 this.shaders.push(arguments[i]);
michael@0 595 }
michael@0 596 }
michael@0 597 Shader.prototype = {
michael@0 598 id : null,
michael@0 599 gl : null,
michael@0 600 compiled : false,
michael@0 601 shader : null,
michael@0 602 shaders : [],
michael@0 603
michael@0 604 destroy : function() {
michael@0 605 if (this.shader != null) deleteShader(this.gl, this.shader);
michael@0 606 },
michael@0 607
michael@0 608 compile : function() {
michael@0 609 this.shader = loadShaderArray(this.gl, this.shaders);
michael@0 610 },
michael@0 611
michael@0 612 use : function() {
michael@0 613 if (this.shader == null)
michael@0 614 this.compile();
michael@0 615 this.gl.useProgram(this.shader.program);
michael@0 616 },
michael@0 617
michael@0 618 uniform1fv : function(name, value) {
michael@0 619 var loc = this.uniform(name);
michael@0 620 this.gl.uniform1fv(loc, value);
michael@0 621 },
michael@0 622
michael@0 623 uniform2fv : function(name, value) {
michael@0 624 var loc = this.uniform(name);
michael@0 625 this.gl.uniform2fv(loc, value);
michael@0 626 },
michael@0 627
michael@0 628 uniform3fv : function(name, value) {
michael@0 629 var loc = this.uniform(name);
michael@0 630 this.gl.uniform3fv(loc, value);
michael@0 631 },
michael@0 632
michael@0 633 uniform4fv : function(name, value) {
michael@0 634 var loc = this.uniform(name);
michael@0 635 this.gl.uniform4fv(loc, value);
michael@0 636 },
michael@0 637
michael@0 638 uniform1f : function(name, value) {
michael@0 639 var loc = this.uniform(name);
michael@0 640 this.gl.uniform1f(loc, value);
michael@0 641 },
michael@0 642
michael@0 643 uniform2f : function(name, v1,v2) {
michael@0 644 var loc = this.uniform(name);
michael@0 645 this.gl.uniform2f(loc, v1,v2);
michael@0 646 },
michael@0 647
michael@0 648 uniform3f : function(name, v1,v2,v3) {
michael@0 649 var loc = this.uniform(name);
michael@0 650 this.gl.uniform3f(loc, v1,v2,v3);
michael@0 651 },
michael@0 652
michael@0 653 uniform4f : function(name, v1,v2,v3,v4) {
michael@0 654 var loc = this.uniform(name);
michael@0 655 this.gl.uniform4f(loc, v1, v2, v3, v4);
michael@0 656 },
michael@0 657
michael@0 658 uniform1iv : function(name, value) {
michael@0 659 var loc = this.uniform(name);
michael@0 660 this.gl.uniform1iv(loc, value);
michael@0 661 },
michael@0 662
michael@0 663 uniform2iv : function(name, value) {
michael@0 664 var loc = this.uniform(name);
michael@0 665 this.gl.uniform2iv(loc, value);
michael@0 666 },
michael@0 667
michael@0 668 uniform3iv : function(name, value) {
michael@0 669 var loc = this.uniform(name);
michael@0 670 this.gl.uniform3iv(loc, value);
michael@0 671 },
michael@0 672
michael@0 673 uniform4iv : function(name, value) {
michael@0 674 var loc = this.uniform(name);
michael@0 675 this.gl.uniform4iv(loc, value);
michael@0 676 },
michael@0 677
michael@0 678 uniform1i : function(name, value) {
michael@0 679 var loc = this.uniform(name);
michael@0 680 this.gl.uniform1i(loc, value);
michael@0 681 },
michael@0 682
michael@0 683 uniform2i : function(name, v1,v2) {
michael@0 684 var loc = this.uniform(name);
michael@0 685 this.gl.uniform2i(loc, v1,v2);
michael@0 686 },
michael@0 687
michael@0 688 uniform3i : function(name, v1,v2,v3) {
michael@0 689 var loc = this.uniform(name);
michael@0 690 this.gl.uniform3i(loc, v1,v2,v3);
michael@0 691 },
michael@0 692
michael@0 693 uniform4i : function(name, v1,v2,v3,v4) {
michael@0 694 var loc = this.uniform(name);
michael@0 695 this.gl.uniform4i(loc, v1, v2, v3, v4);
michael@0 696 },
michael@0 697
michael@0 698 uniformMatrix4fv : function(name, value) {
michael@0 699 var loc = this.uniform(name);
michael@0 700 this.gl.uniformMatrix4fv(loc, false, value);
michael@0 701 },
michael@0 702
michael@0 703 uniformMatrix3fv : function(name, value) {
michael@0 704 var loc = this.uniform(name);
michael@0 705 this.gl.uniformMatrix3fv(loc, false, value);
michael@0 706 },
michael@0 707
michael@0 708 uniformMatrix2fv : function(name, value) {
michael@0 709 var loc = this.uniform(name);
michael@0 710 this.gl.uniformMatrix2fv(loc, false, value);
michael@0 711 },
michael@0 712
michael@0 713 attrib : function(name) {
michael@0 714 if (this.attribLocations[name] == null) {
michael@0 715 var loc = this.gl.getAttribLocation(this.shader.program, name);
michael@0 716 this.attribLocations[name] = loc;
michael@0 717 }
michael@0 718 return this.attribLocations[name];
michael@0 719 },
michael@0 720
michael@0 721 uniform : function(name) {
michael@0 722 if (this.uniformLocations[name] == null) {
michael@0 723 var loc = this.gl.getUniformLocation(this.shader.program, name);
michael@0 724 this.uniformLocations[name] = loc;
michael@0 725 }
michael@0 726 return this.uniformLocations[name];
michael@0 727 }
michael@0 728 }
michael@0 729 Filter = function(gl, shader) {
michael@0 730 Shader.apply(this, arguments);
michael@0 731 }
michael@0 732 Filter.prototype = new Shader();
michael@0 733 Filter.prototype.apply = function(init) {
michael@0 734 this.use();
michael@0 735 var va = this.attrib("Vertex");
michael@0 736 var ta = this.attrib("Tex");
michael@0 737 var vbo = Quad.getCachedVBO(this.gl);
michael@0 738 if (init) init(this);
michael@0 739 vbo.draw(va, null, ta);
michael@0 740 }
michael@0 741
michael@0 742
michael@0 743 VBO = function(gl) {
michael@0 744 this.gl = gl;
michael@0 745 this.data = [];
michael@0 746 this.elementsVBO = null;
michael@0 747 for (var i=1; i<arguments.length; i++) {
michael@0 748 if (arguments[i].elements)
michael@0 749 this.elements = arguments[i];
michael@0 750 else
michael@0 751 this.data.push(arguments[i]);
michael@0 752 }
michael@0 753 }
michael@0 754
michael@0 755 VBO.prototype = {
michael@0 756 initialized : false,
michael@0 757 length : 0,
michael@0 758 vbos : null,
michael@0 759 type : 'TRIANGLES',
michael@0 760 elementsVBO : null,
michael@0 761 elements : null,
michael@0 762
michael@0 763 setData : function() {
michael@0 764 this.destroy();
michael@0 765 this.data = [];
michael@0 766 for (var i=0; i<arguments.length; i++) {
michael@0 767 if (arguments[i].elements)
michael@0 768 this.elements = arguments[i];
michael@0 769 else
michael@0 770 this.data.push(arguments[i]);
michael@0 771 }
michael@0 772 },
michael@0 773
michael@0 774 destroy : function() {
michael@0 775 if (this.vbos != null)
michael@0 776 for (var i=0; i<this.vbos.length; i++)
michael@0 777 this.gl.deleteBuffer(this.vbos[i]);
michael@0 778 if (this.elementsVBO != null)
michael@0 779 this.gl.deleteBuffer(this.elementsVBO);
michael@0 780 this.length = this.elementsLength = 0;
michael@0 781 this.vbos = this.elementsVBO = null;
michael@0 782 this.initialized = false;
michael@0 783 },
michael@0 784
michael@0 785 init : function() {
michael@0 786 this.destroy();
michael@0 787 var gl = this.gl;
michael@0 788
michael@0 789 gl.getError();
michael@0 790 var vbos = [];
michael@0 791 var length = 0;
michael@0 792 for (var i=0; i<this.data.length; i++)
michael@0 793 vbos.push(gl.createBuffer());
michael@0 794 if (this.elements != null)
michael@0 795 this.elementsVBO = gl.createBuffer();
michael@0 796 try {
michael@0 797 throwError(gl, "genBuffers");
michael@0 798 for (var i = 0; i<this.data.length; i++) {
michael@0 799 var d = this.data[i];
michael@0 800 var dlen = Math.floor(d.data.length / d.size);
michael@0 801 if (i == 0 || dlen < length)
michael@0 802 length = dlen;
michael@0 803 if (!d.floatArray)
michael@0 804 d.floatArray = new Float32Array(d.data);
michael@0 805 gl.bindBuffer(gl.ARRAY_BUFFER, vbos[i]);
michael@0 806 throwError(gl, "bindBuffer");
michael@0 807 gl.bufferData(gl.ARRAY_BUFFER, d.floatArray, gl.STATIC_DRAW);
michael@0 808 throwError(gl, "bufferData");
michael@0 809 }
michael@0 810 if (this.elementsVBO != null) {
michael@0 811 var d = this.elements;
michael@0 812 this.elementsLength = d.data.length;
michael@0 813 this.elementsType = d.type == gl.UNSIGNED_BYTE ? d.type : gl.UNSIGNED_SHORT;
michael@0 814 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementsVBO);
michael@0 815 throwError(gl, "bindBuffer ELEMENT_ARRAY_BUFFER");
michael@0 816 if (this.elementsType == gl.UNSIGNED_SHORT && !d.ushortArray) {
michael@0 817 d.ushortArray = new Uint16Array(d.data);
michael@0 818 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, d.ushortArray, gl.STATIC_DRAW);
michael@0 819 } else if (this.elementsType == gl.UNSIGNED_BYTE && !d.ubyteArray) {
michael@0 820 d.ubyteArray = new Uint8Array(d.data);
michael@0 821 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, d.ubyteArray, gl.STATIC_DRAW);
michael@0 822 }
michael@0 823 throwError(gl, "bufferData ELEMENT_ARRAY_BUFFER");
michael@0 824 }
michael@0 825 } catch(e) {
michael@0 826 for (var i=0; i<vbos.length; i++)
michael@0 827 gl.deleteBuffer(vbos[i]);
michael@0 828 throw(e);
michael@0 829 }
michael@0 830
michael@0 831 gl.bindBuffer(gl.ARRAY_BUFFER, null);
michael@0 832 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
michael@0 833
michael@0 834 this.length = length;
michael@0 835 this.vbos = vbos;
michael@0 836
michael@0 837 this.initialized = true;
michael@0 838 },
michael@0 839
michael@0 840 use : function() {
michael@0 841 if (!this.initialized) this.init();
michael@0 842 var gl = this.gl;
michael@0 843 for (var i=0; i<arguments.length; i++) {
michael@0 844 if (arguments[i] == null) continue;
michael@0 845 gl.bindBuffer(gl.ARRAY_BUFFER, this.vbos[i]);
michael@0 846 gl.vertexAttribPointer(arguments[i], this.data[i].size, gl.FLOAT, false, 0, 0);
michael@0 847 gl.enableVertexAttribArray(arguments[i]);
michael@0 848 }
michael@0 849 if (this.elementsVBO != null) {
michael@0 850 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementsVBO);
michael@0 851 }
michael@0 852 },
michael@0 853
michael@0 854 draw : function() {
michael@0 855 var args = [];
michael@0 856 this.use.apply(this, arguments);
michael@0 857 var gl = this.gl;
michael@0 858 if (this.elementsVBO != null) {
michael@0 859 gl.drawElements(gl[this.type], this.elementsLength, this.elementsType, 0);
michael@0 860 } else {
michael@0 861 gl.drawArrays(gl[this.type], 0, this.length);
michael@0 862 }
michael@0 863 }
michael@0 864 }
michael@0 865
michael@0 866 FBO = function(gl, width, height, use_depth) {
michael@0 867 this.gl = gl;
michael@0 868 this.width = width;
michael@0 869 this.height = height;
michael@0 870 if (use_depth != null)
michael@0 871 this.useDepth = use_depth;
michael@0 872 }
michael@0 873 FBO.prototype = {
michael@0 874 initialized : false,
michael@0 875 useDepth : true,
michael@0 876 fbo : null,
michael@0 877 rbo : null,
michael@0 878 texture : null,
michael@0 879
michael@0 880 destroy : function() {
michael@0 881 if (this.fbo) this.gl.deleteFramebuffer(this.fbo);
michael@0 882 if (this.rbo) this.gl.deleteRenderbuffer(this.rbo);
michael@0 883 if (this.texture) this.gl.deleteTexture(this.texture);
michael@0 884 },
michael@0 885
michael@0 886 init : function() {
michael@0 887 var gl = this.gl;
michael@0 888 var w = this.width, h = this.height;
michael@0 889 var fbo = this.fbo != null ? this.fbo : gl.createFramebuffer();
michael@0 890 var rb;
michael@0 891
michael@0 892 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
michael@0 893 checkError(gl, "FBO.init bindFramebuffer");
michael@0 894 if (this.useDepth) {
michael@0 895 rb = this.rbo != null ? this.rbo : gl.createRenderbuffer();
michael@0 896 gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
michael@0 897 checkError(gl, "FBO.init bindRenderbuffer");
michael@0 898 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
michael@0 899 checkError(gl, "FBO.init renderbufferStorage");
michael@0 900 }
michael@0 901
michael@0 902 var tex = this.texture != null ? this.texture : gl.createTexture();
michael@0 903 gl.bindTexture(gl.TEXTURE_2D, tex);
michael@0 904 try {
michael@0 905 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
michael@0 906 } catch (e) { // argh, no null texture support
michael@0 907 var tmp = this.getTempCanvas(w,h);
michael@0 908 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tmp);
michael@0 909 }
michael@0 910 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
michael@0 911 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
michael@0 912 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
michael@0 913 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
michael@0 914 checkError(gl, "FBO.init tex");
michael@0 915
michael@0 916 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
michael@0 917 checkError(gl, "FBO.init bind tex");
michael@0 918
michael@0 919 if (this.useDepth) {
michael@0 920 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb);
michael@0 921 checkError(gl, "FBO.init bind depth buffer");
michael@0 922 }
michael@0 923
michael@0 924 var fbstat = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
michael@0 925 if (fbstat != gl.FRAMEBUFFER_COMPLETE) {
michael@0 926 var glv;
michael@0 927 for (var v in gl) {
michael@0 928 try { glv = gl[v]; } catch (e) { glv = null; }
michael@0 929 if (glv == fbstat) { fbstat = v; break; }}
michael@0 930 log("Framebuffer status: " + fbstat);
michael@0 931 }
michael@0 932 checkError(gl, "FBO.init check fbo");
michael@0 933
michael@0 934 this.fbo = fbo;
michael@0 935 this.rbo = rb;
michael@0 936 this.texture = tex;
michael@0 937 this.initialized = true;
michael@0 938 },
michael@0 939
michael@0 940 getTempCanvas : function(w, h) {
michael@0 941 if (!FBO.tempCanvas) {
michael@0 942 FBO.tempCanvas = document.createElement('canvas');
michael@0 943 }
michael@0 944 FBO.tempCanvas.width = w;
michael@0 945 FBO.tempCanvas.height = h;
michael@0 946 return FBO.tempCanvas;
michael@0 947 },
michael@0 948
michael@0 949 use : function() {
michael@0 950 if (!this.initialized) this.init();
michael@0 951 this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo);
michael@0 952 }
michael@0 953 }
michael@0 954
michael@0 955 function GLError(err, msg, fileName, lineNumber) {
michael@0 956 this.message = msg;
michael@0 957 this.glError = err;
michael@0 958 }
michael@0 959
michael@0 960 GLError.prototype = new Error();
michael@0 961
michael@0 962 function makeGLErrorWrapper(gl, fname) {
michael@0 963 return (function() {
michael@0 964 try {
michael@0 965 var rv = gl[fname].apply(gl, arguments);
michael@0 966 var err = gl.getError();
michael@0 967 if (err != gl.NO_ERROR) {
michael@0 968 throw(new GLError(
michael@0 969 err, "GL error "+getGLErrorAsString(gl, err)+" in "+fname));
michael@0 970 }
michael@0 971 return rv;
michael@0 972 } catch (e) {
michael@0 973 if (e.glError !== undefined) {
michael@0 974 throw e;
michael@0 975 }
michael@0 976 throw(new Error("Threw " + e.name +
michael@0 977 " in " + fname + "\n" +
michael@0 978 e.message + "\n" +
michael@0 979 arguments.callee.caller));
michael@0 980 }
michael@0 981 });
michael@0 982 }
michael@0 983
michael@0 984 function wrapGLContext(gl) {
michael@0 985 var wrap = {};
michael@0 986 for (var i in gl) {
michael@0 987 try {
michael@0 988 if (typeof gl[i] == 'function') {
michael@0 989 wrap[i] = makeGLErrorWrapper(gl, i);
michael@0 990 } else {
michael@0 991 wrap[i] = gl[i];
michael@0 992 }
michael@0 993 } catch (e) {
michael@0 994 // log("wrapGLContext: Error accessing " + i);
michael@0 995 }
michael@0 996 }
michael@0 997 wrap.getError = function(){ return gl.getError(); };
michael@0 998 return wrap;
michael@0 999 }
michael@0 1000
michael@0 1001 // Assert that f generates a specific GL error.
michael@0 1002 function assertGLError(gl, err, name, f) {
michael@0 1003 if (f == null) { f = name; name = null; }
michael@0 1004 var r = false;
michael@0 1005 var glErr = 0;
michael@0 1006 try { f(); } catch(e) { r=true; glErr = e.glError; }
michael@0 1007 if (glErr !== err) {
michael@0 1008 if (glErr === undefined) {
michael@0 1009 testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
michael@0 1010 } else {
michael@0 1011 testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
michael@0 1012 " actual: " + getGLErrorAsString(gl, glErr), name, f);
michael@0 1013 }
michael@0 1014 return false;
michael@0 1015 }
michael@0 1016 return true;
michael@0 1017 }
michael@0 1018
michael@0 1019 // Assert that f generates some GL error. Used in situations where it's
michael@0 1020 // ambigious which of multiple possible errors will be generated.
michael@0 1021 function assertSomeGLError(gl, name, f) {
michael@0 1022 if (f == null) { f = name; name = null; }
michael@0 1023 var r = false;
michael@0 1024 var glErr = 0;
michael@0 1025 var err = 0;
michael@0 1026 try { f(); } catch(e) { r=true; glErr = e.glError; }
michael@0 1027 if (glErr === 0) {
michael@0 1028 if (glErr === undefined) {
michael@0 1029 testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
michael@0 1030 } else {
michael@0 1031 testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
michael@0 1032 " actual: " + getGLErrorAsString(gl, glErr), name, f);
michael@0 1033 }
michael@0 1034 return false;
michael@0 1035 }
michael@0 1036 return true;
michael@0 1037 }
michael@0 1038
michael@0 1039 // Assert that f throws an exception but does not generate a GL error.
michael@0 1040 function assertThrowNoGLError(gl, name, f) {
michael@0 1041 if (f == null) { f = name; name = null; }
michael@0 1042 var r = false;
michael@0 1043 var glErr = undefined;
michael@0 1044 var exp;
michael@0 1045 try { f(); } catch(e) { r=true; glErr = e.glError; exp = e;}
michael@0 1046 if (!r) {
michael@0 1047 testFailed(
michael@0 1048 "assertThrowNoGLError: should have thrown exception", name, f);
michael@0 1049 return false;
michael@0 1050 } else {
michael@0 1051 if (glErr !== undefined) {
michael@0 1052 testFailed(
michael@0 1053 "assertThrowNoGLError: should be no GL error but generated: " +
michael@0 1054 getGLErrorAsString(gl, glErr), name, f);
michael@0 1055 return false;
michael@0 1056 }
michael@0 1057 }
michael@0 1058 testPassed("assertThrowNoGLError", name, f);
michael@0 1059 return true;
michael@0 1060 }
michael@0 1061
michael@0 1062 Quad = {
michael@0 1063 vertices : [
michael@0 1064 -1,-1,0,
michael@0 1065 1,-1,0,
michael@0 1066 -1,1,0,
michael@0 1067 1,-1,0,
michael@0 1068 1,1,0,
michael@0 1069 -1,1,0
michael@0 1070 ],
michael@0 1071 normals : [
michael@0 1072 0,0,-1,
michael@0 1073 0,0,-1,
michael@0 1074 0,0,-1,
michael@0 1075 0,0,-1,
michael@0 1076 0,0,-1,
michael@0 1077 0,0,-1
michael@0 1078 ],
michael@0 1079 texcoords : [
michael@0 1080 0,0,
michael@0 1081 1,0,
michael@0 1082 0,1,
michael@0 1083 1,0,
michael@0 1084 1,1,
michael@0 1085 0,1
michael@0 1086 ],
michael@0 1087 indices : [0,1,2,1,5,2],
michael@0 1088 makeVBO : function(gl) {
michael@0 1089 return new VBO(gl,
michael@0 1090 {size:3, data: Quad.vertices},
michael@0 1091 {size:3, data: Quad.normals},
michael@0 1092 {size:2, data: Quad.texcoords}
michael@0 1093 )
michael@0 1094 },
michael@0 1095 cache: {},
michael@0 1096 getCachedVBO : function(gl) {
michael@0 1097 if (!this.cache[gl])
michael@0 1098 this.cache[gl] = this.makeVBO(gl);
michael@0 1099 return this.cache[gl];
michael@0 1100 }
michael@0 1101 }
michael@0 1102 Cube = {
michael@0 1103 vertices : [ 0.5, -0.5, 0.5, // +X
michael@0 1104 0.5, -0.5, -0.5,
michael@0 1105 0.5, 0.5, -0.5,
michael@0 1106 0.5, 0.5, 0.5,
michael@0 1107
michael@0 1108 0.5, 0.5, 0.5, // +Y
michael@0 1109 0.5, 0.5, -0.5,
michael@0 1110 -0.5, 0.5, -0.5,
michael@0 1111 -0.5, 0.5, 0.5,
michael@0 1112
michael@0 1113 0.5, 0.5, 0.5, // +Z
michael@0 1114 -0.5, 0.5, 0.5,
michael@0 1115 -0.5, -0.5, 0.5,
michael@0 1116 0.5, -0.5, 0.5,
michael@0 1117
michael@0 1118 -0.5, -0.5, 0.5, // -X
michael@0 1119 -0.5, 0.5, 0.5,
michael@0 1120 -0.5, 0.5, -0.5,
michael@0 1121 -0.5, -0.5, -0.5,
michael@0 1122
michael@0 1123 -0.5, -0.5, 0.5, // -Y
michael@0 1124 -0.5, -0.5, -0.5,
michael@0 1125 0.5, -0.5, -0.5,
michael@0 1126 0.5, -0.5, 0.5,
michael@0 1127
michael@0 1128 -0.5, -0.5, -0.5, // -Z
michael@0 1129 -0.5, 0.5, -0.5,
michael@0 1130 0.5, 0.5, -0.5,
michael@0 1131 0.5, -0.5, -0.5,
michael@0 1132 ],
michael@0 1133
michael@0 1134 normals : [ 1, 0, 0,
michael@0 1135 1, 0, 0,
michael@0 1136 1, 0, 0,
michael@0 1137 1, 0, 0,
michael@0 1138
michael@0 1139 0, 1, 0,
michael@0 1140 0, 1, 0,
michael@0 1141 0, 1, 0,
michael@0 1142 0, 1, 0,
michael@0 1143
michael@0 1144 0, 0, 1,
michael@0 1145 0, 0, 1,
michael@0 1146 0, 0, 1,
michael@0 1147 0, 0, 1,
michael@0 1148
michael@0 1149 -1, 0, 0,
michael@0 1150 -1, 0, 0,
michael@0 1151 -1, 0, 0,
michael@0 1152 -1, 0, 0,
michael@0 1153
michael@0 1154 0,-1, 0,
michael@0 1155 0,-1, 0,
michael@0 1156 0,-1, 0,
michael@0 1157 0,-1, 0,
michael@0 1158
michael@0 1159 0, 0,-1,
michael@0 1160 0, 0,-1,
michael@0 1161 0, 0,-1,
michael@0 1162 0, 0,-1
michael@0 1163 ],
michael@0 1164
michael@0 1165 indices : [],
michael@0 1166 create : function(){
michael@0 1167 for (var i = 0; i < 6; i++) {
michael@0 1168 Cube.indices.push(i*4 + 0);
michael@0 1169 Cube.indices.push(i*4 + 1);
michael@0 1170 Cube.indices.push(i*4 + 3);
michael@0 1171 Cube.indices.push(i*4 + 1);
michael@0 1172 Cube.indices.push(i*4 + 2);
michael@0 1173 Cube.indices.push(i*4 + 3);
michael@0 1174 }
michael@0 1175 },
michael@0 1176
michael@0 1177 makeVBO : function(gl) {
michael@0 1178 return new VBO(gl,
michael@0 1179 {size:3, data: Cube.vertices},
michael@0 1180 {size:3, data: Cube.normals},
michael@0 1181 {elements: true, data: Cube.indices}
michael@0 1182 )
michael@0 1183 },
michael@0 1184 cache : {},
michael@0 1185 getCachedVBO : function(gl) {
michael@0 1186 if (!this.cache[gl])
michael@0 1187 this.cache[gl] = this.makeVBO(gl);
michael@0 1188 return this.cache[gl];
michael@0 1189 }
michael@0 1190 }
michael@0 1191 Cube.create();
michael@0 1192
michael@0 1193 Sphere = {
michael@0 1194 vertices : [],
michael@0 1195 normals : [],
michael@0 1196 indices : [],
michael@0 1197 create : function(){
michael@0 1198 var r = 0.75;
michael@0 1199 function vert(theta, phi)
michael@0 1200 {
michael@0 1201 var r = 0.75;
michael@0 1202 var x, y, z, nx, ny, nz;
michael@0 1203
michael@0 1204 nx = Math.sin(theta) * Math.cos(phi);
michael@0 1205 ny = Math.sin(phi);
michael@0 1206 nz = Math.cos(theta) * Math.cos(phi);
michael@0 1207 Sphere.normals.push(nx);
michael@0 1208 Sphere.normals.push(ny);
michael@0 1209 Sphere.normals.push(nz);
michael@0 1210
michael@0 1211 x = r * Math.sin(theta) * Math.cos(phi);
michael@0 1212 y = r * Math.sin(phi);
michael@0 1213 z = r * Math.cos(theta) * Math.cos(phi);
michael@0 1214 Sphere.vertices.push(x);
michael@0 1215 Sphere.vertices.push(y);
michael@0 1216 Sphere.vertices.push(z);
michael@0 1217 }
michael@0 1218 for (var phi = -Math.PI/2; phi < Math.PI/2; phi += Math.PI/20) {
michael@0 1219 var phi2 = phi + Math.PI/20;
michael@0 1220 for (var theta = -Math.PI/2; theta <= Math.PI/2; theta += Math.PI/20) {
michael@0 1221 vert(theta, phi);
michael@0 1222 vert(theta, phi2);
michael@0 1223 }
michael@0 1224 }
michael@0 1225 }
michael@0 1226 }
michael@0 1227
michael@0 1228 Sphere.create();
michael@0 1229
michael@0 1230 initGL_CONTEXT_ID = function(){
michael@0 1231 var c = document.createElement('canvas');
michael@0 1232 var contextNames = ['webgl', 'experimental-webgl'];
michael@0 1233 GL_CONTEXT_ID = null;
michael@0 1234 for (var i=0; i<contextNames.length; i++) {
michael@0 1235 try {
michael@0 1236 if (c.getContext(contextNames[i])) {
michael@0 1237 GL_CONTEXT_ID = contextNames[i];
michael@0 1238 break;
michael@0 1239 }
michael@0 1240 } catch (e) {
michael@0 1241 }
michael@0 1242 }
michael@0 1243 if (!GL_CONTEXT_ID) {
michael@0 1244 log("No WebGL context found. Unable to run tests.");
michael@0 1245 }
michael@0 1246 }
michael@0 1247
michael@0 1248 initGL_CONTEXT_ID();

mercurial