Initial.
authorEugen Sawin <sawine@me73.com>
Thu, 31 Mar 2011 23:53:48 +0200
changeset 06dc831fb5a60
child 1 92e65293655d
Initial.
machine.html
scripts/CanvasMatrix.js
scripts/glMatrix.js
scripts/machine.js
scripts/utils3d.js
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/machine.html	Thu Mar 31 23:53:48 2011 +0200
     1.3 @@ -0,0 +1,39 @@
     1.4 +<html>
     1.5 +<head>
     1.6 +<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     1.7 +<title>Machine</title>
     1.8 +<script src="scripts/CanvasMatrix.js" type="text/javascript"> </script>
     1.9 +<script src="scripts/utils3d.js" type="text/javascript"> </script>
    1.10 +<script src="scripts/glMatrix.js" type="text/javascript"></script>
    1.11 +
    1.12 +<script id="shader-fs" type="x-shader/x-fragment"> 
    1.13 +    #ifdef GL_ES
    1.14 +    precision highp float;
    1.15 +    #endif
    1.16 + 
    1.17 +    void main(void) {
    1.18 +        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    1.19 +    }
    1.20 +</script> 
    1.21 + 
    1.22 +<script id="shader-vs" type="x-shader/x-vertex"> 
    1.23 +    attribute vec3 aVertexPosition;
    1.24 + 
    1.25 +    uniform mat4 uMVMatrix;
    1.26 +    uniform mat4 uPMatrix;
    1.27 + 
    1.28 +    void main(void) {
    1.29 +        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    1.30 +    }
    1.31 +</script>
    1.32 +
    1.33 +<script src="scripts/machine.js" type="text/javascript"></script>
    1.34 +</head>
    1.35 + 
    1.36 +<body onload="main();">
    1.37 +<canvas id="machine" width="500" height="500">
    1.38 +    If you're seeing this your web browser doesn't support the canvas element!
    1.39 +</canvas>
    1.40 +</body>
    1.41 + 
    1.42 +</html>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/scripts/CanvasMatrix.js	Thu Mar 31 23:53:48 2011 +0200
     2.3 @@ -0,0 +1,698 @@
     2.4 +/*
     2.5 +    CanvasMatrix4 class
     2.6 +    
     2.7 +    This class implements a 4x4 matrix. It has functions which
     2.8 +    duplicate the functionality of the OpenGL matrix stack and
     2.9 +    glut functions.
    2.10 +    
    2.11 +    IDL:
    2.12 +    
    2.13 +    [
    2.14 +        Constructor(in CanvasMatrix4 matrix),           // copy passed matrix into new CanvasMatrix4
    2.15 +        Constructor(in sequence<float> array)           // create new CanvasMatrix4 with 16 floats (row major)
    2.16 +        Constructor()                                   // create new CanvasMatrix4 with identity matrix
    2.17 +    ]
    2.18 +    interface CanvasMatrix4 {
    2.19 +        attribute float m11;
    2.20 +        attribute float m12;
    2.21 +        attribute float m13;
    2.22 +        attribute float m14;
    2.23 +        attribute float m21;
    2.24 +        attribute float m22;
    2.25 +        attribute float m23;
    2.26 +        attribute float m24;
    2.27 +        attribute float m31;
    2.28 +        attribute float m32;
    2.29 +        attribute float m33;
    2.30 +        attribute float m34;
    2.31 +        attribute float m41;
    2.32 +        attribute float m42;
    2.33 +        attribute float m43;
    2.34 +        attribute float m44;
    2.35 +
    2.36 +        void load(in CanvasMatrix4 matrix);                 // copy the values from the passed matrix
    2.37 +        void load(in sequence<float> array);                // copy 16 floats into the matrix
    2.38 +        sequence<float> getAsArray();                       // return the matrix as an array of 16 floats
    2.39 +        WebGLFloatArray getAsCanvasFloatArray();           // return the matrix as a WebGLFloatArray with 16 values
    2.40 +        void makeIdentity();                                // replace the matrix with identity
    2.41 +        void transpose();                                   // replace the matrix with its transpose
    2.42 +        void invert();                                      // replace the matrix with its inverse
    2.43 +        
    2.44 +        void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right
    2.45 +        void scale(in float x, in float y, in float z);     // multiply the matrix by passed scale values on the right
    2.46 +        void rotate(in float angle,                         // multiply the matrix by passed rotation values on the right
    2.47 +                    in float x, in float y, in float z);    // (angle is in degrees)
    2.48 +        void multRight(in CanvasMatrix matrix);             // multiply the matrix by the passed matrix on the right
    2.49 +        void multLeft(in CanvasMatrix matrix);              // multiply the matrix by the passed matrix on the left
    2.50 +        void ortho(in float left, in float right,           // multiply the matrix by the passed ortho values on the right
    2.51 +                   in float bottom, in float top, 
    2.52 +                   in float near, in float far);
    2.53 +        void frustum(in float left, in float right,         // multiply the matrix by the passed frustum values on the right
    2.54 +                     in float bottom, in float top, 
    2.55 +                     in float near, in float far);
    2.56 +        void perspective(in float fovy, in float aspect,    // multiply the matrix by the passed perspective values on the right
    2.57 +                         in float zNear, in float zFar);
    2.58 +        void lookat(in float eyex, in float eyey, in float eyez,    // multiply the matrix by the passed lookat 
    2.59 +                    in float ctrx, in float ctry, in float ctrz,    // values on the right
    2.60 +                    in float upx, in float upy, in float upz);
    2.61 +    }
    2.62 +*/
    2.63 +
    2.64 +CanvasMatrix4 = function(m)
    2.65 +{
    2.66 +    if (typeof m == 'object') {
    2.67 +        if ("length" in m && m.length >= 16) {
    2.68 +            this.load(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]);
    2.69 +            return;
    2.70 +        }
    2.71 +        else if (m instanceof CanvasMatrix4) {
    2.72 +            this.load(m);
    2.73 +            return;
    2.74 +        }
    2.75 +    }
    2.76 +    this.makeIdentity();
    2.77 +}
    2.78 +
    2.79 +CanvasMatrix4.prototype.load = function()
    2.80 +{
    2.81 +    if (arguments.length == 1 && typeof arguments[0] == 'object') {
    2.82 +        var matrix = arguments[0];
    2.83 +        
    2.84 +        if ("length" in matrix && matrix.length == 16) {
    2.85 +            this.m11 = matrix[0];
    2.86 +            this.m12 = matrix[1];
    2.87 +            this.m13 = matrix[2];
    2.88 +            this.m14 = matrix[3];
    2.89 +
    2.90 +            this.m21 = matrix[4];
    2.91 +            this.m22 = matrix[5];
    2.92 +            this.m23 = matrix[6];
    2.93 +            this.m24 = matrix[7];
    2.94 +
    2.95 +            this.m31 = matrix[8];
    2.96 +            this.m32 = matrix[9];
    2.97 +            this.m33 = matrix[10];
    2.98 +            this.m34 = matrix[11];
    2.99 +
   2.100 +            this.m41 = matrix[12];
   2.101 +            this.m42 = matrix[13];
   2.102 +            this.m43 = matrix[14];
   2.103 +            this.m44 = matrix[15];
   2.104 +            return;
   2.105 +        }
   2.106 +            
   2.107 +        if (arguments[0] instanceof CanvasMatrix4) {
   2.108 +        
   2.109 +            this.m11 = matrix.m11;
   2.110 +            this.m12 = matrix.m12;
   2.111 +            this.m13 = matrix.m13;
   2.112 +            this.m14 = matrix.m14;
   2.113 +
   2.114 +            this.m21 = matrix.m21;
   2.115 +            this.m22 = matrix.m22;
   2.116 +            this.m23 = matrix.m23;
   2.117 +            this.m24 = matrix.m24;
   2.118 +
   2.119 +            this.m31 = matrix.m31;
   2.120 +            this.m32 = matrix.m32;
   2.121 +            this.m33 = matrix.m33;
   2.122 +            this.m34 = matrix.m34;
   2.123 +
   2.124 +            this.m41 = matrix.m41;
   2.125 +            this.m42 = matrix.m42;
   2.126 +            this.m43 = matrix.m43;
   2.127 +            this.m44 = matrix.m44;
   2.128 +            return;
   2.129 +        }
   2.130 +    }
   2.131 +    
   2.132 +    this.makeIdentity();
   2.133 +}
   2.134 +
   2.135 +CanvasMatrix4.prototype.getAsArray = function()
   2.136 +{
   2.137 +    return [
   2.138 +        this.m11, this.m12, this.m13, this.m14, 
   2.139 +        this.m21, this.m22, this.m23, this.m24, 
   2.140 +        this.m31, this.m32, this.m33, this.m34, 
   2.141 +        this.m41, this.m42, this.m43, this.m44
   2.142 +    ];
   2.143 +}
   2.144 +
   2.145 +CanvasMatrix4.prototype.getAsCanvasFloatArray = function()
   2.146 +{
   2.147 +    return new WebGLFloatArray(this.getAsArray());
   2.148 +}
   2.149 +
   2.150 +CanvasMatrix4.prototype.makeIdentity = function()
   2.151 +{
   2.152 +    this.m11 = 1;
   2.153 +    this.m12 = 0;
   2.154 +    this.m13 = 0;
   2.155 +    this.m14 = 0;
   2.156 +    
   2.157 +    this.m21 = 0;
   2.158 +    this.m22 = 1;
   2.159 +    this.m23 = 0;
   2.160 +    this.m24 = 0;
   2.161 +    
   2.162 +    this.m31 = 0;
   2.163 +    this.m32 = 0;
   2.164 +    this.m33 = 1;
   2.165 +    this.m34 = 0;
   2.166 +    
   2.167 +    this.m41 = 0;
   2.168 +    this.m42 = 0;
   2.169 +    this.m43 = 0;
   2.170 +    this.m44 = 1;
   2.171 +}
   2.172 +
   2.173 +CanvasMatrix4.prototype.transpose = function()
   2.174 +{
   2.175 +    var tmp = this.m12;
   2.176 +    this.m12 = this.m21;
   2.177 +    this.m21 = tmp;
   2.178 +    
   2.179 +    tmp = this.m13;
   2.180 +    this.m13 = this.m31;
   2.181 +    this.m31 = tmp;
   2.182 +    
   2.183 +    tmp = this.m14;
   2.184 +    this.m14 = this.m41;
   2.185 +    this.m41 = tmp;
   2.186 +    
   2.187 +    tmp = this.m23;
   2.188 +    this.m23 = this.m32;
   2.189 +    this.m32 = tmp;
   2.190 +    
   2.191 +    tmp = this.m24;
   2.192 +    this.m24 = this.m42;
   2.193 +    this.m42 = tmp;
   2.194 +    
   2.195 +    tmp = this.m34;
   2.196 +    this.m34 = this.m43;
   2.197 +    this.m43 = tmp;
   2.198 +}
   2.199 +
   2.200 +CanvasMatrix4.prototype.invert = function()
   2.201 +{
   2.202 +    // Calculate the 4x4 determinant
   2.203 +    // If the determinant is zero, 
   2.204 +    // then the inverse matrix is not unique.
   2.205 +    var det = this._determinant4x4();
   2.206 +
   2.207 +    if (Math.abs(det) < 1e-8)
   2.208 +        return null;
   2.209 +
   2.210 +    this._makeAdjoint();
   2.211 +
   2.212 +    // Scale the adjoint matrix to get the inverse
   2.213 +    this.m11 /= det;
   2.214 +    this.m12 /= det;
   2.215 +    this.m13 /= det;
   2.216 +    this.m14 /= det;
   2.217 +    
   2.218 +    this.m21 /= det;
   2.219 +    this.m22 /= det;
   2.220 +    this.m23 /= det;
   2.221 +    this.m24 /= det;
   2.222 +    
   2.223 +    this.m31 /= det;
   2.224 +    this.m32 /= det;
   2.225 +    this.m33 /= det;
   2.226 +    this.m34 /= det;
   2.227 +    
   2.228 +    this.m41 /= det;
   2.229 +    this.m42 /= det;
   2.230 +    this.m43 /= det;
   2.231 +    this.m44 /= det;
   2.232 +}
   2.233 +
   2.234 +CanvasMatrix4.prototype.translate = function(x,y,z)
   2.235 +{
   2.236 +    if (x == undefined)
   2.237 +        x = 0;
   2.238 +        if (y == undefined)
   2.239 +            y = 0;
   2.240 +    if (z == undefined)
   2.241 +        z = 0;
   2.242 +    
   2.243 +    var matrix = new CanvasMatrix4();
   2.244 +    matrix.m41 = x;
   2.245 +    matrix.m42 = y;
   2.246 +    matrix.m43 = z;
   2.247 +
   2.248 +    this.multRight(matrix);
   2.249 +}
   2.250 +
   2.251 +CanvasMatrix4.prototype.scale = function(x,y,z)
   2.252 +{
   2.253 +    if (x == undefined)
   2.254 +        x = 1;
   2.255 +    if (z == undefined) {
   2.256 +        if (y == undefined) {
   2.257 +            y = x;
   2.258 +            z = x;
   2.259 +        }
   2.260 +        else
   2.261 +            z = 1;
   2.262 +    }
   2.263 +    else if (y == undefined)
   2.264 +        y = x;
   2.265 +    
   2.266 +    var matrix = new CanvasMatrix4();
   2.267 +    matrix.m11 = x;
   2.268 +    matrix.m22 = y;
   2.269 +    matrix.m33 = z;
   2.270 +    
   2.271 +    this.multRight(matrix);
   2.272 +}
   2.273 +
   2.274 +CanvasMatrix4.prototype.rotate = function(angle,x,y,z)
   2.275 +{
   2.276 +    // angles are in degrees. Switch to radians
   2.277 +    angle = angle / 180 * Math.PI;
   2.278 +    
   2.279 +    angle /= 2;
   2.280 +    var sinA = Math.sin(angle);
   2.281 +    var cosA = Math.cos(angle);
   2.282 +    var sinA2 = sinA * sinA;
   2.283 +    
   2.284 +    // normalize
   2.285 +    var length = Math.sqrt(x * x + y * y + z * z);
   2.286 +    if (length == 0) {
   2.287 +        // bad vector, just use something reasonable
   2.288 +        x = 0;
   2.289 +        y = 0;
   2.290 +        z = 1;
   2.291 +    } else if (length != 1) {
   2.292 +        x /= length;
   2.293 +        y /= length;
   2.294 +        z /= length;
   2.295 +    }
   2.296 +    
   2.297 +    var mat = new CanvasMatrix4();
   2.298 +
   2.299 +    // optimize case where axis is along major axis
   2.300 +    if (x == 1 && y == 0 && z == 0) {
   2.301 +        mat.m11 = 1;
   2.302 +        mat.m12 = 0;
   2.303 +        mat.m13 = 0;
   2.304 +        mat.m21 = 0;
   2.305 +        mat.m22 = 1 - 2 * sinA2;
   2.306 +        mat.m23 = 2 * sinA * cosA;
   2.307 +        mat.m31 = 0;
   2.308 +        mat.m32 = -2 * sinA * cosA;
   2.309 +        mat.m33 = 1 - 2 * sinA2;
   2.310 +        mat.m14 = mat.m24 = mat.m34 = 0;
   2.311 +        mat.m41 = mat.m42 = mat.m43 = 0;
   2.312 +        mat.m44 = 1;
   2.313 +    } else if (x == 0 && y == 1 && z == 0) {
   2.314 +        mat.m11 = 1 - 2 * sinA2;
   2.315 +        mat.m12 = 0;
   2.316 +        mat.m13 = -2 * sinA * cosA;
   2.317 +        mat.m21 = 0;
   2.318 +        mat.m22 = 1;
   2.319 +        mat.m23 = 0;
   2.320 +        mat.m31 = 2 * sinA * cosA;
   2.321 +        mat.m32 = 0;
   2.322 +        mat.m33 = 1 - 2 * sinA2;
   2.323 +        mat.m14 = mat.m24 = mat.m34 = 0;
   2.324 +        mat.m41 = mat.m42 = mat.m43 = 0;
   2.325 +        mat.m44 = 1;
   2.326 +    } else if (x == 0 && y == 0 && z == 1) {
   2.327 +        mat.m11 = 1 - 2 * sinA2;
   2.328 +        mat.m12 = 2 * sinA * cosA;
   2.329 +        mat.m13 = 0;
   2.330 +        mat.m21 = -2 * sinA * cosA;
   2.331 +        mat.m22 = 1 - 2 * sinA2;
   2.332 +        mat.m23 = 0;
   2.333 +        mat.m31 = 0;
   2.334 +        mat.m32 = 0;
   2.335 +        mat.m33 = 1;
   2.336 +        mat.m14 = mat.m24 = mat.m34 = 0;
   2.337 +        mat.m41 = mat.m42 = mat.m43 = 0;
   2.338 +        mat.m44 = 1;
   2.339 +    } else {
   2.340 +        var x2 = x*x;
   2.341 +        var y2 = y*y;
   2.342 +        var z2 = z*z;
   2.343 +    
   2.344 +        mat.m11 = 1 - 2 * (y2 + z2) * sinA2;
   2.345 +        mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA);
   2.346 +        mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA);
   2.347 +        mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA);
   2.348 +        mat.m22 = 1 - 2 * (z2 + x2) * sinA2;
   2.349 +        mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA);
   2.350 +        mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA);
   2.351 +        mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA);
   2.352 +        mat.m33 = 1 - 2 * (x2 + y2) * sinA2;
   2.353 +        mat.m14 = mat.m24 = mat.m34 = 0;
   2.354 +        mat.m41 = mat.m42 = mat.m43 = 0;
   2.355 +        mat.m44 = 1;
   2.356 +    }
   2.357 +    this.multRight(mat);
   2.358 +}
   2.359 +
   2.360 +CanvasMatrix4.prototype.multRight = function(mat)
   2.361 +{
   2.362 +    var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21
   2.363 +               + this.m13 * mat.m31 + this.m14 * mat.m41);
   2.364 +    var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22
   2.365 +               + this.m13 * mat.m32 + this.m14 * mat.m42);
   2.366 +    var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23
   2.367 +               + this.m13 * mat.m33 + this.m14 * mat.m43);
   2.368 +    var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24
   2.369 +               + this.m13 * mat.m34 + this.m14 * mat.m44);
   2.370 +
   2.371 +    var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21
   2.372 +               + this.m23 * mat.m31 + this.m24 * mat.m41);
   2.373 +    var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22
   2.374 +               + this.m23 * mat.m32 + this.m24 * mat.m42);
   2.375 +    var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23
   2.376 +               + this.m23 * mat.m33 + this.m24 * mat.m43);
   2.377 +    var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24
   2.378 +               + this.m23 * mat.m34 + this.m24 * mat.m44);
   2.379 +
   2.380 +    var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21
   2.381 +               + this.m33 * mat.m31 + this.m34 * mat.m41);
   2.382 +    var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22
   2.383 +               + this.m33 * mat.m32 + this.m34 * mat.m42);
   2.384 +    var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23
   2.385 +               + this.m33 * mat.m33 + this.m34 * mat.m43);
   2.386 +    var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24
   2.387 +               + this.m33 * mat.m34 + this.m34 * mat.m44);
   2.388 +
   2.389 +    var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21
   2.390 +               + this.m43 * mat.m31 + this.m44 * mat.m41);
   2.391 +    var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22
   2.392 +               + this.m43 * mat.m32 + this.m44 * mat.m42);
   2.393 +    var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23
   2.394 +               + this.m43 * mat.m33 + this.m44 * mat.m43);
   2.395 +    var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24
   2.396 +               + this.m43 * mat.m34 + this.m44 * mat.m44);
   2.397 +    
   2.398 +    this.m11 = m11;
   2.399 +    this.m12 = m12;
   2.400 +    this.m13 = m13;
   2.401 +    this.m14 = m14;
   2.402 +    
   2.403 +    this.m21 = m21;
   2.404 +    this.m22 = m22;
   2.405 +    this.m23 = m23;
   2.406 +    this.m24 = m24;
   2.407 +    
   2.408 +    this.m31 = m31;
   2.409 +    this.m32 = m32;
   2.410 +    this.m33 = m33;
   2.411 +    this.m34 = m34;
   2.412 +    
   2.413 +    this.m41 = m41;
   2.414 +    this.m42 = m42;
   2.415 +    this.m43 = m43;
   2.416 +    this.m44 = m44;
   2.417 +}
   2.418 +
   2.419 +CanvasMatrix4.prototype.multLeft = function(mat)
   2.420 +{
   2.421 +    var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21
   2.422 +               + mat.m13 * this.m31 + mat.m14 * this.m41);
   2.423 +    var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22
   2.424 +               + mat.m13 * this.m32 + mat.m14 * this.m42);
   2.425 +    var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23
   2.426 +               + mat.m13 * this.m33 + mat.m14 * this.m43);
   2.427 +    var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24
   2.428 +               + mat.m13 * this.m34 + mat.m14 * this.m44);
   2.429 +
   2.430 +    var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21
   2.431 +               + mat.m23 * this.m31 + mat.m24 * this.m41);
   2.432 +    var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22
   2.433 +               + mat.m23 * this.m32 + mat.m24 * this.m42);
   2.434 +    var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23
   2.435 +               + mat.m23 * this.m33 + mat.m24 * this.m43);
   2.436 +    var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24
   2.437 +               + mat.m23 * this.m34 + mat.m24 * this.m44);
   2.438 +
   2.439 +    var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21
   2.440 +               + mat.m33 * this.m31 + mat.m34 * this.m41);
   2.441 +    var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22
   2.442 +               + mat.m33 * this.m32 + mat.m34 * this.m42);
   2.443 +    var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23
   2.444 +               + mat.m33 * this.m33 + mat.m34 * this.m43);
   2.445 +    var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24
   2.446 +               + mat.m33 * this.m34 + mat.m34 * this.m44);
   2.447 +
   2.448 +    var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21
   2.449 +               + mat.m43 * this.m31 + mat.m44 * this.m41);
   2.450 +    var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22
   2.451 +               + mat.m43 * this.m32 + mat.m44 * this.m42);
   2.452 +    var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23
   2.453 +               + mat.m43 * this.m33 + mat.m44 * this.m43);
   2.454 +    var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24
   2.455 +               + mat.m43 * this.m34 + mat.m44 * this.m44);
   2.456 +    
   2.457 +    this.m11 = m11;
   2.458 +    this.m12 = m12;
   2.459 +    this.m13 = m13;
   2.460 +    this.m14 = m14;
   2.461 +
   2.462 +    this.m21 = m21;
   2.463 +    this.m22 = m22;
   2.464 +    this.m23 = m23;
   2.465 +    this.m24 = m24;
   2.466 +
   2.467 +    this.m31 = m31;
   2.468 +    this.m32 = m32;
   2.469 +    this.m33 = m33;
   2.470 +    this.m34 = m34;
   2.471 +
   2.472 +    this.m41 = m41;
   2.473 +    this.m42 = m42;
   2.474 +    this.m43 = m43;
   2.475 +    this.m44 = m44;
   2.476 +}
   2.477 +
   2.478 +CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far)
   2.479 +{
   2.480 +    var tx = (left + right) / (left - right);
   2.481 +    var ty = (top + bottom) / (top - bottom);
   2.482 +    var tz = (far + near) / (far - near);
   2.483 +    
   2.484 +    var matrix = new CanvasMatrix4();
   2.485 +    matrix.m11 = 2 / (left - right);
   2.486 +    matrix.m12 = 0;
   2.487 +    matrix.m13 = 0;
   2.488 +    matrix.m14 = 0;
   2.489 +    matrix.m21 = 0;
   2.490 +    matrix.m22 = 2 / (top - bottom);
   2.491 +    matrix.m23 = 0;
   2.492 +    matrix.m24 = 0;
   2.493 +    matrix.m31 = 0;
   2.494 +    matrix.m32 = 0;
   2.495 +    matrix.m33 = -2 / (far - near);
   2.496 +    matrix.m34 = 0;
   2.497 +    matrix.m41 = tx;
   2.498 +    matrix.m42 = ty;
   2.499 +    matrix.m43 = tz;
   2.500 +    matrix.m44 = 1;
   2.501 +    
   2.502 +    this.multRight(matrix);
   2.503 +}
   2.504 +
   2.505 +CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far)
   2.506 +{
   2.507 +    var matrix = new CanvasMatrix4();
   2.508 +    var A = (right + left) / (right - left);
   2.509 +    var B = (top + bottom) / (top - bottom);
   2.510 +    var C = -(far + near) / (far - near);
   2.511 +    var D = -(2 * far * near) / (far - near);
   2.512 +    
   2.513 +    matrix.m11 = (2 * near) / (right - left);
   2.514 +    matrix.m12 = 0;
   2.515 +    matrix.m13 = 0;
   2.516 +    matrix.m14 = 0;
   2.517 +    
   2.518 +    matrix.m21 = 0;
   2.519 +    matrix.m22 = 2 * near / (top - bottom);
   2.520 +    matrix.m23 = 0;
   2.521 +    matrix.m24 = 0;
   2.522 +    
   2.523 +    matrix.m31 = A;
   2.524 +    matrix.m32 = B;
   2.525 +    matrix.m33 = C;
   2.526 +    matrix.m34 = -1;
   2.527 +    
   2.528 +    matrix.m41 = 0;
   2.529 +    matrix.m42 = 0;
   2.530 +    matrix.m43 = D;
   2.531 +    matrix.m44 = 0;
   2.532 +    
   2.533 +    this.multRight(matrix);
   2.534 +}
   2.535 +
   2.536 +CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar)
   2.537 +{
   2.538 +    var top = Math.tan(fovy * Math.PI / 360) * zNear;
   2.539 +    var bottom = -top;
   2.540 +    var left = aspect * bottom;
   2.541 +    var right = aspect * top;
   2.542 +    this.frustum(left, right, bottom, top, zNear, zFar);
   2.543 +}
   2.544 +
   2.545 +CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
   2.546 +{
   2.547 +    var matrix = new CanvasMatrix4();
   2.548 +    
   2.549 +    // Make rotation matrix
   2.550 +
   2.551 +    // Z vector
   2.552 +    var zx = eyex - centerx;
   2.553 +    var zy = eyey - centery;
   2.554 +    var zz = eyez - centerz;
   2.555 +    var mag = Math.sqrt(zx * zx + zy * zy + zz * zz);
   2.556 +    if (mag) {
   2.557 +        zx /= mag;
   2.558 +        zy /= mag;
   2.559 +        zz /= mag;
   2.560 +    }
   2.561 +
   2.562 +    // Y vector
   2.563 +    var yx = upx;
   2.564 +    var yy = upy;
   2.565 +    var yz = upz;
   2.566 +
   2.567 +    // X vector = Y cross Z
   2.568 +    xx =  yy * zz - yz * zy;
   2.569 +    xy = -yx * zz + yz * zx;
   2.570 +    xz =  yx * zy - yy * zx;
   2.571 +
   2.572 +    // Recompute Y = Z cross X
   2.573 +    yx = zy * xz - zz * xy;
   2.574 +    yy = -zx * xz + zz * xx;
   2.575 +    yx = zx * xy - zy * xx;
   2.576 +
   2.577 +    // cross product gives area of parallelogram, which is < 1.0 for
   2.578 +    // non-perpendicular unit-length vectors; so normalize x, y here
   2.579 +
   2.580 +    mag = Math.sqrt(xx * xx + xy * xy + xz * xz);
   2.581 +    if (mag) {
   2.582 +        xx /= mag;
   2.583 +        xy /= mag;
   2.584 +        xz /= mag;
   2.585 +    }
   2.586 +
   2.587 +    mag = Math.sqrt(yx * yx + yy * yy + yz * yz);
   2.588 +    if (mag) {
   2.589 +        yx /= mag;
   2.590 +        yy /= mag;
   2.591 +        yz /= mag;
   2.592 +    }
   2.593 +
   2.594 +    matrix.m11 = xx;
   2.595 +    matrix.m12 = xy;
   2.596 +    matrix.m13 = xz;
   2.597 +    matrix.m14 = 0;
   2.598 +    
   2.599 +    matrix.m21 = yx;
   2.600 +    matrix.m22 = yy;
   2.601 +    matrix.m23 = yz;
   2.602 +    matrix.m24 = 0;
   2.603 +    
   2.604 +    matrix.m31 = zx;
   2.605 +    matrix.m32 = zy;
   2.606 +    matrix.m33 = zz;
   2.607 +    matrix.m34 = 0;
   2.608 +    
   2.609 +    matrix.m41 = 0;
   2.610 +    matrix.m42 = 0;
   2.611 +    matrix.m43 = 0;
   2.612 +    matrix.m44 = 1;
   2.613 +    matrix.translate(-eyex, -eyey, -eyez);
   2.614 +    
   2.615 +    this.multRight(matrix);
   2.616 +}
   2.617 +
   2.618 +// Support functions
   2.619 +CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d)
   2.620 +{
   2.621 +    return a * d - b * c;
   2.622 +}
   2.623 +
   2.624 +CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3)
   2.625 +{
   2.626 +    return a1 * this._determinant2x2(b2, b3, c2, c3)
   2.627 +         - b1 * this._determinant2x2(a2, a3, c2, c3)
   2.628 +         + c1 * this._determinant2x2(a2, a3, b2, b3);
   2.629 +}
   2.630 +
   2.631 +CanvasMatrix4.prototype._determinant4x4 = function()
   2.632 +{
   2.633 +    var a1 = this.m11;
   2.634 +    var b1 = this.m12; 
   2.635 +    var c1 = this.m13;
   2.636 +    var d1 = this.m14;
   2.637 +
   2.638 +    var a2 = this.m21;
   2.639 +    var b2 = this.m22; 
   2.640 +    var c2 = this.m23;
   2.641 +    var d2 = this.m24;
   2.642 +
   2.643 +    var a3 = this.m31;
   2.644 +    var b3 = this.m32; 
   2.645 +    var c3 = this.m33;
   2.646 +    var d3 = this.m34;
   2.647 +
   2.648 +    var a4 = this.m41;
   2.649 +    var b4 = this.m42; 
   2.650 +    var c4 = this.m43;
   2.651 +    var d4 = this.m44;
   2.652 +
   2.653 +    return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
   2.654 +         - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
   2.655 +         + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
   2.656 +         - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
   2.657 +}
   2.658 +
   2.659 +CanvasMatrix4.prototype._makeAdjoint = function()
   2.660 +{
   2.661 +    var a1 = this.m11;
   2.662 +    var b1 = this.m12; 
   2.663 +    var c1 = this.m13;
   2.664 +    var d1 = this.m14;
   2.665 +
   2.666 +    var a2 = this.m21;
   2.667 +    var b2 = this.m22; 
   2.668 +    var c2 = this.m23;
   2.669 +    var d2 = this.m24;
   2.670 +
   2.671 +    var a3 = this.m31;
   2.672 +    var b3 = this.m32; 
   2.673 +    var c3 = this.m33;
   2.674 +    var d3 = this.m34;
   2.675 +
   2.676 +    var a4 = this.m41;
   2.677 +    var b4 = this.m42; 
   2.678 +    var c4 = this.m43;
   2.679 +    var d4 = this.m44;
   2.680 +
   2.681 +    // Row column labeling reversed since we transpose rows & columns
   2.682 +    this.m11  =   this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
   2.683 +    this.m21  = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
   2.684 +    this.m31  =   this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
   2.685 +    this.m41  = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
   2.686 +        
   2.687 +    this.m12  = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
   2.688 +    this.m22  =   this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
   2.689 +    this.m32  = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
   2.690 +    this.m42  =   this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
   2.691 +        
   2.692 +    this.m13  =   this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
   2.693 +    this.m23  = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
   2.694 +    this.m33  =   this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
   2.695 +    this.m43  = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
   2.696 +        
   2.697 +    this.m14  = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
   2.698 +    this.m24  =   this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
   2.699 +    this.m34  = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
   2.700 +    this.m44  =   this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
   2.701 +}
   2.702 \ No newline at end of file
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/scripts/glMatrix.js	Thu Mar 31 23:53:48 2011 +0200
     3.3 @@ -0,0 +1,32 @@
     3.4 +// glMatrix v0.9.5
     3.5 +glMatrixArrayType=typeof Float32Array!="undefined"?Float32Array:typeof WebGLFloatArray!="undefined"?WebGLFloatArray:Array;var vec3={};vec3.create=function(a){var b=new glMatrixArrayType(3);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2]}return b};vec3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];return b};vec3.add=function(a,b,c){if(!c||a==c){a[0]+=b[0];a[1]+=b[1];a[2]+=b[2];return a}c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];return c};
     3.6 +vec3.subtract=function(a,b,c){if(!c||a==c){a[0]-=b[0];a[1]-=b[1];a[2]-=b[2];return a}c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];return c};vec3.negate=function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];return b};vec3.scale=function(a,b,c){if(!c||a==c){a[0]*=b;a[1]*=b;a[2]*=b;return a}c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;return c};
     3.7 +vec3.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=Math.sqrt(c*c+d*d+e*e);if(g){if(g==1){b[0]=c;b[1]=d;b[2]=e;return b}}else{b[0]=0;b[1]=0;b[2]=0;return b}g=1/g;b[0]=c*g;b[1]=d*g;b[2]=e*g;return b};vec3.cross=function(a,b,c){c||(c=a);var d=a[0],e=a[1];a=a[2];var g=b[0],f=b[1];b=b[2];c[0]=e*b-a*f;c[1]=a*g-d*b;c[2]=d*f-e*g;return c};vec3.length=function(a){var b=a[0],c=a[1];a=a[2];return Math.sqrt(b*b+c*c+a*a)};vec3.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]};
     3.8 +vec3.direction=function(a,b,c){c||(c=a);var d=a[0]-b[0],e=a[1]-b[1];a=a[2]-b[2];b=Math.sqrt(d*d+e*e+a*a);if(!b){c[0]=0;c[1]=0;c[2]=0;return c}b=1/b;c[0]=d*b;c[1]=e*b;c[2]=a*b;return c};vec3.lerp=function(a,b,c,d){d||(d=a);d[0]=a[0]+c*(b[0]-a[0]);d[1]=a[1]+c*(b[1]-a[1]);d[2]=a[2]+c*(b[2]-a[2]);return d};vec3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+"]"};var mat3={};
     3.9 +mat3.create=function(a){var b=new glMatrixArrayType(9);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9]}return b};mat3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return b};mat3.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a};
    3.10 +mat3.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[5];a[1]=a[3];a[2]=a[6];a[3]=c;a[5]=a[7];a[6]=d;a[7]=e;return a}b[0]=a[0];b[1]=a[3];b[2]=a[6];b[3]=a[1];b[4]=a[4];b[5]=a[7];b[6]=a[2];b[7]=a[5];b[8]=a[8];return b};mat3.toMat4=function(a,b){b||(b=mat4.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=0;b[4]=a[3];b[5]=a[4];b[6]=a[5];b[7]=0;b[8]=a[6];b[9]=a[7];b[10]=a[8];b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};
    3.11 +mat3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+"]"};var mat4={};mat4.create=function(a){var b=new glMatrixArrayType(16);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15]}return b};
    3.12 +mat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return b};mat4.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a};
    3.13 +mat4.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[3],g=a[6],f=a[7],h=a[11];a[1]=a[4];a[2]=a[8];a[3]=a[12];a[4]=c;a[6]=a[9];a[7]=a[13];a[8]=d;a[9]=g;a[11]=a[14];a[12]=e;a[13]=f;a[14]=h;return a}b[0]=a[0];b[1]=a[4];b[2]=a[8];b[3]=a[12];b[4]=a[1];b[5]=a[5];b[6]=a[9];b[7]=a[13];b[8]=a[2];b[9]=a[6];b[10]=a[10];b[11]=a[14];b[12]=a[3];b[13]=a[7];b[14]=a[11];b[15]=a[15];return b};
    3.14 +mat4.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],g=a[4],f=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],o=a[11],m=a[12],n=a[13],p=a[14];a=a[15];return m*k*h*e-j*n*h*e-m*f*l*e+g*n*l*e+j*f*p*e-g*k*p*e-m*k*d*i+j*n*d*i+m*c*l*i-b*n*l*i-j*c*p*i+b*k*p*i+m*f*d*o-g*n*d*o-m*c*h*o+b*n*h*o+g*c*p*o-b*f*p*o-j*f*d*a+g*k*d*a+j*c*h*a-b*k*h*a-g*c*l*a+b*f*l*a};
    3.15 +mat4.inverse=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=a[4],h=a[5],i=a[6],j=a[7],k=a[8],l=a[9],o=a[10],m=a[11],n=a[12],p=a[13],r=a[14],s=a[15],A=c*h-d*f,B=c*i-e*f,t=c*j-g*f,u=d*i-e*h,v=d*j-g*h,w=e*j-g*i,x=k*p-l*n,y=k*r-o*n,z=k*s-m*n,C=l*r-o*p,D=l*s-m*p,E=o*s-m*r,q=1/(A*E-B*D+t*C+u*z-v*y+w*x);b[0]=(h*E-i*D+j*C)*q;b[1]=(-d*E+e*D-g*C)*q;b[2]=(p*w-r*v+s*u)*q;b[3]=(-l*w+o*v-m*u)*q;b[4]=(-f*E+i*z-j*y)*q;b[5]=(c*E-e*z+g*y)*q;b[6]=(-n*w+r*t-s*B)*q;b[7]=(k*w-o*t+m*B)*q;b[8]=(f*D-h*z+j*x)*q;
    3.16 +b[9]=(-c*D+d*z-g*x)*q;b[10]=(n*v-p*t+s*A)*q;b[11]=(-k*v+l*t-m*A)*q;b[12]=(-f*C+h*y-i*x)*q;b[13]=(c*C-d*y+e*x)*q;b[14]=(-n*u+p*B-r*A)*q;b[15]=(k*u-l*B+o*A)*q;return b};mat4.toRotationMat=function(a,b){b||(b=mat4.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};
    3.17 +mat4.toMat3=function(a,b){b||(b=mat3.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[4];b[4]=a[5];b[5]=a[6];b[6]=a[8];b[7]=a[9];b[8]=a[10];return b};mat4.toInverseMat3=function(a,b){var c=a[0],d=a[1],e=a[2],g=a[4],f=a[5],h=a[6],i=a[8],j=a[9],k=a[10],l=k*f-h*j,o=-k*g+h*i,m=j*g-f*i,n=c*l+d*o+e*m;if(!n)return null;n=1/n;b||(b=mat3.create());b[0]=l*n;b[1]=(-k*d+e*j)*n;b[2]=(h*d-e*f)*n;b[3]=o*n;b[4]=(k*c-e*i)*n;b[5]=(-h*c+e*g)*n;b[6]=m*n;b[7]=(-j*c+d*i)*n;b[8]=(f*c-d*g)*n;return b};
    3.18 +mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],f=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],o=a[9],m=a[10],n=a[11],p=a[12],r=a[13],s=a[14];a=a[15];var A=b[0],B=b[1],t=b[2],u=b[3],v=b[4],w=b[5],x=b[6],y=b[7],z=b[8],C=b[9],D=b[10],E=b[11],q=b[12],F=b[13],G=b[14];b=b[15];c[0]=A*d+B*h+t*l+u*p;c[1]=A*e+B*i+t*o+u*r;c[2]=A*g+B*j+t*m+u*s;c[3]=A*f+B*k+t*n+u*a;c[4]=v*d+w*h+x*l+y*p;c[5]=v*e+w*i+x*o+y*r;c[6]=v*g+w*j+x*m+y*s;c[7]=v*f+w*k+x*n+y*a;c[8]=z*d+C*h+D*l+E*p;c[9]=z*e+C*i+D*o+E*r;c[10]=z*
    3.19 +g+C*j+D*m+E*s;c[11]=z*f+C*k+D*n+E*a;c[12]=q*d+F*h+G*l+b*p;c[13]=q*e+F*i+G*o+b*r;c[14]=q*g+F*j+G*m+b*s;c[15]=q*f+F*k+G*n+b*a;return c};mat4.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1];b=b[2];c[0]=a[0]*d+a[4]*e+a[8]*b+a[12];c[1]=a[1]*d+a[5]*e+a[9]*b+a[13];c[2]=a[2]*d+a[6]*e+a[10]*b+a[14];return c};
    3.20 +mat4.multiplyVec4=function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2];b=b[3];c[0]=a[0]*d+a[4]*e+a[8]*g+a[12]*b;c[1]=a[1]*d+a[5]*e+a[9]*g+a[13]*b;c[2]=a[2]*d+a[6]*e+a[10]*g+a[14]*b;c[3]=a[3]*d+a[7]*e+a[11]*g+a[15]*b;return c};
    3.21 +mat4.translate=function(a,b,c){var d=b[0],e=b[1];b=b[2];if(!c||a==c){a[12]=a[0]*d+a[4]*e+a[8]*b+a[12];a[13]=a[1]*d+a[5]*e+a[9]*b+a[13];a[14]=a[2]*d+a[6]*e+a[10]*b+a[14];a[15]=a[3]*d+a[7]*e+a[11]*b+a[15];return a}var g=a[0],f=a[1],h=a[2],i=a[3],j=a[4],k=a[5],l=a[6],o=a[7],m=a[8],n=a[9],p=a[10],r=a[11];c[0]=g;c[1]=f;c[2]=h;c[3]=i;c[4]=j;c[5]=k;c[6]=l;c[7]=o;c[8]=m;c[9]=n;c[10]=p;c[11]=r;c[12]=g*d+j*e+m*b+a[12];c[13]=f*d+k*e+n*b+a[13];c[14]=h*d+l*e+p*b+a[14];c[15]=i*d+o*e+r*b+a[15];return c};
    3.22 +mat4.scale=function(a,b,c){var d=b[0],e=b[1];b=b[2];if(!c||a==c){a[0]*=d;a[1]*=d;a[2]*=d;a[3]*=d;a[4]*=e;a[5]*=e;a[6]*=e;a[7]*=e;a[8]*=b;a[9]*=b;a[10]*=b;a[11]*=b;return a}c[0]=a[0]*d;c[1]=a[1]*d;c[2]=a[2]*d;c[3]=a[3]*d;c[4]=a[4]*e;c[5]=a[5]*e;c[6]=a[6]*e;c[7]=a[7]*e;c[8]=a[8]*b;c[9]=a[9]*b;c[10]=a[10]*b;c[11]=a[11]*b;c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15];return c};
    3.23 +mat4.rotate=function(a,b,c,d){var e=c[0],g=c[1];c=c[2];var f=Math.sqrt(e*e+g*g+c*c);if(!f)return null;if(f!=1){f=1/f;e*=f;g*=f;c*=f}var h=Math.sin(b),i=Math.cos(b),j=1-i;b=a[0];f=a[1];var k=a[2],l=a[3],o=a[4],m=a[5],n=a[6],p=a[7],r=a[8],s=a[9],A=a[10],B=a[11],t=e*e*j+i,u=g*e*j+c*h,v=c*e*j-g*h,w=e*g*j-c*h,x=g*g*j+i,y=c*g*j+e*h,z=e*c*j+g*h;e=g*c*j-e*h;g=c*c*j+i;if(d){if(a!=d){d[12]=a[12];d[13]=a[13];d[14]=a[14];d[15]=a[15]}}else d=a;d[0]=b*t+o*u+r*v;d[1]=f*t+m*u+s*v;d[2]=k*t+n*u+A*v;d[3]=l*t+p*u+B*
    3.24 +v;d[4]=b*w+o*x+r*y;d[5]=f*w+m*x+s*y;d[6]=k*w+n*x+A*y;d[7]=l*w+p*x+B*y;d[8]=b*z+o*e+r*g;d[9]=f*z+m*e+s*g;d[10]=k*z+n*e+A*g;d[11]=l*z+p*e+B*g;return d};mat4.rotateX=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[4],g=a[5],f=a[6],h=a[7],i=a[8],j=a[9],k=a[10],l=a[11];if(c){if(a!=c){c[0]=a[0];c[1]=a[1];c[2]=a[2];c[3]=a[3];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[4]=e*b+i*d;c[5]=g*b+j*d;c[6]=f*b+k*d;c[7]=h*b+l*d;c[8]=e*-d+i*b;c[9]=g*-d+j*b;c[10]=f*-d+k*b;c[11]=h*-d+l*b;return c};
    3.25 +mat4.rotateY=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[0],g=a[1],f=a[2],h=a[3],i=a[8],j=a[9],k=a[10],l=a[11];if(c){if(a!=c){c[4]=a[4];c[5]=a[5];c[6]=a[6];c[7]=a[7];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[0]=e*b+i*-d;c[1]=g*b+j*-d;c[2]=f*b+k*-d;c[3]=h*b+l*-d;c[8]=e*d+i*b;c[9]=g*d+j*b;c[10]=f*d+k*b;c[11]=h*d+l*b;return c};
    3.26 +mat4.rotateZ=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[0],g=a[1],f=a[2],h=a[3],i=a[4],j=a[5],k=a[6],l=a[7];if(c){if(a!=c){c[8]=a[8];c[9]=a[9];c[10]=a[10];c[11]=a[11];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[0]=e*b+i*d;c[1]=g*b+j*d;c[2]=f*b+k*d;c[3]=h*b+l*d;c[4]=e*-d+i*b;c[5]=g*-d+j*b;c[6]=f*-d+k*b;c[7]=h*-d+l*b;return c};
    3.27 +mat4.frustum=function(a,b,c,d,e,g,f){f||(f=mat4.create());var h=b-a,i=d-c,j=g-e;f[0]=e*2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=e*2/i;f[6]=0;f[7]=0;f[8]=(b+a)/h;f[9]=(d+c)/i;f[10]=-(g+e)/j;f[11]=-1;f[12]=0;f[13]=0;f[14]=-(g*e*2)/j;f[15]=0;return f};mat4.perspective=function(a,b,c,d,e){a=c*Math.tan(a*Math.PI/360);b=a*b;return mat4.frustum(-b,b,-a,a,c,d,e)};
    3.28 +mat4.ortho=function(a,b,c,d,e,g,f){f||(f=mat4.create());var h=b-a,i=d-c,j=g-e;f[0]=2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=2/i;f[6]=0;f[7]=0;f[8]=0;f[9]=0;f[10]=-2/j;f[11]=0;f[12]=-(a+b)/h;f[13]=-(d+c)/i;f[14]=-(g+e)/j;f[15]=1;return f};
    3.29 +mat4.lookAt=function(a,b,c,d){d||(d=mat4.create());var e=a[0],g=a[1];a=a[2];var f=c[0],h=c[1],i=c[2];c=b[1];var j=b[2];if(e==b[0]&&g==c&&a==j)return mat4.identity(d);var k,l,o,m;c=e-b[0];j=g-b[1];b=a-b[2];m=1/Math.sqrt(c*c+j*j+b*b);c*=m;j*=m;b*=m;k=h*b-i*j;i=i*c-f*b;f=f*j-h*c;if(m=Math.sqrt(k*k+i*i+f*f)){m=1/m;k*=m;i*=m;f*=m}else f=i=k=0;h=j*f-b*i;l=b*k-c*f;o=c*i-j*k;if(m=Math.sqrt(h*h+l*l+o*o)){m=1/m;h*=m;l*=m;o*=m}else o=l=h=0;d[0]=k;d[1]=h;d[2]=c;d[3]=0;d[4]=i;d[5]=l;d[6]=j;d[7]=0;d[8]=f;d[9]=
    3.30 +o;d[10]=b;d[11]=0;d[12]=-(k*e+i*g+f*a);d[13]=-(h*e+l*g+o*a);d[14]=-(c*e+j*g+b*a);d[15]=1;return d};mat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", "+a[12]+", "+a[13]+", "+a[14]+", "+a[15]+"]"};quat4={};quat4.create=function(a){var b=new glMatrixArrayType(4);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3]}return b};quat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b};
    3.31 +quat4.calculateW=function(a,b){var c=a[0],d=a[1],e=a[2];if(!b||a==b){a[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e));return a}b[0]=c;b[1]=d;b[2]=e;b[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e));return b};quat4.inverse=function(a,b){if(!b||a==b){a[0]*=1;a[1]*=1;a[2]*=1;return a}b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];b[3]=a[3];return b};quat4.length=function(a){var b=a[0],c=a[1],d=a[2];a=a[3];return Math.sqrt(b*b+c*c+d*d+a*a)};
    3.32 +quat4.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=Math.sqrt(c*c+d*d+e*e+g*g);if(f==0){b[0]=0;b[1]=0;b[2]=0;b[3]=0;return b}f=1/f;b[0]=c*f;b[1]=d*f;b[2]=e*f;b[3]=g*f;return b};quat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2];a=a[3];var f=b[0],h=b[1],i=b[2];b=b[3];c[0]=d*b+a*f+e*i-g*h;c[1]=e*b+a*h+g*f-d*i;c[2]=g*b+a*i+d*h-e*f;c[3]=a*b-d*f-e*h-g*i;return c};
    3.33 +quat4.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2];b=a[0];var f=a[1],h=a[2];a=a[3];var i=a*d+f*g-h*e,j=a*e+h*d-b*g,k=a*g+b*e-f*d;d=-b*d-f*e-h*g;c[0]=i*a+d*-b+j*-h-k*-f;c[1]=j*a+d*-f+k*-b-i*-h;c[2]=k*a+d*-h+i*-f-j*-b;return c};quat4.toMat3=function(a,b){b||(b=mat3.create());var c=a[0],d=a[1],e=a[2],g=a[3],f=c+c,h=d+d,i=e+e,j=c*f,k=c*h;c=c*i;var l=d*h;d=d*i;e=e*i;f=g*f;h=g*h;g=g*i;b[0]=1-(l+e);b[1]=k-g;b[2]=c+h;b[3]=k+g;b[4]=1-(j+e);b[5]=d-f;b[6]=c-h;b[7]=d+f;b[8]=1-(j+l);return b};
    3.34 +quat4.toMat4=function(a,b){b||(b=mat4.create());var c=a[0],d=a[1],e=a[2],g=a[3],f=c+c,h=d+d,i=e+e,j=c*f,k=c*h;c=c*i;var l=d*h;d=d*i;e=e*i;f=g*f;h=g*h;g=g*i;b[0]=1-(l+e);b[1]=k-g;b[2]=c+h;b[3]=0;b[4]=k+g;b[5]=1-(j+e);b[6]=d-f;b[7]=0;b[8]=c-h;b[9]=d+f;b[10]=1-(j+l);b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};quat4.slerp=function(a,b,c,d){d||(d=a);var e=c;if(a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]<0)e=-1*c;d[0]=1-c*a[0]+e*b[0];d[1]=1-c*a[1]+e*b[1];d[2]=1-c*a[2]+e*b[2];d[3]=1-c*a[3]+e*b[3];return d};
    3.35 +quat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+"]"};
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/scripts/machine.js	Thu Mar 31 23:53:48 2011 +0200
     4.3 @@ -0,0 +1,129 @@
     4.4 +function main()
     4.5 +{
     4.6 +    var canvas = document.getElementById("machine");
     4.7 +    var context = new Context(canvas);
     4.8 +    var gl = context.gl;
     4.9 +    var object = new Box(1, context);
    4.10 +    context.object = object
    4.11 +    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    4.12 +    gl.enable(gl.DEPTH_TEST);
    4.13 +    draw(context);
    4.14 +}
    4.15 +
    4.16 +function Context(canvas)
    4.17 +{
    4.18 +    try 
    4.19 +    {
    4.20 +	this.gl = canvas.getContext("experimental-webgl");
    4.21 +	this.viewport = {'width': canvas.width,
    4.22 +			 'height': canvas.height};
    4.23 +    } 
    4.24 +    catch(e) 
    4.25 +    {
    4.26 +	alert(e);
    4.27 +    }
    4.28 +    if (!this.gl) alert("Failed: WebGL init.");
    4.29 +    this.mvMatrix = mat4.create();
    4.30 +    this.pMatrix = mat4.create();
    4.31 +    this.shader = new Shader(this);    
    4.32 +}
    4.33 +Context.prototype.updateMatrixUniforms = function()
    4.34 +{
    4.35 +    var gl = this.gl;
    4.36 +    var program = this.shader;
    4.37 +    var pMatrix = this.pMatrix;
    4.38 +    var mvMatrix = this.mvMatrix;
    4.39 +    gl.uniformMatrix4fv(program.pMatrixUniform, false, pMatrix);
    4.40 +    gl.uniformMatrix4fv(program.mvMatrixUniform, false, mvMatrix);
    4.41 +}
    4.42 +
    4.43 +function Shader(context)
    4.44 +{
    4.45 +    var gl = context.gl;
    4.46 +    var fragment = loadShader(gl, "shader-fs");
    4.47 +    var vertex = loadShader(gl, "shader-vs");
    4.48 +    this.program = gl.createProgram();
    4.49 +    gl.attachShader(this.program, vertex);
    4.50 +    gl.attachShader(this.program, fragment);
    4.51 +    gl.linkProgram(this.program);
    4.52 +
    4.53 +    if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
    4.54 +    {
    4.55 +	alert("Failed: Shader init.");
    4.56 +    }
    4.57 +
    4.58 +    gl.useProgram(this.program);
    4.59 +    this.vertexPosition = gl.getAttribLocation(this.program, "aVertexPosition");
    4.60 +    gl.enableVertexAttribArray(this.vertexPosition);
    4.61 +    this.pMatrixUniform = gl.getUniformLocation(this.program, "uPMatrix");
    4.62 +    this.mvMatrixUniform = gl.getUniformLocation(this.program, "uMVMatrix");
    4.63 +
    4.64 +    function loadShader(gl, id)
    4.65 +    {
    4.66 +	var script = document.getElementById(id);
    4.67 +	if (!script) return null;
    4.68 +	
    4.69 +	var str = "";
    4.70 +	var child = script.firstChild;
    4.71 +	while (child)
    4.72 +	{
    4.73 +	    if (child.nodeType == 3) str += child.textContent;
    4.74 +	    child = child.nextSibling;
    4.75 +	}
    4.76 +	
    4.77 +	var shader;
    4.78 +	var common = "x-shader/x-";
    4.79 +	if (script.type == common + "fragment") shader = gl.createShader(gl.FRAGMENT_SHADER);
    4.80 +	else if (script.type == common + "vertex") shader = gl.createShader(gl.VERTEX_SHADER);
    4.81 +	else return null;
    4.82 +
    4.83 +	gl.shaderSource(shader, str);
    4.84 +	gl.compileShader(shader);
    4.85 +
    4.86 +	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
    4.87 +        {
    4.88 +	    alert(gl.getShaderInfoLog(shader));
    4.89 +	    return null;
    4.90 +	}
    4.91 +
    4.92 +	return shader;
    4.93 +    }
    4.94 +}
    4.95 +
    4.96 +
    4.97 +function Box(size, context)
    4.98 +{
    4.99 +    var gl = context.gl;
   4.100 +    this.size = size || 1;
   4.101 +    this.buffer = gl.createBuffer();
   4.102 +    gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
   4.103 +    var vertices = [1.0, 1.0, 0.0,
   4.104 +		    -1.0, 1.0, 0.0,
   4.105 +		    1.0, -1.0, 0.0,
   4.106 +		    -1.0, -1.0, 0.0];
   4.107 +    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
   4.108 +    this.itemSize = 3;
   4.109 +    this.numItems = 4;
   4.110 +}
   4.111 +
   4.112 +function draw(context)
   4.113 +{
   4.114 +    var gl = context.gl;
   4.115 +    var viewport = context.viewport;
   4.116 +    var shader = context.shader;
   4.117 +    var mvMatrix = context.mvMatrix;
   4.118 +    var pMatrix = context.pMatrix;
   4.119 +    var object = context.object;
   4.120 +    gl.viewport(0, 0, viewport.width, viewport.height);
   4.121 +    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
   4.122 +    mat4.perspective(45, viewport.width / viewport.height, 0.1, 100.0, pMatrix);
   4.123 +    mat4.identity(mvMatrix);
   4.124 +    mat4.translate(mvMatrix, [0.0, 0.0, -7.0]);
   4.125 +    gl.bindBuffer(gl.ARRAY_BUFFER, object.buffer);
   4.126 +    gl.vertexAttribPointer(shader.vertexPosition, object.itemSize, gl.FLOAT, false, 0, 0);
   4.127 +    context.updateMatrixUniforms();
   4.128 +    //gl.uniformMatrix4fv(shader.pMatrixUniform, false, pMatrix);
   4.129 +    //gl.uniformMatrix4fv(shader.mvMatrixUniform, false, mvMatrix);
   4.130 +    gl.drawArrays(gl.TRIANGLE_STRIP, 0, object.numItems);
   4.131 +    return context;
   4.132 +}
   4.133 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/scripts/utils3d.js	Thu Mar 31 23:53:48 2011 +0200
     5.3 @@ -0,0 +1,530 @@
     5.4 +//
     5.5 +// initWebGL
     5.6 +//
     5.7 +// Initialize the Canvas element with the passed name as a WebGL object and return the
     5.8 +// WebGLRenderingContext. 
     5.9 +//
    5.10 +// Load shaders with the passed names and create a program with them. Return this program 
    5.11 +// in the 'program' property of the returned context.
    5.12 +//
    5.13 +// For each string in the passed attribs array, bind an attrib with that name at that index.
    5.14 +// Once the attribs are bound, link the program and then use it.
    5.15 +//
    5.16 +// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
    5.17 +// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
    5.18 +//
    5.19 +function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
    5.20 +{
    5.21 +    var canvas = document.getElementById(canvasName);
    5.22 +    var gl = canvas.getContext("webkit-3d");
    5.23 +
    5.24 +    // create our shaders
    5.25 +    var vertexShader = loadShader(gl, vshader);
    5.26 +    var fragmentShader = loadShader(gl, fshader);
    5.27 +
    5.28 +    if (!vertexShader || !fragmentShader)
    5.29 +        return null;
    5.30 +
    5.31 +    // Create the program object
    5.32 +    gl.program = gl.createProgram();
    5.33 +
    5.34 +    if (!gl.program)
    5.35 +        return null;
    5.36 +
    5.37 +    // Attach our two shaders to the program
    5.38 +    gl.attachShader (gl.program, vertexShader);
    5.39 +    gl.attachShader (gl.program, fragmentShader);
    5.40 +
    5.41 +    // Bind attributes
    5.42 +    for (var i in attribs)
    5.43 +        gl.bindAttribLocation (gl.program, i, attribs[i]);
    5.44 +
    5.45 +    // Link the program
    5.46 +    gl.linkProgram(gl.program);
    5.47 +
    5.48 +    // Check the link status
    5.49 +    var linked = gl.getProgrami(gl.program, gl.LINK_STATUS);
    5.50 +    if (!linked) {
    5.51 +        // something went wrong with the link
    5.52 +        var error = gl.getProgramInfoLog (gl.program);
    5.53 +        console.log("Error in program linking:"+error);
    5.54 +
    5.55 +        gl.deleteProgram(gl.program);
    5.56 +        gl.deleteProgram(fragmentShader);
    5.57 +        gl.deleteProgram(vertexShader);
    5.58 +
    5.59 +        return null;
    5.60 +    }
    5.61 +
    5.62 +    gl.useProgram(gl.program);
    5.63 +
    5.64 +    gl.clearColor (clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
    5.65 +    gl.clearDepth (clearDepth);
    5.66 +
    5.67 +    gl.enable(gl.DEPTH_TEST);
    5.68 +    gl.enable(gl.BLEND);
    5.69 +    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    5.70 +
    5.71 +    return gl;
    5.72 +}
    5.73 +
    5.74 +//
    5.75 +// loadShader
    5.76 +//
    5.77 +// 'shaderId' is the id of a <script> element containing the shader source string.
    5.78 +// Load this shader and return the WebGLShader object corresponding to it.
    5.79 +//
    5.80 +function loadShader(ctx, shaderId)
    5.81 +{
    5.82 +    var shaderScript = document.getElementById(shaderId);
    5.83 +    if (!shaderScript) {
    5.84 +        console.log("*** Error: shader script '"+shaderId+"' not found");
    5.85 +        return null;
    5.86 +    }
    5.87 +        
    5.88 +    if (shaderScript.type == "x-shader/x-vertex")
    5.89 +        var shaderType = ctx.VERTEX_SHADER;
    5.90 +    else if (shaderScript.type == "x-shader/x-fragment")
    5.91 +        var shaderType = ctx.FRAGMENT_SHADER;
    5.92 +    else {
    5.93 +        console.log("*** Error: shader script '"+shaderId+"' of undefined type '"+shaderScript.type+"'");       
    5.94 +        return null;
    5.95 +    }
    5.96 +
    5.97 +    // Create the shader object
    5.98 +    var shader = ctx.createShader(shaderType);
    5.99 +    if (shader == null) {
   5.100 +        console.log("*** Error: unable to create shader '"+shaderId+"'");       
   5.101 +        return null;
   5.102 +    }
   5.103 +
   5.104 +    // Load the shader source
   5.105 +    ctx.shaderSource(shader, shaderScript.text);
   5.106 +
   5.107 +    // Compile the shader
   5.108 +    ctx.compileShader(shader);
   5.109 +
   5.110 +    // Check the compile status
   5.111 +    var compiled = ctx.getShaderi(shader, ctx.COMPILE_STATUS);
   5.112 +    if (!compiled) {
   5.113 +        // Something went wrong during compilation; get the error
   5.114 +        var error = ctx.getShaderInfoLog(shader);
   5.115 +        console.log("*** Error compiling shader '"+shaderId+"':"+error);
   5.116 +        ctx.deleteShader(shader);
   5.117 +        return null;
   5.118 +    }
   5.119 +
   5.120 +    return shader;
   5.121 +}
   5.122 +
   5.123 +// 
   5.124 +// makeBox
   5.125 +//
   5.126 +// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
   5.127 +// Return an object with the following properties:
   5.128 +//
   5.129 +//  normalObject        WebGLBuffer object for normals
   5.130 +//  texCoordObject      WebGLBuffer object for texCoords
   5.131 +//  vertexObject        WebGLBuffer object for vertices
   5.132 +//  indexObject         WebGLBuffer object for indices
   5.133 +//  numIndices          The number of indices in the indexObject
   5.134 +// 
   5.135 +function makeBox(ctx)
   5.136 +{
   5.137 +    // box
   5.138 +    //    v6----- v5
   5.139 +    //   /|      /|
   5.140 +    //  v1------v0|
   5.141 +    //  | |     | |
   5.142 +    //  | |v7---|-|v4
   5.143 +    //  |/      |/
   5.144 +    //  v2------v3
   5.145 +    //
   5.146 +    // vertex coords array
   5.147 +    var vertices = new WebGLFloatArray(
   5.148 +        [  1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
   5.149 +           1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
   5.150 +           1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 top
   5.151 +          -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
   5.152 +          -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 bottom
   5.153 +           1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1 ]   // v4-v7-v6-v5 back
   5.154 +    );
   5.155 +
   5.156 +    // normal array
   5.157 +    var normals = new WebGLFloatArray(
   5.158 +        [  0, 0, 1,   0, 0, 1,   0, 0, 1,   0, 0, 1,     // v0-v1-v2-v3 front
   5.159 +           1, 0, 0,   1, 0, 0,   1, 0, 0,   1, 0, 0,     // v0-v3-v4-v5 right
   5.160 +           0, 1, 0,   0, 1, 0,   0, 1, 0,   0, 1, 0,     // v0-v5-v6-v1 top
   5.161 +          -1, 0, 0,  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,     // v1-v6-v7-v2 left
   5.162 +           0,-1, 0,   0,-1, 0,   0,-1, 0,   0,-1, 0,     // v7-v4-v3-v2 bottom
   5.163 +           0, 0,-1,   0, 0,-1,   0, 0,-1,   0, 0,-1 ]    // v4-v7-v6-v5 back
   5.164 +       );
   5.165 +
   5.166 +
   5.167 +    // texCoord array
   5.168 +    var texCoords = new WebGLFloatArray(
   5.169 +        [  1, 1,   0, 1,   0, 0,   1, 0,    // v0-v1-v2-v3 front
   5.170 +           0, 1,   0, 0,   1, 0,   1, 1,    // v0-v3-v4-v5 right
   5.171 +           1, 0,   1, 1,   0, 1,   0, 0,    // v0-v5-v6-v1 top
   5.172 +           1, 1,   0, 1,   0, 0,   1, 0,    // v1-v6-v7-v2 left
   5.173 +           0, 0,   1, 0,   1, 1,   0, 1,    // v7-v4-v3-v2 bottom
   5.174 +           0, 0,   1, 0,   1, 1,   0, 1 ]   // v4-v7-v6-v5 back
   5.175 +       );
   5.176 +
   5.177 +    // index array
   5.178 +    var indices = new WebGLUnsignedByteArray(
   5.179 +        [  0, 1, 2,   0, 2, 3,    // front
   5.180 +           4, 5, 6,   4, 6, 7,    // right
   5.181 +           8, 9,10,   8,10,11,    // top
   5.182 +          12,13,14,  12,14,15,    // left
   5.183 +          16,17,18,  16,18,19,    // bottom
   5.184 +          20,21,22,  20,22,23 ]   // back
   5.185 +      );
   5.186 +
   5.187 +    var retval = { };
   5.188 +    
   5.189 +    retval.normalObject = ctx.createBuffer();
   5.190 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
   5.191 +    ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
   5.192 +    
   5.193 +    retval.texCoordObject = ctx.createBuffer();
   5.194 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
   5.195 +    ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
   5.196 +
   5.197 +    retval.vertexObject = ctx.createBuffer();
   5.198 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
   5.199 +    ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
   5.200 +    
   5.201 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, 0);
   5.202 +
   5.203 +    retval.indexObject = ctx.createBuffer();
   5.204 +    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
   5.205 +    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
   5.206 +    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, 0);
   5.207 +    
   5.208 +    retval.numIndices = indices.length;
   5.209 +
   5.210 +    return retval;
   5.211 +}
   5.212 +
   5.213 +// 
   5.214 +// makeSphere
   5.215 +//
   5.216 +// Create a sphere with the passed number of latitude and longitude bands and the passed radius. 
   5.217 +// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
   5.218 +// Return an object with the following properties:
   5.219 +//
   5.220 +//  normalObject        WebGLBuffer object for normals
   5.221 +//  texCoordObject      WebGLBuffer object for texCoords
   5.222 +//  vertexObject        WebGLBuffer object for vertices
   5.223 +//  indexObject         WebGLBuffer object for indices
   5.224 +//  numIndices          The number of indices in the indexObject
   5.225 +// 
   5.226 +function makeSphere(ctx, radius, lats, longs)
   5.227 +{
   5.228 +    var geometryData = [ ];
   5.229 +    var normalData = [ ];
   5.230 +    var texCoordData = [ ];
   5.231 +    var indexData = [ ];
   5.232 +    
   5.233 +    for (var latNumber = 0; latNumber <= lats; ++latNumber) {
   5.234 +        for (var longNumber = 0; longNumber <= longs; ++longNumber) {
   5.235 +            var theta = latNumber * Math.PI / lats;
   5.236 +            var phi = longNumber * 2 * Math.PI / longs;
   5.237 +            var sinTheta = Math.sin(theta);
   5.238 +            var sinPhi = Math.sin(phi);
   5.239 +            var cosTheta = Math.cos(theta);
   5.240 +            var cosPhi = Math.cos(phi);
   5.241 +            
   5.242 +            var x = cosPhi * sinTheta;
   5.243 +            var y = cosTheta;
   5.244 +            var z = sinPhi * sinTheta;
   5.245 +            var u = 1-(longNumber/longs);
   5.246 +            var v = latNumber/lats;
   5.247 +            
   5.248 +            normalData.push(x);
   5.249 +            normalData.push(y);
   5.250 +            normalData.push(z);
   5.251 +            texCoordData.push(u);
   5.252 +            texCoordData.push(v);
   5.253 +            geometryData.push(radius * x);
   5.254 +            geometryData.push(radius * y);
   5.255 +            geometryData.push(radius * z);
   5.256 +        }
   5.257 +    }
   5.258 +    
   5.259 +    longs += 1;
   5.260 +    for (var latNumber = 0; latNumber < lats; ++latNumber) {
   5.261 +        for (var longNumber = 0; longNumber < longs; ++longNumber) {
   5.262 +            var first = (latNumber * longs) + (longNumber % longs);
   5.263 +            var second = first + longs;
   5.264 +            indexData.push(first);
   5.265 +            indexData.push(second);
   5.266 +            indexData.push(first+1);
   5.267 +
   5.268 +            indexData.push(second);
   5.269 +            indexData.push(second+1);
   5.270 +            indexData.push(first+1);
   5.271 +        }
   5.272 +    }
   5.273 +    
   5.274 +    var retval = { };
   5.275 +    
   5.276 +    retval.normalObject = ctx.createBuffer();
   5.277 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
   5.278 +    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(normalData), ctx.STATIC_DRAW);
   5.279 +
   5.280 +    retval.texCoordObject = ctx.createBuffer();
   5.281 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
   5.282 +    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(texCoordData), ctx.STATIC_DRAW);
   5.283 +
   5.284 +    retval.vertexObject = ctx.createBuffer();
   5.285 +    ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
   5.286 +    ctx.bufferData(ctx.ARRAY_BUFFER, new WebGLFloatArray(geometryData), ctx.STATIC_DRAW);
   5.287 +    
   5.288 +    retval.numIndices = indexData.length;
   5.289 +    retval.indexObject = ctx.createBuffer();
   5.290 +    ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
   5.291 +    ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexData), ctx.STREAM_DRAW);
   5.292 +    
   5.293 +    return retval;
   5.294 +}
   5.295 +
   5.296 +//
   5.297 +// loadObj
   5.298 +//
   5.299 +// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
   5.300 +// When the object load is complete, the 'loaded' property becomes true and the following 
   5.301 +// properties are set:
   5.302 +//
   5.303 +//  normalObject        WebGLBuffer object for normals
   5.304 +//  texCoordObject      WebGLBuffer object for texCoords
   5.305 +//  vertexObject        WebGLBuffer object for vertices
   5.306 +//  indexObject         WebGLBuffer object for indices
   5.307 +//  numIndices          The number of indices in the indexObject
   5.308 +//  
   5.309 +function loadObj(ctx, url)
   5.310 +{
   5.311 +    var obj = { loaded : false };
   5.312 +    obj.ctx = ctx;
   5.313 +    var req = new XMLHttpRequest();
   5.314 +    req.obj = obj;
   5.315 +    req.onreadystatechange = function () { processLoadObj(req) };
   5.316 +    req.open("GET", url, true);
   5.317 +    req.send(null);
   5.318 +    return obj;
   5.319 +}
   5.320 +
   5.321 +function processLoadObj(req) 
   5.322 +{
   5.323 +    console.log("req="+req)
   5.324 +    // only if req shows "complete"
   5.325 +    if (req.readyState == 4) {
   5.326 +        doLoadObj(req.obj, req.responseText);
   5.327 +    }
   5.328 +}
   5.329 +
   5.330 +function doLoadObj(obj, text)
   5.331 +{
   5.332 +    vertexArray = [ ];
   5.333 +    normalArray = [ ];
   5.334 +    textureArray = [ ];
   5.335 +    indexArray = [ ];
   5.336 +    
   5.337 +    var vertex = [ ];
   5.338 +    var normal = [ ];
   5.339 +    var texture = [ ];
   5.340 +    var facemap = { };
   5.341 +    var index = 0;
   5.342 +        
   5.343 +    var lines = text.split("\n");
   5.344 +    for (var lineIndex in lines) {
   5.345 +        var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
   5.346 +        
   5.347 +        // ignore comments
   5.348 +        if (line[0] == "#")
   5.349 +            continue;
   5.350 +            
   5.351 +        var array = line.split(" ");
   5.352 +        if (array[0] == "v") {
   5.353 +            // vertex
   5.354 +            vertex.push(parseFloat(array[1]));
   5.355 +            vertex.push(parseFloat(array[2]));
   5.356 +            vertex.push(parseFloat(array[3]));
   5.357 +        }
   5.358 +        else if (array[0] == "vt") {
   5.359 +            // normal
   5.360 +            texture.push(parseFloat(array[1]));
   5.361 +            texture.push(parseFloat(array[2]));
   5.362 +        }
   5.363 +        else if (array[0] == "vn") {
   5.364 +            // normal
   5.365 +            normal.push(parseFloat(array[1]));
   5.366 +            normal.push(parseFloat(array[2]));
   5.367 +            normal.push(parseFloat(array[3]));
   5.368 +        }
   5.369 +        else if (array[0] == "f") {
   5.370 +            // face
   5.371 +            if (array.length != 4) {
   5.372 +                console.log("*** Error: face '"+line+"' not handled");
   5.373 +                continue;
   5.374 +            }
   5.375 +            
   5.376 +            for (var i = 1; i < 4; ++i) {
   5.377 +                if (!(array[i] in facemap)) {
   5.378 +                    // add a new entry to the map and arrays
   5.379 +                    var f = array[i].split("/");
   5.380 +                    var vtx, nor, tex;
   5.381 +                    
   5.382 +                    if (f.length == 1) {
   5.383 +                        vtx = parseInt(f[0]) - 1;
   5.384 +                        nor = vtx;
   5.385 +                        tex = vtx;
   5.386 +                    }
   5.387 +                    else if (f.length = 3) {
   5.388 +                        vtx = parseInt(f[0]) - 1;
   5.389 +                        tex = parseInt(f[1]) - 1;
   5.390 +                        nor = parseInt(f[2]) - 1;
   5.391 +                    }
   5.392 +                    else {
   5.393 +                        console.log("*** Error: did not understand face '"+array[i]+"'");
   5.394 +                        return null;
   5.395 +                    }
   5.396 +                    
   5.397 +                    // do the vertices
   5.398 +                    var x = 0;
   5.399 +                    var y = 0;
   5.400 +                    var z = 0;
   5.401 +                    if (vtx * 3 + 2 < vertex.length) {
   5.402 +                        x = vertex[vtx*3];
   5.403 +                        y = vertex[vtx*3+1];
   5.404 +                        z = vertex[vtx*3+2];
   5.405 +                    }
   5.406 +                    vertexArray.push(x);
   5.407 +                    vertexArray.push(y);
   5.408 +                    vertexArray.push(z);
   5.409 +                    
   5.410 +                    // do the textures
   5.411 +                    x = 0;
   5.412 +                    y = 0;
   5.413 +                    if (tex * 2 + 1 < texture.length) {
   5.414 +                        x = texture[tex*2];
   5.415 +                        y = texture[tex*2+1];
   5.416 +                    }
   5.417 +                    textureArray.push(x);
   5.418 +                    textureArray.push(y);
   5.419 +                    
   5.420 +                    // do the normals
   5.421 +                    x = 0;
   5.422 +                    y = 0;
   5.423 +                    z = 1;
   5.424 +                    if (nor * 3 + 2 < normal.length) {
   5.425 +                        x = normal[nor*3];
   5.426 +                        y = normal[nor*3+1];
   5.427 +                        z = normal[nor*3+2];
   5.428 +                    }
   5.429 +                    normalArray.push(x);
   5.430 +                    normalArray.push(y);
   5.431 +                    normalArray.push(z);
   5.432 +                    
   5.433 +                    facemap[array[i]] = index++;
   5.434 +                }
   5.435 +                
   5.436 +                indexArray.push(facemap[array[i]]);
   5.437 +            }
   5.438 +        }
   5.439 +    }
   5.440 +
   5.441 +    // set the VBOs
   5.442 +    obj.normalObject = obj.ctx.createBuffer();
   5.443 +    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
   5.444 +    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(normalArray), obj.ctx.STATIC_DRAW);
   5.445 +
   5.446 +    obj.texCoordObject = obj.ctx.createBuffer();
   5.447 +    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
   5.448 +    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(textureArray), obj.ctx.STATIC_DRAW);
   5.449 +
   5.450 +    obj.vertexObject = obj.ctx.createBuffer();
   5.451 +    obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
   5.452 +    obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new WebGLFloatArray(vertexArray), obj.ctx.STATIC_DRAW);
   5.453 +    
   5.454 +    obj.numIndices = indexArray.length;
   5.455 +    obj.indexObject = obj.ctx.createBuffer();
   5.456 +    obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
   5.457 +    obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(indexArray), obj.ctx.STREAM_DRAW);
   5.458 +    
   5.459 +    obj.loaded = true;
   5.460 +}
   5.461 +
   5.462 +//
   5.463 +// loadImageTexture
   5.464 +//
   5.465 +// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
   5.466 +//
   5.467 +function loadImageTexture(ctx, url)
   5.468 +{
   5.469 +    var texture = ctx.createTexture();
   5.470 +    texture.image = new Image();
   5.471 +    texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
   5.472 +    texture.image.src = url;
   5.473 +    return texture;
   5.474 +}
   5.475 +
   5.476 +function doLoadImageTexture(ctx, image, texture)
   5.477 +{
   5.478 +    ctx.enable(ctx.TEXTURE_2D);
   5.479 +    ctx.bindTexture(ctx.TEXTURE_2D, texture);
   5.480 +    ctx.texImage2D(ctx.TEXTURE_2D, 0, image);
   5.481 +    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
   5.482 +    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR);
   5.483 +    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
   5.484 +    ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
   5.485 +    ctx.generateMipmap(ctx.TEXTURE_2D)
   5.486 +    ctx.bindTexture(ctx.TEXTURE_2D, 0);
   5.487 +}
   5.488 +
   5.489 +//
   5.490 +// Framerate object
   5.491 +//
   5.492 +// This object keeps track of framerate and displays it as the innerHTML text of the 
   5.493 +// HTML element with the passed id. Once created you call snapshot at the end
   5.494 +// of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
   5.495 +//
   5.496 +Framerate = function(id)
   5.497 +{
   5.498 +    this.numFramerates = 10;
   5.499 +    this.framerateUpdateInterval = 500;
   5.500 +    this.id = id;
   5.501 +
   5.502 +    this.renderTime = -1;
   5.503 +    this.framerates = [ ];
   5.504 +    self = this;
   5.505 +    var fr = function() { self.updateFramerate() }
   5.506 +    setInterval(fr, this.framerateUpdateInterval);
   5.507 +}
   5.508 +
   5.509 +Framerate.prototype.updateFramerate = function()
   5.510 +{
   5.511 +    var tot = 0;
   5.512 +    for (var i = 0; i < this.framerates.length; ++i)
   5.513 +        tot += this.framerates[i];
   5.514 +        
   5.515 +    var framerate = tot / this.framerates.length;
   5.516 +    framerate = Math.round(framerate);
   5.517 +    document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
   5.518 +}
   5.519 +
   5.520 +Framerate.prototype.snapshot = function()
   5.521 +{
   5.522 +    if (this.renderTime < 0)
   5.523 +        this.renderTime = new Date().getTime();
   5.524 +    else {
   5.525 +        var newTime = new Date().getTime();
   5.526 +        var t = newTime - this.renderTime;
   5.527 +        var framerate = 1000/t;
   5.528 +        this.framerates.push(framerate);
   5.529 +        while (this.framerates.length > this.numFramerates)
   5.530 +            this.framerates.shift();
   5.531 +        this.renderTime = newTime;
   5.532 +    }
   5.533 +}
   5.534 \ No newline at end of file