美文网首页
WebGL编程指南函数库

WebGL编程指南函数库

作者: antlove | 来源:发表于2020-07-04 10:03 被阅读0次

    一下是WebGL编程指南中提供的函数库
    cuon-matrix.js

    // cuon-matrix.js (c) 2012 kanda and matsuda
    /** 
     * This is a class treating 4x4 matrix.
     * This class contains the function that is equivalent to OpenGL matrix stack.
     * The matrix after conversion is calculated by multiplying a conversion matrix from the right.
     * The matrix is replaced by the calculated result.
     */
    
    /**
     * Constructor of Matrix4
     * If opt_src is specified, new matrix is initialized by opt_src.
     * Otherwise, new matrix is initialized by identity matrix.
     * @param opt_src source matrix(option)
     */
    var Matrix4 = function(opt_src) {
      var i, s, d;
      if (opt_src && typeof opt_src === 'object' && opt_src.hasOwnProperty('elements')) {
        s = opt_src.elements;
        d = new Float32Array(16);
        for (i = 0; i < 16; ++i) {
          d[i] = s[i];
        }
        this.elements = d;
      } else {
        this.elements = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
      }
    };
    
    /**
     * Set the identity matrix.
     * @return this
     */
    Matrix4.prototype.setIdentity = function() {
      var e = this.elements;
      e[0] = 1;   e[4] = 0;   e[8]  = 0;   e[12] = 0;
      e[1] = 0;   e[5] = 1;   e[9]  = 0;   e[13] = 0;
      e[2] = 0;   e[6] = 0;   e[10] = 1;   e[14] = 0;
      e[3] = 0;   e[7] = 0;   e[11] = 0;   e[15] = 1;
      return this;
    };
    
    /**
     * Copy matrix.
     * @param src source matrix
     * @return this
     */
    Matrix4.prototype.set = function(src) {
      var i, s, d;
    
      s = src.elements;
      d = this.elements;
    
      if (s === d) {
        return;
      }
        
      for (i = 0; i < 16; ++i) {
        d[i] = s[i];
      }
    
      return this;
    };
    
    /**
     * Multiply the matrix from the right.
     * @param other The multiply matrix
     * @return this
     */
    Matrix4.prototype.concat = function(other) {
      var i, e, a, b, ai0, ai1, ai2, ai3;
      
      // Calculate e = a * b
      e = this.elements;
      a = this.elements;
      b = other.elements;
      
      // If e equals b, copy b to temporary matrix.
      if (e === b) {
        b = new Float32Array(16);
        for (i = 0; i < 16; ++i) {
          b[i] = e[i];
        }
      }
      
      for (i = 0; i < 4; i++) {
        ai0=a[i];  ai1=a[i+4];  ai2=a[i+8];  ai3=a[i+12];
        e[i]    = ai0 * b[0]  + ai1 * b[1]  + ai2 * b[2]  + ai3 * b[3];
        e[i+4]  = ai0 * b[4]  + ai1 * b[5]  + ai2 * b[6]  + ai3 * b[7];
        e[i+8]  = ai0 * b[8]  + ai1 * b[9]  + ai2 * b[10] + ai3 * b[11];
        e[i+12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15];
      }
      
      return this;
    };
    Matrix4.prototype.multiply = Matrix4.prototype.concat;
    
    /**
     * Multiply the three-dimensional vector.
     * @param pos  The multiply vector
     * @return The result of multiplication(Float32Array)
     */
    Matrix4.prototype.multiplyVector3 = function(pos) {
      var e = this.elements;
      var p = pos.elements;
      var v = new Vector3();
      var result = v.elements;
    
      result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + e[11];
      result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + e[12];
      result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + e[13];
    
      return v;
    };
    
    /**
     * Multiply the four-dimensional vector.
     * @param pos  The multiply vector
     * @return The result of multiplication(Float32Array)
     */
    Matrix4.prototype.multiplyVector4 = function(pos) {
      var e = this.elements;
      var p = pos.elements;
      var v = new Vector4();
      var result = v.elements;
    
      result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + p[3] * e[12];
      result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + p[3] * e[13];
      result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + p[3] * e[14];
      result[3] = p[0] * e[3] + p[1] * e[7] + p[2] * e[11] + p[3] * e[15];
    
      return v;
    };
    
    /**
     * Transpose the matrix.
     * @return this
     */
    Matrix4.prototype.transpose = function() {
      var e, t;
    
      e = this.elements;
    
      t = e[ 1];  e[ 1] = e[ 4];  e[ 4] = t;
      t = e[ 2];  e[ 2] = e[ 8];  e[ 8] = t;
      t = e[ 3];  e[ 3] = e[12];  e[12] = t;
      t = e[ 6];  e[ 6] = e[ 9];  e[ 9] = t;
      t = e[ 7];  e[ 7] = e[13];  e[13] = t;
      t = e[11];  e[11] = e[14];  e[14] = t;
    
      return this;
    };
    
    /**
     * Calculate the inverse matrix of specified matrix, and set to this.
     * @param other The source matrix
     * @return this
     */
    Matrix4.prototype.setInverseOf = function(other) {
      var i, s, d, inv, det;
    
      s = other.elements;
      d = this.elements;
      inv = new Float32Array(16);
    
      inv[0]  =   s[5]*s[10]*s[15] - s[5] *s[11]*s[14] - s[9] *s[6]*s[15]
                + s[9]*s[7] *s[14] + s[13]*s[6] *s[11] - s[13]*s[7]*s[10];
      inv[4]  = - s[4]*s[10]*s[15] + s[4] *s[11]*s[14] + s[8] *s[6]*s[15]
                - s[8]*s[7] *s[14] - s[12]*s[6] *s[11] + s[12]*s[7]*s[10];
      inv[8]  =   s[4]*s[9] *s[15] - s[4] *s[11]*s[13] - s[8] *s[5]*s[15]
                + s[8]*s[7] *s[13] + s[12]*s[5] *s[11] - s[12]*s[7]*s[9];
      inv[12] = - s[4]*s[9] *s[14] + s[4] *s[10]*s[13] + s[8] *s[5]*s[14]
                - s[8]*s[6] *s[13] - s[12]*s[5] *s[10] + s[12]*s[6]*s[9];
    
      inv[1]  = - s[1]*s[10]*s[15] + s[1] *s[11]*s[14] + s[9] *s[2]*s[15]
                - s[9]*s[3] *s[14] - s[13]*s[2] *s[11] + s[13]*s[3]*s[10];
      inv[5]  =   s[0]*s[10]*s[15] - s[0] *s[11]*s[14] - s[8] *s[2]*s[15]
                + s[8]*s[3] *s[14] + s[12]*s[2] *s[11] - s[12]*s[3]*s[10];
      inv[9]  = - s[0]*s[9] *s[15] + s[0] *s[11]*s[13] + s[8] *s[1]*s[15]
                - s[8]*s[3] *s[13] - s[12]*s[1] *s[11] + s[12]*s[3]*s[9];
      inv[13] =   s[0]*s[9] *s[14] - s[0] *s[10]*s[13] - s[8] *s[1]*s[14]
                + s[8]*s[2] *s[13] + s[12]*s[1] *s[10] - s[12]*s[2]*s[9];
    
      inv[2]  =   s[1]*s[6]*s[15] - s[1] *s[7]*s[14] - s[5] *s[2]*s[15]
                + s[5]*s[3]*s[14] + s[13]*s[2]*s[7]  - s[13]*s[3]*s[6];
      inv[6]  = - s[0]*s[6]*s[15] + s[0] *s[7]*s[14] + s[4] *s[2]*s[15]
                - s[4]*s[3]*s[14] - s[12]*s[2]*s[7]  + s[12]*s[3]*s[6];
      inv[10] =   s[0]*s[5]*s[15] - s[0] *s[7]*s[13] - s[4] *s[1]*s[15]
                + s[4]*s[3]*s[13] + s[12]*s[1]*s[7]  - s[12]*s[3]*s[5];
      inv[14] = - s[0]*s[5]*s[14] + s[0] *s[6]*s[13] + s[4] *s[1]*s[14]
                - s[4]*s[2]*s[13] - s[12]*s[1]*s[6]  + s[12]*s[2]*s[5];
    
      inv[3]  = - s[1]*s[6]*s[11] + s[1]*s[7]*s[10] + s[5]*s[2]*s[11]
                - s[5]*s[3]*s[10] - s[9]*s[2]*s[7]  + s[9]*s[3]*s[6];
      inv[7]  =   s[0]*s[6]*s[11] - s[0]*s[7]*s[10] - s[4]*s[2]*s[11]
                + s[4]*s[3]*s[10] + s[8]*s[2]*s[7]  - s[8]*s[3]*s[6];
      inv[11] = - s[0]*s[5]*s[11] + s[0]*s[7]*s[9]  + s[4]*s[1]*s[11]
                - s[4]*s[3]*s[9]  - s[8]*s[1]*s[7]  + s[8]*s[3]*s[5];
      inv[15] =   s[0]*s[5]*s[10] - s[0]*s[6]*s[9]  - s[4]*s[1]*s[10]
                + s[4]*s[2]*s[9]  + s[8]*s[1]*s[6]  - s[8]*s[2]*s[5];
    
      det = s[0]*inv[0] + s[1]*inv[4] + s[2]*inv[8] + s[3]*inv[12];
      if (det === 0) {
        return this;
      }
    
      det = 1 / det;
      for (i = 0; i < 16; i++) {
        d[i] = inv[i] * det;
      }
    
      return this;
    };
    
    /**
     * Calculate the inverse matrix of this, and set to this.
     * @return this
     */
    Matrix4.prototype.invert = function() {
      return this.setInverseOf(this);
    };
    
    /**
     * Set the orthographic projection matrix.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @return this
     */
    Matrix4.prototype.setOrtho = function(left, right, bottom, top, near, far) {
      var e, rw, rh, rd;
    
      if (left === right || bottom === top || near === far) {
        throw 'null frustum';
      }
    
      rw = 1 / (right - left);
      rh = 1 / (top - bottom);
      rd = 1 / (far - near);
    
      e = this.elements;
    
      e[0]  = 2 * rw;
      e[1]  = 0;
      e[2]  = 0;
      e[3]  = 0;
    
      e[4]  = 0;
      e[5]  = 2 * rh;
      e[6]  = 0;
      e[7]  = 0;
    
      e[8]  = 0;
      e[9]  = 0;
      e[10] = -2 * rd;
      e[11] = 0;
    
      e[12] = -(right + left) * rw;
      e[13] = -(top + bottom) * rh;
      e[14] = -(far + near) * rd;
      e[15] = 1;
    
      return this;
    };
    
    /**
     * Multiply the orthographic projection matrix from the right.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
     * @return this
     */
    Matrix4.prototype.ortho = function(left, right, bottom, top, near, far) {
      return this.concat(new Matrix4().setOrtho(left, right, bottom, top, near, far));
    };
    
    /**
     * Set the perspective projection matrix.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.setFrustum = function(left, right, bottom, top, near, far) {
      var e, rw, rh, rd;
    
      if (left === right || top === bottom || near === far) {
        throw 'null frustum';
      }
      if (near <= 0) {
        throw 'near <= 0';
      }
      if (far <= 0) {
        throw 'far <= 0';
      }
    
      rw = 1 / (right - left);
      rh = 1 / (top - bottom);
      rd = 1 / (far - near);
    
      e = this.elements;
    
      e[ 0] = 2 * near * rw;
      e[ 1] = 0;
      e[ 2] = 0;
      e[ 3] = 0;
    
      e[ 4] = 0;
      e[ 5] = 2 * near * rh;
      e[ 6] = 0;
      e[ 7] = 0;
    
      e[ 8] = (right + left) * rw;
      e[ 9] = (top + bottom) * rh;
      e[10] = -(far + near) * rd;
      e[11] = -1;
    
      e[12] = 0;
      e[13] = 0;
      e[14] = -2 * near * far * rd;
      e[15] = 0;
    
      return this;
    };
    
    /**
     * Multiply the perspective projection matrix from the right.
     * @param left The coordinate of the left of clipping plane.
     * @param right The coordinate of the right of clipping plane.
     * @param bottom The coordinate of the bottom of clipping plane.
     * @param top The coordinate of the top top clipping plane.
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.frustum = function(left, right, bottom, top, near, far) {
      return this.concat(new Matrix4().setFrustum(left, right, bottom, top, near, far));
    };
    
    /**
     * Set the perspective projection matrix by fovy and aspect.
     * @param fovy The angle between the upper and lower sides of the frustum.
     * @param aspect The aspect ratio of the frustum. (width/height)
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.setPerspective = function(fovy, aspect, near, far) {
      var e, rd, s, ct;
    
      if (near === far || aspect === 0) {
        throw 'null frustum';
      }
      if (near <= 0) {
        throw 'near <= 0';
      }
      if (far <= 0) {
        throw 'far <= 0';
      }
    
      fovy = Math.PI * fovy / 180 / 2;
      s = Math.sin(fovy);
      if (s === 0) {
        throw 'null frustum';
      }
    
      rd = 1 / (far - near);
      ct = Math.cos(fovy) / s;
    
      e = this.elements;
    
      e[0]  = ct / aspect;
      e[1]  = 0;
      e[2]  = 0;
      e[3]  = 0;
    
      e[4]  = 0;
      e[5]  = ct;
      e[6]  = 0;
      e[7]  = 0;
    
      e[8]  = 0;
      e[9]  = 0;
      e[10] = -(far + near) * rd;
      e[11] = -1;
    
      e[12] = 0;
      e[13] = 0;
      e[14] = -2 * near * far * rd;
      e[15] = 0;
    
      return this;
    };
    
    /**
     * Multiply the perspective projection matrix from the right.
     * @param fovy The angle between the upper and lower sides of the frustum.
     * @param aspect The aspect ratio of the frustum. (width/height)
     * @param near The distances to the nearer depth clipping plane. This value must be plus value.
     * @param far The distances to the farther depth clipping plane. This value must be plus value.
     * @return this
     */
    Matrix4.prototype.perspective = function(fovy, aspect, near, far) {
      return this.concat(new Matrix4().setPerspective(fovy, aspect, near, far));
    };
    
    /**
     * Set the matrix for scaling.
     * @param x The scale factor along the X axis
     * @param y The scale factor along the Y axis
     * @param z The scale factor along the Z axis
     * @return this
     */
    Matrix4.prototype.setScale = function(x, y, z) {
      var e = this.elements;
      e[0] = x;  e[4] = 0;  e[8]  = 0;  e[12] = 0;
      e[1] = 0;  e[5] = y;  e[9]  = 0;  e[13] = 0;
      e[2] = 0;  e[6] = 0;  e[10] = z;  e[14] = 0;
      e[3] = 0;  e[7] = 0;  e[11] = 0;  e[15] = 1;
      return this;
    };
    
    /**
     * Multiply the matrix for scaling from the right.
     * @param x The scale factor along the X axis
     * @param y The scale factor along the Y axis
     * @param z The scale factor along the Z axis
     * @return this
     */
    Matrix4.prototype.scale = function(x, y, z) {
      var e = this.elements;
      e[0] *= x;  e[4] *= y;  e[8]  *= z;
      e[1] *= x;  e[5] *= y;  e[9]  *= z;
      e[2] *= x;  e[6] *= y;  e[10] *= z;
      e[3] *= x;  e[7] *= y;  e[11] *= z;
      return this;
    };
    
    /**
     * Set the matrix for translation.
     * @param x The X value of a translation.
     * @param y The Y value of a translation.
     * @param z The Z value of a translation.
     * @return this
     */
    Matrix4.prototype.setTranslate = function(x, y, z) {
      var e = this.elements;
      e[0] = 1;  e[4] = 0;  e[8]  = 0;  e[12] = x;
      e[1] = 0;  e[5] = 1;  e[9]  = 0;  e[13] = y;
      e[2] = 0;  e[6] = 0;  e[10] = 1;  e[14] = z;
      e[3] = 0;  e[7] = 0;  e[11] = 0;  e[15] = 1;
      return this;
    };
    
    /**
     * Multiply the matrix for translation from the right.
     * @param x The X value of a translation.
     * @param y The Y value of a translation.
     * @param z The Z value of a translation.
     * @return this
     */
    Matrix4.prototype.translate = function(x, y, z) {
      var e = this.elements;
      e[12] += e[0] * x + e[4] * y + e[8]  * z;
      e[13] += e[1] * x + e[5] * y + e[9]  * z;
      e[14] += e[2] * x + e[6] * y + e[10] * z;
      e[15] += e[3] * x + e[7] * y + e[11] * z;
      return this;
    };
    
    /**
     * Set the matrix for rotation.
     * The vector of rotation axis may not be normalized.
     * @param angle The angle of rotation (degrees)
     * @param x The X coordinate of vector of rotation axis.
     * @param y The Y coordinate of vector of rotation axis.
     * @param z The Z coordinate of vector of rotation axis.
     * @return this
     */
    Matrix4.prototype.setRotate = function(angle, x, y, z) {
      var e, s, c, len, rlen, nc, xy, yz, zx, xs, ys, zs;
    
      angle = Math.PI * angle / 180;
      e = this.elements;
    
      s = Math.sin(angle);
      c = Math.cos(angle);
    
      if (0 !== x && 0 === y && 0 === z) {
        // Rotation around X axis
        if (x < 0) {
          s = -s;
        }
        e[0] = 1;  e[4] = 0;  e[ 8] = 0;  e[12] = 0;
        e[1] = 0;  e[5] = c;  e[ 9] =-s;  e[13] = 0;
        e[2] = 0;  e[6] = s;  e[10] = c;  e[14] = 0;
        e[3] = 0;  e[7] = 0;  e[11] = 0;  e[15] = 1;
      } else if (0 === x && 0 !== y && 0 === z) {
        // Rotation around Y axis
        if (y < 0) {
          s = -s;
        }
        e[0] = c;  e[4] = 0;  e[ 8] = s;  e[12] = 0;
        e[1] = 0;  e[5] = 1;  e[ 9] = 0;  e[13] = 0;
        e[2] =-s;  e[6] = 0;  e[10] = c;  e[14] = 0;
        e[3] = 0;  e[7] = 0;  e[11] = 0;  e[15] = 1;
      } else if (0 === x && 0 === y && 0 !== z) {
        // Rotation around Z axis
        if (z < 0) {
          s = -s;
        }
        e[0] = c;  e[4] =-s;  e[ 8] = 0;  e[12] = 0;
        e[1] = s;  e[5] = c;  e[ 9] = 0;  e[13] = 0;
        e[2] = 0;  e[6] = 0;  e[10] = 1;  e[14] = 0;
        e[3] = 0;  e[7] = 0;  e[11] = 0;  e[15] = 1;
      } else {
        // Rotation around another axis
        len = Math.sqrt(x*x + y*y + z*z);
        if (len !== 1) {
          rlen = 1 / len;
          x *= rlen;
          y *= rlen;
          z *= rlen;
        }
        nc = 1 - c;
        xy = x * y;
        yz = y * z;
        zx = z * x;
        xs = x * s;
        ys = y * s;
        zs = z * s;
    
        e[ 0] = x*x*nc +  c;
        e[ 1] = xy *nc + zs;
        e[ 2] = zx *nc - ys;
        e[ 3] = 0;
    
        e[ 4] = xy *nc - zs;
        e[ 5] = y*y*nc +  c;
        e[ 6] = yz *nc + xs;
        e[ 7] = 0;
    
        e[ 8] = zx *nc + ys;
        e[ 9] = yz *nc - xs;
        e[10] = z*z*nc +  c;
        e[11] = 0;
    
        e[12] = 0;
        e[13] = 0;
        e[14] = 0;
        e[15] = 1;
      }
    
      return this;
    };
    
    /**
     * Multiply the matrix for rotation from the right.
     * The vector of rotation axis may not be normalized.
     * @param angle The angle of rotation (degrees)
     * @param x The X coordinate of vector of rotation axis.
     * @param y The Y coordinate of vector of rotation axis.
     * @param z The Z coordinate of vector of rotation axis.
     * @return this
     */
    Matrix4.prototype.rotate = function(angle, x, y, z) {
      return this.concat(new Matrix4().setRotate(angle, x, y, z));
    };
    
    /**
     * Set the viewing matrix.
     * @param eyeX, eyeY, eyeZ The position of the eye point.
     * @param centerX, centerY, centerZ The position of the reference point.
     * @param upX, upY, upZ The direction of the up vector.
     * @return this
     */
    Matrix4.prototype.setLookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
      var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz;
    
      fx = centerX - eyeX;
      fy = centerY - eyeY;
      fz = centerZ - eyeZ;
    
      // Normalize f.
      rlf = 1 / Math.sqrt(fx*fx + fy*fy + fz*fz);
      fx *= rlf;
      fy *= rlf;
      fz *= rlf;
    
      // Calculate cross product of f and up.
      sx = fy * upZ - fz * upY;
      sy = fz * upX - fx * upZ;
      sz = fx * upY - fy * upX;
    
      // Normalize s.
      rls = 1 / Math.sqrt(sx*sx + sy*sy + sz*sz);
      sx *= rls;
      sy *= rls;
      sz *= rls;
    
      // Calculate cross product of s and f.
      ux = sy * fz - sz * fy;
      uy = sz * fx - sx * fz;
      uz = sx * fy - sy * fx;
    
      // Set to this.
      e = this.elements;
      e[0] = sx;
      e[1] = ux;
      e[2] = -fx;
      e[3] = 0;
    
      e[4] = sy;
      e[5] = uy;
      e[6] = -fy;
      e[7] = 0;
    
      e[8] = sz;
      e[9] = uz;
      e[10] = -fz;
      e[11] = 0;
    
      e[12] = 0;
      e[13] = 0;
      e[14] = 0;
      e[15] = 1;
    
      // Translate.
      return this.translate(-eyeX, -eyeY, -eyeZ);
    };
    
    /**
     * Multiply the viewing matrix from the right.
     * @param eyeX, eyeY, eyeZ The position of the eye point.
     * @param centerX, centerY, centerZ The position of the reference point.
     * @param upX, upY, upZ The direction of the up vector.
     * @return this
     */
    Matrix4.prototype.lookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
      return this.concat(new Matrix4().setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ));
    };
    
    /**
     * Multiply the matrix for project vertex to plane from the right.
     * @param plane The array[A, B, C, D] of the equation of plane "Ax + By + Cz + D = 0".
     * @param light The array which stored coordinates of the light. if light[3]=0, treated as parallel light.
     * @return this
     */
    Matrix4.prototype.dropShadow = function(plane, light) {
      var mat = new Matrix4();
      var e = mat.elements;
    
      var dot = plane[0] * light[0] + plane[1] * light[1] + plane[2] * light[2] + plane[3] * light[3];
    
      e[ 0] = dot - light[0] * plane[0];
      e[ 1] =     - light[1] * plane[0];
      e[ 2] =     - light[2] * plane[0];
      e[ 3] =     - light[3] * plane[0];
    
      e[ 4] =     - light[0] * plane[1];
      e[ 5] = dot - light[1] * plane[1];
      e[ 6] =     - light[2] * plane[1];
      e[ 7] =     - light[3] * plane[1];
    
      e[ 8] =     - light[0] * plane[2];
      e[ 9] =     - light[1] * plane[2];
      e[10] = dot - light[2] * plane[2];
      e[11] =     - light[3] * plane[2];
    
      e[12] =     - light[0] * plane[3];
      e[13] =     - light[1] * plane[3];
      e[14] =     - light[2] * plane[3];
      e[15] = dot - light[3] * plane[3];
    
      return this.concat(mat);
    }
    
    /**
     * Multiply the matrix for project vertex to plane from the right.(Projected by parallel light.)
     * @param normX, normY, normZ The normal vector of the plane.(Not necessary to be normalized.)
     * @param planeX, planeY, planeZ The coordinate of arbitrary points on a plane.
     * @param lightX, lightY, lightZ The vector of the direction of light.(Not necessary to be normalized.)
     * @return this
     */
    Matrix4.prototype.dropShadowDirectionally = function(normX, normY, normZ, planeX, planeY, planeZ, lightX, lightY, lightZ) {
      var a = planeX * normX + planeY * normY + planeZ * normZ;
      return this.dropShadow([normX, normY, normZ, -a], [lightX, lightY, lightZ, 0]);
    };
    
    /**
     * Constructor of Vector3
     * If opt_src is specified, new vector is initialized by opt_src.
     * @param opt_src source vector(option)
     */
    var Vector3 = function(opt_src) {
      var v = new Float32Array(3);
      if (opt_src && typeof opt_src === 'object') {
        v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2];
      } 
      this.elements = v;
    }
    
    /**
      * Normalize.
      * @return this
      */
    Vector3.prototype.normalize = function() {
      var v = this.elements;
      var c = v[0], d = v[1], e = v[2], g = Math.sqrt(c*c+d*d+e*e);
      if(g){
        if(g == 1)
            return this;
       } else {
         v[0] = 0; v[1] = 0; v[2] = 0;
         return this;
       }
       g = 1/g;
       v[0] = c*g; v[1] = d*g; v[2] = e*g;
       return this;
    };
    
    /**
     * Constructor of Vector4
     * If opt_src is specified, new vector is initialized by opt_src.
     * @param opt_src source vector(option)
     */
    var Vector4 = function(opt_src) {
      var v = new Float32Array(4);
      if (opt_src && typeof opt_src === 'object') {
        v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2]; v[3] = opt_src[3];
      } 
      this.elements = v;
    }
    

    cuon-utils.js

    // cuon-utils.js (c) 2012 kanda and matsuda
    /**
     * Create a program object and make current
     * @param gl GL context
     * @param vshader a vertex shader program (string)
     * @param fshader a fragment shader program (string)
     * @return true, if the program object was created and successfully made current 
     */
    function initShaders(gl, vshader, fshader) {
      var program = createProgram(gl, vshader, fshader);
      if (!program) {
        console.log('Failed to create program');
        return false;
      }
    
      gl.useProgram(program);
      gl.program = program;
    
      return true;
    }
    
    /**
     * Create the linked program object
     * @param gl GL context
     * @param vshader a vertex shader program (string)
     * @param fshader a fragment shader program (string)
     * @return created program object, or null if the creation has failed
     */
    function createProgram(gl, vshader, fshader) {
      // Create shader object
      var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
      var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
      if (!vertexShader || !fragmentShader) {
        return null;
      }
    
      // Create a program object
      var program = gl.createProgram();
      if (!program) {
        return null;
      }
    
      // Attach the shader objects
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
    
      // Link the program object
      gl.linkProgram(program);
    
      // Check the result of linking
      var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
      if (!linked) {
        var error = gl.getProgramInfoLog(program);
        console.log('Failed to link program: ' + error);
        gl.deleteProgram(program);
        gl.deleteShader(fragmentShader);
        gl.deleteShader(vertexShader);
        return null;
      }
      return program;
    }
    
    /**
     * Create a shader object
     * @param gl GL context
     * @param type the type of the shader object to be created
     * @param source shader program (string)
     * @return created shader object, or null if the creation has failed.
     */
    function loadShader(gl, type, source) {
      // Create shader object
      var shader = gl.createShader(type);
      if (shader == null) {
        console.log('unable to create shader');
        return null;
      }
    
      // Set the shader program
      gl.shaderSource(shader, source);
    
      // Compile the shader
      gl.compileShader(shader);
    
      // Check the result of compilation
      var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
      if (!compiled) {
        var error = gl.getShaderInfoLog(shader);
        console.log('Failed to compile shader: ' + error);
        gl.deleteShader(shader);
        return null;
      }
    
      return shader;
    }
    
    /** 
     * Initialize and get the rendering for WebGL
     * @param canvas <cavnas> element
     * @param opt_debug flag to initialize the context for debugging
     * @return the rendering context for WebGL
     */
    function getWebGLContext(canvas, opt_debug) {
      // Get the rendering context for WebGL
      var gl = WebGLUtils.setupWebGL(canvas);
      if (!gl) return null;
    
      // if opt_debug is explicitly false, create the context for debugging
      if (arguments.length < 2 || opt_debug) {
        gl = WebGLDebugUtils.makeDebugContext(gl);
      }
    
      return gl;
    }
    

    webgl-debug.js

    //Copyright (c) 2009 The Chromium Authors. All rights reserved.
    //Use of this source code is governed by a BSD-style license that can be
    //found in the LICENSE file.
    
    // Various functions for helping debug WebGL apps.
    
    WebGLDebugUtils = function() {
    
    /**
     * Wrapped logging function.
     * @param {string} msg Message to log.
     */
    var log = function(msg) {
      if (window.console && window.console.log) {
        window.console.log(msg);
      }
    };
    
    /**
     * Which arguements are enums.
     * @type {!Object.<number, string>}
     */
    var glValidEnumContexts = {
    
      // Generic setters and getters
    
      'enable': { 0:true },
      'disable': { 0:true },
      'getParameter': { 0:true },
    
      // Rendering
    
      'drawArrays': { 0:true },
      'drawElements': { 0:true, 2:true },
    
      // Shaders
    
      'createShader': { 0:true },
      'getShaderParameter': { 1:true },
      'getProgramParameter': { 1:true },
    
      // Vertex attributes
    
      'getVertexAttrib': { 1:true },
      'vertexAttribPointer': { 2:true },
    
      // Textures
    
      'bindTexture': { 0:true },
      'activeTexture': { 0:true },
      'getTexParameter': { 0:true, 1:true },
      'texParameterf': { 0:true, 1:true },
      'texParameteri': { 0:true, 1:true, 2:true },
      'texImage2D': { 0:true, 2:true, 6:true, 7:true },
      'texSubImage2D': { 0:true, 6:true, 7:true },
      'copyTexImage2D': { 0:true, 2:true },
      'copyTexSubImage2D': { 0:true },
      'generateMipmap': { 0:true },
    
      // Buffer objects
    
      'bindBuffer': { 0:true },
      'bufferData': { 0:true, 2:true },
      'bufferSubData': { 0:true },
      'getBufferParameter': { 0:true, 1:true },
    
      // Renderbuffers and framebuffers
    
      'pixelStorei': { 0:true, 1:true },
      'readPixels': { 4:true, 5:true },
      'bindRenderbuffer': { 0:true },
      'bindFramebuffer': { 0:true },
      'checkFramebufferStatus': { 0:true },
      'framebufferRenderbuffer': { 0:true, 1:true, 2:true },
      'framebufferTexture2D': { 0:true, 1:true, 2:true },
      'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true },
      'getRenderbufferParameter': { 0:true, 1:true },
      'renderbufferStorage': { 0:true, 1:true },
    
      // Frame buffer operations (clear, blend, depth test, stencil)
    
      'clear': { 0:true },
      'depthFunc': { 0:true },
      'blendFunc': { 0:true, 1:true },
      'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true },
      'blendEquation': { 0:true },
      'blendEquationSeparate': { 0:true, 1:true },
      'stencilFunc': { 0:true },
      'stencilFuncSeparate': { 0:true, 1:true },
      'stencilMaskSeparate': { 0:true },
      'stencilOp': { 0:true, 1:true, 2:true },
      'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true },
    
      // Culling
    
      'cullFace': { 0:true },
      'frontFace': { 0:true },
    };
    
    /**
     * Map of numbers to names.
     * @type {Object}
     */
    var glEnums = null;
    
    /**
     * Initializes this module. Safe to call more than once.
     * @param {!WebGLRenderingContext} ctx A WebGL context. If
     *    you have more than one context it doesn't matter which one
     *    you pass in, it is only used to pull out constants.
     */
    function init(ctx) {
      if (glEnums == null) {
        glEnums = { };
        for (var propertyName in ctx) {
          if (typeof ctx[propertyName] == 'number') {
            glEnums[ctx[propertyName]] = propertyName;
          }
        }
      }
    }
    
    /**
     * Checks the utils have been initialized.
     */
    function checkInit() {
      if (glEnums == null) {
        throw 'WebGLDebugUtils.init(ctx) not called';
      }
    }
    
    /**
     * Returns true or false if value matches any WebGL enum
     * @param {*} value Value to check if it might be an enum.
     * @return {boolean} True if value matches one of the WebGL defined enums
     */
    function mightBeEnum(value) {
      checkInit();
      return (glEnums[value] !== undefined);
    }
    
    /**
     * Gets an string version of an WebGL enum.
     *
     * Example:
     *   var str = WebGLDebugUtil.glEnumToString(ctx.getError());
     *
     * @param {number} value Value to return an enum for
     * @return {string} The string version of the enum.
     */
    function glEnumToString(value) {
      checkInit();
      var name = glEnums[value];
      return (name !== undefined) ? name :
          ("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")");
    }
    
    /**
     * Returns the string version of a WebGL argument.
     * Attempts to convert enum arguments to strings.
     * @param {string} functionName the name of the WebGL function.
     * @param {number} argumentIndx the index of the argument.
     * @param {*} value The value of the argument.
     * @return {string} The value as a string.
     */
    function glFunctionArgToString(functionName, argumentIndex, value) {
      var funcInfo = glValidEnumContexts[functionName];
      if (funcInfo !== undefined) {
        if (funcInfo[argumentIndex]) {
          return glEnumToString(value);
        }
      }
      return value.toString();
    }
    
    /**
     * Given a WebGL context returns a wrapped context that calls
     * gl.getError after every command and calls a function if the
     * result is not gl.NO_ERROR.
     *
     * @param {!WebGLRenderingContext} ctx The webgl context to
     *        wrap.
     * @param {!function(err, funcName, args): void} opt_onErrorFunc
     *        The function to call when gl.getError returns an
     *        error. If not specified the default function calls
     *        console.log with a message.
     */
    function makeDebugContext(ctx, opt_onErrorFunc) {
      init(ctx);
      opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
            // apparently we can't do args.join(",");
            var argStr = "";
            for (var ii = 0; ii < args.length; ++ii) {
              argStr += ((ii == 0) ? '' : ', ') +
                  glFunctionArgToString(functionName, ii, args[ii]);
            }
            log("WebGL error "+ glEnumToString(err) + " in "+ functionName +
                "(" + argStr + ")");
          };
    
      // Holds booleans for each GL error so after we get the error ourselves
      // we can still return it to the client app.
      var glErrorShadow = { };
    
      // Makes a function that calls a WebGL function and then calls getError.
      function makeErrorWrapper(ctx, functionName) {
        return function() {
          var result = ctx[functionName].apply(ctx, arguments);
          var err = ctx.getError();
          if (err != 0) {
            glErrorShadow[err] = true;
            opt_onErrorFunc(err, functionName, arguments);
          }
          return result;
        };
      }
    
      // Make a an object that has a copy of every property of the WebGL context
      // but wraps all functions.
      var wrapper = {};
      for (var propertyName in ctx) {
        if (typeof ctx[propertyName] == 'function') {
           wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
         } else {
           wrapper[propertyName] = ctx[propertyName];
         }
      }
    
      // Override the getError function with one that returns our saved results.
      wrapper.getError = function() {
        for (var err in glErrorShadow) {
          if (glErrorShadow[err]) {
            glErrorShadow[err] = false;
            return err;
          }
        }
        return ctx.NO_ERROR;
      };
    
      return wrapper;
    }
    
    function resetToInitialState(ctx) {
      var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
      var tmp = ctx.createBuffer();
      ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp);
      for (var ii = 0; ii < numAttribs; ++ii) {
        ctx.disableVertexAttribArray(ii);
        ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0);
        ctx.vertexAttrib1f(ii, 0);
      }
      ctx.deleteBuffer(tmp);
    
      var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
      for (var ii = 0; ii < numTextureUnits; ++ii) {
        ctx.activeTexture(ctx.TEXTURE0 + ii);
        ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null);
        ctx.bindTexture(ctx.TEXTURE_2D, null);
      }
    
      ctx.activeTexture(ctx.TEXTURE0);
      ctx.useProgram(null);
      ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
      ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
      ctx.bindFramebuffer(ctx.FRAMEBUFFER, null);
      ctx.bindRenderbuffer(ctx.RENDERBUFFER, null);
      ctx.disable(ctx.BLEND);
      ctx.disable(ctx.CULL_FACE);
      ctx.disable(ctx.DEPTH_TEST);
      ctx.disable(ctx.DITHER);
      ctx.disable(ctx.SCISSOR_TEST);
      ctx.blendColor(0, 0, 0, 0);
      ctx.blendEquation(ctx.FUNC_ADD);
      ctx.blendFunc(ctx.ONE, ctx.ZERO);
      ctx.clearColor(0, 0, 0, 0);
      ctx.clearDepth(1);
      ctx.clearStencil(-1);
      ctx.colorMask(true, true, true, true);
      ctx.cullFace(ctx.BACK);
      ctx.depthFunc(ctx.LESS);
      ctx.depthMask(true);
      ctx.depthRange(0, 1);
      ctx.frontFace(ctx.CCW);
      ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE);
      ctx.lineWidth(1);
      ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4);
      ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4);
      ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false);
      ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
      // TODO: Delete this IF.
      if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) {
        ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL);
      }
      ctx.polygonOffset(0, 0);
      ctx.sampleCoverage(1, false);
      ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height);
      ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF);
      ctx.stencilMask(0xFFFFFFFF);
      ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP);
      ctx.viewport(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
      ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
    
      // TODO: This should NOT be needed but Firefox fails with 'hint'
      while(ctx.getError());
    }
    
    function makeLostContextSimulatingContext(ctx) {
      var wrapper_ = {};
      var contextId_ = 1;
      var contextLost_ = false;
      var resourceId_ = 0;
      var resourceDb_ = [];
      var onLost_ = undefined;
      var onRestored_ = undefined;
      var nextOnRestored_ = undefined;
    
      // Holds booleans for each GL error so can simulate errors.
      var glErrorShadow_ = { };
    
      function isWebGLObject(obj) {
        //return false;
        return (obj instanceof WebGLBuffer ||
                obj instanceof WebGLFramebuffer ||
                obj instanceof WebGLProgram ||
                obj instanceof WebGLRenderbuffer ||
                obj instanceof WebGLShader ||
                obj instanceof WebGLTexture);
      }
    
      function checkResources(args) {
        for (var ii = 0; ii < args.length; ++ii) {
          var arg = args[ii];
          if (isWebGLObject(arg)) {
            return arg.__webglDebugContextLostId__ == contextId_;
          }
        }
        return true;
      }
    
      function clearErrors() {
        var k = Object.keys(glErrorShadow_);
        for (var ii = 0; ii < k.length; ++ii) {
          delete glErrorShdow_[k];
        }
      }
    
      // Makes a function that simulates WebGL when out of context.
      function makeLostContextWrapper(ctx, functionName) {
        var f = ctx[functionName];
        return function() {
          // Only call the functions if the context is not lost.
          if (!contextLost_) {
            if (!checkResources(arguments)) {
              glErrorShadow_[ctx.INVALID_OPERATION] = true;
              return;
            }
            var result = f.apply(ctx, arguments);
            return result;
          }
        };
      }
    
      for (var propertyName in ctx) {
        if (typeof ctx[propertyName] == 'function') {
           wrapper_[propertyName] = makeLostContextWrapper(ctx, propertyName);
         } else {
           wrapper_[propertyName] = ctx[propertyName];
         }
      }
    
      function makeWebGLContextEvent(statusMessage) {
        return {statusMessage: statusMessage};
      }
    
      function freeResources() {
        for (var ii = 0; ii < resourceDb_.length; ++ii) {
          var resource = resourceDb_[ii];
          if (resource instanceof WebGLBuffer) {
            ctx.deleteBuffer(resource);
          } else if (resource instanceof WebctxFramebuffer) {
            ctx.deleteFramebuffer(resource);
          } else if (resource instanceof WebctxProgram) {
            ctx.deleteProgram(resource);
          } else if (resource instanceof WebctxRenderbuffer) {
            ctx.deleteRenderbuffer(resource);
          } else if (resource instanceof WebctxShader) {
            ctx.deleteShader(resource);
          } else if (resource instanceof WebctxTexture) {
            ctx.deleteTexture(resource);
          }
        }
      }
    
      wrapper_.loseContext = function() {
        if (!contextLost_) {
          contextLost_ = true;
          ++contextId_;
          while (ctx.getError());
          clearErrors();
          glErrorShadow_[ctx.CONTEXT_LOST_WEBGL] = true;
          setTimeout(function() {
              if (onLost_) {
                onLost_(makeWebGLContextEvent("context lost"));
              }
            }, 0);
        }
      };
    
      wrapper_.restoreContext = function() {
        if (contextLost_) {
          if (onRestored_) {
            setTimeout(function() {
                freeResources();
                resetToInitialState(ctx);
                contextLost_ = false;
                if (onRestored_) {
                  var callback = onRestored_;
                  onRestored_ = nextOnRestored_;
                  nextOnRestored_ = undefined;
                  callback(makeWebGLContextEvent("context restored"));
                }
              }, 0);
          } else {
            throw "You can not restore the context without a listener"
          }
        }
      };
    
      // Wrap a few functions specially.
      wrapper_.getError = function() {
        if (!contextLost_) {
          var err;
          while (err = ctx.getError()) {
            glErrorShadow_[err] = true;
          }
        }
        for (var err in glErrorShadow_) {
          if (glErrorShadow_[err]) {
            delete glErrorShadow_[err];
            return err;
          }
        }
        return ctx.NO_ERROR;
      };
    
      var creationFunctions = [
        "createBuffer",
        "createFramebuffer",
        "createProgram",
        "createRenderbuffer",
        "createShader",
        "createTexture"
      ];
      for (var ii = 0; ii < creationFunctions.length; ++ii) {
        var functionName = creationFunctions[ii];
        wrapper_[functionName] = function(f) {
          return function() {
            if (contextLost_) {
              return null;
            }
            var obj = f.apply(ctx, arguments);
            obj.__webglDebugContextLostId__ = contextId_;
            resourceDb_.push(obj);
            return obj;
          };
        }(ctx[functionName]);
      }
    
      var functionsThatShouldReturnNull = [
        "getActiveAttrib",
        "getActiveUniform",
        "getBufferParameter",
        "getContextAttributes",
        "getAttachedShaders",
        "getFramebufferAttachmentParameter",
        "getParameter",
        "getProgramParameter",
        "getProgramInfoLog",
        "getRenderbufferParameter",
        "getShaderParameter",
        "getShaderInfoLog",
        "getShaderSource",
        "getTexParameter",
        "getUniform",
        "getUniformLocation",
        "getVertexAttrib"
      ];
      for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) {
        var functionName = functionsThatShouldReturnNull[ii];
        wrapper_[functionName] = function(f) {
          return function() {
            if (contextLost_) {
              return null;
            }
            return f.apply(ctx, arguments);
          }
        }(wrapper_[functionName]);
      }
    
      var isFunctions = [
        "isBuffer",
        "isEnabled",
        "isFramebuffer",
        "isProgram",
        "isRenderbuffer",
        "isShader",
        "isTexture"
      ];
      for (var ii = 0; ii < isFunctions.length; ++ii) {
        var functionName = isFunctions[ii];
        wrapper_[functionName] = function(f) {
          return function() {
            if (contextLost_) {
              return false;
            }
            return f.apply(ctx, arguments);
          }
        }(wrapper_[functionName]);
      }
    
      wrapper_.checkFramebufferStatus = function(f) {
        return function() {
          if (contextLost_) {
            return ctx.FRAMEBUFFER_UNSUPPORTED;
          }
          return f.apply(ctx, arguments);
        };
      }(wrapper_.checkFramebufferStatus);
    
      wrapper_.getAttribLocation = function(f) {
        return function() {
          if (contextLost_) {
            return -1;
          }
          return f.apply(ctx, arguments);
        };
      }(wrapper_.getAttribLocation);
    
      wrapper_.getVertexAttribOffset = function(f) {
        return function() {
          if (contextLost_) {
            return 0;
          }
          return f.apply(ctx, arguments);
        };
      }(wrapper_.getVertexAttribOffset);
    
      wrapper_.isContextLost = function() {
        return contextLost_;
      };
    
      function wrapEvent(listener) {
        if (typeof(listener) == "function") {
          return listener;
        } else {
          return function(info) {
            listener.handleEvent(info);
          }
        }
      }
    
      wrapper_.registerOnContextLostListener = function(listener) {
        onLost_ = wrapEvent(listener);
      };
    
      wrapper_.registerOnContextRestoredListener = function(listener) {
        if (contextLost_) {
          nextOnRestored_ = wrapEvent(listener);
        } else {
          onRestored_ = wrapEvent(listener);
        }
      }
    
      return wrapper_;
    }
    
    return {
      /**
       * Initializes this module. Safe to call more than once.
       * @param {!WebGLRenderingContext} ctx A WebGL context. If
       *    you have more than one context it doesn't matter which one
       *    you pass in, it is only used to pull out constants.
       */
      'init': init,
    
      /**
       * Returns true or false if value matches any WebGL enum
       * @param {*} value Value to check if it might be an enum.
       * @return {boolean} True if value matches one of the WebGL defined enums
       */
      'mightBeEnum': mightBeEnum,
    
      /**
       * Gets an string version of an WebGL enum.
       *
       * Example:
       *   WebGLDebugUtil.init(ctx);
       *   var str = WebGLDebugUtil.glEnumToString(ctx.getError());
       *
       * @param {number} value Value to return an enum for
       * @return {string} The string version of the enum.
       */
      'glEnumToString': glEnumToString,
    
      /**
       * Converts the argument of a WebGL function to a string.
       * Attempts to convert enum arguments to strings.
       *
       * Example:
       *   WebGLDebugUtil.init(ctx);
       *   var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D);
       *
       * would return 'TEXTURE_2D'
       *
       * @param {string} functionName the name of the WebGL function.
       * @param {number} argumentIndx the index of the argument.
       * @param {*} value The value of the argument.
       * @return {string} The value as a string.
       */
      'glFunctionArgToString': glFunctionArgToString,
    
      /**
       * Given a WebGL context returns a wrapped context that calls
       * gl.getError after every command and calls a function if the
       * result is not NO_ERROR.
       *
       * You can supply your own function if you want. For example, if you'd like
       * an exception thrown on any GL error you could do this
       *
       *    function throwOnGLError(err, funcName, args) {
       *      throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" +
       *            funcName;
       *    };
       *
       *    ctx = WebGLDebugUtils.makeDebugContext(
       *        canvas.getContext("webgl"), throwOnGLError);
       *
       * @param {!WebGLRenderingContext} ctx The webgl context to wrap.
       * @param {!function(err, funcName, args): void} opt_onErrorFunc The function
       *     to call when gl.getError returns an error. If not specified the default
       *     function calls console.log with a message.
       */
      'makeDebugContext': makeDebugContext,
    
      /**
       * Given a WebGL context returns a wrapped context that adds 4
       * functions.
       *
       * ctx.loseContext:
       *   simulates a lost context event.
       *
       * ctx.restoreContext:
       *   simulates the context being restored.
       *
       * ctx.registerOnContextLostListener(listener):
       *   lets you register a listener for context lost. Use instead
       *   of addEventListener('webglcontextlostevent', listener);
       *
       * ctx.registerOnContextRestoredListener(listener):
       *   lets you register a listener for context restored. Use
       *   instead of addEventListener('webglcontextrestored',
       *   listener);
       *
       * @param {!WebGLRenderingContext} ctx The webgl context to wrap.
       */
      'makeLostContextSimulatingContext': makeLostContextSimulatingContext,
    
      /**
       * Resets a context to the initial state.
       * @param {!WebGLRenderingContext} ctx The webgl context to
       *     reset.
       */
      'resetToInitialState': resetToInitialState
    };
    
    }();
    

    webgl-utils.js

    /*
     * Copyright 2010, Google Inc.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are
     * met:
     *
     *     * Redistributions of source code must retain the above copyright
     * notice, this list of conditions and the following disclaimer.
     *     * Redistributions in binary form must reproduce the above
     * copyright notice, this list of conditions and the following disclaimer
     * in the documentation and/or other materials provided with the
     * distribution.
     *     * Neither the name of Google Inc. nor the names of its
     * contributors may be used to endorse or promote products derived from
     * this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    
    /**
     * @fileoverview This file contains functions every webgl program will need
     * a version of one way or another.
     *
     * Instead of setting up a context manually it is recommended to
     * use. This will check for success or failure. On failure it
     * will attempt to present an approriate message to the user.
     *
     *       gl = WebGLUtils.setupWebGL(canvas);
     *
     * For animated WebGL apps use of setTimeout or setInterval are
     * discouraged. It is recommended you structure your rendering
     * loop like this.
     *
     *       function render() {
     *         window.requestAnimationFrame(render, canvas);
     *
     *         // do rendering
     *         ...
     *       }
     *       render();
     *
     * This will call your rendering function up to the refresh rate
     * of your display but will stop rendering if your app is not
     * visible.
     */
    
    WebGLUtils = function() {
    
    /**
     * Creates the HTLM for a failure message
     * @param {string} canvasContainerId id of container of th
     *        canvas.
     * @return {string} The html.
     */
    var makeFailHTML = function(msg) {
      return '' +
            '<div style="margin: auto; width:500px;z-index:10000;margin-top:20em;text-align:center;">' + msg + '</div>';
      return '' +'<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +'<td align="center">' +'<div style="display: table-cell; vertical-align: middle;">' +'<div style="">' + msg + '</div>' +'</div>' +'</td></tr></table>';
    };
    
    /**
     * Mesasge for getting a webgl browser
     * @type {string}
     */
    var GET_A_WEBGL_BROWSER = '' +
      'This page requires a browser that supports WebGL.<br/>' +
      '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
    
    /**
     * Mesasge for need better hardware
     * @type {string}
     */
    var OTHER_PROBLEM = '' +
      "It doesn't appear your computer can support WebGL.<br/>" +
      '<a href="http://get.webgl.org">Click here for more information.</a>';
    
    /**
     * Creates a webgl context. If creation fails it will
     * change the contents of the container of the <canvas>
     * tag to an error message with the correct links for WebGL.
     * @param {Element} canvas. The canvas element to create a
     *     context from.
     * @param {WebGLContextCreationAttirbutes} opt_attribs Any
     *     creation attributes you want to pass in.
     * @param {function:(msg)} opt_onError An function to call
     *     if there is an error during creation.
     * @return {WebGLRenderingContext} The created context.
     */
    var setupWebGL = function(canvas, opt_attribs, opt_onError) {
      function handleCreationError(msg) {
          var container = document.getElementsByTagName("body")[0];
        //var container = canvas.parentNode;
        if (container) {
          var str = window.WebGLRenderingContext ?
               OTHER_PROBLEM :
               GET_A_WEBGL_BROWSER;
          if (msg) {
            str += "<br/><br/>Status: " + msg;
          }
          container.innerHTML = makeFailHTML(str);
        }
      };
    
      opt_onError = opt_onError || handleCreationError;
    
      if (canvas.addEventListener) {
        canvas.addEventListener("webglcontextcreationerror", function(event) {
              opt_onError(event.statusMessage);
            }, false);
      }
      var context = create3DContext(canvas, opt_attribs);
      if (!context) {
        if (!window.WebGLRenderingContext) {
          opt_onError("");
        } else {
          opt_onError("");
        }
      }
    
      return context;
    };
    
    /**
     * Creates a webgl context.
     * @param {!Canvas} canvas The canvas tag to get context
     *     from. If one is not passed in one will be created.
     * @return {!WebGLContext} The created context.
     */
    var create3DContext = function(canvas, opt_attribs) {
      var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
      var context = null;
      for (var ii = 0; ii < names.length; ++ii) {
        try {
          context = canvas.getContext(names[ii], opt_attribs);
        } catch(e) {}
        if (context) {
          break;
        }
      }
      return context;
    }
    
    return {
      create3DContext: create3DContext,
      setupWebGL: setupWebGL
    };
    }();
    
    /**
     * Provides requestAnimationFrame in a cross browser
     * way.
     */
    if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = (function() {
        return window.requestAnimationFrame ||
               window.webkitRequestAnimationFrame ||
               window.mozRequestAnimationFrame ||
               window.oRequestAnimationFrame ||
               window.msRequestAnimationFrame ||
               function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
                 window.setTimeout(callback, 1000/60);
               };
      })();
    }
    
    /** * ERRATA: 'cancelRequestAnimationFrame' renamed to 'cancelAnimationFrame' to reflect an update to the W3C Animation-Timing Spec. 
     * 
     * Cancels an animation frame request. 
     * Checks for cross-browser support, falls back to clearTimeout. 
     * @param {number}  Animation frame request. */
    if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = (window.cancelRequestAnimationFrame ||
                                     window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
                                     window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame ||
                                     window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame ||
                                     window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame ||
                                     window.clearTimeout);
    }
    

    相关文章

      网友评论

          本文标题:WebGL编程指南函数库

          本文链接:https://www.haomeiwen.com/subject/ucoyqktx.html