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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/canvas/test/webgl-conformance/conformance/more/util.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1248 @@
     1.4 +/*
     1.5 +Utilities for the OpenGL ES 2.0 HTML Canvas context
     1.6 +
     1.7 +Copyright (C) 2011  Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
     1.8 +
     1.9 +Permission is hereby granted, free of charge, to any person
    1.10 +obtaining a copy of this software and associated documentation
    1.11 +files (the "Software"), to deal in the Software without
    1.12 +restriction, including without limitation the rights to use,
    1.13 +copy, modify, merge, publish, distribute, sublicense, and/or sell
    1.14 +copies of the Software, and to permit persons to whom the
    1.15 +Software is furnished to do so, subject to the following
    1.16 +conditions:
    1.17 +
    1.18 +The above copyright notice and this permission notice shall be
    1.19 +included in all copies or substantial portions of the Software.
    1.20 +
    1.21 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.22 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    1.23 +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    1.24 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    1.25 +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    1.26 +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    1.27 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    1.28 +OTHER DEALINGS IN THE SOFTWARE.
    1.29 +*/
    1.30 +
    1.31 +function loadTexture(gl, elem, mipmaps) {
    1.32 +  var tex = gl.createTexture();
    1.33 +  gl.bindTexture(gl.TEXTURE_2D, tex);
    1.34 +  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, elem);
    1.35 +  if (mipmaps != false)
    1.36 +    gl.generateMipmap(gl.TEXTURE_2D);
    1.37 +  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    1.38 +  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    1.39 +  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    1.40 +  if (mipmaps)
    1.41 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    1.42 +  else
    1.43 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    1.44 +  return tex;
    1.45 +}
    1.46 +
    1.47 +function getShader(gl, id) {
    1.48 +  var shaderScript = document.getElementById(id);
    1.49 +  if (!shaderScript) {
    1.50 +    throw(new Error("No shader element with id: "+id));
    1.51 +  }
    1.52 +
    1.53 +  var str = "";
    1.54 +  var k = shaderScript.firstChild;
    1.55 +  while (k) {
    1.56 +    if (k.nodeType == 3)
    1.57 +      str += k.textContent;
    1.58 +    k = k.nextSibling;
    1.59 +  }
    1.60 +
    1.61 +  var shader;
    1.62 +  if (shaderScript.type == "x-shader/x-fragment") {
    1.63 +    shader = gl.createShader(gl.FRAGMENT_SHADER);
    1.64 +  } else if (shaderScript.type == "x-shader/x-vertex") {
    1.65 +    shader = gl.createShader(gl.VERTEX_SHADER);
    1.66 +  } else {
    1.67 +    throw(new Error("Unknown shader type "+shaderScript.type));
    1.68 +  }
    1.69 +
    1.70 +  gl.shaderSource(shader, str);
    1.71 +  gl.compileShader(shader);
    1.72 +
    1.73 +  if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) != 1) {
    1.74 +    var ilog = gl.getShaderInfoLog(shader);
    1.75 +    gl.deleteShader(shader);
    1.76 +    throw(new Error("Failed to compile shader "+shaderScript.id + ", Shader info log: " + ilog));
    1.77 +  }
    1.78 +  return shader;
    1.79 +}
    1.80 +
    1.81 +function loadShaderArray(gl, shaders) {
    1.82 +  var id = gl.createProgram();
    1.83 +  var shaderObjs = [];
    1.84 +  for (var i=0; i<shaders.length; ++i) {
    1.85 +    try {
    1.86 +      var sh = getShader(gl, shaders[i]);
    1.87 +      shaderObjs.push(sh);
    1.88 +      gl.attachShader(id, sh);
    1.89 +    } catch (e) {
    1.90 +      var pr = {program: id, shaders: shaderObjs};
    1.91 +      deleteShader(gl, pr);
    1.92 +      throw (e);
    1.93 +    }
    1.94 +  }
    1.95 +  var prog = {program: id, shaders: shaderObjs};
    1.96 +  gl.linkProgram(id);
    1.97 +  gl.validateProgram(id);
    1.98 +  if (gl.getProgramParameter(id, gl.LINK_STATUS) != 1) {
    1.99 +    deleteShader(gl,prog);
   1.100 +    throw(new Error("Failed to link shader"));
   1.101 +  }
   1.102 +  if (gl.getProgramParameter(id, gl.VALIDATE_STATUS) != 1) {
   1.103 +    deleteShader(gl,prog);
   1.104 +    throw(new Error("Failed to validate shader"));
   1.105 +  }
   1.106 +  return prog;
   1.107 +}
   1.108 +function loadShader(gl) {
   1.109 +  var sh = [];
   1.110 +  for (var i=1; i<arguments.length; ++i)
   1.111 +    sh.push(arguments[i]);
   1.112 +  return loadShaderArray(gl, sh);
   1.113 +}
   1.114 +
   1.115 +function deleteShader(gl, sh) {
   1.116 +  gl.useProgram(null);
   1.117 +  sh.shaders.forEach(function(s){
   1.118 +    gl.detachShader(sh.program, s);
   1.119 +    gl.deleteShader(s);
   1.120 +  });
   1.121 +  gl.deleteProgram(sh.program);
   1.122 +}
   1.123 +
   1.124 +function getGLErrorAsString(ctx, err) {
   1.125 +  if (err === ctx.NO_ERROR) {
   1.126 +    return "NO_ERROR";
   1.127 +  }
   1.128 +  for (var name in ctx) {
   1.129 +    if (ctx[name] === err) {
   1.130 +      return name;
   1.131 +    }
   1.132 +  }
   1.133 +  return err.toString();
   1.134 +}
   1.135 +
   1.136 +function checkError(gl, msg) {
   1.137 +  var e = gl.getError();
   1.138 +  if (e != gl.NO_ERROR) {
   1.139 +    log("Error " + getGLErrorAsString(gl, e) + " at " + msg);
   1.140 +  }
   1.141 +  return e;
   1.142 +}
   1.143 +
   1.144 +function throwError(gl, msg) {
   1.145 +  var e = gl.getError();
   1.146 +  if (e != 0) {
   1.147 +    throw(new Error("Error " + getGLErrorAsString(gl, e) + " at " + msg));
   1.148 +  }
   1.149 +}
   1.150 +
   1.151 +Math.cot = function(z) { return 1.0 / Math.tan(z); }
   1.152 +
   1.153 +/*
   1.154 +  Matrix utilities, using the OpenGL element order where
   1.155 +  the last 4 elements are the translation column.
   1.156 +
   1.157 +  Uses flat arrays as matrices for performance.
   1.158 +
   1.159 +  Most operations have in-place variants to avoid allocating temporary matrices.
   1.160 +
   1.161 +  Naming logic:
   1.162 +    Matrix.method operates on a 4x4 Matrix and returns a new Matrix.
   1.163 +    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)))
   1.164 +    Matrix.method[3x3]InPlace(args, target) stores its result in the target matrix.
   1.165 +
   1.166 +    Matrix.scale([sx, sy, sz]) -- non-uniform scale by vector
   1.167 +    Matrix.scale1(s)           -- uniform scale by scalar
   1.168 +    Matrix.scale3(sx, sy, sz)  -- non-uniform scale by scalars
   1.169 +
   1.170 +    Ditto for translate.
   1.171 +*/
   1.172 +Matrix = {
   1.173 +  identity : [
   1.174 +    1.0, 0.0, 0.0, 0.0,
   1.175 +    0.0, 1.0, 0.0, 0.0,
   1.176 +    0.0, 0.0, 1.0, 0.0,
   1.177 +    0.0, 0.0, 0.0, 1.0
   1.178 +  ],
   1.179 +
   1.180 +  newIdentity : function() {
   1.181 +    return [
   1.182 +      1.0, 0.0, 0.0, 0.0,
   1.183 +      0.0, 1.0, 0.0, 0.0,
   1.184 +      0.0, 0.0, 1.0, 0.0,
   1.185 +      0.0, 0.0, 0.0, 1.0
   1.186 +    ];
   1.187 +  },
   1.188 +
   1.189 +  newIdentity3x3 : function() {
   1.190 +    return [
   1.191 +      1.0, 0.0, 0.0,
   1.192 +      0.0, 1.0, 0.0,
   1.193 +      0.0, 0.0, 1.0
   1.194 +    ];
   1.195 +  },
   1.196 +
   1.197 +  copyMatrix : function(src, dst) {
   1.198 +    for (var i=0; i<16; i++) dst[i] = src[i];
   1.199 +    return dst;
   1.200 +  },
   1.201 +
   1.202 +  to3x3 : function(m) {
   1.203 +    return [
   1.204 +      m[0], m[1], m[2],
   1.205 +      m[4], m[5], m[6],
   1.206 +      m[8], m[9], m[10]
   1.207 +    ];
   1.208 +  },
   1.209 +
   1.210 +  // orthonormal matrix inverse
   1.211 +  inverseON : function(m) {
   1.212 +    var n = this.transpose4x4(m);
   1.213 +    var t = [m[12], m[13], m[14]];
   1.214 +    n[3] = n[7] = n[11] = 0;
   1.215 +    n[12] = -Vec3.dot([n[0], n[4], n[8]], t);
   1.216 +    n[13] = -Vec3.dot([n[1], n[5], n[9]], t);
   1.217 +    n[14] = -Vec3.dot([n[2], n[6], n[10]], t);
   1.218 +    return n;
   1.219 +  },
   1.220 +
   1.221 +  inverseTo3x3 : function(m) {
   1.222 +    return this.inverse4x4to3x3InPlace(m, this.newIdentity3x3());
   1.223 +  },
   1.224 +
   1.225 +  inverseTo3x3InPlace : function(m,n) {
   1.226 +    var a11 = m[10]*m[5]-m[6]*m[9],
   1.227 +        a21 = -m[10]*m[1]+m[2]*m[9],
   1.228 +        a31 = m[6]*m[1]-m[2]*m[5],
   1.229 +        a12 = -m[10]*m[4]+m[6]*m[8],
   1.230 +        a22 = m[10]*m[0]-m[2]*m[8],
   1.231 +        a32 = -m[6]*m[0]+m[2]*m[4],
   1.232 +        a13 = m[9]*m[4]-m[5]*m[8],
   1.233 +        a23 = -m[9]*m[0]+m[1]*m[8],
   1.234 +        a33 = m[5]*m[0]-m[1]*m[4];
   1.235 +    var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13);
   1.236 +    if (det == 0) // no inverse
   1.237 +      return [1,0,0,0,1,0,0,0,1];
   1.238 +    var idet = 1 / det;
   1.239 +    n[0] = idet*a11;
   1.240 +    n[1] = idet*a21;
   1.241 +    n[2] = idet*a31;
   1.242 +    n[3] = idet*a12;
   1.243 +    n[4] = idet*a22;
   1.244 +    n[5] = idet*a32;
   1.245 +    n[6] = idet*a13;
   1.246 +    n[7] = idet*a23;
   1.247 +    n[8] = idet*a33;
   1.248 +    return n;
   1.249 +  },
   1.250 +
   1.251 +  inverse3x3 : function(m) {
   1.252 +    return this.inverse3x3InPlace(m, this.newIdentity3x3());
   1.253 +  },
   1.254 +
   1.255 +  inverse3x3InPlace : function(m,n) {
   1.256 +    var a11 = m[8]*m[4]-m[5]*m[7],
   1.257 +        a21 = -m[8]*m[1]+m[2]*m[7],
   1.258 +        a31 = m[5]*m[1]-m[2]*m[4],
   1.259 +        a12 = -m[8]*m[3]+m[5]*m[6],
   1.260 +        a22 = m[8]*m[0]-m[2]*m[6],
   1.261 +        a32 = -m[5]*m[0]+m[2]*m[3],
   1.262 +        a13 = m[7]*m[4]-m[4]*m[8],
   1.263 +        a23 = -m[7]*m[0]+m[1]*m[6],
   1.264 +        a33 = m[4]*m[0]-m[1]*m[3];
   1.265 +    var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13);
   1.266 +    if (det == 0) // no inverse
   1.267 +      return [1,0,0,0,1,0,0,0,1];
   1.268 +    var idet = 1 / det;
   1.269 +    n[0] = idet*a11;
   1.270 +    n[1] = idet*a21;
   1.271 +    n[2] = idet*a31;
   1.272 +    n[3] = idet*a12;
   1.273 +    n[4] = idet*a22;
   1.274 +    n[5] = idet*a32;
   1.275 +    n[6] = idet*a13;
   1.276 +    n[7] = idet*a23;
   1.277 +    n[8] = idet*a33;
   1.278 +    return n;
   1.279 +  },
   1.280 +
   1.281 +  frustum : function (left, right, bottom, top, znear, zfar) {
   1.282 +    var X = 2*znear/(right-left);
   1.283 +    var Y = 2*znear/(top-bottom);
   1.284 +    var A = (right+left)/(right-left);
   1.285 +    var B = (top+bottom)/(top-bottom);
   1.286 +    var C = -(zfar+znear)/(zfar-znear);
   1.287 +    var D = -2*zfar*znear/(zfar-znear);
   1.288 +
   1.289 +    return [
   1.290 +      X, 0, 0, 0,
   1.291 +      0, Y, 0, 0,
   1.292 +      A, B, C, -1,
   1.293 +      0, 0, D, 0
   1.294 +    ];
   1.295 + },
   1.296 +
   1.297 +  perspective : function (fovy, aspect, znear, zfar) {
   1.298 +    var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
   1.299 +    var ymin = -ymax;
   1.300 +    var xmin = ymin * aspect;
   1.301 +    var xmax = ymax * aspect;
   1.302 +
   1.303 +    return this.frustum(xmin, xmax, ymin, ymax, znear, zfar);
   1.304 +  },
   1.305 +
   1.306 +  mul4x4 : function (a,b) {
   1.307 +    return this.mul4x4InPlace(a,b,this.newIdentity());
   1.308 +  },
   1.309 +
   1.310 +  mul4x4InPlace : function (a, b, c) {
   1.311 +        c[0] =   b[0] * a[0] +
   1.312 +                 b[0+1] * a[4] +
   1.313 +                 b[0+2] * a[8] +
   1.314 +                 b[0+3] * a[12];
   1.315 +        c[0+1] = b[0] * a[1] +
   1.316 +                 b[0+1] * a[5] +
   1.317 +                 b[0+2] * a[9] +
   1.318 +                 b[0+3] * a[13];
   1.319 +        c[0+2] = b[0] * a[2] +
   1.320 +                 b[0+1] * a[6] +
   1.321 +                 b[0+2] * a[10] +
   1.322 +                 b[0+3] * a[14];
   1.323 +        c[0+3] = b[0] * a[3] +
   1.324 +                 b[0+1] * a[7] +
   1.325 +                 b[0+2] * a[11] +
   1.326 +                 b[0+3] * a[15];
   1.327 +        c[4] =   b[4] * a[0] +
   1.328 +                 b[4+1] * a[4] +
   1.329 +                 b[4+2] * a[8] +
   1.330 +                 b[4+3] * a[12];
   1.331 +        c[4+1] = b[4] * a[1] +
   1.332 +                 b[4+1] * a[5] +
   1.333 +                 b[4+2] * a[9] +
   1.334 +                 b[4+3] * a[13];
   1.335 +        c[4+2] = b[4] * a[2] +
   1.336 +                 b[4+1] * a[6] +
   1.337 +                 b[4+2] * a[10] +
   1.338 +                 b[4+3] * a[14];
   1.339 +        c[4+3] = b[4] * a[3] +
   1.340 +                 b[4+1] * a[7] +
   1.341 +                 b[4+2] * a[11] +
   1.342 +                 b[4+3] * a[15];
   1.343 +        c[8] =   b[8] * a[0] +
   1.344 +                 b[8+1] * a[4] +
   1.345 +                 b[8+2] * a[8] +
   1.346 +                 b[8+3] * a[12];
   1.347 +        c[8+1] = b[8] * a[1] +
   1.348 +                 b[8+1] * a[5] +
   1.349 +                 b[8+2] * a[9] +
   1.350 +                 b[8+3] * a[13];
   1.351 +        c[8+2] = b[8] * a[2] +
   1.352 +                 b[8+1] * a[6] +
   1.353 +                 b[8+2] * a[10] +
   1.354 +                 b[8+3] * a[14];
   1.355 +        c[8+3] = b[8] * a[3] +
   1.356 +                 b[8+1] * a[7] +
   1.357 +                 b[8+2] * a[11] +
   1.358 +                 b[8+3] * a[15];
   1.359 +        c[12] =   b[12] * a[0] +
   1.360 +                 b[12+1] * a[4] +
   1.361 +                 b[12+2] * a[8] +
   1.362 +                 b[12+3] * a[12];
   1.363 +        c[12+1] = b[12] * a[1] +
   1.364 +                 b[12+1] * a[5] +
   1.365 +                 b[12+2] * a[9] +
   1.366 +                 b[12+3] * a[13];
   1.367 +        c[12+2] = b[12] * a[2] +
   1.368 +                 b[12+1] * a[6] +
   1.369 +                 b[12+2] * a[10] +
   1.370 +                 b[12+3] * a[14];
   1.371 +        c[12+3] = b[12] * a[3] +
   1.372 +                 b[12+1] * a[7] +
   1.373 +                 b[12+2] * a[11] +
   1.374 +                 b[12+3] * a[15];
   1.375 +    return c;
   1.376 +  },
   1.377 +
   1.378 +  mulv4 : function (a, v) {
   1.379 +    c = new Array(4);
   1.380 +    for (var i=0; i<4; ++i) {
   1.381 +      var x = 0;
   1.382 +      for (var k=0; k<4; ++k)
   1.383 +        x += v[k] * a[k*4+i];
   1.384 +      c[i] = x;
   1.385 +    }
   1.386 +    return c;
   1.387 +  },
   1.388 +
   1.389 +  rotate : function (angle, axis) {
   1.390 +    axis = Vec3.normalize(axis);
   1.391 +    var x=axis[0], y=axis[1], z=axis[2];
   1.392 +    var c = Math.cos(angle);
   1.393 +    var c1 = 1-c;
   1.394 +    var s = Math.sin(angle);
   1.395 +    return [
   1.396 +      x*x*c1+c, y*x*c1+z*s, z*x*c1-y*s, 0,
   1.397 +      x*y*c1-z*s, y*y*c1+c, y*z*c1+x*s, 0,
   1.398 +      x*z*c1+y*s, y*z*c1-x*s, z*z*c1+c, 0,
   1.399 +      0,0,0,1
   1.400 +    ];
   1.401 +  },
   1.402 +  rotateInPlace : function(angle, axis, m) {
   1.403 +    axis = Vec3.normalize(axis);
   1.404 +    var x=axis[0], y=axis[1], z=axis[2];
   1.405 +    var c = Math.cos(angle);
   1.406 +    var c1 = 1-c;
   1.407 +    var s = Math.sin(angle);
   1.408 +    var tmpMatrix = this.tmpMatrix;
   1.409 +    var tmpMatrix2 = this.tmpMatrix2;
   1.410 +    tmpMatrix[0] = x*x*c1+c; tmpMatrix[1] = y*x*c1+z*s; tmpMatrix[2] = z*x*c1-y*s; tmpMatrix[3] = 0;
   1.411 +    tmpMatrix[4] = x*y*c1-z*s; tmpMatrix[5] = y*y*c1+c; tmpMatrix[6] = y*z*c1+x*s; tmpMatrix[7] = 0;
   1.412 +    tmpMatrix[8] = x*z*c1+y*s; tmpMatrix[9] = y*z*c1-x*s; tmpMatrix[10] = z*z*c1+c; tmpMatrix[11] = 0;
   1.413 +    tmpMatrix[12] = 0; tmpMatrix[13] = 0; tmpMatrix[14] = 0; tmpMatrix[15] = 1;
   1.414 +    this.copyMatrix(m, tmpMatrix2);
   1.415 +    return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
   1.416 +  },
   1.417 +
   1.418 +  scale : function(v) {
   1.419 +    return [
   1.420 +      v[0], 0, 0, 0,
   1.421 +      0, v[1], 0, 0,
   1.422 +      0, 0, v[2], 0,
   1.423 +      0, 0, 0, 1
   1.424 +    ];
   1.425 +  },
   1.426 +  scale3 : function(x,y,z) {
   1.427 +    return [
   1.428 +      x, 0, 0, 0,
   1.429 +      0, y, 0, 0,
   1.430 +      0, 0, z, 0,
   1.431 +      0, 0, 0, 1
   1.432 +    ];
   1.433 +  },
   1.434 +  scale1 : function(s) {
   1.435 +    return [
   1.436 +      s, 0, 0, 0,
   1.437 +      0, s, 0, 0,
   1.438 +      0, 0, s, 0,
   1.439 +      0, 0, 0, 1
   1.440 +    ];
   1.441 +  },
   1.442 +  scale3InPlace : function(x, y, z, m) {
   1.443 +    var tmpMatrix = this.tmpMatrix;
   1.444 +    var tmpMatrix2 = this.tmpMatrix2;
   1.445 +    tmpMatrix[0] = x; tmpMatrix[1] = 0; tmpMatrix[2] = 0; tmpMatrix[3] = 0;
   1.446 +    tmpMatrix[4] = 0; tmpMatrix[5] = y; tmpMatrix[6] = 0; tmpMatrix[7] = 0;
   1.447 +    tmpMatrix[8] = 0; tmpMatrix[9] = 0; tmpMatrix[10] = z; tmpMatrix[11] = 0;
   1.448 +    tmpMatrix[12] = 0; tmpMatrix[13] = 0; tmpMatrix[14] = 0; tmpMatrix[15] = 1;
   1.449 +    this.copyMatrix(m, tmpMatrix2);
   1.450 +    return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
   1.451 +  },
   1.452 +  scale1InPlace : function(s, m) { return this.scale3InPlace(s, s, s, m); },
   1.453 +  scaleInPlace : function(s, m) { return this.scale3InPlace(s[0],s[1],s[2],m); },
   1.454 +
   1.455 +  translate3 : function(x,y,z) {
   1.456 +    return [
   1.457 +      1, 0, 0, 0,
   1.458 +      0, 1, 0, 0,
   1.459 +      0, 0, 1, 0,
   1.460 +      x, y, z, 1
   1.461 +    ];
   1.462 +  },
   1.463 +
   1.464 +  translate : function(v) {
   1.465 +    return this.translate3(v[0], v[1], v[2]);
   1.466 +  },
   1.467 +  tmpMatrix : [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0],
   1.468 +  tmpMatrix2 : [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0],
   1.469 +  translate3InPlace : function(x,y,z,m) {
   1.470 +    var tmpMatrix = this.tmpMatrix;
   1.471 +    var tmpMatrix2 = this.tmpMatrix2;
   1.472 +    tmpMatrix[0] = 1; tmpMatrix[1] = 0; tmpMatrix[2] = 0; tmpMatrix[3] = 0;
   1.473 +    tmpMatrix[4] = 0; tmpMatrix[5] = 1; tmpMatrix[6] = 0; tmpMatrix[7] = 0;
   1.474 +    tmpMatrix[8] = 0; tmpMatrix[9] = 0; tmpMatrix[10] = 1; tmpMatrix[11] = 0;
   1.475 +    tmpMatrix[12] = x; tmpMatrix[13] = y; tmpMatrix[14] = z; tmpMatrix[15] = 1;
   1.476 +    this.copyMatrix(m, tmpMatrix2);
   1.477 +    return this.mul4x4InPlace(tmpMatrix2, tmpMatrix, m);
   1.478 +  },
   1.479 +  translateInPlace : function(v,m){ return this.translate3InPlace(v[0], v[1], v[2], m); },
   1.480 +
   1.481 +  lookAt : function (eye, center, up) {
   1.482 +    var z = Vec3.direction(eye, center);
   1.483 +    var x = Vec3.normalizeInPlace(Vec3.cross(up, z));
   1.484 +    var y = Vec3.normalizeInPlace(Vec3.cross(z, x));
   1.485 +
   1.486 +    var m = [
   1.487 +      x[0], y[0], z[0], 0,
   1.488 +      x[1], y[1], z[1], 0,
   1.489 +      x[2], y[2], z[2], 0,
   1.490 +      0, 0, 0, 1
   1.491 +    ];
   1.492 +
   1.493 +    var t = [
   1.494 +      1, 0, 0, 0,
   1.495 +      0, 1, 0, 0,
   1.496 +      0, 0, 1, 0,
   1.497 +      -eye[0], -eye[1], -eye[2], 1
   1.498 +    ];
   1.499 +
   1.500 +    return this.mul4x4(m,t);
   1.501 +  },
   1.502 +
   1.503 +  transpose4x4 : function(m) {
   1.504 +    return [
   1.505 +      m[0], m[4], m[8], m[12],
   1.506 +      m[1], m[5], m[9], m[13],
   1.507 +      m[2], m[6], m[10], m[14],
   1.508 +      m[3], m[7], m[11], m[15]
   1.509 +    ];
   1.510 +  },
   1.511 +
   1.512 +  transpose4x4InPlace : function(m) {
   1.513 +    var tmp = 0.0;
   1.514 +    tmp = m[1]; m[1] = m[4]; m[4] = tmp;
   1.515 +    tmp = m[2]; m[2] = m[8]; m[8] = tmp;
   1.516 +    tmp = m[3]; m[3] = m[12]; m[12] = tmp;
   1.517 +    tmp = m[6]; m[6] = m[9]; m[9] = tmp;
   1.518 +    tmp = m[7]; m[7] = m[13]; m[13] = tmp;
   1.519 +    tmp = m[11]; m[11] = m[14]; m[14] = tmp;
   1.520 +    return m;
   1.521 +  },
   1.522 +
   1.523 +  transpose3x3 : function(m) {
   1.524 +    return [
   1.525 +      m[0], m[3], m[6],
   1.526 +      m[1], m[4], m[7],
   1.527 +      m[2], m[5], m[8]
   1.528 +    ];
   1.529 +  },
   1.530 +
   1.531 +  transpose3x3InPlace : function(m) {
   1.532 +    var tmp = 0.0;
   1.533 +    tmp = m[1]; m[1] = m[3]; m[3] = tmp;
   1.534 +    tmp = m[2]; m[2] = m[6]; m[6] = tmp;
   1.535 +    tmp = m[5]; m[5] = m[7]; m[7] = tmp;
   1.536 +    return m;
   1.537 +  },
   1.538 +}
   1.539 +
   1.540 +Vec3 = {
   1.541 +  make : function() { return [0,0,0]; },
   1.542 +  copy : function(v) { return [v[0],v[1],v[2]]; },
   1.543 +
   1.544 +  add : function (u,v) {
   1.545 +    return [u[0]+v[0], u[1]+v[1], u[2]+v[2]];
   1.546 +  },
   1.547 +
   1.548 +  sub : function (u,v) {
   1.549 +    return [u[0]-v[0], u[1]-v[1], u[2]-v[2]];
   1.550 +  },
   1.551 +
   1.552 +  negate : function (u) {
   1.553 +    return [-u[0], -u[1], -u[2]];
   1.554 +  },
   1.555 +
   1.556 +  direction : function (u,v) {
   1.557 +    return this.normalizeInPlace(this.sub(u,v));
   1.558 +  },
   1.559 +
   1.560 +  normalizeInPlace : function(v) {
   1.561 +    var imag = 1.0 / Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
   1.562 +    v[0] *= imag; v[1] *= imag; v[2] *= imag;
   1.563 +    return v;
   1.564 +  },
   1.565 +
   1.566 +  normalize : function(v) {
   1.567 +    return this.normalizeInPlace(this.copy(v));
   1.568 +  },
   1.569 +
   1.570 +  scale : function(f, v) {
   1.571 +    return [f*v[0], f*v[1], f*v[2]];
   1.572 +  },
   1.573 +
   1.574 +  dot : function(u,v) {
   1.575 +    return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
   1.576 +  },
   1.577 +
   1.578 +  inner : function(u,v) {
   1.579 +    return [u[0]*v[0], u[1]*v[1], u[2]*v[2]];
   1.580 +  },
   1.581 +
   1.582 +  cross : function(u,v) {
   1.583 +    return [
   1.584 +      u[1]*v[2] - u[2]*v[1],
   1.585 +      u[2]*v[0] - u[0]*v[2],
   1.586 +      u[0]*v[1] - u[1]*v[0]
   1.587 +    ];
   1.588 +  }
   1.589 +}
   1.590 +
   1.591 +Shader = function(gl){
   1.592 +  this.gl = gl;
   1.593 +  this.shaders = [];
   1.594 +  this.uniformLocations = {};
   1.595 +  this.attribLocations = {};
   1.596 +  for (var i=1; i<arguments.length; i++) {
   1.597 +    this.shaders.push(arguments[i]);
   1.598 +  }
   1.599 +}
   1.600 +Shader.prototype = {
   1.601 +  id : null,
   1.602 +  gl : null,
   1.603 +  compiled : false,
   1.604 +  shader : null,
   1.605 +  shaders : [],
   1.606 +
   1.607 +  destroy : function() {
   1.608 +    if (this.shader != null) deleteShader(this.gl, this.shader);
   1.609 +  },
   1.610 +
   1.611 +  compile : function() {
   1.612 +    this.shader = loadShaderArray(this.gl, this.shaders);
   1.613 +  },
   1.614 +
   1.615 +  use : function() {
   1.616 +    if (this.shader == null)
   1.617 +      this.compile();
   1.618 +    this.gl.useProgram(this.shader.program);
   1.619 +  },
   1.620 +
   1.621 +  uniform1fv : function(name, value) {
   1.622 +    var loc = this.uniform(name);
   1.623 +    this.gl.uniform1fv(loc, value);
   1.624 +  },
   1.625 +
   1.626 +  uniform2fv : function(name, value) {
   1.627 +    var loc = this.uniform(name);
   1.628 +    this.gl.uniform2fv(loc, value);
   1.629 +  },
   1.630 +
   1.631 +  uniform3fv : function(name, value) {
   1.632 +    var loc = this.uniform(name);
   1.633 +    this.gl.uniform3fv(loc, value);
   1.634 +  },
   1.635 +
   1.636 +  uniform4fv : function(name, value) {
   1.637 +    var loc = this.uniform(name);
   1.638 +    this.gl.uniform4fv(loc, value);
   1.639 +  },
   1.640 +
   1.641 +  uniform1f : function(name, value) {
   1.642 +    var loc = this.uniform(name);
   1.643 +    this.gl.uniform1f(loc, value);
   1.644 +  },
   1.645 +
   1.646 +  uniform2f : function(name, v1,v2) {
   1.647 +    var loc = this.uniform(name);
   1.648 +    this.gl.uniform2f(loc, v1,v2);
   1.649 +  },
   1.650 +
   1.651 +  uniform3f : function(name, v1,v2,v3) {
   1.652 +    var loc = this.uniform(name);
   1.653 +    this.gl.uniform3f(loc, v1,v2,v3);
   1.654 +  },
   1.655 +
   1.656 +  uniform4f : function(name, v1,v2,v3,v4) {
   1.657 +    var loc = this.uniform(name);
   1.658 +    this.gl.uniform4f(loc, v1, v2, v3, v4);
   1.659 +  },
   1.660 +
   1.661 +  uniform1iv : function(name, value) {
   1.662 +    var loc = this.uniform(name);
   1.663 +    this.gl.uniform1iv(loc, value);
   1.664 +  },
   1.665 +
   1.666 +  uniform2iv : function(name, value) {
   1.667 +    var loc = this.uniform(name);
   1.668 +    this.gl.uniform2iv(loc, value);
   1.669 +  },
   1.670 +
   1.671 +  uniform3iv : function(name, value) {
   1.672 +    var loc = this.uniform(name);
   1.673 +    this.gl.uniform3iv(loc, value);
   1.674 +  },
   1.675 +
   1.676 +  uniform4iv : function(name, value) {
   1.677 +    var loc = this.uniform(name);
   1.678 +    this.gl.uniform4iv(loc, value);
   1.679 +  },
   1.680 +
   1.681 +  uniform1i : function(name, value) {
   1.682 +    var loc = this.uniform(name);
   1.683 +    this.gl.uniform1i(loc, value);
   1.684 +  },
   1.685 +
   1.686 +  uniform2i : function(name, v1,v2) {
   1.687 +    var loc = this.uniform(name);
   1.688 +    this.gl.uniform2i(loc, v1,v2);
   1.689 +  },
   1.690 +
   1.691 +  uniform3i : function(name, v1,v2,v3) {
   1.692 +    var loc = this.uniform(name);
   1.693 +    this.gl.uniform3i(loc, v1,v2,v3);
   1.694 +  },
   1.695 +
   1.696 +  uniform4i : function(name, v1,v2,v3,v4) {
   1.697 +    var loc = this.uniform(name);
   1.698 +    this.gl.uniform4i(loc, v1, v2, v3, v4);
   1.699 +  },
   1.700 +
   1.701 +  uniformMatrix4fv : function(name, value) {
   1.702 +    var loc = this.uniform(name);
   1.703 +    this.gl.uniformMatrix4fv(loc, false, value);
   1.704 +  },
   1.705 +
   1.706 +  uniformMatrix3fv : function(name, value) {
   1.707 +    var loc = this.uniform(name);
   1.708 +    this.gl.uniformMatrix3fv(loc, false, value);
   1.709 +  },
   1.710 +
   1.711 +  uniformMatrix2fv : function(name, value) {
   1.712 +    var loc = this.uniform(name);
   1.713 +    this.gl.uniformMatrix2fv(loc, false, value);
   1.714 +  },
   1.715 +
   1.716 +  attrib : function(name) {
   1.717 +    if (this.attribLocations[name] == null) {
   1.718 +      var loc = this.gl.getAttribLocation(this.shader.program, name);
   1.719 +      this.attribLocations[name] = loc;
   1.720 +    }
   1.721 +    return this.attribLocations[name];
   1.722 +  },
   1.723 +
   1.724 +  uniform : function(name) {
   1.725 +    if (this.uniformLocations[name] == null) {
   1.726 +      var loc = this.gl.getUniformLocation(this.shader.program, name);
   1.727 +      this.uniformLocations[name] = loc;
   1.728 +    }
   1.729 +    return this.uniformLocations[name];
   1.730 +  }
   1.731 +}
   1.732 +Filter = function(gl, shader) {
   1.733 +  Shader.apply(this, arguments);
   1.734 +}
   1.735 +Filter.prototype = new Shader();
   1.736 +Filter.prototype.apply = function(init) {
   1.737 +  this.use();
   1.738 +  var va = this.attrib("Vertex");
   1.739 +  var ta = this.attrib("Tex");
   1.740 +  var vbo = Quad.getCachedVBO(this.gl);
   1.741 +  if (init) init(this);
   1.742 +  vbo.draw(va, null, ta);
   1.743 +}
   1.744 +
   1.745 +
   1.746 +VBO = function(gl) {
   1.747 +  this.gl = gl;
   1.748 +  this.data = [];
   1.749 +  this.elementsVBO = null;
   1.750 +  for (var i=1; i<arguments.length; i++) {
   1.751 +    if (arguments[i].elements)
   1.752 +      this.elements = arguments[i];
   1.753 +    else
   1.754 +      this.data.push(arguments[i]);
   1.755 +  }
   1.756 +}
   1.757 +
   1.758 +VBO.prototype = {
   1.759 +  initialized : false,
   1.760 +  length : 0,
   1.761 +  vbos : null,
   1.762 +  type : 'TRIANGLES',
   1.763 +  elementsVBO : null,
   1.764 +  elements : null,
   1.765 +
   1.766 +  setData : function() {
   1.767 +    this.destroy();
   1.768 +    this.data = [];
   1.769 +    for (var i=0; i<arguments.length; i++) {
   1.770 +      if (arguments[i].elements)
   1.771 +        this.elements = arguments[i];
   1.772 +      else
   1.773 +        this.data.push(arguments[i]);
   1.774 +    }
   1.775 +  },
   1.776 +
   1.777 +  destroy : function() {
   1.778 +    if (this.vbos != null)
   1.779 +      for (var i=0; i<this.vbos.length; i++)
   1.780 +        this.gl.deleteBuffer(this.vbos[i]);
   1.781 +    if (this.elementsVBO != null)
   1.782 +      this.gl.deleteBuffer(this.elementsVBO);
   1.783 +    this.length = this.elementsLength = 0;
   1.784 +    this.vbos = this.elementsVBO = null;
   1.785 +    this.initialized = false;
   1.786 +  },
   1.787 +
   1.788 +  init : function() {
   1.789 +    this.destroy();
   1.790 +    var gl = this.gl;
   1.791 +
   1.792 +    gl.getError();
   1.793 +    var vbos = [];
   1.794 +    var length = 0;
   1.795 +    for (var i=0; i<this.data.length; i++)
   1.796 +      vbos.push(gl.createBuffer());
   1.797 +    if (this.elements != null)
   1.798 +      this.elementsVBO = gl.createBuffer();
   1.799 +    try {
   1.800 +      throwError(gl, "genBuffers");
   1.801 +      for (var i = 0; i<this.data.length; i++) {
   1.802 +        var d = this.data[i];
   1.803 +        var dlen = Math.floor(d.data.length / d.size);
   1.804 +        if (i == 0 || dlen < length)
   1.805 +            length = dlen;
   1.806 +        if (!d.floatArray)
   1.807 +          d.floatArray = new Float32Array(d.data);
   1.808 +        gl.bindBuffer(gl.ARRAY_BUFFER, vbos[i]);
   1.809 +        throwError(gl, "bindBuffer");
   1.810 +        gl.bufferData(gl.ARRAY_BUFFER, d.floatArray, gl.STATIC_DRAW);
   1.811 +        throwError(gl, "bufferData");
   1.812 +      }
   1.813 +      if (this.elementsVBO != null) {
   1.814 +        var d = this.elements;
   1.815 +        this.elementsLength = d.data.length;
   1.816 +        this.elementsType = d.type == gl.UNSIGNED_BYTE ? d.type : gl.UNSIGNED_SHORT;
   1.817 +        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementsVBO);
   1.818 +        throwError(gl, "bindBuffer ELEMENT_ARRAY_BUFFER");
   1.819 +        if (this.elementsType == gl.UNSIGNED_SHORT && !d.ushortArray) {
   1.820 +          d.ushortArray = new Uint16Array(d.data);
   1.821 +          gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, d.ushortArray, gl.STATIC_DRAW);
   1.822 +        } else if (this.elementsType == gl.UNSIGNED_BYTE && !d.ubyteArray) {
   1.823 +          d.ubyteArray = new Uint8Array(d.data);
   1.824 +          gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, d.ubyteArray, gl.STATIC_DRAW);
   1.825 +        }
   1.826 +        throwError(gl, "bufferData ELEMENT_ARRAY_BUFFER");
   1.827 +      }
   1.828 +    } catch(e) {
   1.829 +      for (var i=0; i<vbos.length; i++)
   1.830 +        gl.deleteBuffer(vbos[i]);
   1.831 +      throw(e);
   1.832 +    }
   1.833 +
   1.834 +    gl.bindBuffer(gl.ARRAY_BUFFER, null);
   1.835 +    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
   1.836 +
   1.837 +    this.length = length;
   1.838 +    this.vbos = vbos;
   1.839 +
   1.840 +    this.initialized = true;
   1.841 +  },
   1.842 +
   1.843 +  use : function() {
   1.844 +    if (!this.initialized) this.init();
   1.845 +    var gl = this.gl;
   1.846 +    for (var i=0; i<arguments.length; i++) {
   1.847 +      if (arguments[i] == null) continue;
   1.848 +      gl.bindBuffer(gl.ARRAY_BUFFER, this.vbos[i]);
   1.849 +      gl.vertexAttribPointer(arguments[i], this.data[i].size, gl.FLOAT, false, 0, 0);
   1.850 +      gl.enableVertexAttribArray(arguments[i]);
   1.851 +    }
   1.852 +    if (this.elementsVBO != null) {
   1.853 +      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.elementsVBO);
   1.854 +    }
   1.855 +  },
   1.856 +
   1.857 +  draw : function() {
   1.858 +    var args = [];
   1.859 +    this.use.apply(this, arguments);
   1.860 +    var gl = this.gl;
   1.861 +    if (this.elementsVBO != null) {
   1.862 +      gl.drawElements(gl[this.type], this.elementsLength, this.elementsType, 0);
   1.863 +    } else {
   1.864 +      gl.drawArrays(gl[this.type], 0, this.length);
   1.865 +    }
   1.866 +  }
   1.867 +}
   1.868 +
   1.869 +FBO = function(gl, width, height, use_depth) {
   1.870 +  this.gl = gl;
   1.871 +  this.width = width;
   1.872 +  this.height = height;
   1.873 +  if (use_depth != null)
   1.874 +    this.useDepth = use_depth;
   1.875 +}
   1.876 +FBO.prototype = {
   1.877 +  initialized : false,
   1.878 +  useDepth : true,
   1.879 +  fbo : null,
   1.880 +  rbo : null,
   1.881 +  texture : null,
   1.882 +
   1.883 +  destroy : function() {
   1.884 +    if (this.fbo) this.gl.deleteFramebuffer(this.fbo);
   1.885 +    if (this.rbo) this.gl.deleteRenderbuffer(this.rbo);
   1.886 +    if (this.texture) this.gl.deleteTexture(this.texture);
   1.887 +  },
   1.888 +
   1.889 +  init : function() {
   1.890 +    var gl = this.gl;
   1.891 +    var w = this.width, h = this.height;
   1.892 +    var fbo = this.fbo != null ? this.fbo : gl.createFramebuffer();
   1.893 +    var rb;
   1.894 +
   1.895 +    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
   1.896 +    checkError(gl, "FBO.init bindFramebuffer");
   1.897 +    if (this.useDepth) {
   1.898 +      rb = this.rbo != null ? this.rbo : gl.createRenderbuffer();
   1.899 +      gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
   1.900 +      checkError(gl, "FBO.init bindRenderbuffer");
   1.901 +      gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
   1.902 +      checkError(gl, "FBO.init renderbufferStorage");
   1.903 +    }
   1.904 +
   1.905 +    var tex = this.texture != null ? this.texture : gl.createTexture();
   1.906 +    gl.bindTexture(gl.TEXTURE_2D, tex);
   1.907 +    try {
   1.908 +      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
   1.909 +    } catch (e) { // argh, no null texture support
   1.910 +      var tmp = this.getTempCanvas(w,h);
   1.911 +      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tmp);
   1.912 +    }
   1.913 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
   1.914 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
   1.915 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
   1.916 +    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
   1.917 +    checkError(gl, "FBO.init tex");
   1.918 +
   1.919 +    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
   1.920 +    checkError(gl, "FBO.init bind tex");
   1.921 +
   1.922 +    if (this.useDepth) {
   1.923 +      gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb);
   1.924 +      checkError(gl, "FBO.init bind depth buffer");
   1.925 +    }
   1.926 +
   1.927 +    var fbstat = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
   1.928 +    if (fbstat != gl.FRAMEBUFFER_COMPLETE) {
   1.929 +      var glv;
   1.930 +      for (var v in gl) {
   1.931 +        try { glv = gl[v]; } catch (e) { glv = null; }
   1.932 +        if (glv == fbstat) { fbstat = v; break; }}
   1.933 +        log("Framebuffer status: " + fbstat);
   1.934 +    }
   1.935 +    checkError(gl, "FBO.init check fbo");
   1.936 +
   1.937 +    this.fbo = fbo;
   1.938 +    this.rbo = rb;
   1.939 +    this.texture = tex;
   1.940 +    this.initialized = true;
   1.941 +  },
   1.942 +
   1.943 +  getTempCanvas : function(w, h) {
   1.944 +    if (!FBO.tempCanvas) {
   1.945 +      FBO.tempCanvas = document.createElement('canvas');
   1.946 +    }
   1.947 +    FBO.tempCanvas.width = w;
   1.948 +    FBO.tempCanvas.height = h;
   1.949 +    return FBO.tempCanvas;
   1.950 +  },
   1.951 +
   1.952 +  use : function() {
   1.953 +    if (!this.initialized) this.init();
   1.954 +    this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo);
   1.955 +  }
   1.956 +}
   1.957 +
   1.958 +function GLError(err, msg, fileName, lineNumber) {
   1.959 +  this.message = msg;
   1.960 +  this.glError = err;
   1.961 +}
   1.962 +
   1.963 +GLError.prototype = new Error();
   1.964 +
   1.965 +function makeGLErrorWrapper(gl, fname) {
   1.966 +  return (function() {
   1.967 +    try {
   1.968 +      var rv = gl[fname].apply(gl, arguments);
   1.969 +      var err = gl.getError();
   1.970 +      if (err != gl.NO_ERROR) {
   1.971 +        throw(new GLError(
   1.972 +            err, "GL error "+getGLErrorAsString(gl, err)+" in "+fname));
   1.973 +      }
   1.974 +      return rv;
   1.975 +    } catch (e) {
   1.976 +      if (e.glError !== undefined) {
   1.977 +        throw e;
   1.978 +      }
   1.979 +      throw(new Error("Threw " + e.name +
   1.980 +                      " in " + fname + "\n" +
   1.981 +                      e.message + "\n" +
   1.982 +                      arguments.callee.caller));
   1.983 +    }
   1.984 +  });
   1.985 +}
   1.986 +
   1.987 +function wrapGLContext(gl) {
   1.988 +  var wrap = {};
   1.989 +  for (var i in gl) {
   1.990 +    try {
   1.991 +      if (typeof gl[i] == 'function') {
   1.992 +          wrap[i] = makeGLErrorWrapper(gl, i);
   1.993 +      } else {
   1.994 +          wrap[i] = gl[i];
   1.995 +      }
   1.996 +    } catch (e) {
   1.997 +      // log("wrapGLContext: Error accessing " + i);
   1.998 +    }
   1.999 +  }
  1.1000 +  wrap.getError = function(){ return gl.getError(); };
  1.1001 +  return wrap;
  1.1002 +}
  1.1003 +
  1.1004 +// Assert that f generates a specific GL error.
  1.1005 +function assertGLError(gl, err, name, f) {
  1.1006 +  if (f == null) { f = name; name = null; }
  1.1007 +  var r = false;
  1.1008 +  var glErr = 0;
  1.1009 +  try { f(); } catch(e) { r=true; glErr = e.glError; }
  1.1010 +  if (glErr !== err) {
  1.1011 +    if (glErr === undefined) {
  1.1012 +      testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
  1.1013 +    } else {
  1.1014 +      testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
  1.1015 +                 " actual: " + getGLErrorAsString(gl, glErr), name, f);
  1.1016 +    }
  1.1017 +    return false;
  1.1018 +  }
  1.1019 +  return true;
  1.1020 +}
  1.1021 +
  1.1022 +// Assert that f generates some GL error. Used in situations where it's
  1.1023 +// ambigious which of multiple possible errors will be generated.
  1.1024 +function assertSomeGLError(gl, name, f) {
  1.1025 +  if (f == null) { f = name; name = null; }
  1.1026 +  var r = false;
  1.1027 +  var glErr = 0;
  1.1028 +  var err = 0;
  1.1029 +  try { f(); } catch(e) { r=true; glErr = e.glError; }
  1.1030 +  if (glErr === 0) {
  1.1031 +    if (glErr === undefined) {
  1.1032 +      testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
  1.1033 +    } else {
  1.1034 +      testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
  1.1035 +                 " actual: " + getGLErrorAsString(gl, glErr), name, f);
  1.1036 +    }
  1.1037 +    return false;
  1.1038 +  }
  1.1039 +  return true;
  1.1040 +}
  1.1041 +
  1.1042 +// Assert that f throws an exception but does not generate a GL error.
  1.1043 +function assertThrowNoGLError(gl, name, f) {
  1.1044 +  if (f == null) { f = name; name = null; }
  1.1045 +  var r = false;
  1.1046 +  var glErr = undefined;
  1.1047 +  var exp;
  1.1048 +  try { f(); } catch(e) { r=true; glErr = e.glError; exp = e;}
  1.1049 +  if (!r) {
  1.1050 +    testFailed(
  1.1051 +      "assertThrowNoGLError: should have thrown exception", name, f);
  1.1052 +    return false;
  1.1053 +  } else {
  1.1054 +    if (glErr !== undefined) {
  1.1055 +      testFailed(
  1.1056 +        "assertThrowNoGLError: should be no GL error but generated: " +
  1.1057 +        getGLErrorAsString(gl, glErr), name, f);
  1.1058 +      return false;
  1.1059 +    }
  1.1060 +  }
  1.1061 +  testPassed("assertThrowNoGLError", name, f);
  1.1062 +  return true;
  1.1063 +}
  1.1064 +
  1.1065 +Quad = {
  1.1066 +  vertices : [
  1.1067 +    -1,-1,0,
  1.1068 +    1,-1,0,
  1.1069 +    -1,1,0,
  1.1070 +    1,-1,0,
  1.1071 +    1,1,0,
  1.1072 +    -1,1,0
  1.1073 +  ],
  1.1074 +  normals : [
  1.1075 +    0,0,-1,
  1.1076 +    0,0,-1,
  1.1077 +    0,0,-1,
  1.1078 +    0,0,-1,
  1.1079 +    0,0,-1,
  1.1080 +    0,0,-1
  1.1081 +  ],
  1.1082 +  texcoords : [
  1.1083 +    0,0,
  1.1084 +    1,0,
  1.1085 +    0,1,
  1.1086 +    1,0,
  1.1087 +    1,1,
  1.1088 +    0,1
  1.1089 +  ],
  1.1090 +  indices : [0,1,2,1,5,2],
  1.1091 +  makeVBO : function(gl) {
  1.1092 +    return new VBO(gl,
  1.1093 +        {size:3, data: Quad.vertices},
  1.1094 +        {size:3, data: Quad.normals},
  1.1095 +        {size:2, data: Quad.texcoords}
  1.1096 +    )
  1.1097 +  },
  1.1098 +  cache: {},
  1.1099 +  getCachedVBO : function(gl) {
  1.1100 +    if (!this.cache[gl])
  1.1101 +      this.cache[gl] = this.makeVBO(gl);
  1.1102 +    return this.cache[gl];
  1.1103 +  }
  1.1104 +}
  1.1105 +Cube = {
  1.1106 +  vertices : [  0.5, -0.5,  0.5, // +X
  1.1107 +                0.5, -0.5, -0.5,
  1.1108 +                0.5,  0.5, -0.5,
  1.1109 +                0.5,  0.5,  0.5,
  1.1110 +
  1.1111 +                0.5,  0.5,  0.5, // +Y
  1.1112 +                0.5,  0.5, -0.5,
  1.1113 +                -0.5,  0.5, -0.5,
  1.1114 +                -0.5,  0.5,  0.5,
  1.1115 +
  1.1116 +                0.5,  0.5,  0.5, // +Z
  1.1117 +                -0.5,  0.5,  0.5,
  1.1118 +                -0.5, -0.5,  0.5,
  1.1119 +                0.5, -0.5,  0.5,
  1.1120 +
  1.1121 +                -0.5, -0.5,  0.5, // -X
  1.1122 +                -0.5,  0.5,  0.5,
  1.1123 +                -0.5,  0.5, -0.5,
  1.1124 +                -0.5, -0.5, -0.5,
  1.1125 +
  1.1126 +                -0.5, -0.5,  0.5, // -Y
  1.1127 +                -0.5, -0.5, -0.5,
  1.1128 +                0.5, -0.5, -0.5,
  1.1129 +                0.5, -0.5,  0.5,
  1.1130 +
  1.1131 +                -0.5, -0.5, -0.5, // -Z
  1.1132 +                -0.5,  0.5, -0.5,
  1.1133 +                0.5,  0.5, -0.5,
  1.1134 +                0.5, -0.5, -0.5,
  1.1135 +      ],
  1.1136 +
  1.1137 +  normals : [ 1, 0, 0,
  1.1138 +              1, 0, 0,
  1.1139 +              1, 0, 0,
  1.1140 +              1, 0, 0,
  1.1141 +
  1.1142 +              0, 1, 0,
  1.1143 +              0, 1, 0,
  1.1144 +              0, 1, 0,
  1.1145 +              0, 1, 0,
  1.1146 +
  1.1147 +              0, 0, 1,
  1.1148 +              0, 0, 1,
  1.1149 +              0, 0, 1,
  1.1150 +              0, 0, 1,
  1.1151 +
  1.1152 +              -1, 0, 0,
  1.1153 +              -1, 0, 0,
  1.1154 +              -1, 0, 0,
  1.1155 +              -1, 0, 0,
  1.1156 +
  1.1157 +              0,-1, 0,
  1.1158 +              0,-1, 0,
  1.1159 +              0,-1, 0,
  1.1160 +              0,-1, 0,
  1.1161 +
  1.1162 +              0, 0,-1,
  1.1163 +              0, 0,-1,
  1.1164 +              0, 0,-1,
  1.1165 +              0, 0,-1
  1.1166 +      ],
  1.1167 +
  1.1168 +  indices : [],
  1.1169 +  create : function(){
  1.1170 +    for (var i = 0; i < 6; i++) {
  1.1171 +      Cube.indices.push(i*4 + 0);
  1.1172 +      Cube.indices.push(i*4 + 1);
  1.1173 +      Cube.indices.push(i*4 + 3);
  1.1174 +      Cube.indices.push(i*4 + 1);
  1.1175 +      Cube.indices.push(i*4 + 2);
  1.1176 +      Cube.indices.push(i*4 + 3);
  1.1177 +    }
  1.1178 +  },
  1.1179 +
  1.1180 +  makeVBO : function(gl) {
  1.1181 +    return new VBO(gl,
  1.1182 +        {size:3, data: Cube.vertices},
  1.1183 +        {size:3, data: Cube.normals},
  1.1184 +        {elements: true, data: Cube.indices}
  1.1185 +    )
  1.1186 +  },
  1.1187 +  cache : {},
  1.1188 +  getCachedVBO : function(gl) {
  1.1189 +    if (!this.cache[gl])
  1.1190 +      this.cache[gl] = this.makeVBO(gl);
  1.1191 +    return this.cache[gl];
  1.1192 +  }
  1.1193 +}
  1.1194 +Cube.create();
  1.1195 +
  1.1196 +Sphere = {
  1.1197 +  vertices : [],
  1.1198 +  normals : [],
  1.1199 +  indices : [],
  1.1200 +  create : function(){
  1.1201 +    var r = 0.75;
  1.1202 +    function vert(theta, phi)
  1.1203 +    {
  1.1204 +      var r = 0.75;
  1.1205 +      var x, y, z, nx, ny, nz;
  1.1206 +
  1.1207 +      nx = Math.sin(theta) * Math.cos(phi);
  1.1208 +      ny = Math.sin(phi);
  1.1209 +      nz = Math.cos(theta) * Math.cos(phi);
  1.1210 +      Sphere.normals.push(nx);
  1.1211 +      Sphere.normals.push(ny);
  1.1212 +      Sphere.normals.push(nz);
  1.1213 +
  1.1214 +      x = r * Math.sin(theta) * Math.cos(phi);
  1.1215 +      y = r * Math.sin(phi);
  1.1216 +      z = r * Math.cos(theta) * Math.cos(phi);
  1.1217 +      Sphere.vertices.push(x);
  1.1218 +      Sphere.vertices.push(y);
  1.1219 +      Sphere.vertices.push(z);
  1.1220 +    }
  1.1221 +    for (var phi = -Math.PI/2; phi < Math.PI/2; phi += Math.PI/20) {
  1.1222 +      var phi2 = phi + Math.PI/20;
  1.1223 +      for (var theta = -Math.PI/2; theta <= Math.PI/2; theta += Math.PI/20) {
  1.1224 +        vert(theta, phi);
  1.1225 +        vert(theta, phi2);
  1.1226 +      }
  1.1227 +    }
  1.1228 +  }
  1.1229 +}
  1.1230 +
  1.1231 +Sphere.create();
  1.1232 +
  1.1233 +initGL_CONTEXT_ID = function(){
  1.1234 +  var c = document.createElement('canvas');
  1.1235 +  var contextNames = ['webgl', 'experimental-webgl'];
  1.1236 +  GL_CONTEXT_ID = null;
  1.1237 +  for (var i=0; i<contextNames.length; i++) {
  1.1238 +    try {
  1.1239 +      if (c.getContext(contextNames[i])) {
  1.1240 +        GL_CONTEXT_ID = contextNames[i];
  1.1241 +        break;
  1.1242 +      }
  1.1243 +    } catch (e) {
  1.1244 +    }
  1.1245 +  }
  1.1246 +  if (!GL_CONTEXT_ID) {
  1.1247 +    log("No WebGL context found. Unable to run tests.");
  1.1248 +  }
  1.1249 +}
  1.1250 +
  1.1251 +initGL_CONTEXT_ID();

mercurial