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