| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Utilities for the OpenGL ES 2.0 HTML Canvas context | |
| 3 | |
| 4 Copyright (C) 2011 Ilmari Heikkinen <ilmari.heikkinen@gmail.com> | |
| 5 | |
| 6 Permission is hereby granted, free of charge, to any person | |
| 7 obtaining a copy of this software and associated documentation | |
| 8 files (the "Software"), to deal in the Software without | |
| 9 restriction, including without limitation the rights to use, | |
| 10 copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 11 copies of the Software, and to permit persons to whom the | |
| 12 Software is furnished to do so, subject to the following | |
| 13 conditions: | |
| 14 | |
| 15 The above copyright notice and this permission notice shall be | |
| 16 included in all copies or substantial portions of the Software. | |
| 17 | |
| 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
| 20 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
| 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
| 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
| 25 OTHER DEALINGS IN THE SOFTWARE. | |
| 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 // Assert that f generates a specific GL error. | |
| 1002 function assertGLError(gl, err, name, f) { | |
| 1003 if (f == null) { f = name; name = null; } | |
| 1004 var r = false; | |
| 1005 var glErr = 0; | |
| 1006 try { f(); } catch(e) { r=true; glErr = e.glError; } | |
| 1007 if (glErr !== err) { | |
| 1008 if (glErr === undefined) { | |
| 1009 testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f); | |
| 1010 } else { | |
| 1011 testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) + | |
| 1012 " actual: " + getGLErrorAsString(gl, glErr), name, f); | |
| 1013 } | |
| 1014 return false; | |
| 1015 } | |
| 1016 return true; | |
| 1017 } | |
| 1018 | |
| 1019 // Assert that f generates some GL error. Used in situations where it's | |
| 1020 // ambigious which of multiple possible errors will be generated. | |
| 1021 function assertSomeGLError(gl, name, f) { | |
| 1022 if (f == null) { f = name; name = null; } | |
| 1023 var r = false; | |
| 1024 var glErr = 0; | |
| 1025 var err = 0; | |
| 1026 try { f(); } catch(e) { r=true; glErr = e.glError; } | |
| 1027 if (glErr === 0) { | |
| 1028 if (glErr === undefined) { | |
| 1029 testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f); | |
| 1030 } else { | |
| 1031 testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) + | |
| 1032 " actual: " + getGLErrorAsString(gl, glErr), name, f); | |
| 1033 } | |
| 1034 return false; | |
| 1035 } | |
| 1036 return true; | |
| 1037 } | |
| 1038 | |
| 1039 // Assert that f throws an exception but does not generate a GL error. | |
| 1040 function assertThrowNoGLError(gl, name, f) { | |
| 1041 if (f == null) { f = name; name = null; } | |
| 1042 var r = false; | |
| 1043 var glErr = undefined; | |
| 1044 var exp; | |
| 1045 try { f(); } catch(e) { r=true; glErr = e.glError; exp = e;} | |
| 1046 if (!r) { | |
| 1047 testFailed( | |
| 1048 "assertThrowNoGError: should have thrown exception", name, f); | |
| 1049 return false; | |
| 1050 } else { | |
| 1051 if (glErr !== undefined) { | |
| 1052 testFailed( | |
| 1053 "assertThrowNoGError: should be no GL error but generated: " + | |
| 1054 getGLErrorAsString(gl, glErr), name, f); | |
| 1055 return false; | |
| 1056 } else { | |
| 1057 // console.log("threw:" + exp); | |
| 1058 } | |
| 1059 } | |
| 1060 return true; | |
| 1061 } | |
| 1062 | |
| 1063 Quad = { | |
| 1064 vertices : [ | |
| 1065 -1,-1,0, | |
| 1066 1,-1,0, | |
| 1067 -1,1,0, | |
| 1068 1,-1,0, | |
| 1069 1,1,0, | |
| 1070 -1,1,0 | |
| 1071 ], | |
| 1072 normals : [ | |
| 1073 0,0,-1, | |
| 1074 0,0,-1, | |
| 1075 0,0,-1, | |
| 1076 0,0,-1, | |
| 1077 0,0,-1, | |
| 1078 0,0,-1 | |
| 1079 ], | |
| 1080 texcoords : [ | |
| 1081 0,0, | |
| 1082 1,0, | |
| 1083 0,1, | |
| 1084 1,0, | |
| 1085 1,1, | |
| 1086 0,1 | |
| 1087 ], | |
| 1088 indices : [0,1,2,1,5,2], | |
| 1089 makeVBO : function(gl) { | |
| 1090 return new VBO(gl, | |
| 1091 {size:3, data: Quad.vertices}, | |
| 1092 {size:3, data: Quad.normals}, | |
| 1093 {size:2, data: Quad.texcoords} | |
| 1094 ) | |
| 1095 }, | |
| 1096 cache: {}, | |
| 1097 getCachedVBO : function(gl) { | |
| 1098 if (!this.cache[gl]) | |
| 1099 this.cache[gl] = this.makeVBO(gl); | |
| 1100 return this.cache[gl]; | |
| 1101 } | |
| 1102 } | |
| 1103 Cube = { | |
| 1104 vertices : [ 0.5, -0.5, 0.5, // +X | |
| 1105 0.5, -0.5, -0.5, | |
| 1106 0.5, 0.5, -0.5, | |
| 1107 0.5, 0.5, 0.5, | |
| 1108 | |
| 1109 0.5, 0.5, 0.5, // +Y | |
| 1110 0.5, 0.5, -0.5, | |
| 1111 -0.5, 0.5, -0.5, | |
| 1112 -0.5, 0.5, 0.5, | |
| 1113 | |
| 1114 0.5, 0.5, 0.5, // +Z | |
| 1115 -0.5, 0.5, 0.5, | |
| 1116 -0.5, -0.5, 0.5, | |
| 1117 0.5, -0.5, 0.5, | |
| 1118 | |
| 1119 -0.5, -0.5, 0.5, // -X | |
| 1120 -0.5, 0.5, 0.5, | |
| 1121 -0.5, 0.5, -0.5, | |
| 1122 -0.5, -0.5, -0.5, | |
| 1123 | |
| 1124 -0.5, -0.5, 0.5, // -Y | |
| 1125 -0.5, -0.5, -0.5, | |
| 1126 0.5, -0.5, -0.5, | |
| 1127 0.5, -0.5, 0.5, | |
| 1128 | |
| 1129 -0.5, -0.5, -0.5, // -Z | |
| 1130 -0.5, 0.5, -0.5, | |
| 1131 0.5, 0.5, -0.5, | |
| 1132 0.5, -0.5, -0.5, | |
| 1133 ], | |
| 1134 | |
| 1135 normals : [ 1, 0, 0, | |
| 1136 1, 0, 0, | |
| 1137 1, 0, 0, | |
| 1138 1, 0, 0, | |
| 1139 | |
| 1140 0, 1, 0, | |
| 1141 0, 1, 0, | |
| 1142 0, 1, 0, | |
| 1143 0, 1, 0, | |
| 1144 | |
| 1145 0, 0, 1, | |
| 1146 0, 0, 1, | |
| 1147 0, 0, 1, | |
| 1148 0, 0, 1, | |
| 1149 | |
| 1150 -1, 0, 0, | |
| 1151 -1, 0, 0, | |
| 1152 -1, 0, 0, | |
| 1153 -1, 0, 0, | |
| 1154 | |
| 1155 0,-1, 0, | |
| 1156 0,-1, 0, | |
| 1157 0,-1, 0, | |
| 1158 0,-1, 0, | |
| 1159 | |
| 1160 0, 0,-1, | |
| 1161 0, 0,-1, | |
| 1162 0, 0,-1, | |
| 1163 0, 0,-1 | |
| 1164 ], | |
| 1165 | |
| 1166 indices : [], | |
| 1167 create : function(){ | |
| 1168 for (var i = 0; i < 6; i++) { | |
| 1169 Cube.indices.push(i*4 + 0); | |
| 1170 Cube.indices.push(i*4 + 1); | |
| 1171 Cube.indices.push(i*4 + 3); | |
| 1172 Cube.indices.push(i*4 + 1); | |
| 1173 Cube.indices.push(i*4 + 2); | |
| 1174 Cube.indices.push(i*4 + 3); | |
| 1175 } | |
| 1176 }, | |
| 1177 | |
| 1178 makeVBO : function(gl) { | |
| 1179 return new VBO(gl, | |
| 1180 {size:3, data: Cube.vertices}, | |
| 1181 {size:3, data: Cube.normals}, | |
| 1182 {elements: true, data: Cube.indices} | |
| 1183 ) | |
| 1184 }, | |
| 1185 cache : {}, | |
| 1186 getCachedVBO : function(gl) { | |
| 1187 if (!this.cache[gl]) | |
| 1188 this.cache[gl] = this.makeVBO(gl); | |
| 1189 return this.cache[gl]; | |
| 1190 } | |
| 1191 } | |
| 1192 Cube.create(); | |
| 1193 | |
| 1194 Sphere = { | |
| 1195 vertices : [], | |
| 1196 normals : [], | |
| 1197 indices : [], | |
| 1198 create : function(){ | |
| 1199 var r = 0.75; | |
| 1200 function vert(theta, phi) | |
| 1201 { | |
| 1202 var r = 0.75; | |
| 1203 var x, y, z, nx, ny, nz; | |
| 1204 | |
| 1205 nx = Math.sin(theta) * Math.cos(phi); | |
| 1206 ny = Math.sin(phi); | |
| 1207 nz = Math.cos(theta) * Math.cos(phi); | |
| 1208 Sphere.normals.push(nx); | |
| 1209 Sphere.normals.push(ny); | |
| 1210 Sphere.normals.push(nz); | |
| 1211 | |
| 1212 x = r * Math.sin(theta) * Math.cos(phi); | |
| 1213 y = r * Math.sin(phi); | |
| 1214 z = r * Math.cos(theta) * Math.cos(phi); | |
| 1215 Sphere.vertices.push(x); | |
| 1216 Sphere.vertices.push(y); | |
| 1217 Sphere.vertices.push(z); | |
| 1218 } | |
| 1219 for (var phi = -Math.PI/2; phi < Math.PI/2; phi += Math.PI/20) { | |
| 1220 var phi2 = phi + Math.PI/20; | |
| 1221 for (var theta = -Math.PI/2; theta <= Math.PI/2; theta += Math.PI/20) { | |
| 1222 vert(theta, phi); | |
| 1223 vert(theta, phi2); | |
| 1224 } | |
| 1225 } | |
| 1226 } | |
| 1227 } | |
| 1228 | |
| 1229 Sphere.create(); | |
| 1230 | |
| 1231 initGL_CONTEXT_ID = function(){ | |
| 1232 var c = document.createElement('canvas'); | |
| 1233 var contextNames = ['webgl', 'experimental-webgl']; | |
| 1234 GL_CONTEXT_ID = null; | |
| 1235 for (var i=0; i<contextNames.length; i++) { | |
| 1236 try { | |
| 1237 if (c.getContext(contextNames[i])) { | |
| 1238 GL_CONTEXT_ID = contextNames[i]; | |
| 1239 break; | |
| 1240 } | |
| 1241 } catch (e) {} | |
| 1242 } | |
| 1243 if (!GL_CONTEXT_ID) { | |
| 1244 log("No WebGL context found. Unable to run tests."); | |
| 1245 } | |
| 1246 } | |
| 1247 | |
| 1248 initGL_CONTEXT_ID(); | |
| OLD | NEW |