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 "assertThrowNoGLError: should have thrown exception", name, f); |
| 1049 return false; |
| 1050 } else { |
| 1051 if (glErr !== undefined) { |
| 1052 testFailed( |
| 1053 "assertThrowNoGLError: should be no GL error but generated: " + |
| 1054 getGLErrorAsString(gl, glErr), name, f); |
| 1055 return false; |
| 1056 } |
| 1057 } |
| 1058 testPassed("assertThrowNoGLError", name, f); |
| 1059 return true; |
| 1060 } |
| 1061 |
| 1062 Quad = { |
| 1063 vertices : [ |
| 1064 -1,-1,0, |
| 1065 1,-1,0, |
| 1066 -1,1,0, |
| 1067 1,-1,0, |
| 1068 1,1,0, |
| 1069 -1,1,0 |
| 1070 ], |
| 1071 normals : [ |
| 1072 0,0,-1, |
| 1073 0,0,-1, |
| 1074 0,0,-1, |
| 1075 0,0,-1, |
| 1076 0,0,-1, |
| 1077 0,0,-1 |
| 1078 ], |
| 1079 texcoords : [ |
| 1080 0,0, |
| 1081 1,0, |
| 1082 0,1, |
| 1083 1,0, |
| 1084 1,1, |
| 1085 0,1 |
| 1086 ], |
| 1087 indices : [0,1,2,1,5,2], |
| 1088 makeVBO : function(gl) { |
| 1089 return new VBO(gl, |
| 1090 {size:3, data: Quad.vertices}, |
| 1091 {size:3, data: Quad.normals}, |
| 1092 {size:2, data: Quad.texcoords} |
| 1093 ) |
| 1094 }, |
| 1095 cache: {}, |
| 1096 getCachedVBO : function(gl) { |
| 1097 if (!this.cache[gl]) |
| 1098 this.cache[gl] = this.makeVBO(gl); |
| 1099 return this.cache[gl]; |
| 1100 } |
| 1101 } |
| 1102 Cube = { |
| 1103 vertices : [ 0.5, -0.5, 0.5, // +X |
| 1104 0.5, -0.5, -0.5, |
| 1105 0.5, 0.5, -0.5, |
| 1106 0.5, 0.5, 0.5, |
| 1107 |
| 1108 0.5, 0.5, 0.5, // +Y |
| 1109 0.5, 0.5, -0.5, |
| 1110 -0.5, 0.5, -0.5, |
| 1111 -0.5, 0.5, 0.5, |
| 1112 |
| 1113 0.5, 0.5, 0.5, // +Z |
| 1114 -0.5, 0.5, 0.5, |
| 1115 -0.5, -0.5, 0.5, |
| 1116 0.5, -0.5, 0.5, |
| 1117 |
| 1118 -0.5, -0.5, 0.5, // -X |
| 1119 -0.5, 0.5, 0.5, |
| 1120 -0.5, 0.5, -0.5, |
| 1121 -0.5, -0.5, -0.5, |
| 1122 |
| 1123 -0.5, -0.5, 0.5, // -Y |
| 1124 -0.5, -0.5, -0.5, |
| 1125 0.5, -0.5, -0.5, |
| 1126 0.5, -0.5, 0.5, |
| 1127 |
| 1128 -0.5, -0.5, -0.5, // -Z |
| 1129 -0.5, 0.5, -0.5, |
| 1130 0.5, 0.5, -0.5, |
| 1131 0.5, -0.5, -0.5, |
| 1132 ], |
| 1133 |
| 1134 normals : [ 1, 0, 0, |
| 1135 1, 0, 0, |
| 1136 1, 0, 0, |
| 1137 1, 0, 0, |
| 1138 |
| 1139 0, 1, 0, |
| 1140 0, 1, 0, |
| 1141 0, 1, 0, |
| 1142 0, 1, 0, |
| 1143 |
| 1144 0, 0, 1, |
| 1145 0, 0, 1, |
| 1146 0, 0, 1, |
| 1147 0, 0, 1, |
| 1148 |
| 1149 -1, 0, 0, |
| 1150 -1, 0, 0, |
| 1151 -1, 0, 0, |
| 1152 -1, 0, 0, |
| 1153 |
| 1154 0,-1, 0, |
| 1155 0,-1, 0, |
| 1156 0,-1, 0, |
| 1157 0,-1, 0, |
| 1158 |
| 1159 0, 0,-1, |
| 1160 0, 0,-1, |
| 1161 0, 0,-1, |
| 1162 0, 0,-1 |
| 1163 ], |
| 1164 |
| 1165 indices : [], |
| 1166 create : function(){ |
| 1167 for (var i = 0; i < 6; i++) { |
| 1168 Cube.indices.push(i*4 + 0); |
| 1169 Cube.indices.push(i*4 + 1); |
| 1170 Cube.indices.push(i*4 + 3); |
| 1171 Cube.indices.push(i*4 + 1); |
| 1172 Cube.indices.push(i*4 + 2); |
| 1173 Cube.indices.push(i*4 + 3); |
| 1174 } |
| 1175 }, |
| 1176 |
| 1177 makeVBO : function(gl) { |
| 1178 return new VBO(gl, |
| 1179 {size:3, data: Cube.vertices}, |
| 1180 {size:3, data: Cube.normals}, |
| 1181 {elements: true, data: Cube.indices} |
| 1182 ) |
| 1183 }, |
| 1184 cache : {}, |
| 1185 getCachedVBO : function(gl) { |
| 1186 if (!this.cache[gl]) |
| 1187 this.cache[gl] = this.makeVBO(gl); |
| 1188 return this.cache[gl]; |
| 1189 } |
| 1190 } |
| 1191 Cube.create(); |
| 1192 |
| 1193 Sphere = { |
| 1194 vertices : [], |
| 1195 normals : [], |
| 1196 indices : [], |
| 1197 create : function(){ |
| 1198 var r = 0.75; |
| 1199 function vert(theta, phi) |
| 1200 { |
| 1201 var r = 0.75; |
| 1202 var x, y, z, nx, ny, nz; |
| 1203 |
| 1204 nx = Math.sin(theta) * Math.cos(phi); |
| 1205 ny = Math.sin(phi); |
| 1206 nz = Math.cos(theta) * Math.cos(phi); |
| 1207 Sphere.normals.push(nx); |
| 1208 Sphere.normals.push(ny); |
| 1209 Sphere.normals.push(nz); |
| 1210 |
| 1211 x = r * Math.sin(theta) * Math.cos(phi); |
| 1212 y = r * Math.sin(phi); |
| 1213 z = r * Math.cos(theta) * Math.cos(phi); |
| 1214 Sphere.vertices.push(x); |
| 1215 Sphere.vertices.push(y); |
| 1216 Sphere.vertices.push(z); |
| 1217 } |
| 1218 for (var phi = -Math.PI/2; phi < Math.PI/2; phi += Math.PI/20) { |
| 1219 var phi2 = phi + Math.PI/20; |
| 1220 for (var theta = -Math.PI/2; theta <= Math.PI/2; theta += Math.PI/20) { |
| 1221 vert(theta, phi); |
| 1222 vert(theta, phi2); |
| 1223 } |
| 1224 } |
| 1225 } |
| 1226 } |
| 1227 |
| 1228 Sphere.create(); |
| 1229 |
| 1230 initGL_CONTEXT_ID = function(){ |
| 1231 var c = document.createElement('canvas'); |
| 1232 var contextNames = ['webgl', 'experimental-webgl']; |
| 1233 GL_CONTEXT_ID = null; |
| 1234 for (var i=0; i<contextNames.length; i++) { |
| 1235 try { |
| 1236 if (c.getContext(contextNames[i])) { |
| 1237 GL_CONTEXT_ID = contextNames[i]; |
| 1238 break; |
| 1239 } |
| 1240 } catch (e) {} |
| 1241 } |
| 1242 if (!GL_CONTEXT_ID) { |
| 1243 log("No WebGL context found. Unable to run tests."); |
| 1244 } |
| 1245 } |
| 1246 |
| 1247 initGL_CONTEXT_ID(); |
OLD | NEW |