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