Full Code of greggman/tdl for AI

master 6b633052599e cached
38 files
463.7 KB
140.4k tokens
34 symbols
1 requests
Download .txt
Showing preview only (481K chars total). Download the full file or copy to clipboard to get everything.
Repository: greggman/tdl
Branch: master
Commit: 6b633052599e
Files: 38
Total size: 463.7 KB

Directory structure:
gitextract_7m630dcz/

├── .gitignore
├── Gruntfile.js
├── README.md
├── bower.json
├── docs.md
├── example/
│   ├── example-requirejs.html
│   ├── example-requirejs.js
│   ├── example.html
│   ├── example2.html
│   ├── line.html
│   └── picking.html
├── js/
│   └── require.js
├── jsdoc.conf.json
├── package.json
└── tdl/
    ├── base-rs.js
    ├── base.js
    ├── buffers.js
    ├── clock.js
    ├── fast.js
    ├── fps.js
    ├── framebuffers.js
    ├── fullscreen.js
    ├── io.js
    ├── loader.js
    ├── log.js
    ├── math.js
    ├── misc.js
    ├── models.js
    ├── particles.js
    ├── primitives.js
    ├── programs.js
    ├── quaternions.js
    ├── screenshot.js
    ├── shader.js
    ├── string.js
    ├── sync.js
    ├── textures.js
    └── webgl.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
docs
*.Makefile
*.mk
*.ncb
*.ninja
*.props
*.pyc
*.rules
*.scons
*.sdf
*.sln
*.suo
*.targets
*.user
*.vcproj
*.vcxproj
*.vcxproj.filters
*.vpj
*.vpw
*.vpwhistu
*.vtg
*.xcodeproj
*~
.*.sw?
.DS_Store
.cproject
.gdb_history
.gdbinit
.metadata
.project
tags
Thumbs.db
v8.log
node_modules



================================================
FILE: Gruntfile.js
================================================
"use strict";

module.exports = function(grunt) {

  grunt.initConfig({
    jsdoc: {
      tdl: {
        src: ['tdl/*.js'],
        options: {
          destination: 'docs/gen',
          configure: 'jsdoc.conf.json',
          template: 'node_modules/ink-docstrap/template',
          private: false,
        },
      },
    },
    clean: [
        'docs/gen',
    ],
    uglify: {
      my_target: {
        files: {
          'build/tdl.min.js': [
            'tdl/base.js',
            'tdl/buffers.js',
            'tdl/clock.js',
            'tdl/fast.js',
            'tdl/fps.js',
            'tdl/framebuffers.js',
            'tdl/fullscreen.js',
            'tdl/io.js',
            'tdl/loader.js',
            'tdl/log.js',
            'tdl/math.js',
            'tdl/misc.js',
            'tdl/models.js',
            'tdl/particles.js',
            'tdl/primitives.js',
            'tdl/programs.js',
            'tdl/quaternions.js',
            'tdl/screenshot.js',
            'tdl/shader.js',
            'tdl/string.js',
            'tdl/sync.js',
            'tdl/textures.js',
            'tdl/webgl.js',
          ],
        },
      },
    },
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-jsdoc');
  grunt.loadNpmTasks('grunt-contrib-uglify');

  grunt.registerTask('default', ['clean', 'jsdoc', 'uglify']);
};



================================================
FILE: README.md
================================================
TDL
===

Please check out [TWGL](http://twgljs.org). It's arguably the spiritual successor to TDL.

TDL is a **low-level** library for WebGL apps. It currently focuses on speed of rendering rather than ease of use.

Some [terse docs can be found at here](docs.md)

Note: By **low-level** I mean TDL doesn't currently provide any 3D knowledge. 
There are almost no built in shaders. There is no scene graph. There are just some objects for wrapping WebGL
shaders and helping to easily associate vertex data with attributes and update uniforms. 

Example: Assuming a shaders like this.

    <script id="vshader" type="not-js">
    attribute vec4 position;
    attribute vec2 texcoord;
    
    uniform mat4 u_worldMatrix;
    uniform mat4 u_projectionMatrix;
    
    varying vec2 v_texcoord;
    
    void main() {
      gl_Position = u_projectionMatrix * u_worldMatrix * position;
      v_texcoord = texcoord;
    }
    </script>
    
    <script id="fshader" type="not-js">
    varying vec2 v_texcoord;
    uniform sampler2D u_texture;
    
    void main() {
      gl_FragColor = texture2D(u_texture, v_texcoord);
    }
    </script>

In WebGL you'd do this

    // At init time:
    var program = UtilToCompileShaders("vshader", "fshader");
    var positionLoc = gl.getAttribLocation(program, "position");
    var texcoordLoc = gl.getAttribLocation(program, "texcoord");
    var worldMatLoc = gl.getUniformLocation(program, "u_worldMatrix");
    var projectionMatLoc = gl.getUniformLocation(program, "u_projectionMatrix");
    var textureLoc = gl.getUniformLocation(program, "u_texture");

    var positions = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positions);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positionData), gl.STATIC_DRAW);
    
    var tecoords = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texcoords);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoordData), gl.STATIC_DRAW);
    
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, someImage);


    // At draw time
    gl.bindBuffer(gl.ARRAY_BUFFER, positions);
    gl.enableVertexAttribArray(programLoc);
    gl.vertexAttribPointer(programLoc, 3, gl.FLOAT, false, 0, 0);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, positions);
    gl.enableVertexAttribArray(texcoordLoc);
    gl.vertexAttribPointer(tecoordLoc, 2, gl.FLOAT, false, 0, 0);
    
    gl.useProgram(program);
    gl.uniformMatrix4f(projectionMatLoc, false, projectionMatrix);
    
    for (var i = 0; i < 3; ++i)
    {
        gl.uniformMatrix4f(worldMatLoc, false, computeWorldMatrix(i));
        gl.drawArrays(gl.TRIANGLES, 0, num);
    }
    
In TDL that would be shortened to

    // At init time.
    var program = tdl.programs.loadProgramFromScriptTags("vshader", "fshader");
    var arrays = {
      position: new tdl.primitives.AttribBuffer(3, positionData),
      texcoord: new tdl.primitives.AttribBuffer(2, texcoordData),
    };
    var textures = {
      u_texture: new tdl.textures.loadTexture(someImage),
    }
    var model = new tdl.models.Model(program, arrays, textures);
  
    
    // At Draw time
    var sharedUniforms = {
      u_projectionMatrix: projectionMatrix,
    };
    var perObjectUniforms = {
      u_worldMatrix: worldMatrix,
    };
    
    model.drawPrep(sharedUniforms);
    
    for (var i = 0; i < 3; ++i)
    {
        perObjectUnifirms.u_worldMatrix = computeWorldMatrix(i);
        model.draw(perObjectuniforms);
    }



================================================
FILE: bower.json
================================================
{
  "name": "tdl",
  "version": "0.0.8",
  "authors": [
    {
      "name": "Gregg Tavares",
      "email": "github@greggman.com",
      "homepage": "http://games.greggman.com"
    }
  ],
  "description": "A JavaScript library for WebGL",
  "main": "tdl/base.js",
  "moduleType": [
    "amd"
  ],
  "keywords": [
    "webgl",
    "tdl"
  ],
  "license": "MIT",
  "homepage": "https://github.com/greggman/tdl",
  "repository": "git://github.com/greggman/tdl.git",
  "ignore": [
    "**/.*",
    "*.md",
    "Gruntfile.js",
    "package.json",
    "bower.json",
    "node_modules",
    "docs",
    "build",
    "example",
    "js",
    "bower_components",
    "test",
    "tests"
  ]
}


================================================
FILE: docs.md
================================================
TDL Docs
========
I hope the code is pretty straight forward. There's some simple examples here

<a href="http://greggman.github.com/tdl/example/example.html">http://greggman.github.com/tdl/example/example.html</a>

<a href="http://greggman.github.com/tdl/example/example2.html">http://greggman.github.com/tdl/example/example2.html</a>

<a href="http://greggman.github.com/tdl/example/picking.html">http://greggman.github.com/tdl/example/picking.html</a>

More complex samples can be found at <a href="http://webglsamples.googlecode.com">http://webglsamples.googlecode.com</a>

Briefly...

Your startup code should look like this

    canvas = document.getElementById("canvas");
    gl = tdl.webgl.setupWebGL(canvas);
    if (!gl) {
      return;  // Do nothing
    }

Where "canvas" is the id of the canvas you want to draw into. 
tdl.webgl.setupWebGL will replace the contents of the containing div 
with a link to getting a WebGL capable browser if the user's browser 
does not support WebGL. 

Otherwise...

Loading Shaders
---------------

    var program = tdl.programs.loadProgram(vertexShaderSource, fragmentShaderSource);

Compiles your shaders and creates a Program object.

Loading Textures
----------------

    var textures = {
      name1: tdl.textures.loadTexture(url),
      name2: tdl.textures.loadTexture(url)
    };

Loads your textures. The property names must match whatever you called the samplers 
in your shaders. loadTexture can take `[url]` for an image, `[r,g,b,a]` for solid 
texture. `[url,url,url,url,url,url]` for a cubemap and also `[url]` for a cubemap 
where all 6 faces are in a cross. It can also take an img or canvas tag.

Create Vertices or a Mesh
-------------------------

    var arrays = tdl.primitives.createSphere(1, 10, 10);

Creates vertices

The tdl.primitives functions return an object like this 

    {
        position: AttribBuffer,
        normal: AttribBuffer,
        texCoord: AttribBuffer
    };

The property names must match the attributes in your vertex shader if you want to 
add more.
 
A call to tdl.primitives.addTangentsAndBinormals adds the fields "tangent" and 
"binormal"

Create a Model
--------------

Once you have a program, a texture object and an arrays object you make a new 
model with

    var model = new tdl.models.Model(program, array, textures);


Rendering
---------

To draw the model there are 2 functions, `model.drawPrep(uniformMap)` and 
`model.draw(uniformMap)`.

Both of them take an object with uniformName/value pairs.

model.drawPrep binds the program, binds all the textures and attributes and 
sets whatever uniforms you pass in.

model.draw sets any more uniforms you pass in and then calls gl.drawElements.  
The idea is you call `model.drawPrep` once and then `model.draw` to draw a 
bunch of the same model, changing as few uniforms as possible. This is the 
fastest way to use WebGL.

Your rendering loop should look something like this

    function render() {
      var time = tdl.webgl.animationTime();
      model.drawPrep({...});
      model.draw({...});
      tdl.webgl.requestAnimationFrame(render, canvas);
    }
    render();  // call the first render manually to start it off.  


Math
----

The math is a little funky. There are 2 math libraries, math.js and fast.js.  
math.js comes from O3D and uses `JavaScript` arrays. A Matrix in that 
library is a an array of numbers.  fast.js uses `Float32Array` for its storage 
and most functions take a destination object as the first argument. 
Theoretically this is faster because you can avoid a certain number of 
allocations. It also means the numbers in the array do not have to be queried 
and converted from `JavaScript` Number to floats before calling glUniform.


================================================
FILE: example/example-requirejs.html
================================================
<!--
 * Copyright 2009, 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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL TDL Example</title>
<style>
html, body {
  width: 100%;
  height: 100%;
  border: 0px;
  padding: 0px;
  margin: 0px;
  background-color: red;
  font-family: sans-serif;
  overflow: hidden;
  color: #fff;
}
a {
  color: #fff;
}
#info {
    font-size: small;
    position: absolute;
	top: 0px; width: 100%;
	padding: 5px;
	text-align: center;
	z-index: 2;
}
CANVAS {
  background-color: gray;
}
.fpsContainer {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  color: white;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
#viewContainer {
  width: 100%;
  height: 100%;
}
</style>
<script data-main="example-requirejs.js" src="../js/require.js"></script>
</head>
<body>
<div id="info"><a href="http://github.com/greggman/tdl" target="_blank">tdl.js</a> - example</div>
<div class="fpsContainer">
  <div class="fps">fps: <span id="fps"></div>
</div>
<div id="viewContainer">
<canvas id="canvas" width="1024" height="1024" style="width: 100%; height: 100%;"></canvas>
</div>
</body>
<script id="sphereVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
uniform vec3 lightWorldPos;
uniform mat4 world;
uniform mat4 viewInverse;
uniform mat4 worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
  v_texCoord = texCoord;
  v_position = (worldViewProjection * position);
  v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
  v_surfaceToLight = lightWorldPos - (world * position).xyz;
  v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
  gl_Position = v_position;
}

</script>
<script id="sphereFragmentShader" type="text/something-not-javascript">
precision mediump float;
uniform vec4 lightColor;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform sampler2D diffuseSampler;
uniform vec4 specular;
uniform sampler2D bumpSampler;
uniform float shininess;
uniform float specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}
void main() {
  vec4 diffuse = texture2D(diffuseSampler, v_texCoord);
  vec3 normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(normal, surfaceToLight),
                    dot(normal, halfVector), shininess);
  gl_FragColor = vec4((
  lightColor * (diffuse * litR.y
                        + specular * litR.z * specularFactor)).rgb,
      diffuse.a);
}
</script>
</html>




================================================
FILE: example/example-requirejs.js
================================================
var main = function(
   TDLBuffers,
   TDLFast,
   TDLFps,
   TDLLog,
   TDLMath,
   TDLModels,
   TDLPrimitives,
   TDLPrograms,
   TDLTextures,
   TDLWebGL) {
  // globals
  var gl;                   // the gl context.
  var canvas;               // the canvas
  var math;                 // the math lib.
  var fast;                 // the fast math lib.
  var g_fpsTimer;           // object to measure frames per second;
  var g_logGLCalls = true;  // whether or not to log webgl calls
  var g_debug = false;      // whether or not to debug.
  var g_drawOnce = false;   // draw just one frame.

  //g_drawOnce = true;
  //g_debug = true;

  var g_eyeSpeed          = 0.5;
  var g_eyeHeight         = 2;
  var g_eyeRadius         = 9;

  function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
    for (var ii = 0; ii < args.length; ++ii) {
      if (args[ii] === undefined) {
        TDLLog.error("undefined passed to gl." + functionName + "(" +
                     TDLWebGL.glFunctionArgsToString(functionName, args) + ")");
      }
    }
  }

  function Log(msg) {
    if (g_logGLCalls) {
      TDLLog.log(msg);
    }
  }

  function LogGLCall(functionName, args) {
    if (g_logGLCalls) {
      ValidateNoneOfTheArgsAreUndefined(functionName, args)
      TDLLog.log("gl." + functionName + "(" +
                  TDLWebGL.glFunctionArgsToString(functionName, args) + ")");
    }
  }

  function createProgramFromTags(vertexTagId, fragmentTagId) {
    return TDLPrograms.loadProgram(
        document.getElementById(vertexTagId).text,
        document.getElementById(fragmentTagId).text);
  }

  /**
   * Sets up Planet.
   */
  function setupSphere() {
    var textures = {
      diffuseSampler: TDLTextures.loadTexture('assets/sometexture.png')};
    var program = createProgramFromTags(
        'sphereVertexShader',
        'sphereFragmentShader');
    var arrays = TDLPrimitives.createSphere(0.4, 10, 12);

    return new TDLModels.Model(program, arrays, textures);
  }

  function initialize() {
    math = TDLMath;
    fast = TDLFast;
    canvas = document.getElementById("canvas");
    g_fpsTimer = new TDLFps.FPSTimer();

    gl = TDLWebGL.setupWebGL(canvas);
    if (!gl) {
      return false;
    }
    if (g_debug) {
      gl = TDLWebGL.makeDebugContext(gl, undefined, LogGLCall);
    }

    Log("--Setup Sphere---------------------------------------");
    var sphere = setupSphere();

    var then = 0.0;
    var clock = 0.0;
    var fpsElem = document.getElementById("fps");

    // pre-allocate a bunch of arrays
    var projection = new Float32Array(16);
    var view = new Float32Array(16);
    var world = new Float32Array(16);
    var worldInverse = new Float32Array(16);
    var worldInverseTranspose = new Float32Array(16);
    var viewProjection = new Float32Array(16);
    var worldViewProjection = new Float32Array(16);
    var viewInverse = new Float32Array(16);
    var viewProjectionInverse = new Float32Array(16);
    var eyePosition = new Float32Array(3);
    var target = new Float32Array(3);
    var up = new Float32Array([0,1,0]);
    var lightWorldPos = new Float32Array(3);
    var v3t0 = new Float32Array(3);
    var v3t1 = new Float32Array(3);
    var v3t2 = new Float32Array(3);
    var v3t3 = new Float32Array(3);
    var m4t0 = new Float32Array(16);
    var m4t1 = new Float32Array(16);
    var m4t2 = new Float32Array(16);
    var m4t3 = new Float32Array(16);
    var zero4 = new Float32Array(4);
    var one4 = new Float32Array([1,1,1,1]);

    // Sphere uniforms.
    var sphereConst = {
      viewInverse: viewInverse,
      lightWorldPos: lightWorldPos,
      specular: one4,
      shininess: 50,
      specularFactor: 0.2};
    var spherePer = {
      lightColor: new Float32Array([0,0,0,1]),
      world: world,
      worldViewProjection: worldViewProjection,
      worldInverse: worldInverse,
      worldInverseTranspose: worldInverseTranspose};

    var frameCount = 0;
    function render() {
      ++frameCount;
      if (!g_drawOnce) {
        TDLWebGL.requestAnimationFrame(render, canvas);
      }
      var now = (new Date()).getTime() * 0.001;
      var elapsedTime;
      if(then == 0.0) {
        elapsedTime = 0.0;
      } else {
        elapsedTime = now - then;
      }
      then = now;

      g_fpsTimer.update(elapsedTime);
      fpsElem.innerHTML = g_fpsTimer.averageFPS;

      clock += elapsedTime;
      eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius;
      eyePosition[1] = g_eyeHeight;
      eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius;

      gl.colorMask(true, true, true, true);
      gl.depthMask(true);
      gl.clearColor(0,0,0,0);
      gl.clearDepth(1);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

      gl.enable(gl.CULL_FACE);
      gl.enable(gl.DEPTH_TEST);

      fast.matrix4.perspective(
          projection,
          math.degToRad(60),
          canvas.clientWidth / canvas.clientHeight,
          1,
          5000);
      fast.matrix4.lookAt(
          view,
          eyePosition,
          target,
          up);
      fast.matrix4.mul(viewProjection, view, projection);
      fast.matrix4.inverse(viewInverse, view);
      fast.matrix4.inverse(viewProjectionInverse, viewProjection);

      fast.matrix4.getAxis(v3t0, viewInverse, 0); // x
      fast.matrix4.getAxis(v3t1, viewInverse, 1); // y;
      fast.matrix4.getAxis(v3t2, viewInverse, 2); // z;
      fast.mulScalarVector(v3t0, 10, v3t0);
      fast.mulScalarVector(v3t1, 10, v3t1);
      fast.mulScalarVector(v3t2, 10, v3t2);
      fast.addVector(lightWorldPos, eyePosition, v3t0);
      fast.addVector(lightWorldPos, lightWorldPos, v3t1);
      fast.addVector(lightWorldPos, lightWorldPos, v3t2);

  //      view: view,
  //      projection: projection,
  //      viewProjection: viewProjection,

      Log("--Draw sphere---------------------------------------");
      sphere.drawPrep(sphereConst);
      var across = 6;
      var lightColor = spherePer.lightColor;
      var half = (across - 1) * 0.5;
      for (var xx = 0; xx < across; ++xx) {
        for (var yy = 0; yy < across; ++yy) {
          for (var zz = 0; zz < across; ++zz) {
            lightColor[0] = xx / across;
            lightColor[1] = yy / across;
            lightColor[2] = zz / across;
            var scale = (xx + yy + zz) % 4 / 4 + 0.5;
            fast.matrix4.scaling(m4t0, [scale, scale, scale]);
            fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]);
            fast.matrix4.mul(world, m4t0, m4t1);
            fast.matrix4.mul(worldViewProjection, world, viewProjection);
            fast.matrix4.inverse(worldInverse, world);
            fast.matrix4.transpose(worldInverseTranspose, worldInverse);
            sphere.draw(spherePer);
          }
        }
      }

      // Set the alpha to 255.
      gl.colorMask(false, false, false, true);
      gl.clearColor(0,0,0,1);
      gl.clear(gl.COLOR_BUFFER_BIT);

      // turn off logging after 1 frame.
      g_logGLCalls = false;
    }
    render();
    return true;
  }
  initialize();
}

requirejs(
    [ '../tdl/buffers',
      '../tdl/fast',
      '../tdl/fps',
      '../tdl/log',
      '../tdl/math',
      '../tdl/models',
      '../tdl/primitives',
      '../tdl/programs',
      '../tdl/textures',
      '../tdl/webgl',
    ],
    main);


================================================
FILE: example/example.html
================================================
<!--
 * Copyright 2009, 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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL TDL Example</title>
<style>
html, body {
  width: 100%;
  height: 100%;
  border: 0px;
  padding: 0px;
  margin: 0px;
  background-color: red;
  font-family: sans-serif;
  overflow: hidden;
  color: #fff;
}
a {
  color: #fff;
}
#info {
    font-size: small;
    position: absolute;
	top: 0px; width: 100%;
	padding: 5px;
	text-align: center;
	z-index: 2;
}
CANVAS {
  background-color: gray;
}
.fpsContainer {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  color: white;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
#viewContainer {
  width: 100%;
  height: 100%;
}
</style>
<script type="text/javascript" src="../tdl/base.js"></script>
<script type="text/javascript">
tdl.require('tdl.buffers');
tdl.require('tdl.fast');
tdl.require('tdl.fps');
tdl.require('tdl.log');
tdl.require('tdl.math');
tdl.require('tdl.models');
tdl.require('tdl.primitives');
tdl.require('tdl.programs');
tdl.require('tdl.textures');
tdl.require('tdl.webgl');
window.onload = initialize;

// globals
var gl;                   // the gl context.
var canvas;               // the canvas
var math;                 // the math lib.
var fast;                 // the fast math lib.
var g_fpsTimer;           // object to measure frames per second;
var g_logGLCalls = true;  // whether or not to log webgl calls
var g_debug = false;      // whether or not to debug.
var g_drawOnce = false;   // draw just one frame.

//g_drawOnce = true;
//g_debug = true;

var g_eyeSpeed          = 0.5;
var g_eyeHeight         = 2;
var g_eyeRadius         = 9;

function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
  for (var ii = 0; ii < args.length; ++ii) {
    if (args[ii] === undefined) {
      tdl.error("undefined passed to gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
    }
  }
}

function Log(msg) {
  if (g_logGLCalls) {
    tdl.log(msg);
  }
}

function LogGLCall(functionName, args) {
  if (g_logGLCalls) {
    ValidateNoneOfTheArgsAreUndefined(functionName, args)
    tdl.log("gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
  }
}

function createProgramFromTags(vertexTagId, fragmentTagId) {
  return tdl.programs.loadProgram(
      document.getElementById(vertexTagId).text,
      document.getElementById(fragmentTagId).text);
}

/**
 * Sets up Planet.
 */
function setupSphere() {
  var textures = {
    diffuseSampler: tdl.textures.loadTexture('assets/sometexture.png')};
  var program = createProgramFromTags(
      'sphereVertexShader',
      'sphereFragmentShader');
  var arrays = tdl.primitives.createSphere(0.4, 10, 12);

  return new tdl.models.Model(program, arrays, textures);
}

function initialize() {
  math = tdl.math;
  fast = tdl.fast;
  canvas = document.getElementById("canvas");
  g_fpsTimer = new tdl.fps.FPSTimer();

  gl = tdl.webgl.setupWebGL(canvas);
  if (!gl) {
    return false;
  }
  if (g_debug) {
    gl = tdl.webgl.makeDebugContext(gl, undefined, LogGLCall);
  }

  Log("--Setup Sphere---------------------------------------");
  var sphere = setupSphere();

  var then = 0.0;
  var clock = 0.0;
  var fpsElem = document.getElementById("fps");

  // pre-allocate a bunch of arrays
  var projection = new Float32Array(16);
  var view = new Float32Array(16);
  var world = new Float32Array(16);
  var worldInverse = new Float32Array(16);
  var worldInverseTranspose = new Float32Array(16);
  var viewProjection = new Float32Array(16);
  var worldViewProjection = new Float32Array(16);
  var viewInverse = new Float32Array(16);
  var viewProjectionInverse = new Float32Array(16);
  var eyePosition = new Float32Array(3);
  var target = new Float32Array(3);
  var up = new Float32Array([0,1,0]);
  var lightWorldPos = new Float32Array(3);
  var v3t0 = new Float32Array(3);
  var v3t1 = new Float32Array(3);
  var v3t2 = new Float32Array(3);
  var v3t3 = new Float32Array(3);
  var m4t0 = new Float32Array(16);
  var m4t1 = new Float32Array(16);
  var m4t2 = new Float32Array(16);
  var m4t3 = new Float32Array(16);
  var zero4 = new Float32Array(4);
  var one4 = new Float32Array([1,1,1,1]);

  // Sphere uniforms.
  var sphereConst = {
    viewInverse: viewInverse,
    lightWorldPos: lightWorldPos,
    specular: one4,
    shininess: 50,
    specularFactor: 0.2};
  var spherePer = {
    lightColor: new Float32Array([0,0,0,1]),
    world: world,
    worldViewProjection: worldViewProjection,
    worldInverse: worldInverse,
    worldInverseTranspose: worldInverseTranspose};

  var frameCount = 0;
  function render() {
    ++frameCount;
    if (!g_drawOnce) {
      tdl.webgl.requestAnimationFrame(render, canvas);
    }
    var now = (new Date()).getTime() * 0.001;
    var elapsedTime;
    if(then == 0.0) {
      elapsedTime = 0.0;
    } else {
      elapsedTime = now - then;
    }
    then = now;

    g_fpsTimer.update(elapsedTime);
    fpsElem.innerHTML = g_fpsTimer.averageFPS;

    clock += elapsedTime;
    eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius;
    eyePosition[1] = g_eyeHeight;
    eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius;

    gl.colorMask(true, true, true, true);
    gl.depthMask(true);
    gl.clearColor(0,0,0,0);
    gl.clearDepth(1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    fast.matrix4.perspective(
        projection,
        math.degToRad(60),
        canvas.clientWidth / canvas.clientHeight,
        1,
        5000);
    fast.matrix4.lookAt(
        view,
        eyePosition,
        target,
        up);
    fast.matrix4.mul(viewProjection, view, projection);
    fast.matrix4.inverse(viewInverse, view);
    fast.matrix4.inverse(viewProjectionInverse, viewProjection);

    fast.matrix4.getAxis(v3t0, viewInverse, 0); // x
    fast.matrix4.getAxis(v3t1, viewInverse, 1); // y;
    fast.matrix4.getAxis(v3t2, viewInverse, 2); // z;
    fast.mulScalarVector(v3t0, 10, v3t0);
    fast.mulScalarVector(v3t1, 10, v3t1);
    fast.mulScalarVector(v3t2, 10, v3t2);
    fast.addVector(lightWorldPos, eyePosition, v3t0);
    fast.addVector(lightWorldPos, lightWorldPos, v3t1);
    fast.addVector(lightWorldPos, lightWorldPos, v3t2);

//      view: view,
//      projection: projection,
//      viewProjection: viewProjection,

    Log("--Draw sphere---------------------------------------");
    sphere.drawPrep(sphereConst);
    var across = 6;
    var lightColor = spherePer.lightColor;
    var half = (across - 1) * 0.5;
    for (var xx = 0; xx < across; ++xx) {
      for (var yy = 0; yy < across; ++yy) {
        for (var zz = 0; zz < across; ++zz) {
          lightColor[0] = xx / across;
          lightColor[1] = yy / across;
          lightColor[2] = zz / across;
          var scale = (xx + yy + zz) % 4 / 4 + 0.5;
          fast.matrix4.scaling(m4t0, [scale, scale, scale]);
          fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]);
          fast.matrix4.mul(world, m4t0, m4t1);
          fast.matrix4.mul(worldViewProjection, world, viewProjection);
          fast.matrix4.inverse(worldInverse, world);
          fast.matrix4.transpose(worldInverseTranspose, worldInverse);
          sphere.draw(spherePer);
        }
      }
    }

    // Set the alpha to 255.
    gl.colorMask(false, false, false, true);
    gl.clearColor(0,0,0,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // turn off logging after 1 frame.
    g_logGLCalls = false;
  }
  render();
  return true;
}
</script>
</head>
<body>
<div id="info"><a href="http://threedlibrary.googlecode.com" target="_blank">tdl.js</a> - example</div>
<div class="fpsContainer">
  <div class="fps">fps: <span id="fps"></span></div>
</div>
<div id="viewContainer">
<canvas id="canvas" width="1024" height="1024" style="width: 100%; height: 100%;"></canvas>
</div>
</body>
<script id="sphereVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
uniform vec3 lightWorldPos;
uniform mat4 world;
uniform mat4 viewInverse;
uniform mat4 worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
  v_texCoord = texCoord;
  v_position = (worldViewProjection * position);
  v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
  v_surfaceToLight = lightWorldPos - (world * position).xyz;
  v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
  gl_Position = v_position;
}

</script>
<script id="sphereFragmentShader" type="text/something-not-javascript">
precision mediump float;
uniform vec4 lightColor;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform sampler2D diffuseSampler;
uniform vec4 specular;
uniform sampler2D bumpSampler;
uniform float shininess;
uniform float specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}
void main() {
  vec4 diffuse = texture2D(diffuseSampler, v_texCoord);
  vec3 normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(normal, surfaceToLight),
                    dot(normal, halfVector), shininess);
  gl_FragColor = vec4((
  lightColor * (diffuse * litR.y
                        + specular * litR.z * specularFactor)).rgb,
      diffuse.a);
}
</script>
</html>




================================================
FILE: example/example2.html
================================================
<!--
 * Copyright 2009, 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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL TDL Example</title>
<style>
CANVAS {
  background-color: gray;
}
.fpsContainer {
  position: absolute;
  top: 90px;
  left: 20px;
  z-index: 2;
  color: white;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
</style>
<script type="text/javascript" src="../tdl/base.js"></script>
<script type="text/javascript">
tdl.require('tdl.buffers');
tdl.require('tdl.fast');
tdl.require('tdl.fps');
tdl.require('tdl.log');
tdl.require('tdl.math');
tdl.require('tdl.misc');
tdl.require('tdl.models');
tdl.require('tdl.primitives');
tdl.require('tdl.programs');
tdl.require('tdl.textures');
tdl.require('tdl.webgl');
window.onload = initialize;

var g = {
 across: 10,
 hdiv: 10,
 vdiv: 12
};

// globals
var gl;                   // the gl context.
var canvas;               // the canvas
var math;                 // the math lib.
var fast;                 // the fast math lib.
var g_fpsTimer;           // object to measure frames per second;
var g_logGLCalls = true;  // whether or not to log webgl calls
var g_debug = false;      // whether or not to debug.
var g_drawOnce = false;   // draw just one frame.

//g_drawOnce = true;
//g_debug = true;

var g_eyeSpeed          = 0.5;
var g_eyeHeight         = 2;
var g_eyeRadius         = 9;

function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
  for (var ii = 0; ii < args.length; ++ii) {
    if (args[ii] === undefined) {
      tdl.error("undefined passed to gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
    }
  }
}

function Log(msg) {
  if (g_logGLCalls) {
    tdl.log(msg);
  }
}

function LogGLCall(functionName, args) {
  if (g_logGLCalls) {
    ValidateNoneOfTheArgsAreUndefined(functionName, args)
    tdl.log("gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
  }
}

function createProgramFromTags(vertexTagId, fragmentTagId) {
  return tdl.programs.loadProgram(
      document.getElementById(vertexTagId).text,
      document.getElementById(fragmentTagId).text);
}

/**
 * Sets up Planet.
 */
function setupSphere() {
  var textures = {};
  var program = createProgramFromTags(
      'sphereVertexShader',
      'sphereFragmentShader');
  var arrays = tdl.primitives.createSphere(0.4, g.hdiv, g.vdiv);

  return new tdl.models.Model(program, arrays, textures);
}

function initialize() {
  math = tdl.math;
  fast = tdl.fast;
  canvas = document.getElementById("canvas");
  g_fpsTimer = new tdl.fps.FPSTimer();

  gl = tdl.webgl.setupWebGL(canvas);
  if (!gl) {
    return false;
  }
  if (g_debug) {
    gl = tdl.webgl.makeDebugContext(gl, undefined, LogGLCall);
  }

  tdl.misc.applyUrlSettings(g);

  Log("--Setup Sphere---------------------------------------");
  var sphere = setupSphere();

  var then = 0.0;
  var clock = 0.0;
  var fpsElem = document.getElementById("fps");

  // pre-allocate a bunch of arrays
  var projection = new Float32Array(16);
  var view = new Float32Array(16);
  var world = new Float32Array(16);
  var worldInverse = new Float32Array(16);
  var worldInverseTranspose = new Float32Array(16);
  var viewProjection = new Float32Array(16);
  var worldViewProjection = new Float32Array(16);
  var viewInverse = new Float32Array(16);
  var viewProjectionInverse = new Float32Array(16);
  var eyePosition = new Float32Array(3);
  var target = new Float32Array(3);
  var up = new Float32Array([0,1,0]);
  var lightWorldPos = new Float32Array(3);
  var v3t0 = new Float32Array(3);
  var v3t1 = new Float32Array(3);
  var v3t2 = new Float32Array(3);
  var v3t3 = new Float32Array(3);
  var m4t0 = new Float32Array(16);
  var m4t1 = new Float32Array(16);
  var m4t2 = new Float32Array(16);
  var m4t3 = new Float32Array(16);
  var zero4 = new Float32Array(4);
  var one4 = new Float32Array([1,1,1,1]);

  // Sphere uniforms.
  var sphereConst = {
    viewInverse: viewInverse,
    lightWorldPos: lightWorldPos,
    specular: one4,
    shininess: 50,
    specularFactor: 0.2};
  var spherePer = {
    lightColor: new Float32Array([0,0,0,1]),
    world: world,
    worldViewProjection: worldViewProjection,
    worldInverse: worldInverse,
    worldInverseTranspose: worldInverseTranspose};

  var frameCount = 0;
  function render() {
    ++frameCount;
    if (!g_drawOnce) {
      tdl.webgl.requestAnimationFrame(render, canvas);
    }
    var now = (new Date()).getTime() * 0.001;
    var elapsedTime;
    if(then == 0.0) {
      elapsedTime = 0.0;
    } else {
      elapsedTime = now - then;
    }
    then = now;

    g_fpsTimer.update(elapsedTime);
    fpsElem.innerHTML = g_fpsTimer.averageFPS;

    clock += elapsedTime;
    eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius;
    eyePosition[1] = g_eyeHeight;
    eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius;

    gl.colorMask(true, true, true, true);
    gl.depthMask(true);
    gl.clearColor(0.5,0.5,0.5,1);
    gl.clearDepth(1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    fast.matrix4.perspective(
        projection,
        math.degToRad(60),
        canvas.clientWidth / canvas.clientHeight,
        1,
        5000);
    fast.matrix4.lookAt(
        view,
        eyePosition,
        target,
        up);
    fast.matrix4.mul(viewProjection, view, projection);
    fast.matrix4.inverse(viewInverse, view);
    fast.matrix4.inverse(viewProjectionInverse, viewProjection);

    fast.matrix4.getAxis(v3t0, viewInverse, 0); // x
    fast.matrix4.getAxis(v3t1, viewInverse, 1); // y;
    fast.matrix4.getAxis(v3t2, viewInverse, 2); // z;
    fast.mulScalarVector(v3t0, 10, v3t0);
    fast.mulScalarVector(v3t1, 10, v3t1);
    fast.mulScalarVector(v3t2, 10, v3t2);
    fast.addVector(lightWorldPos, eyePosition, v3t0);
    fast.addVector(lightWorldPos, lightWorldPos, v3t1);
    fast.addVector(lightWorldPos, lightWorldPos, v3t2);

//      view: view,
//      projection: projection,
//      viewProjection: viewProjection,

    Log("--Draw sphere---------------------------------------");
    sphere.drawPrep(sphereConst);
    var across = g.across;
    var lightColor = spherePer.lightColor;
    var half = (across - 1) * 0.5;
    for (var xx = 0; xx < across; ++xx) {
      for (var yy = 0; yy < across; ++yy) {
        for (var zz = 0; zz < across; ++zz) {
          lightColor[0] = xx / across;
          lightColor[1] = yy / across;
          lightColor[2] = zz / across;
          var scale = (xx + yy + zz) % 4 / 4 + 0.5;
          fast.matrix4.scaling(m4t0, [scale, scale, scale]);
          fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]);
          fast.matrix4.mul(world, m4t0, m4t1);
          fast.matrix4.translation(world, [xx - half, yy - half, zz - half]);
          fast.matrix4.mul(worldViewProjection, world, viewProjection);
          fast.matrix4.inverse(worldInverse, world);
          fast.matrix4.transpose(worldInverseTranspose, worldInverse);
          sphere.draw(spherePer);
        }
      }
    }

    // turn off logging after 1 frame.
    g_logGLCalls = false;
  }
  render();
  return true;
}
</script>
</head>
<body>
<h1>WebGL Spheres</h1>
<div>
<div class="fpsContainer">
  <div class="fps">fps: <span id="fps"></span></div>
</div>
<div id="viewContainer">
<canvas id="canvas" width="800" height="600"></canvas>
</div>
</div>
</body>
<script id="sphereVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
uniform vec3 lightWorldPos;
uniform mat4 world;
uniform mat4 viewInverse;
uniform mat4 worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
  v_texCoord = texCoord;
  v_position = (worldViewProjection * position);
  v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
  v_surfaceToLight = lightWorldPos - (world * position).xyz;
  v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
  gl_Position = v_position;
}

</script>
<script id="sphereFragmentShader" type="text/something-not-javascript">
precision mediump float;
uniform vec4 lightColor;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform vec4 specular;
uniform sampler2D bumpSampler;
uniform float shininess;
uniform float specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}
void main() {
  vec4 diffuse = vec4(1,1,1,1);
  vec3 normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(normal, surfaceToLight),
                    dot(normal, halfVector), shininess);
  gl_FragColor = vec4((
  lightColor * (diffuse * litR.y
                        + specular * litR.z * specularFactor)).rgb,
      diffuse.a);
}
</script>
</html>




================================================
FILE: example/line.html
================================================
<!--
 * Copyright 2009, 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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL TDL Example</title>
<style>
html, body {
  width: 100%;
  height: 100%;
  border: 0px;
  padding: 0px;
  margin: 0px;
  background-color: red;
  font-family: sans-serif;
  overflow: hidden;
  color: #fff;
}
a {
  color: #fff;
}
#info {
    font-size: small;
    position: absolute;
    top: 0px; width: 100%;
    padding: 5px;
    text-align: center;
    z-index: 2;
}
CANVAS {
  background-color: gray;
}
.fpsContainer {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  color: white;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
#viewContainer {
  width: 100%;
  height: 100%;
}
</style>
<script type="text/javascript" src="../tdl/base.js"></script>
<script type="text/javascript">
tdl.require('tdl.buffers');
tdl.require('tdl.fast');
tdl.require('tdl.fps');
tdl.require('tdl.log');
tdl.require('tdl.math');
tdl.require('tdl.models');
tdl.require('tdl.primitives');
tdl.require('tdl.programs');
tdl.require('tdl.webgl');
window.onload = initialize;

// globals
var gl;                   // the gl context.
var canvas;               // the canvas
var math;                 // the math lib.
var fast;                 // the fast math lib.
var g_fpsTimer;           // object to measure frames per second;
var g_logGLCalls = true;  // whether or not to log webgl calls
var g_debug = false;      // whether or not to debug.
var g_drawOnce = false;   // draw just one frame.

//g_drawOnce = true;
//g_debug = true;

var g_eyeSpeed          = 0.5;
var g_eyeHeight         = 2;
var g_eyeRadius         = 9;

function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
  for (var ii = 0; ii < args.length; ++ii) {
    if (args[ii] === undefined) {
      tdl.error("undefined passed to gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
    }
  }
}

function Log(msg) {
  if (g_logGLCalls) {
    tdl.log(msg);
  }
}

function LogGLCall(functionName, args) {
  if (g_logGLCalls) {
    ValidateNoneOfTheArgsAreUndefined(functionName, args)
    tdl.log("gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
  }
}

function createProgramFromTags(vertexTagId, fragmentTagId) {
  return tdl.programs.loadProgram(
      document.getElementById(vertexTagId).text,
      document.getElementById(fragmentTagId).text);
}

/**
 * Sets up Line.
 */
function setupLine() {
 
  var program = createProgramFromTags(
      'lineVertexShader',
      'lineFragmentShader');
  var arrays = tdl.primitives.createLine([
    0.0,0.0,0.0,
    0.0,0.0,0.5,
    0.5,0.0,0.5,
    0.5,0.0,0.0
    ]);

  return new tdl.models.Model(program, arrays, null, 3);
}

function initialize() {

  math = tdl.math;
  fast = tdl.fast;
  canvas = document.getElementById("canvas");
  g_fpsTimer = new tdl.fps.FPSTimer();

  gl = tdl.webgl.setupWebGL(canvas);
  if (!gl) {
    return false;
  }
  if (g_debug) {
    gl = tdl.webgl.makeDebugContext(gl, undefined, LogGLCall);
  }

  Log("--Setup Line---------------------------------------");
  var line = setupLine();

  var then = 0.0;
  var clock = 0.0;
  var fpsElem = document.getElementById("fps");

  // pre-allocate a bunch of arrays
  var projection = new Float32Array(16);
  var view = new Float32Array(16);
  var world = new Float32Array(16);
  var worldInverse = new Float32Array(16);
  var worldInverseTranspose = new Float32Array(16);
  var viewProjection = new Float32Array(16);
  var worldViewProjection = new Float32Array(16);
  var viewInverse = new Float32Array(16);
  var viewProjectionInverse = new Float32Array(16);
  var eyePosition = new Float32Array(3);
  var target = new Float32Array(3);
  var up = new Float32Array([0,1,0]);
  var lightWorldPos = new Float32Array(3);
  var v3t0 = new Float32Array(3);
  var v3t1 = new Float32Array(3);
  var v3t2 = new Float32Array(3);
  var v3t3 = new Float32Array(3);
  var m4t0 = new Float32Array(16);
  var m4t1 = new Float32Array(16);
  var m4t2 = new Float32Array(16);
  var m4t3 = new Float32Array(16);
  var zero4 = new Float32Array(4);
  var one4 = new Float32Array([1,1,1,1]);

  // Line uniforms.
  var lineConst = {
    viewInverse: viewInverse,
    lightWorldPos: lightWorldPos,
    specular: one4,
    shininess: 50,
    specularFactor: 0.2};
  var linePer = {
    lightColor: new Float32Array([0,0,0,1]),
    world: world,
    worldViewProjection: worldViewProjection,
    worldInverse: worldInverse,
    worldInverseTranspose: worldInverseTranspose};

  var frameCount = 0;
  function render() {
    ++frameCount;
    if (!g_drawOnce) {
      tdl.webgl.requestAnimationFrame(render, canvas);
    }
    var now = (new Date()).getTime() * 0.001;
    var elapsedTime;
    if(then == 0.0) {
      elapsedTime = 0.0;
    } else {
      elapsedTime = now - then;
    }
    then = now;

    g_fpsTimer.update(elapsedTime);
    fpsElem.innerHTML = g_fpsTimer.averageFPS;

    clock += elapsedTime;
    eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius;
    eyePosition[1] = g_eyeHeight;
    eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius;

    gl.colorMask(true, true, true, true);
    gl.depthMask(true);
    gl.clearColor(0,0,0,0);
    gl.clearDepth(1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    fast.matrix4.perspective(
        projection,
        math.degToRad(60),
        canvas.clientWidth / canvas.clientHeight,
        1,
        5000);
    fast.matrix4.lookAt(
        view,
        eyePosition,
        target,
        up);
    fast.matrix4.mul(viewProjection, view, projection);
    fast.matrix4.inverse(viewInverse, view);
    fast.matrix4.inverse(viewProjectionInverse, viewProjection);

    fast.matrix4.getAxis(v3t0, viewInverse, 0); // x
    fast.matrix4.getAxis(v3t1, viewInverse, 1); // y;
    fast.matrix4.getAxis(v3t2, viewInverse, 2); // z;
    fast.mulScalarVector(v3t0, 10, v3t0);
    fast.mulScalarVector(v3t1, 10, v3t1);
    fast.mulScalarVector(v3t2, 10, v3t2);
    fast.addVector(lightWorldPos, eyePosition, v3t0);
    fast.addVector(lightWorldPos, lightWorldPos, v3t1);
    fast.addVector(lightWorldPos, lightWorldPos, v3t2);

//      view: view,
//      projection: projection,
//      viewProjection: viewProjection,

    Log("--Draw line---------------------------------------");
    gl.lineWidth(1.0);
    line.drawPrep(lineConst);
    var across = 5;
    var lightColor = linePer.lightColor;
    var half = (across - 1) * 0.5;
    for (var xx = 0; xx < across; ++xx) {
      for (var yy = 0; yy < across; ++yy) {
        for (var zz = 0; zz < across; ++zz) {
          lightColor[0] = xx / across;
          lightColor[1] = yy / across;
          lightColor[2] = zz / across;
          var scale = (xx + yy + zz) % 4 / 4 + 0.5;
          fast.matrix4.scaling(m4t0, [scale, scale, scale]);
          fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]);
          fast.matrix4.mul(world, m4t0, m4t1);
          fast.matrix4.mul(worldViewProjection, world, viewProjection);
          fast.matrix4.inverse(worldInverse, world);
          fast.matrix4.transpose(worldInverseTranspose, worldInverse);
          line.draw(linePer);
        }
      }
    }

    // Set the alpha to 255.
    gl.colorMask(false, false, false, true);
    gl.clearColor(0,0,0,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // turn off logging after 1 frame.
    g_logGLCalls = false;
  }
  render();
  return true;
}
</script>
</head>
<body>
<div id="info"><a href="http://threedlibrary.googlecode.com" target="_blank">tdl.js</a> - example</div>
<div class="fpsContainer">
  <div class="fps">fps: <span id="fps"></span></div>
</div>
<div id="viewContainer">
<canvas id="canvas" width="1024" height="1024" style="width: 100%; height: 100%;"></canvas>
</div>
</body>
<script id="lineVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
uniform vec3 lightWorldPos;
uniform mat4 world;
uniform mat4 viewInverse;
uniform mat4 worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
varying vec4 v_position;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
  v_position = (worldViewProjection * position);
  v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
  v_surfaceToLight = lightWorldPos - (world * position).xyz;
  v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
  gl_Position = v_position;
}

</script>
<script id="lineFragmentShader" type="text/something-not-javascript">
precision mediump float;
uniform vec4 lightColor;
varying vec4 v_position;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform sampler2D diffuseSampler;
uniform vec4 specular;
uniform sampler2D bumpSampler;
uniform float shininess;
uniform float specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}
void main() {
  vec3 normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(normal, surfaceToLight),
                    dot(normal, halfVector), shininess);
  gl_FragColor = vec4((
  lightColor * (litR.y
                        + specular * litR.z * specularFactor)).rgb,
      1.0);
}
</script>
</html>




================================================
FILE: example/picking.html
================================================
<!--
 * Copyright 2009, 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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL TDL Example</title>
<style>
html, body {
  width: 100%;
  height: 100%;
  border: 0px;
  padding: 0px;
  margin: 0px;
  background-color: red;
  font-family: sans-serif;
  overflow: hidden;
  color: #fff;
}
a {
  color: #fff;
}
#info {
    font-size: small;
    position: absolute;
	top: 0px; width: 100%;
	padding: 5px;
	text-align: center;
	z-index: 2;
}
CANVAS {
  background-color: gray;
}
.fpsContainer {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  color: white;
  font-family: sans-serif;
  background-color: rgba(0,0,0,0.5);
  border-radius: 10px;
  padding: 10px;
}
#viewContainer {
  width: 100%;
  height: 100%;
}
</style>
<script type="text/javascript" src="../tdl/base.js"></script>
<script type="text/javascript">
tdl.require('tdl.buffers');
tdl.require('tdl.fast');
tdl.require('tdl.fps');
tdl.require('tdl.framebuffers');
tdl.require('tdl.log');
tdl.require('tdl.math');
tdl.require('tdl.models');
tdl.require('tdl.primitives');
tdl.require('tdl.programs');
tdl.require('tdl.textures');
tdl.require('tdl.webgl');
window.onload = initialize;

// globals
var gl;                   // the gl context.
var canvas;               // the canvas
var math;                 // the math lib.
var fast;                 // the fast math lib.
var g_fpsTimer;           // object to measure frames per second;
var g_logGLCalls = true;  // whether or not to log webgl calls
var g_debug = false;      // whether or not to debug.
var g_drawOnce = false;   // draw just one frame.

//g_drawOnce = true;
//g_debug = true;

var g_eyeSpeed          = 0.2;
var g_eyeHeight         = 2;
var g_eyeRadius         = 9;

function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
  for (var ii = 0; ii < args.length; ++ii) {
    if (args[ii] === undefined) {
      tdl.error("undefined passed to gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
    }
  }
}

function Log(msg) {
  if (g_logGLCalls) {
    tdl.log(msg);
  }
}

function LogGLCall(functionName, args) {
  if (g_logGLCalls) {
    ValidateNoneOfTheArgsAreUndefined(functionName, args)
    tdl.log("gl." + functionName + "(" +
                tdl.webgl.glFunctionArgsToString(functionName, args) + ")");
  }
}

function createProgramFromTags(vertexTagId, fragmentTagId) {
  return tdl.programs.loadProgram(
      document.getElementById(vertexTagId).text,
      document.getElementById(fragmentTagId).text);
}

/**
 * Sets up Planet.
 */
function setupSphere() {
  var textures = {
    diffuseSampler: tdl.textures.loadTexture('assets/sometexture.png')};
  var program = createProgramFromTags(
      'sphereVertexShader',
      'sphereFragmentShader');
  var arrays = tdl.primitives.createSphere(0.4, 10, 12);

  return new tdl.models.Model(program, arrays, textures);
}

function initialize() {
  math = tdl.math;
  fast = tdl.fast;
  canvas = document.getElementById("canvas");
  g_fpsTimer = new tdl.fps.FPSTimer();

  gl = tdl.webgl.setupWebGL(canvas);
  if (!gl) {
    return false;
  }
  if (g_debug) {
    gl = tdl.webgl.makeDebugContext(gl, undefined, LogGLCall);
  }

  Log("--Setup Sphere---------------------------------------");
  var sphere = setupSphere();

  var pickingProgram = createProgramFromTags(
      'pickingVertexShader',
      'pickingFragmentShader');

  var pickingFramebuffer = new tdl.framebuffers.Framebuffer(gl.canvas.width, gl.canvas.height, true);
  var backbuffer = tdl.framebuffers.getBackBuffer(gl.canvas);

  var then = 0.0;
  var clock = 0.0;
  var fpsElem = document.getElementById("fps");
  var pickElem = document.getElementById("pick");
  var pickIndex = -1;

  // pre-allocate a bunch of arrays
  var projection = new Float32Array(16);
  var view = new Float32Array(16);
  var world = new Float32Array(16);
  var worldInverse = new Float32Array(16);
  var worldInverseTranspose = new Float32Array(16);
  var viewProjection = new Float32Array(16);
  var worldViewProjection = new Float32Array(16);
  var viewInverse = new Float32Array(16);
  var viewProjectionInverse = new Float32Array(16);
  var eyePosition = new Float32Array(3);
  var target = new Float32Array(3);
  var up = new Float32Array([0,1,0]);
  var lightWorldPos = new Float32Array(3);
  var v3t0 = new Float32Array(3);
  var v3t1 = new Float32Array(3);
  var v3t2 = new Float32Array(3);
  var v3t3 = new Float32Array(3);
  var m4t0 = new Float32Array(16);
  var m4t1 = new Float32Array(16);
  var m4t2 = new Float32Array(16);
  var m4t3 = new Float32Array(16);
  var zero4 = new Float32Array(4);
  var one4 = new Float32Array([1,1,1,1]);

  // Sphere uniforms.
  var sphereConst = {
    viewInverse: viewInverse,
    lightWorldPos: lightWorldPos,
    specular: one4,
    shininess: 50,
    specularFactor: 0.2};
  var spherePer = {
    lightColor: new Float32Array([0,0,0,1]),
    world: world,
    worldViewProjection: worldViewProjection,
    worldInverse: worldInverse,
    worldInverseTranspose: worldInverseTranspose};
  var pickingPer = {
    u_color: new Float32Array(4),
    worldViewProjection: worldViewProjection
  };

  var frameCount = 0;
  function render() {
    ++frameCount;
    if (!g_drawOnce) {
      tdl.webgl.requestAnimationFrame(render, canvas);
    }
    var now = (new Date()).getTime() * 0.001;
    var elapsedTime;
    if(then == 0.0) {
      elapsedTime = 0.0;
    } else {
      elapsedTime = now - then;
    }
    then = now;

    g_fpsTimer.update(elapsedTime);
    fpsElem.innerHTML = g_fpsTimer.averageFPS;

    clock += elapsedTime;
    eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius;
    eyePosition[1] = g_eyeHeight;
    eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius;

    gl.colorMask(true, true, true, true);
    gl.depthMask(true);
    gl.clearColor(0,0,0,0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    drawScene(false);

    // Set the alpha to 255.
    gl.colorMask(false, false, false, true);
    gl.clearColor(0,0,0,1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // turn off logging after 1 frame.
    g_logGLCalls = false;
  }

  canvas.addEventListener('click', pick, false);

  var pickColor = new Uint8Array(4);
  function pick(event) {
    var info = getEventInfo(event);
    var m = getRelativeCoordinates(info);
    // convert mouse coords to WebGL coords
    var pickX = m.x * pickingFramebuffer.width / gl.canvas.clientWidth;
    var pickY = pickingFramebuffer.height - (m.y * pickingFramebuffer.height / gl.canvas.clientHeight) - 1;

    // Bind the picking framebuffer to draw offscreen
    pickingFramebuffer.bind();

    // clear to 1,1,1,1 (outside the range of objects)
    gl.colorMask(true, true, true, true);
    gl.depthMask(true);
    gl.clearColor(1,1,1,1);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);
    gl.disable(gl.BLEND);

    // Swap in the picking program
    sphere.oldProgram = sphere.program;
    sphere.program = pickingProgram;

    // Draw the scene to the framebuffer
    drawScene(true);

    // Read the pixel under the mouse
    gl.readPixels(pickX, pickY, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pickColor);

    // Compute which model by drawing order was picked.
    pickIndex = pickColor[0] + pickColor[1] * 0x100 + pickColor[2] * 0x10000;
    pickElem.innerHTML = pickIndex;

    // Restore the old program
    sphere.program = sphere.oldProgram;

    // Restore the backbuffer so future drawing is visible again
    backbuffer.bind();
  }

  function drawScene(picking) {
    fast.matrix4.perspective(
        projection,
        math.degToRad(60),
        canvas.clientWidth / canvas.clientHeight,
        1,
        5000);
    fast.matrix4.lookAt(
        view,
        eyePosition,
        target,
        up);
    fast.matrix4.mul(viewProjection, view, projection);
    fast.matrix4.inverse(viewInverse, view);
    fast.matrix4.inverse(viewProjectionInverse, viewProjection);

    fast.matrix4.getAxis(v3t0, viewInverse, 0); // x
    fast.matrix4.getAxis(v3t1, viewInverse, 1); // y;
    fast.matrix4.getAxis(v3t2, viewInverse, 2); // z;
    fast.mulScalarVector(v3t0, 10, v3t0);
    fast.mulScalarVector(v3t1, 10, v3t1);
    fast.mulScalarVector(v3t2, 10, v3t2);
    fast.addVector(lightWorldPos, eyePosition, v3t0);
    fast.addVector(lightWorldPos, lightWorldPos, v3t1);
    fast.addVector(lightWorldPos, lightWorldPos, v3t2);

  //      view: view,
  //      projection: projection,
  //      viewProjection: viewProjection,

    Log("--Draw sphere---------------------------------------");
    sphere.drawPrep(sphereConst);
    var modelCount = 0;
    var across = 6;
    var lightColor = spherePer.lightColor;
    var half = (across - 1) * 0.5;
    for (var xx = 0; xx < across; ++xx) {
      for (var yy = 0; yy < across; ++yy) {
        for (var zz = 0; zz < across; ++zz) {
          lightColor[0] = xx / across;
          lightColor[1] = yy / across;
          lightColor[2] = zz / across;
          var scale = (xx + yy + zz) % 4 / 4 + 0.5;
          fast.matrix4.scaling(m4t0, [scale, scale, scale]);
          fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]);
          fast.matrix4.mul(world, m4t0, m4t1);
          fast.matrix4.mul(worldViewProjection, world, viewProjection);
          if (picking) {
            // convert model count to a color.
            pickingPer.u_color[0] = ((modelCount >>  0) & 0xFF) / 255;
            pickingPer.u_color[1] = ((modelCount >>  8) & 0xFF) / 255;
            pickingPer.u_color[2] = ((modelCount >> 16) & 0xFF) / 255;
            pickingPer.u_color[3] = ((modelCount >> 24) & 0xFF) / 255;
            sphere.draw(pickingPer);
          } else {
            // highlight picked object.
            if (pickIndex == modelCount && (Math.floor(clock * 4) & 1)) {
              lightColor[0] = 255;
              lightColor[1] = 255;
              lightColor[2] = 255;
            }
            fast.matrix4.inverse(worldInverse, world);
            fast.matrix4.transpose(worldInverseTranspose, worldInverse);
            sphere.draw(spherePer);
          }
          ++modelCount;
        }
      }
    }
  }

  render();
  return true;
}

/**
 * Returns the absolute position of an element for certain browsers.
 * @param {HTML Element} element The element to get a position for.
 * @return {Object} An object containing x and y as the absolute position
 *     of the given element.
 */
var getAbsolutePosition = function(element) {
  var r = { x: element.offsetLeft, y: element.offsetTop };
  if (element.offsetParent) {
    var tmp = getAbsolutePosition(element.offsetParent);
    r.x += tmp.x;
    r.y += tmp.y;
  }
  return r;
};

 /**
  * Retrieve the coordinates of the given event relative to the center
  * of the widget.
  *
  * @param {eventInfo} eventInfo As returned from
  *     CLIENT3DJS.util.getEventInfo.
  * @param {HTML Element} opt_reference A DOM element whose position we want
  *     to transform the mouse coordinates to. If it is not passed in the
  *     element in the eventInfo will be used.
  * @return {Object} An object containing keys 'x' and 'y'.
  */
var getRelativeCoordinates = function(eventInfo, opt_reference) {
  var x, y;
  var event = eventInfo.event;
  var element = eventInfo.element;
  var reference = opt_reference || eventInfo.element;
  if (!window.opera && typeof event.offsetX != 'undefined') {
    // Use offset coordinates and find common offsetParent
    var pos = { x: event.offsetX, y: event.offsetY };
    // Send the coordinates upwards through the offsetParent chain.
    var e = element;
    while (e) {
      e.mouseX = pos.x;
      e.mouseY = pos.y;
      pos.x += e.offsetLeft;
      pos.y += e.offsetTop;
      e = e.offsetParent;
    }
    // Look for the coordinates starting from the reference element.
    var e = reference;
    var offset = { x: 0, y: 0 }
    while (e) {
      if (typeof e.mouseX != 'undefined') {
        x = e.mouseX - offset.x;
        y = e.mouseY - offset.y;
        break;
      }
      offset.x += e.offsetLeft;
      offset.y += e.offsetTop;
      e = e.offsetParent;
    }
    // Reset stored coordinates
    e = element;
    while (e) {
      e.mouseX = undefined;
      e.mouseY = undefined;
      e = e.offsetParent;
    }
  } else {
    // Use absolute coordinates
    var pos = getAbsolutePosition(reference);
    x = event.pageX - pos.x;
    y = event.pageY - pos.y;
  }
  // Subtract distance to middle
  return { x: x, y: y };
};

var getEventInfo = function(event) {
  event = event ? event : window.event;
  var element = event.target ? event.target : event.srcElement;
  return {
    event: event,
    element: element,
    name: (element.id ? element.id : ('->' + element.toString())),
    wheel: (event.detail ? event.detail : -event.wheelDelta),
    shift: (event.modifiers ? (event.modifiers & Event.SHIFT_MASK) : event.shiftKey)
  };
};

</script>
</head>
<body>
<div id="info"><a href="http://threedlibrary.googlecode.com" target="_blank">tdl.js</a> - example</div>
<div class="fpsContainer">
  <div class="fps">fps: <span id="fps"></span></div>
  <div>You picked: <span id="pick"></span></div>
</div>
<div id="viewContainer">
<canvas id="canvas" width="1024" height="1024" style="width: 100%; height: 100%;"></canvas>
</div>
</body>
<script id="sphereVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
uniform vec3 lightWorldPos;
uniform mat4 world;
uniform mat4 viewInverse;
uniform mat4 worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texCoord;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;
void main() {
  v_texCoord = texCoord;
  v_position = (worldViewProjection * position);
  v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
  v_surfaceToLight = lightWorldPos - (world * position).xyz;
  v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
  gl_Position = v_position;
}

</script>
<script id="sphereFragmentShader" type="text/something-not-javascript">
precision mediump float;
uniform vec4 lightColor;
varying vec4 v_position;
varying vec2 v_texCoord;
varying vec3 v_normal;
varying vec3 v_surfaceToLight;
varying vec3 v_surfaceToView;

uniform sampler2D diffuseSampler;
uniform vec4 specular;
uniform sampler2D bumpSampler;
uniform float shininess;
uniform float specularFactor;

vec4 lit(float l ,float h, float m) {
  return vec4(1.0,
              max(l, 0.0),
              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
              1.0);
}
void main() {
  vec4 diffuse = texture2D(diffuseSampler, v_texCoord);
  vec3 normal = normalize(v_normal);
  vec3 surfaceToLight = normalize(v_surfaceToLight);
  vec3 surfaceToView = normalize(v_surfaceToView);
  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
  vec4 litR = lit(dot(normal, surfaceToLight),
                    dot(normal, halfVector), shininess);
  gl_FragColor = vec4((
  lightColor * (diffuse * litR.y
                        + specular * litR.z * specularFactor)).rgb,
      diffuse.a);
}
</script>
<script id="pickingVertexShader" type="text/something-not-javascript">
uniform mat4 worldViewProjection;
attribute vec4 position;
void main() {
  gl_Position = worldViewProjection * position;
}

</script>
<script id="pickingFragmentShader" type="text/something-not-javascript">
precision mediump float;

uniform vec4 u_color;

void main() {
  gl_FragColor = u_color;
}
</script>
</html>




================================================
FILE: js/require.js
================================================
/*
 RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
 Available via the MIT or new BSD license.
 see: http://github.com/jrburke/requirejs for details
*/
var requirejs,require,define;
(function(ca){function G(b){return"[object Function]"===M.call(b)}function H(b){return"[object Array]"===M.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function U(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function s(b,c){return ga.call(b,c)}function j(b,c){return s(b,c)&&b[c]}function B(b,c){for(var d in b)if(s(b,d)&&c(b[d],d))break}function V(b,c,d,g){c&&B(c,function(c,h){if(d||!s(b,h))g&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
RegExp)?(b[h]||(b[h]={}),V(b[h],c,d,g)):b[h]=c});return b}function t(b,c){return function(){return c.apply(b,arguments)}}function da(b){throw b;}function ea(b){if(!b)return b;var c=ca;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,g){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=g;d&&(c.originalError=d);return c}function ha(b){function c(a,e,b){var f,n,c,d,g,h,i,I=e&&e.split("/");n=I;var m=l.map,k=m&&m["*"];if(a&&"."===a.charAt(0))if(e){n=
I.slice(0,I.length-1);a=a.split("/");e=a.length-1;l.nodeIdCompat&&R.test(a[e])&&(a[e]=a[e].replace(R,""));n=a=n.concat(a);d=n.length;for(e=0;e<d;e++)if(c=n[e],"."===c)n.splice(e,1),e-=1;else if(".."===c)if(1===e&&(".."===n[2]||".."===n[0]))break;else 0<e&&(n.splice(e-1,2),e-=2);a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if(b&&m&&(I||k)){n=a.split("/");e=n.length;a:for(;0<e;e-=1){d=n.slice(0,e).join("/");if(I)for(c=I.length;0<c;c-=1)if(b=j(m,I.slice(0,c).join("/")))if(b=j(b,d)){f=b;
g=e;break a}!h&&(k&&j(k,d))&&(h=j(k,d),i=e)}!f&&h&&(f=h,g=i);f&&(n.splice(0,g,f),a=n.join("/"))}return(f=j(l.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(e){if(e.getAttribute("data-requiremodule")===a&&e.getAttribute("data-requirecontext")===i.contextName)return e.parentNode.removeChild(e),!0})}function g(a){var e=j(l.paths,a);if(e&&H(e)&&1<e.length)return e.shift(),i.require.undef(a),i.require([a]),!0}function u(a){var e,b=a?a.indexOf("!"):-1;-1<b&&(e=a.substring(0,
b),a=a.substring(b+1,a.length));return[e,a]}function m(a,e,b,f){var n,d,g=null,h=e?e.name:null,l=a,m=!0,k="";a||(m=!1,a="_@r"+(M+=1));a=u(a);g=a[0];a=a[1];g&&(g=c(g,h,f),d=j(p,g));a&&(g?k=d&&d.normalize?d.normalize(a,function(a){return c(a,h,f)}):c(a,h,f):(k=c(a,h,f),a=u(k),g=a[0],k=a[1],b=!0,n=i.nameToUrl(k)));b=g&&!d&&!b?"_unnormalized"+(Q+=1):"";return{prefix:g,name:k,parentMap:e,unnormalized:!!b,url:n,originalName:l,isDefine:m,id:(g?g+"!"+k:k)+b}}function q(a){var e=a.id,b=j(k,e);b||(b=k[e]=new i.Module(a));
return b}function r(a,e,b){var f=a.id,n=j(k,f);if(s(p,f)&&(!n||n.defineEmitComplete))"defined"===e&&b(p[f]);else if(n=q(a),n.error&&"error"===e)b(n.error);else n.on(e,b)}function w(a,e){var b=a.requireModules,f=!1;if(e)e(a);else if(v(b,function(e){if(e=j(k,e))e.error=a,e.events.error&&(f=!0,e.emit("error",a))}),!f)h.onError(a)}function x(){S.length&&(ia.apply(A,[A.length,0].concat(S)),S=[])}function y(a){delete k[a];delete W[a]}function F(a,e,b){var f=a.map.id;a.error?a.emit("error",a.error):(e[f]=
!0,v(a.depMaps,function(f,c){var d=f.id,g=j(k,d);g&&(!a.depMatched[c]&&!b[d])&&(j(e,d)?(a.defineDep(c,p[d]),a.check()):F(g,e,b))}),b[f]=!0)}function D(){var a,e,b=(a=1E3*l.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],c=[],h=!1,k=!0;if(!X){X=!0;B(W,function(a){var i=a.map,m=i.id;if(a.enabled&&(i.isDefine||c.push(a),!a.error))if(!a.inited&&b)g(m)?h=e=!0:(f.push(m),d(m));else if(!a.inited&&(a.fetched&&i.isDefine)&&(h=!0,!i.prefix))return k=!1});if(b&&f.length)return a=C("timeout","Load timeout for modules: "+
f,null,f),a.contextName=i.contextName,w(a);k&&v(c,function(a){F(a,{},{})});if((!b||e)&&h)if((z||fa)&&!Y)Y=setTimeout(function(){Y=0;D()},50);X=!1}}function E(a){s(p,a[0])||q(m(a[0],null,!0)).init(a[1],a[2])}function K(a){var a=a.currentTarget||a.srcElement,e=i.onScriptLoad;a.detachEvent&&!Z?a.detachEvent("onreadystatechange",e):a.removeEventListener("load",e,!1);e=i.onScriptError;(!a.detachEvent||Z)&&a.removeEventListener("error",e,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function L(){var a;
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var X,$,i,N,Y,l={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},k={},W={},aa={},A=[],p={},T={},ba={},M=1,Q=1;N={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?p[a.map.id]=a.exports:a.exports=p[a.map.id]={}},module:function(a){return a.module?
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return j(l.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};$=function(a){this.events=j(aa,a.id)||{};this.map=a;this.shim=j(l.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};$.prototype={init:function(a,e,b,f){f=f||{};if(!this.inited){this.factory=e;if(b)this.on("error",b);else this.events.error&&(b=t(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
b;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,e){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=e)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],t(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
this.map.url;T[a]||(T[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,e,b=this.map.id;e=this.depExports;var f=this.exports,c=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(c)){if(this.events.error&&this.map.isDefine||h.onError!==da)try{f=i.execCb(b,c,e,f)}catch(d){a=d}else f=i.execCb(b,c,e,f);this.map.isDefine&&void 0===f&&((e=this.module)?f=e.exports:this.usingExports&&
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=c;this.exports=f;if(this.map.isDefine&&!this.ignore&&(p[b]=f,h.onResourceLoad))h.onResourceLoad(i,this.map,this.depMaps);y(b);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
this.map,b=a.id,d=m(a.prefix);this.depMaps.push(d);r(d,"defined",t(this,function(f){var d,g;g=j(ba,this.map.id);var J=this.map.name,u=this.map.parentMap?this.map.parentMap.name:null,p=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(J=f.normalize(J,function(a){return c(a,u,!0)})||""),f=m(a.prefix+"!"+J,this.map.parentMap),r(f,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),g=j(k,f.id)){this.depMaps.push(f);
if(this.events.error)g.on("error",t(this,function(a){this.emit("error",a)}));g.enable()}}else g?(this.map.url=i.nameToUrl(g),this.load()):(d=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),d.error=t(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(k,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),d.fromText=t(this,function(f,c){var g=a.name,J=m(g),k=O;c&&(f=c);k&&(O=!1);q(J);s(l.config,b)&&(l.config[g]=l.config[b]);try{h.exec(f)}catch(j){return w(C("fromtexteval",
"fromText eval for "+b+" failed: "+j,j,[b]))}k&&(O=!0);this.depMaps.push(J);i.completeLoad(g);p([g],d)}),f.load(a.name,p,d,l))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){W[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,t(this,function(a,b){var c,f;if("string"===typeof a){a=m(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=j(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;r(a,"defined",t(this,function(a){this.defineDep(b,
a);this.check()}));this.errback&&r(a,"error",t(this,this.errback))}c=a.id;f=k[c];!s(N,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,t(this,function(a){var b=j(k,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:l,contextName:b,registry:k,defined:p,urlFetched:T,defQueue:A,Module:$,makeModuleMap:m,
nextTick:h.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=l.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(l[b]||(l[b]={}),V(l[b],a,!0,!0)):l[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(ba[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),l.shim=b);a.packages&&v(a.packages,function(a){var b,
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(l.paths[b]=a.location);l.pkgs[b]=a.name+"/"+(a.main||"main").replace(ja,"").replace(R,"")});B(k,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=m(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ca,arguments));return b||a.exports&&ea(a.exports)}},makeRequire:function(a,e){function g(f,c,d){var j,l;e.enableBuildCallback&&(c&&G(c))&&(c.__requireJsBuild=
!0);if("string"===typeof f){if(G(c))return w(C("requireargs","Invalid require call"),d);if(a&&s(N,f))return N[f](k[a.id]);if(h.get)return h.get(i,f,a,g);j=m(f,a,!1,!0);j=j.id;return!s(p,j)?w(C("notloaded",'Module name "'+j+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):p[j]}L();i.nextTick(function(){L();l=q(m(null,a));l.skipMap=e.skipMap;l.init(f,c,d,{enabled:!0});D()});return g}e=e||{};V(g,{isBrowser:z,toUrl:function(b){var e,d=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==
d&&(!("."===g||".."===g)||1<d))e=b.substring(d,b.length),b=b.substring(0,d);return i.nameToUrl(c(b,a&&a.id,!0),e,!0)},defined:function(b){return s(p,m(b,a,!1,!0).id)},specified:function(b){b=m(b,a,!1,!0).id;return s(p,b)||s(k,b)}});a||(g.undef=function(b){x();var c=m(b,a,!0),e=j(k,b);d(b);delete p[b];delete T[c.url];delete aa[b];U(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&(aa[b]=e.events),y(b))});return g},enable:function(a){j(k,a.id)&&q(a).enable()},completeLoad:function(a){var b,
c,f=j(l.shim,a)||{},d=f.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=j(k,a);if(!b&&!s(p,a)&&c&&!c.inited){if(l.enforceDefine&&(!d||!ea(d)))return g(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,f.deps||[],f.exportsFn])}D()},nameToUrl:function(a,b,c){var f,d,g;(f=j(l.pkgs,a))&&(a=f);if(f=j(ba,a))return i.nameToUrl(f,b,c);if(h.jsExtRegExp.test(a))f=a+(b||"");else{f=l.paths;a=a.split("/");for(d=a.length;0<d;d-=1)if(g=a.slice(0,
d).join("/"),g=j(f,g)){H(g)&&(g=g[0]);a.splice(0,d,g);break}f=a.join("/");f+=b||(/^data\:|\?/.test(f)||c?"":".js");f=("/"===f.charAt(0)||f.match(/^[\w\+\.\-]+:/)?"":l.baseUrl)+f}return l.urlArgs?f+((-1===f.indexOf("?")?"?":"&")+l.urlArgs):f},load:function(a,b){h.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ka.test((a.currentTarget||a.srcElement).readyState))P=null,a=K(a),i.completeLoad(a.id)},onScriptError:function(a){var b=K(a);if(!g(b.id))return w(C("scripterror",
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var h,x,y,D,K,E,P,L,q,Q,la=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ma=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,R=/\.js$/,ja=/^\.\//;x=Object.prototype;var M=x.toString,ga=x.hasOwnProperty,ia=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),fa=!z&&"undefined"!==typeof importScripts,ka=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
Z="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},r={},S=[],O=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;r=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(r=require,require=void 0);h=requirejs=function(b,c,d,g){var u,m="_";!H(b)&&"string"!==typeof b&&(u=b,H(c)?(b=c,c=d,d=g):b=[]);u&&u.context&&(m=u.context);(g=j(F,m))||(g=F[m]=h.s.newContext(m));u&&g.configure(u);return g.require(b,c,d)};h.config=function(b){return h(b)};
h.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=h);h.version="2.1.11";h.jsExtRegExp=/^\/|:|\?|\.js$/;h.isBrowser=z;x=h.s={contexts:F,newContext:ha};h({});v(["toUrl","undef","defined","specified"],function(b){h[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;h.onError=da;h.createNode=function(b){var c=
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};h.load=function(b,c,d){var g=b&&b.config||{};if(z)return g=h.createNode(g,c,d),g.setAttribute("data-requirecontext",b.contextName),g.setAttribute("data-requiremodule",c),g.attachEvent&&!(g.attachEvent.toString&&0>g.attachEvent.toString().indexOf("[native code"))&&!Z?(O=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):
(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,L=g,D?y.insertBefore(g,D):y.appendChild(g),L=null,g;if(fa)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};z&&!r.skipDataMain&&U(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(K=b.getAttribute("data-main"))return q=K,r.baseUrl||(E=q.split("/"),q=E.pop(),Q=E.length?E.join("/")+"/":"./",r.baseUrl=
Q),q=q.replace(R,""),h.jsExtRegExp.test(q)&&(q=K),r.deps=r.deps?r.deps.concat(q):[q],!0});define=function(b,c,d){var g,h;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(g=L))P&&"interactive"===P.readyState||U(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),g=P;g&&(b||
(b=g.getAttribute("data-requiremodule")),h=F[g.getAttribute("data-requirecontext")])}(h?h.defQueue:S).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)};h(r)}})(this);


================================================
FILE: jsdoc.conf.json
================================================
{
	"tags"      : {
		"allowUnknownTags" : false
	},
	"plugins"   : ["plugins/markdown"],
	"templates" : {
		"cleverLinks"           : false,
		"monospaceLinks"        : false,
		"dateFormat"            : "ddd MMM Do YYYY",
		"outputSourceFiles"     : false,
		"outputSourcePath"      : false,
		"systemName"            : "ThreeDLibrary",
		"footer"                : "",
		"copyright"             : "copyright Google, Greggman",
		"navType"               : "vertical",
		"theme"                 : "cerulean",
		"linenums"              : true,
		"collapseSymbols"       : false,
		"inverseNav"            : true,
		"highlightTutorialCode" : true
	},
	"markdown"  : {
		"parser"   : "gfm",
		"hardwrap" : true
	}
}


================================================
FILE: package.json
================================================
{
  "name": "tdl",
  "version": "0.0.8",
  "description": "Some WebGL Library",
  "main": "tdl/base.js",
  "directories": {
    "doc": "docs",
    "example": "example"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/greggman/tdl.git"
  },
  "keywords": [
    "WebGL"
  ],
  "author": "Greggman",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/greggman/tdl/issues"
  },
  "homepage": "https://github.com/greggman/tdl",
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-contrib-clean": "^0.6.0",
    "grunt-contrib-uglify": "^0.7.0",
    "grunt-jsdoc": "^0.5.7"
  }
}


================================================
FILE: tdl/base-rs.js
================================================
/*
 * Copyright 2014, Gregg Tavares.
 * 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 Gregg Tavares. 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.
 */

// emulate tdl/base.js for require.js

define(function() {

// Was base.js already included?
var haveBaseJS = (this.tdl !== undefined);
if (haveBaseJS) {
  tdl.provide('tdl.base-rs');
  return;
}

this.tdl = {base:{}};
this.goog = {};

var noop = function() {};

// Let's assume if the user is using require JS they don't need tdl.require
// If that's not the case we'd need provide a version of tdl.require that
// ignores the tdl files but not the user's files. Probably hooked into requirejs
tdl.require = noop;
tdl.provide = noop;


/**
 * Determine whether a value is an array. Do not use instanceof because that
 * will not work for V8 arrays (the browser thinks they are Objects).
 * @param {*} value A value.
 * @return {boolean} Whether the value is an array.
 */
tdl.base.isArray = function(value) {
  var valueAsObject = /** @type {!Object} */ (value);
  return typeof(value) === 'object' && value !== null &&
      'length' in valueAsObject && 'splice' in valueAsObject;
};

/**
 * A stub for later optionally converting obfuscated names
 * @private
 * @param {string} name Name to un-obfuscate.
 * @return {string} un-obfuscated name.
 */
tdl.base.maybeDeobfuscateFunctionName_ = function(name) {
  return name;
};

/**
 * Makes one class inherit from another.
 * @param {!Object} subClass Class that wants to inherit.
 * @param {!Object} superClass Class to inherit from.
 */
tdl.base.inherit = function(subClass, superClass) {
  /**
   * TmpClass.
   * @ignore
   * @constructor
   */
  var TmpClass = function() { };
  TmpClass.prototype = superClass.prototype;
  subClass.prototype = new TmpClass();
};

/**
 * Parses an error stack from an exception
 * @param {!Exception} excp The exception to get a stack trace from.
 * @return {!Array.<string>} An array of strings of the stack trace.
 */
tdl.base.parseErrorStack = function(excp) {
  var stack = [];
  var name;
  var line;

  if (!excp || !excp.stack) {
    return stack;
  }

  var stacklist = excp.stack.split('\n');

  for (var i = 0; i < stacklist.length - 1; i++) {
    var framedata = stacklist[i];

    name = framedata.match(/^([a-zA-Z0-9_$]*)/)[1];
    if (name) {
      name = tdl.base.maybeDeobfuscateFunctionName_(name);
    } else {
      name = 'anonymous';
    }

    var result = framedata.match(/(.*:[0-9]+)$/);
    line = result && result[1];

    if (!line) {
      line = '(unknown)';
    }

    stack[stack.length] = name + ' : ' + line
  }

  // remove top level anonymous functions to match IE
  var omitRegexp = /^anonymous :/;
  while (stack.length && omitRegexp.exec(stack[stack.length - 1])) {
    stack.length = stack.length - 1;
  }

  return stack;
};

/**
 * Gets a function name from a function object.
 * @param {!function(...): *} aFunction The function object to try to get a
 *      name from.
 * @return {string} function name or 'anonymous' if not found.
 */
tdl.base.getFunctionName = function(aFunction) {
  var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/);
  if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) {
    return tdl.base.maybeDeobfuscateFunctionName_(regexpResult[2]);
  }
  return 'anonymous';
};

/**
 * Pretty prints an exception's stack, if it has one.
 * @param {Array.<string>} stack An array of errors.
 * @return {string} The pretty stack.
 */
tdl.base.formatErrorStack = function(stack) {
  var result = '';
  for (var i = 0; i < stack.length; i++) {
    result += '> ' + stack[i] + '\n';
  }
  return result;
};

/**
 * Gets a stack trace as a string.
 * @param {number} stripCount The number of entries to strip from the top of the
 *     stack. Example: Pass in 1 to remove yourself from the stack trace.
 * @return {string} The stack trace.
 */
tdl.base.getStackTrace = function(stripCount) {
  var result = '';

  if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
    for (var a = arguments.caller; a != null; a = a.caller) {
      result += '> ' + tdl.base.getFunctionName(a.callee) + '\n';
      if (a.caller == a) {
        result += '*';
        break;
      }
    }
  } else { // Mozilla, not ECMA
    // fake an exception so we can get Mozilla's error stack
    var testExcp;
    try {
      eval('var var;');
    } catch (testExcp) {
      var stack = tdl.base.parseErrorStack(testExcp);
      result += tdl.base.formatErrorStack(stack.slice(3 + stripCount,
                                                        stack.length));
    }
  }

  return result;
};

/**
 * Returns true if the user's browser is Microsoft IE.
 * @return {boolean} true if the user's browser is Microsoft IE.
 */
tdl.base.IsMSIE = function() {
  var ua = navigator.userAgent.toLowerCase();
  var msie = /msie/.test(ua) && !/opera/.test(ua);
  return msie;
};

return {};
});


================================================
FILE: tdl/base.js
================================================
/*
 * Copyright 2009, 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 Base for all tdl sample utilties.
 *
 * The main point of this module is to provide a central place to
 * have an init function to register an tdl namespace object because many other
 * modules need access to it.
 */

/**
 * A namespace for all the tdl utility libraries.
 * @namespace
 */
var tdl = tdl || {};

/**
 * Define this because the Google internal JSCompiler needs goog.typedef below.
 */
var goog = goog || {};


if (!window.Int32Array) {
  window.Int32Array = function() { };
  window.Float32Array = function() { };
  window.Uint16Array = function() { };
}

/**
 * A macro for defining composite types.
 *
 * By assigning goog.typedef to a name, this tells Google internal JSCompiler
 * that this is not the name of a class, but rather it's the name of a composite
 * type.
 *
 * For example,
 * /** @type {Array|NodeList} / goog.ArrayLike = goog.typedef;
 * will tell JSCompiler to replace all appearances of goog.ArrayLike in type
 * definitions with the union of Array and NodeList.
 *
 * Does nothing in uncompiled code.
 */
goog.typedef = true;

/**
 * Reference to the global context.  In most cases this will be 'window'.
 */
tdl.global = this;

/**
 * Some javascripts don't support __defineGetter__ or __defineSetter__
 * so we define some here so at least we don't get compile errors.
 * We expect the initialzation code will check and complain. This stubs
 * are just here to make sure we can actually get to the initialization code.
 */
//if (!Object.prototype.__defineSetter__) {
//  Object.prototype.__defineSetter__ = function() {}
//  Object.prototype.__defineGetter__ = function() {}
//}
//
/**
 * Flag used to force a function to run in the browser when it is called
 * from V8.
 * @type {boolean}
 */
tdl.BROWSER_ONLY = true;

/**
 * Array of namespaces that have been provided.
 * @private
 * @type {!Array.<string>}
 */
tdl.provided_ = [];

/**
 * Creates object stubs for a namespace. When present in a file,
 * tdl.provide also indicates that the file defines the indicated
 * object.
 * @param {string} name name of the object that this file defines.
 */
tdl.provide = function(name) {
  // Ensure that the same namespace isn't provided twice.
  if (tdl.getObjectByName(name) &&
      !tdl.implicitNamespaces_[name]) {
    throw 'Namespace "' + name + '" already declared.';
  }

  var namespace = name;
  while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {
    tdl.implicitNamespaces_[namespace] = true;
  }

  tdl.exportPath_(name);
  tdl.provided_.push(name);
};


/**
 * Namespaces implicitly defined by tdl.provide. For example,
 * tdl.provide('tdl.events.Event') implicitly declares
 * that 'tdl' and 'tdl.events' must be namespaces.
 *
 * @type {Object}
 * @private
 */
tdl.implicitNamespaces_ = {};

/**
 * Builds an object structure for the provided namespace path,
 * ensuring that names that already exist are not overwritten. For
 * example:
 * "a.b.c" -> a = {};a.b={};a.b.c={};
 * Used by tdl.provide and tdl.exportSymbol.
 * @param {string} name name of the object that this file defines.
 * @param {Object} opt_object the object to expose at the end of the path.
 * @param {Object} opt_objectToExportTo The object to add the path to; default
 *     is |tdl.global|.
 * @private
 */
tdl.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
  var parts = name.split('.');
  var cur = opt_objectToExportTo || tdl.global;
  var part;

  // Internet Explorer exhibits strange behavior when throwing errors from
  // methods externed in this manner.  See the testExportSymbolExceptions in
  // base_test.html for an example.
  if (!(parts[0] in cur) && cur.execScript) {
    cur.execScript('var ' + parts[0]);
  }

  // Parentheses added to eliminate strict JS warning in Firefox.
  while (parts.length && (part = parts.shift())) {
    if (!parts.length && tdl.isDef(opt_object)) {
      // last part and we have an object; use it.
      cur[part] = opt_object;
    } else if (cur[part]) {
      cur = cur[part];
    } else {
      cur = cur[part] = {};
    }
  }
};


/**
 * Returns an object based on its fully qualified external name.  If you are
 * using a compilation pass that renames property names beware that using this
 * function will not find renamed properties.
 *
 * @param {string} name The fully qualified name.
 * @param {Object} opt_obj The object within which to look; default is
 *     |tdl.global|.
 * @return {Object} The object or, if not found, null.
 */
tdl.getObjectByName = function(name, opt_obj) {
  var parts = name.split('.');
  var cur = opt_obj || tdl.global;
  for (var pp = 0; pp < parts.length; ++pp) {
    var part = parts[pp];
    if (cur[part]) {
      cur = cur[part];
    } else {
      return null;
    }
  }
  return cur;
};


/**
 * Implements a system for the dynamic resolution of dependencies.
 * @param {string} rule Rule to include, in the form tdl.package.part.
 */
tdl.require = function(rule) {
  // TODO(gman): For some unknown reason, when we call
  // tdl.util.getScriptTagText_ it calls
  // document.getElementsByTagName('script') and for some reason the scripts do
  // not always show up. Calling it here seems to fix that as long as we
  // actually ask for the length, at least in FF 3.5.1 It would be nice to
  // figure out why.
  var dummy = document.getElementsByTagName('script').length;
  // if the object already exists we do not need do do anything
  if (tdl.getObjectByName(rule)) {
    return;
  }
  var path = tdl.getPathFromRule_(rule);
  if (path) {
    tdl.included_[path] = true;
    tdl.writeScripts_();
  } else {
    throw new Error('tdl.require could not find: ' + rule);
  }
};


/**
 * Path for included scripts.
 * @type {string}
 */
tdl.basePath = '';


/**
 * Object used to keep track of urls that have already been added. This
 * record allows the prevention of circular dependencies.
 * @type {Object}
 * @private
 */
tdl.included_ = {};


/**
 * This object is used to keep track of dependencies and other data that is
 * used for loading scripts.
 * @private
 * @type {Object}
 */
tdl.dependencies_ = {
  visited: {},  // used when resolving dependencies to prevent us from
                // visiting the file twice.
  written: {}  // used to keep track of script files we have written.
};


/**
 * Tries to detect the base path of the tdl-base.js script that
 * bootstraps the tdl libraries.
 * @private
 */
tdl.findBasePath_ = function() {
  var doc = tdl.global.document;
  if (typeof doc == 'undefined') {
    return;
  }
  if (tdl.global.BASE_PATH) {
    tdl.basePath = tdl.global.BASE_PATH;
    return;
  } else {
    // HACKHACK to hide compiler warnings :(
    tdl.global.BASE_PATH = null;
  }
  var expectedBase = 'tdl/base.js';
  var scripts = doc.getElementsByTagName('script');
  for (var script, i = 0; script = scripts[i]; i++) {
    var src = script.src;
    var l = src.length;
    if (src.substr(l - expectedBase.length) == expectedBase) {
      tdl.basePath = src.substr(0, l - expectedBase.length);
      return;
    }
  }
};


/**
 * Writes a script tag if, and only if, that script hasn't already been added
 * to the document.  (Must be called at execution time.)
 * @param {string} src Script source.
 * @private
 */
tdl.writeScriptTag_ = function(src) {
  var doc = tdl.global.document;
  if (typeof doc != 'undefined' &&
      !tdl.dependencies_.written[src]) {
    tdl.dependencies_.written[src] = true;
    var html = '<script type="text/javascript" src="' +
               src + '"></' + 'script>'
    doc.write(html);
  }
};


/**
 * Resolves dependencies based on the dependencies added using addDependency
 * and calls writeScriptTag_ in the correct order.
 * @private
 */
tdl.writeScripts_ = function() {
  // the scripts we need to write this time.
  var scripts = [];
  var seenScript = {};
  var deps = tdl.dependencies_;

  function visitNode(path) {
    if (path in deps.written) {
      return;
    }

    // we have already visited this one. We can get here if we have cyclic
    // dependencies.
    if (path in deps.visited) {
      if (!(path in seenScript)) {
        seenScript[path] = true;
        scripts.push(path);
      }
      return;
    }

    deps.visited[path] = true;

    if (!(path in seenScript)) {
      seenScript[path] = true;
      scripts.push(path);
    }
  }

  for (var path in tdl.included_) {
    if (!deps.written[path]) {
      visitNode(path);
    }
  }

  for (var i = 0; i < scripts.length; i++) {
    if (scripts[i]) {
      tdl.writeScriptTag_(tdl.basePath + scripts[i]);
    } else {
      throw Error('Undefined script input');
    }
  }
};


/**
 * Looks at the dependency rules and tries to determine the script file that
 * fulfills a particular rule.
 * @param {string} rule In the form tdl.namespace.Class or
 *     project.script.
 * @return {string?} Url corresponding to the rule, or null.
 * @private
 */
tdl.getPathFromRule_ = function(rule) {
  var parts = rule.split('.');
  return parts.join('/') + '.js';
};

tdl.findBasePath_();

/**
 * Returns true if the specified value is not |undefined|.
 * WARNING: Do not use this to test if an object has a property. Use the in
 * operator instead.
 * @param {*} val Variable to test.
 * @return {boolean} Whether variable is defined.
 */
tdl.isDef = function(val) {
  return typeof val != 'undefined';
};


/**
 * Exposes an unobfuscated global namespace path for the given object.
 * Note that fields of the exported object *will* be obfuscated,
 * unless they are exported in turn via this function or
 * tdl.exportProperty.
 *
 * <p>Also handy for making public items that are defined in anonymous
 * closures.
 *
 * ex. tdl.exportSymbol('Foo', Foo);
 *
 * ex. tdl.exportSymbol('public.path.Foo.staticFunction',
 *                        Foo.staticFunction);
 *     public.path.Foo.staticFunction();
 *
 * ex. tdl.exportSymbol('public.path.Foo.prototype.myMethod',
 *                        Foo.prototype.myMethod);
 *     new public.path.Foo().myMethod();
 *
 * @param {string} publicPath Unobfuscated name to export.
 * @param {Object} object Object the name should point to.
 * @param {Object} opt_objectToExportTo The object to add the path to; default
 *     is |tdl.global|.
 */
tdl.exportSymbol = function(publicPath, object, opt_objectToExportTo) {
  tdl.exportPath_(publicPath, object, opt_objectToExportTo);
};

tdl.provide('tdl.base');

/**
 * The base module for tdl.
 * @namespace
 */
tdl.base = tdl.base || {};

/**
 * Determine whether a value is an array. Do not use instanceof because that
 * will not work for V8 arrays (the browser thinks they are Objects).
 * @param {*} value A value.
 * @return {boolean} Whether the value is an array.
 */
tdl.base.isArray = function(value) {
  var valueAsObject = /** @type {!Object} */ (value);
  return typeof(value) === 'object' && value !== null &&
      'length' in valueAsObject && 'splice' in valueAsObject;
};

/**
 * A stub for later optionally converting obfuscated names
 * @private
 * @param {string} name Name to un-obfuscate.
 * @return {string} un-obfuscated name.
 */
tdl.base.maybeDeobfuscateFunctionName_ = function(name) {
  return name;
};

/**
 * Makes one class inherit from another.
 * @param {!Object} subClass Class that wants to inherit.
 * @param {!Object} superClass Class to inherit from.
 */
tdl.base.inherit = function(subClass, superClass) {
  /**
   * TmpClass.
   * @ignore
   * @constructor
   */
  var TmpClass = function() { };
  TmpClass.prototype = superClass.prototype;
  subClass.prototype = new TmpClass();
};

/**
 * Parses an error stack from an exception
 * @param {!Exception} excp The exception to get a stack trace from.
 * @return {!Array.<string>} An array of strings of the stack trace.
 */
tdl.base.parseErrorStack = function(excp) {
  var stack = [];
  var name;
  var line;

  if (!excp || !excp.stack) {
    return stack;
  }

  var stacklist = excp.stack.split('\n');

  for (var i = 0; i < stacklist.length - 1; i++) {
    var framedata = stacklist[i];

    name = framedata.match(/^([a-zA-Z0-9_$]*)/)[1];
    if (name) {
      name = tdl.base.maybeDeobfuscateFunctionName_(name);
    } else {
      name = 'anonymous';
    }

    var result = framedata.match(/(.*:[0-9]+)$/);
    line = result && result[1];

    if (!line) {
      line = '(unknown)';
    }

    stack[stack.length] = name + ' : ' + line
  }

  // remove top level anonymous functions to match IE
  var omitRegexp = /^anonymous :/;
  while (stack.length && omitRegexp.exec(stack[stack.length - 1])) {
    stack.length = stack.length - 1;
  }

  return stack;
};

/**
 * Gets a function name from a function object.
 * @param {!function(...): *} aFunction The function object to try to get a
 *      name from.
 * @return {string} function name or 'anonymous' if not found.
 */
tdl.base.getFunctionName = function(aFunction) {
  var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/);
  if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) {
    return tdl.base.maybeDeobfuscateFunctionName_(regexpResult[2]);
  }
  return 'anonymous';
};

/**
 * Pretty prints an exception's stack, if it has one.
 * @param {Array.<string>} stack An array of errors.
 * @return {string} The pretty stack.
 */
tdl.base.formatErrorStack = function(stack) {
  var result = '';
  for (var i = 0; i < stack.length; i++) {
    result += '> ' + stack[i] + '\n';
  }
  return result;
};

/**
 * Gets a stack trace as a string.
 * @param {number} stripCount The number of entries to strip from the top of the
 *     stack. Example: Pass in 1 to remove yourself from the stack trace.
 * @return {string} The stack trace.
 */
tdl.base.getStackTrace = function(stripCount) {
  var result = '';

  if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
    for (var a = arguments.caller; a != null; a = a.caller) {
      result += '> ' + tdl.base.getFunctionName(a.callee) + '\n';
      if (a.caller == a) {
        result += '*';
        break;
      }
    }
  } else { // Mozilla, not ECMA
    // fake an exception so we can get Mozilla's error stack
    var testExcp;
    try {
      eval('var var;');
    } catch (testExcp) {
      var stack = tdl.base.parseErrorStack(testExcp);
      result += tdl.base.formatErrorStack(stack.slice(3 + stripCount,
                                                        stack.length));
    }
  }

  return result;
};

/**
 * Returns true if the user's browser is Microsoft IE.
 * @return {boolean} true if the user's browser is Microsoft IE.
 */
tdl.base.IsMSIE = function() {
  var ua = navigator.userAgent.toLowerCase();
  var msie = /msie/.test(ua) && !/opera/.test(ua);
  return msie;
};

// Handle case where we are NOT using require.js
function define() {
  var args = [];
  for (var ii = 0; ii < arguments.length; ++ii) {
    args.push(arguments[ii]);
  }
  if (args.length == 1) {
    args.unshift([]);
  }
  if (args.length == 2) {
    args.unshift(undefined);
  }

  var id = args[0];
  var deps = args[1];
  var obj = args[2];

  for (var ii = 0; ii < deps.length; ++ii) {
    // assume format is './name'
    var name = deps[ii].replace('./', 'tdl.');
    tdl.require(name);
  }
  if (typeof obj == "function") {
    obj();
  }
}


================================================
FILE: tdl/buffers.js
================================================
/*
 * Copyright 2009, 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 objects to deal with WebGL
 *               buffers.
 */
define(['./base-rs'], function(BaseRS) {

tdl.provide('tdl.buffers');
/**
 * A module for buffers.
 * @namespace
 */
tdl.buffers = tdl.buffers || {};

/**
 * A Buffer represnets a WebGL buffer.
 * @constructor
 * @param {tdl.primitives.AttribBuffer} array AttribBuffer with
 *        data.
 * @param {number?} opt_target Assumes gl.ARRAY_BUFFER
 */
tdl.buffers.Buffer = function(array, opt_target) {
  var target = opt_target || gl.ARRAY_BUFFER;
  var buf = gl.createBuffer();
  this.target = target;
  this.buf = buf;
  this.set(array);
};

/**
 * Sets the contents of this buffer from the contents of the
 * given AttribBuffer.
 * @param {tdl.primitives.AttribBuffer} array AttribBuffer with
 *        data.
 * @param {number?} opt_usage GL buffer usage. Defaults to
 *        gl.STATIC_DRAW.
 */
tdl.buffers.Buffer.prototype.set = function(array, opt_usage) {
  this.numComponents_ = array.numComponents;
  this.numElements_ = array.numElements;
  this.totalComponents_ = this.numComponents_ * this.numElements_;
  if (array.buffer instanceof Float32Array) {
    this.type_ = gl.FLOAT;
    this.normalize_ = false;
  } else if (array.buffer instanceof Uint8Array) {
    this.type_ = gl.UNSIGNED_BYTE;
    this.normalize_ = true;
  } else if (array.buffer instanceof Int8Array) {
    this.type_ = gl.BYTE;
    this.normalize_ = true;
  } else if (array.buffer instanceof Uint16Array) {
    this.type_ = gl.UNSIGNED_SHORT;
    this.normalize_ = true;
  } else if (array.buffer instanceof Int16Array) {
    this.type_ = gl.SHORT;
    this.normalize_ = true;
  } else {
    throw("unhandled type:" + (typeof array.buffer));
  }
  gl.bindBuffer(this.target, this.buf);
  gl.bufferData(this.target, array.buffer, opt_usage || gl.STATIC_DRAW);
}

/**
 * Sets part of a buffer.
 * @param {ArrayBufferView} array some typed array buffer view
 * @param {number} the offset in bytes into the buffer to copy
 *        the array.
 */
tdl.buffers.Buffer.prototype.setRange = function(array, offset) {
  gl.bindBuffer(this.target, this.buf);
  gl.bufferSubData(this.target, offset, array);
};

/**
 * Gets the type of the buffer. Eg. `gl.FLOAT`
 * @return {number}
 */
tdl.buffers.Buffer.prototype.type = function() {
  return this.type_;
};

/**
 * Gets the number of components per element of buffer.
 * @return {number} num components per element in buffer
 */
tdl.buffers.Buffer.prototype.numComponents = function() {
  return this.numComponents_;
};

/**
 * Gets the number of elements in the buffer
 * @return {number} num elements in buffer
 */
tdl.buffers.Buffer.prototype.numElements = function() {
  return this.numElements_;
};

/**
 * Gets the total components in the buffer.
 * @return {number} Basically this is numComponents *
 *         numElements
 */
tdl.buffers.Buffer.prototype.totalComponents = function() {
  return this.totalComponents_;
};

/**
 * Get the WebGLBuffer for this buffer.
 * @return {WebGLBuffer} the WebGLBuffer for this buffer.
 */
tdl.buffers.Buffer.prototype.buffer = function() {
  return this.buf;
};

/**
 * Get the stride?
 * @return {number} stride.
 */
tdl.buffers.Buffer.prototype.stride = function() {
  return 0;
};

/**
 * Gets whether the data in this buffer should be normalized.
 * @return {boolean} normalizaiton.
 */
tdl.buffers.Buffer.prototype.normalize = function() {
  return this.normalize_;
}

/**
 * Get the offset?
 * @return {number} offset.
 */
tdl.buffers.Buffer.prototype.offset = function() {
  return 0;
};

return tdl.buffers;
});


================================================
FILE: tdl/clock.js
================================================
/*
 * Copyright 2009, 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 various functions for managing a clock
 */
define(['./base-rs', './io', './log'], function(BaseRS, IO, Log) {

tdl.provide('tdl.clock');
/**
 * Clock related stuff
 * @namespace
 */
tdl.clock = tdl.clock || {};

/**
 * Creates a clock. Optionally synced to a server
 * @param {number} opt_syncRate. If passed, this is the number of seconds
 *        between syncing to the server. If not passed the local clock is used.
 *        Note: If the client is faster than the server this means it's possible
 *        the clock will report a certain time and then later a previous time.
 */
tdl.clock.createClock = function(opt_syncRate, opt_url) {
  if (opt_syncRate) {
    return new tdl.clock.SyncedClock(opt_syncRate, opt_url);
  } else {
    return new tdl.clock.LocalClock();
  }
};

/**
 * A clock that gets the local current time in seconds.
 * @constructor
 * @private
 */
tdl.clock.LocalClock = function() {
}

/**
 * Gets the current time in seconds.
 * @return {number} current time in seconds
 */
tdl.clock.LocalClock.prototype.getTime = function() {
  return (new Date()).getTime() * 0.001;
}

/**
 * A clock that gets the current time in seconds attempting to eep the clock
 * synced to the server.
 * @constructor
 * @private
 */
tdl.clock.SyncedClock = function(opt_syncRate, opt_url) {
  this.url = opt_url || window.location.href;
  this.syncRate = opt_syncRate || 10;
  this.timeOffset = 0;
  this.syncToServer();
}

tdl.clock.SyncedClock.prototype.getLocalTime_ = function() {
  return (new Date()).getTime() * 0.001;
}

tdl.clock.SyncedClock.prototype.syncToServer = function() {
  var that = this;
  var sendTime = this.getLocalTime_();
  tdl.io.sendJSON(this.url, {cmd: 'time'}, function(obj, exception) {
    if (exception) {
      tdl.log("error: syncToServer: " + exception);
    } else {
      var receiveTime = that.getLocalTime_();
      var duration = receiveTime - sendTime;
      var serverTime = obj.time + duration * 0.5;
      that.timeOffset = serverTime - receiveTime;
      tdl.log("new timeoffset: " + that.timeOffset);
    }
    setTimeout(function() {
        that.syncToServer();
      }, that.syncRate * 1000);
  });
};

/**
 * Gets the current time in seconds.
 * @return {number} current time in seconds
 */
tdl.clock.SyncedClock.prototype.getTime = function() {
  return (new Date()).getTime() * 0.001 + this.timeOffset;
}

return tdl.clock;
});


================================================
FILE: tdl/fast.js
================================================
/*
 * Copyright 2009, 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 matrix/vector math functions.
 */
define(['./base-rs'], function(BaseRS) {

tdl.provide('tdl.fast');

/**
 * A module for math for tdl.fast.
 * @namespace
 */
tdl.fast = tdl.fast || {};

if (!window.Float32Array) {
  // This just makes some errors go away when there is no WebGL.
  window.Float32Array = function() { };
}

tdl.fast.temp0v3_ = new Float32Array(3);
tdl.fast.temp1v3_ = new Float32Array(3);
tdl.fast.temp2v3_ = new Float32Array(3);

tdl.fast.temp0v4_ = new Float32Array(4);
tdl.fast.temp1v4_ = new Float32Array(4);
tdl.fast.temp2v4_ = new Float32Array(4);

tdl.fast.temp0m4_ = new Float32Array(16);
tdl.fast.temp1m4_ = new Float32Array(16);
tdl.fast.temp2m4_ = new Float32Array(16);

/**
 * Functions which deal with 4-by-4 transformation matrices are kept in their
 * own namespsace.
 * @namespace
 */
tdl.fast.matrix4 = tdl.fast.matrix4 || {};

/**
 * Functions that are specifically row major are kept in their own namespace.
 * @namespace
 */
tdl.fast.rowMajor = tdl.fast.rowMajor || {};

/**
 * Functions that are specifically column major are kept in their own namespace.
 * @namespace
 */
tdl.fast.columnMajor = tdl.fast.columnMajor || {};

/**
 * An Array of 2 floats
 * @typedef {Float32Array} tdl.fast.Vector2
 */

/**
 * An Array of 3 floats
 * @typedef {Float32Array} tdl.fast.Vector3
 */

/**
 * An Array of 4 floats
 * @typedef {Float32Array} tdl.fast.Vector4
 */

/**
 * An Array of floats.
 * @typedef {Float32Array} tdl.fast.Vector
 */

/**
 * A 2x2 Matrix of floats
 * @typedef {Float32Array} tdl.fast.Matrix2
 */

/**
 * A 3x3 Matrix of floats
 * @typedef {Float32Array} tdl.fast.Matrix3
 */

/**
 * A 4x4 Matrix of floats
 * @typedef {Float32Array} tdl.fast.Matrix4
 */

/**
 * A arbitrary size Matrix of floats
 * @typedef {Array<Number[]>} tdl.fast.Matrix
 */

/**
 * Adds two vectors; assumes a and b have the same dimension.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 */
tdl.fast.addVector = function(dst, a, b) {
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    dst[i] = a[i] + b[i];
  return dst;
};

/**
 * Subtracts two vectors.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 */
tdl.fast.subVector = function(dst, a, b) {
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    dst[i] = a[i] - b[i];
  return dst;
};

/**
 * Performs linear interpolation on two vectors.
 * Given vectors a and b and interpolation coefficient t, returns
 * (1 - t) * a + t * b.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 * @param {number} t Interpolation coefficient.
 */
tdl.fast.lerpVector = function(dst, a, b, t) {
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    dst[i] = (1 - t) * a[i] + t * b[i];
  return dst;
};

/**
 * Divides a vector by a scalar.
 * @param {tdl.fast.Vector} dst The vector.
 * @param {tdl.fast.Vector} v The vector.
 * @param {number} k The scalar.
 * @return {tdl.fast.Vector} dst.
 */
tdl.fast.divVectorScalar = function(dst, v, k) {
  var vLength = v.length;
  for (var i = 0; i < vLength; ++i)
    dst[i] = v[i] / k;
  return dst;
};

/**
 * Computes the cross product of two vectors; assumes both vectors have
 * three entries.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 * @return {tdl.fast.Vector} The vector a cross b.
 */
tdl.fast.cross = function(dst, a, b) {
  dst[0] = a[1] * b[2] - a[2] * b[1];
  dst[1] = a[2] * b[0] - a[0] * b[2];
  dst[2] = a[0] * b[1] - a[1] * b[0];
  return dst;
};

/**
 * Computes the dot product of two vectors; assumes both vectors have
 * three entries.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 * @return {number} dot product
 */
tdl.fast.dot = function(a, b) {
  return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
};

/**
 * Divides a vector by its Euclidean length and returns the quotient.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a The vector.
 * @return {tdl.fast.Vector} The normalized vector.
 */
tdl.fast.normalize = function(dst, a) {
  var n = 0.0;
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    n += a[i] * a[i];
  n = Math.sqrt(n);
  if (n > 0.00001) {
    for (var i = 0; i < aLength; ++i)
      dst[i] = a[i] / n;
  } else {
    for (var i = 0; i < aLength; ++i)
      dst[i] = 0;
  }
  return dst;
};

/**
 * Negates a vector.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} -v.
 */
tdl.fast.negativeVector = function(dst, v) {
 var vLength = v.length;
 for (var i = 0; i < vLength; ++i) {
   dst[i] = -v[i];
 }
 return dst;
};

/**
 * Negates a matrix.
 * @param {tdl.fast.Matrix} dst matrix.
 * @param {tdl.fast.Matrix} v The matrix.
 * @return {tdl.fast.Matrix} -v.
 */
tdl.fast.negativeMatrix = function(dst, v) {
  var vLength = v.length;
  for (var i = 0; i < vLength; ++i) {
    dst[i] = -v[i];
  }
  return dst;
};

/**
 * Copies a vector.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} A copy of v.
 */
tdl.fast.copyVector = function(dst, v) {
  dst.set(v);
  return dst;
};

/**
 * Copies a matrix.
 * @param {tdl.fast.Matrix} m The matrix.
 * @return {tdl.fast.Matrix} A copy of m.
 */
tdl.fast.copyMatrix = function(dst, m) {
  dst.set(m);
  return dst;
};

/**
 * Multiplies a scalar by a vector.
 * @param {tdl.fast.Vector} dst vector.
 * @param {number} k The scalar.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} The product of k and v.
 */
tdl.fast.mulScalarVector = function(dst, k, v) {
  var vLength = v.length;
  for (var i = 0; i < vLength; ++i) {
    dst[i] = k * v[i];
  }
  return dst;
};

/**
 * Multiplies a vector by a scalar.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} v The vector.
 * @param {number} k The scalar.
 * @return {tdl.fast.Vector} The product of k and v.
 */
tdl.fast.mulVectorScalar = function(dst, v, k) {
  return tdl.fast.mulScalarVector(dst, k, v);
};

/**
 * Multiplies a scalar by a matrix.
 * @param {tdl.fast.Matrix} dst matrix.
 * @param {number} k The scalar.
 * @param {tdl.fast.Matrix} m The matrix.
 * @return {tdl.fast.Matrix} The product of m and k.
 */
tdl.fast.mulScalarMatrix = function(dst, k, m) {
  var mLength = m.length;
  for (var i = 0; i < mLength; ++i) {
    dst[i] = k * m[i];
  }
  return dst;
};

/**
 * Multiplies a matrix by a scalar.
 * @param {tdl.fast.Matrix} dst matrix.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} k The scalar.
 * @return {tdl.fast.Matrix} The product of m and k.
 */
tdl.fast.mulMatrixScalar = function(dst, m, k) {
  return tdl.fast.mulScalarMatrix(dst, k, m);
};

/**
 * Multiplies a vector by another vector (component-wise); assumes a and
 * b have the same length.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 * @return {tdl.fast.Vector} The vector of products of entries of a and
 *     b.
 */
tdl.fast.mulVectorVector = function(dst, a, b) {
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    dst[i] = a[i] * b[i];
  return dst;
};

/**
 * Divides a vector by another vector (component-wise); assumes a and
 * b have the same length.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} a Operand vector.
 * @param {tdl.fast.Vector} b Operand vector.
 * @return {tdl.fast.Vector} The vector of quotients of entries of a and
 *     b.
 */
tdl.fast.divVectorVector = function(dst, a, b) {
  var aLength = a.length;
  for (var i = 0; i < aLength; ++i)
    dst[i] = a[i] / b[i];
  return dst;
};

/**
 * Multiplies a vector by a matrix; treats the vector as a row vector; assumes
 * matrix entries are accessed in [row][column] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} v The vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @return {tdl.fast.Vector} The product of v and m as a row vector.
 */
tdl.fast.rowMajor.mulVectorMatrix4 = function(dst, v, m) {
  for (var i = 0; i < 4; ++i) {
    dst[i] = 0.0;
    for (var j = 0; j < 4; ++j)
      dst[i] += v[j] * m[j * 4 + i];
  }
  return dst;
};

/**
 * Multiplies a vector by a matrix; treats the vector as a row vector; assumes
 * matrix entries are accessed in [column][row] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Vector} v The vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @return {tdl.fast.Vector} The product of v and m as a row vector.
 */
tdl.fast.columnMajor.mulVectorMatrix4 = function(dst, v, m) {
  var mLength = m.length;
  var vLength = v.length;
  for (var i = 0; i < 4; ++i) {
    dst[i] = 0.0;
    var col = i * 4;
    for (var j = 0; j < 4; ++j)
      dst[i] += v[j] * m[col + j];
  }
  return dst;
};

/**
 * Multiplies a vector by a matrix; treats the vector as a row vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} The product of m and v as a row vector.
 */
tdl.fast.mulVectorMatrix4 = null;

/**
 * Multiplies a matrix by a vector; treats the vector as a column vector.
 * assumes matrix entries are accessed in [row][column] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} The product of m and v as a column vector.
 */
tdl.fast.rowMajor.mulMatrix4Vector = function(dst, m, v) {
  for (var i = 0; i < 4; ++i) {
    dst[i] = 0.0;
    var row = i * 4;
    for (var j = 0; j < 4; ++j)
      dst[i] += m[row + j] * v[j];
  }
  return dst;
};

/**
 * Multiplies a matrix by a vector; treats the vector as a column vector;
 * assumes matrix entries are accessed in [column][row] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} The product of m and v as a column vector.
 */
tdl.fast.columnMajor.mulMatrix4Vector = function(dst, m, v) {
  for (var i = 0; i < 4; ++i) {
    dst[i] = 0.0;
    for (var j = 0; j < 4; ++j)
      dst[i] += v[j] * m[j * 4 + i];
  }
  return dst;
};

/**
 * Multiplies a matrix by a vector; treats the vector as a column vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {tdl.fast.Vector} v The vector.
 * @return {tdl.fast.Vector} The product of m and v as a column vector.
 */
tdl.fast.mulMatrix4Vector = null;

/**
 * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3;
 * assumes matrix entries are accessed in [row][column] fashion.
 * @param {tdl.fast.Matrix3} dst matrix.
 * @param {tdl.fast.Matrix3} a The matrix on the left.
 * @param {tdl.fast.Matrix3} b The matrix on the right.
 * @return {tdl.fast.Matrix3} The matrix product of a and b.
 */
tdl.fast.rowMajor.mulMatrixMatrix3 = function(dst, a, b) {
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a10 = a[3 + 0];
  var a11 = a[3 + 1];
  var a12 = a[3 + 2];
  var a20 = a[6 + 0];
  var a21 = a[6 + 1];
  var a22 = a[6 + 2];
  var b00 = b[0];
  var b01 = b[1];
  var b02 = b[2];
  var b10 = b[3 + 0];
  var b11 = b[3 + 1];
  var b12 = b[3 + 2];
  var b20 = b[6 + 0];
  var b21 = b[6 + 1];
  var b22 = b[6 + 2];
  dst[0] = a00 * b00 + a01 * b10 + a02 * b20;
  dst[1] = a00 * b01 + a01 * b11 + a02 * b21;
  dst[2] = a00 * b02 + a01 * b12 + a02 * b22;
  dst[3] = a10 * b00 + a11 * b10 + a12 * b20;
  dst[4] = a10 * b01 + a11 * b11 + a12 * b21;
  dst[5] = a10 * b02 + a11 * b12 + a12 * b22;
  dst[6] = a20 * b00 + a21 * b10 + a22 * b20;
  dst[7] = a20 * b01 + a21 * b11 + a22 * b21;
  dst[8] = a20 * b02 + a21 * b12 + a22 * b22;
  return dst;
};

/**
 * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3;
 * assumes matrix entries are accessed in [column][row] fashion.
 * @param {tdl.fast.Matrix3} dst matrix.
 * @param {tdl.fast.Matrix3} a The matrix on the left.
 * @param {tdl.fast.Matrix3} b The matrix on the right.
 * @return {tdl.fast.Matrix3} The matrix product of a and b.
 */
tdl.fast.columnMajor.mulMatrixMatrix3 = function(dst, a, b) {
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a10 = a[3 + 0];
  var a11 = a[3 + 1];
  var a12 = a[3 + 2];
  var a20 = a[6 + 0];
  var a21 = a[6 + 1];
  var a22 = a[6 + 2];
  var b00 = b[0];
  var b01 = b[1];
  var b02 = b[2];
  var b10 = b[3 + 0];
  var b11 = b[3 + 1];
  var b12 = b[3 + 2];
  var b20 = b[6 + 0];
  var b21 = b[6 + 1];
  var b22 = b[6 + 2];
  dst[0] = a00 * b00 + a10 * b01 + a20 * b02;
  dst[1] = a01 * b00 + a11 * b01 + a21 * b02;
  dst[2] = a02 * b00 + a12 * b01 + a22 * b02;
  dst[3] = a00 * b10 + a10 * b11 + a20 * b12;
  dst[4] = a01 * b10 + a11 * b11 + a21 * b12;
  dst[5] = a02 * b10 + a12 * b11 + a22 * b12;
  dst[6] = a00 * b20 + a10 * b21 + a20 * b22;
  dst[7] = a01 * b20 + a11 * b21 + a21 * b22;
  dst[8] = a02 * b20 + a12 * b21 + a22 * b22;
  return dst;
};

/**
 * Multiplies two 3-by-3 matrices; assumes that the given matrices are 3-by-3.
 * @param {tdl.fast.Matrix3} a The matrix on the left.
 * @param {tdl.fast.Matrix3} b The matrix on the right.
 * @return {tdl.fast.Matrix3} The matrix product of a and b.
 */
tdl.fast.mulMatrixMatrix3 = null;

/**
 * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4;
 * assumes matrix entries are accessed in [row][column] fashion.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @param {tdl.fast.Matrix4} a The matrix on the left.
 * @param {tdl.fast.Matrix4} b The matrix on the right.
 * @return {tdl.fast.Matrix4} The matrix product of a and b.
 */
tdl.fast.rowMajor.mulMatrixMatrix4 = function(dst, a, b) {
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a03 = a[3];
  var a10 = a[ 4 + 0];
  var a11 = a[ 4 + 1];
  var a12 = a[ 4 + 2];
  var a13 = a[ 4 + 3];
  var a20 = a[ 8 + 0];
  var a21 = a[ 8 + 1];
  var a22 = a[ 8 + 2];
  var a23 = a[ 8 + 3];
  var a30 = a[12 + 0];
  var a31 = a[12 + 1];
  var a32 = a[12 + 2];
  var a33 = a[12 + 3];
  var b00 = b[0];
  var b01 = b[1];
  var b02 = b[2];
  var b03 = b[3];
  var b10 = b[ 4 + 0];
  var b11 = b[ 4 + 1];
  var b12 = b[ 4 + 2];
  var b13 = b[ 4 + 3];
  var b20 = b[ 8 + 0];
  var b21 = b[ 8 + 1];
  var b22 = b[ 8 + 2];
  var b23 = b[ 8 + 3];
  var b30 = b[12 + 0];
  var b31 = b[12 + 1];
  var b32 = b[12 + 2];
  var b33 = b[12 + 3];
  dst[ 0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30;
  dst[ 1] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31;
  dst[ 2] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32;
  dst[ 3] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33;
  dst[ 4] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30;
  dst[ 5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31;
  dst[ 6] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32;
  dst[ 7] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33;
  dst[ 8] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30;
  dst[ 9] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31;
  dst[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32;
  dst[11] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33;
  dst[12] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30;
  dst[13] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31;
  dst[14] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32;
  dst[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33;
  return dst;
};

/**
 * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4;
 * assumes matrix entries are accessed in [column][row] fashion.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @param {tdl.fast.Matrix4} a The matrix on the left.
 * @param {tdl.fast.Matrix4} b The matrix on the right.
 * @return {tdl.fast.Matrix4} The matrix product of a and b.
 */
tdl.fast.columnMajor.mulMatrixMatrix4 = function(dst, a, b) {
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a03 = a[3];
  var a10 = a[ 4 + 0];
  var a11 = a[ 4 + 1];
  var a12 = a[ 4 + 2];
  var a13 = a[ 4 + 3];
  var a20 = a[ 8 + 0];
  var a21 = a[ 8 + 1];
  var a22 = a[ 8 + 2];
  var a23 = a[ 8 + 3];
  var a30 = a[12 + 0];
  var a31 = a[12 + 1];
  var a32 = a[12 + 2];
  var a33 = a[12 + 3];
  var b00 = b[0];
  var b01 = b[1];
  var b02 = b[2];
  var b03 = b[3];
  var b10 = b[ 4 + 0];
  var b11 = b[ 4 + 1];
  var b12 = b[ 4 + 2];
  var b13 = b[ 4 + 3];
  var b20 = b[ 8 + 0];
  var b21 = b[ 8 + 1];
  var b22 = b[ 8 + 2];
  var b23 = b[ 8 + 3];
  var b30 = b[12 + 0];
  var b31 = b[12 + 1];
  var b32 = b[12 + 2];
  var b33 = b[12 + 3];
  dst[ 0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03;
  dst[ 1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03;
  dst[ 2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03;
  dst[ 3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03;
  dst[ 4] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13;
  dst[ 5] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13;
  dst[ 6] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13;
  dst[ 7] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13;
  dst[ 8] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23;
  dst[ 9] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23;
  dst[10] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23;
  dst[11] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23;
  dst[12] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33;
  dst[13] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33;
  dst[14] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33;
  dst[15] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33;
  return dst;
};

/**
 * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4.
 * @param {tdl.fast.Matrix4} a The matrix on the left.
 * @param {tdl.fast.Matrix4} b The matrix on the right.
 * @return {tdl.fast.Matrix4} The matrix product of a and b.
 */
tdl.fast.mulMatrixMatrix4 = null;

/**
 * Gets the jth column of the given matrix m; assumes matrix entries are
 * accessed in [row][column] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} j The index of the desired column.
 * @return {tdl.fast.Vector} The jth column of m as a vector.
 */
tdl.fast.rowMajor.column4 = function(dst, m, j) {
  for (var i = 0; i < 4; ++i) {
    dst[i] = m[i * 4 + j];
  }
  return dst;
};

/**
 * Gets the jth column of the given matrix m; assumes matrix entries are
 * accessed in [column][row] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} j The index of the desired column.
 * @return {tdl.fast.Vector} The jth column of m as a vector.
 */
tdl.fast.columnMajor.column4 = function(dst, m, j) {
  var off = j * 4;
  dst[0] = m[off + 0];
  dst[1] = m[off + 1];
  dst[2] = m[off + 2];
  dst[3] = m[off + 3];
  return dst;
};

/**
 * Gets the jth column of the given matrix m.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} j The index of the desired column.
 * @return {tdl.fast.Vector} The jth column of m as a vector.
 */
tdl.fast.column4 = null;

/**
 * Gets the ith row of the given matrix m; assumes matrix entries are
 * accessed in [row][column] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} i The index of the desired row.
 * @return {tdl.fast.Vector} The ith row of m.
 */
tdl.fast.rowMajor.row4 = function(dst, m, i) {
  var off = i * 4;
  dst[0] = m[off + 0];
  dst[1] = m[off + 1];
  dst[2] = m[off + 2];
  dst[3] = m[off + 3];
  return dst;
};

/**
 * Gets the ith row of the given matrix m; assumes matrix entries are
 * accessed in [column][row] fashion.
 * @param {tdl.fast.Vector} dst vector.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} i The index of the desired row.
 * @return {tdl.fast.Vector} The ith row of m.
 */
tdl.fast.columnMajor.row4 = function(dst, m, i) {
  for (var j = 0; j < 4; ++j) {
    dst[j] = m[j * 4 + i];
  }
  return dst;
};

/**
 * Gets the ith row of the given matrix m.
 * @param {tdl.fast.Matrix} m The matrix.
 * @param {number} i The index of the desired row.
 * @return {tdl.fast.Vector} The ith row of m.
 */
tdl.fast.row4 = null;

/**
 * Creates an n-by-n identity matrix.
 *
 * @param {tdl.fast.Matrix} dst matrix.
 * @return {tdl.fast.Matrix} An n-by-n identity matrix.
 */
tdl.fast.identity4 = function(dst) {
  dst[ 0] = 1;
  dst[ 1] = 0;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = 1;
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = 0;
  dst[ 9] = 0;
  dst[10] = 1;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;
  return dst;
};

/**
 * Takes the transpose of a matrix.
 * @param {tdl.fast.Matrix} dst matrix.
 * @param {tdl.fast.Matrix} m The matrix.
 * @return {tdl.fast.Matrix} The transpose of m.
 */
tdl.fast.transpose4 = function(dst, m) {
  if (dst === m) {
    var t;

    t = m[1];
    m[1] = m[4];
    m[4] = t;

    t = m[2];
    m[2] = m[8];
    m[8] = t;

    t = m[3];
    m[3] = m[12];
    m[12] = t;

    t = m[6];
    m[6] = m[9];
    m[9] = t;

    t = m[7];
    m[7] = m[13];
    m[13] = t;

    t = m[11];
    m[11] = m[14];
    m[14] = t;
    return dst;
  }

  var m00 = m[0 * 4 + 0];
  var m01 = m[0 * 4 + 1];
  var m02 = m[0 * 4 + 2];
  var m03 = m[0 * 4 + 3];
  var m10 = m[1 * 4 + 0];
  var m11 = m[1 * 4 + 1];
  var m12 = m[1 * 4 + 2];
  var m13 = m[1 * 4 + 3];
  var m20 = m[2 * 4 + 0];
  var m21 = m[2 * 4 + 1];
  var m22 = m[2 * 4 + 2];
  var m23 = m[2 * 4 + 3];
  var m30 = m[3 * 4 + 0];
  var m31 = m[3 * 4 + 1];
  var m32 = m[3 * 4 + 2];
  var m33 = m[3 * 4 + 3];

  dst[ 0] = m00;
  dst[ 1] = m10;
  dst[ 2] = m20;
  dst[ 3] = m30;
  dst[ 4] = m01;
  dst[ 5] = m11;
  dst[ 6] = m21;
  dst[ 7] = m31;
  dst[ 8] = m02;
  dst[ 9] = m12;
  dst[10] = m22;
  dst[11] = m32;
  dst[12] = m03;
  dst[13] = m13;
  dst[14] = m23;
  dst[15] = m33;
  return dst;
};

/**
 * Computes the inverse of a 4-by-4 matrix.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @return {tdl.fast.Matrix4} The inverse of m.
 */
tdl.fast.inverse4 = function(dst, m) {
  var m00 = m[0 * 4 + 0];
  var m01 = m[0 * 4 + 1];
  var m02 = m[0 * 4 + 2];
  var m03 = m[0 * 4 + 3];
  var m10 = m[1 * 4 + 0];
  var m11 = m[1 * 4 + 1];
  var m12 = m[1 * 4 + 2];
  var m13 = m[1 * 4 + 3];
  var m20 = m[2 * 4 + 0];
  var m21 = m[2 * 4 + 1];
  var m22 = m[2 * 4 + 2];
  var m23 = m[2 * 4 + 3];
  var m30 = m[3 * 4 + 0];
  var m31 = m[3 * 4 + 1];
  var m32 = m[3 * 4 + 2];
  var m33 = m[3 * 4 + 3];
  var tmp_0  = m22 * m33;
  var tmp_1  = m32 * m23;
  var tmp_2  = m12 * m33;
  var tmp_3  = m32 * m13;
  var tmp_4  = m12 * m23;
  var tmp_5  = m22 * m13;
  var tmp_6  = m02 * m33;
  var tmp_7  = m32 * m03;
  var tmp_8  = m02 * m23;
  var tmp_9  = m22 * m03;
  var tmp_10 = m02 * m13;
  var tmp_11 = m12 * m03;
  var tmp_12 = m20 * m31;
  var tmp_13 = m30 * m21;
  var tmp_14 = m10 * m31;
  var tmp_15 = m30 * m11;
  var tmp_16 = m10 * m21;
  var tmp_17 = m20 * m11;
  var tmp_18 = m00 * m31;
  var tmp_19 = m30 * m01;
  var tmp_20 = m00 * m21;
  var tmp_21 = m20 * m01;
  var tmp_22 = m00 * m11;
  var tmp_23 = m10 * m01;

  var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) -
      (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
  var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) -
      (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
  var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) -
      (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
  var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) -
      (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);

  var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);

  dst[ 0] = d * t0;
  dst[ 1] = d * t1;
  dst[ 2] = d * t2;
  dst[ 3] = d * t3;
  dst[ 4] = d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) -
          (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30));
  dst[ 5] = d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) -
          (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30));
  dst[ 6] = d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) -
          (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30));
  dst[ 7] = d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) -
          (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20));
  dst[ 8] = d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) -
          (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33));
  dst[ 9] = d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) -
          (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33));
  dst[10] = d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) -
          (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33));
  dst[11] = d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) -
          (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23));
  dst[12] = d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) -
          (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22));
  dst[13] = d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) -
          (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02));
  dst[14] = d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) -
          (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12));
  dst[15] = d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) -
          (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02));
  return dst;
};

/**
 * Computes the inverse of a 4-by-4 matrix.
 * Note: It is faster to call this than tdl.fast.inverse.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @return {tdl.fast.Matrix4} The inverse of m.
 */
tdl.fast.matrix4.inverse = function(dst,m) {
  return tdl.fast.inverse4(dst,m);
};

/**
 * Multiplies two 4-by-4 matrices; assumes that the given matrices are 4-by-4.
 * Note: It is faster to call this than tdl.fast.mul.
 * @param {tdl.fast.Matrix4} a The matrix on the left.
 * @param {tdl.fast.Matrix4} b The matrix on the right.
 * @return {tdl.fast.Matrix4} The matrix product of a and b.
 */
tdl.fast.matrix4.mul = function(dst, a, b) {
  return tdl.fast.mulMatrixMatrix4(dst, a, b);
};

/**
 * Copies a Matrix4.
 * Note: It is faster to call this than tdl.fast.copy.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @return {tdl.fast.Matrix4} A copy of m.
 */
tdl.fast.matrix4.copy = function(dst, m) {
  return tdl.fast.copyMatrix(dst, m);
};

/**
 * Sets the translation component of a 4-by-4 matrix to the given
 * vector.
 * @param {tdl.fast.Matrix4} a The matrix.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} v The vector.
 * @return {tdl.fast.Matrix4} a once modified.
 */
tdl.fast.matrix4.setTranslation = function(a, v) {
  a[12] = v[0];
  a[13] = v[1];
  a[14] = v[2];
  a[15] = 1;
  return a;
};

/**
 * Returns the translation component of a 4-by-4 matrix as a vector with 3
 * entries.
 * @return {tdl.fast.Vector3} dst vector..
 * @param {tdl.fast.Matrix4} m The matrix.
 * @return {tdl.fast.Vector3} The translation component of m.
 */
tdl.fast.matrix4.getTranslation = function(dst, m) {
  dst[0] = m[12];
  dst[1] = m[13];
  dst[2] = m[14];
  return dst;
};

/**
 * Creates a 4-by-4 identity matrix.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @return {tdl.fast.Matrix4} The 4-by-4 identity.
 */
tdl.fast.matrix4.identity = function(dst) {
  return tdl.fast.identity4(dst);
};

tdl.fast.matrix4.getAxis = function(dst, m, axis) {
  var off = axis * 4;
  dst[0] = m[off + 0];
  dst[1] = m[off + 1];
  dst[2] = m[off + 2];
  return dst;
};

/**
 * Computes a 4-by-4 perspective transformation matrix given the angular height
 * of the frustum, the aspect ratio, and the near and far clipping planes.  The
 * arguments define a frustum extending in the negative z direction.  The given
 * angle is the vertical angle of the frustum, and the horizontal angle is
 * determined to produce the given aspect ratio.  The arguments near and far are
 * the distances to the near and far clipping planes.  Note that near and far
 * are not z coordinates, but rather they are distances along the negative
 * z-axis.  The matrix generated sends the viewing frustum to the unit box.
 * We assume a unit box extending from -1 to 1 in the x and y dimensions and
 * from 0 to 1 in the z dimension.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @param {number} angle The camera angle from top to bottom (in radians).
 * @param {number} aspect The aspect ratio width / height.
 * @param {number} zNear The depth (negative z coordinate)
 *     of the near clipping plane.
 * @param {number} zFar The depth (negative z coordinate)
 *     of the far clipping plane.
 * @return {tdl.fast.Matrix4} The perspective matrix.
 */
tdl.fast.matrix4.perspective = function(dst, angle, aspect, zNear, zFar) {
  var f = Math.tan(Math.PI * 0.5 - 0.5 * angle);
  var rangeInv = 1.0 / (zNear - zFar);

  dst[0]  = f / aspect;
  dst[1]  = 0;
  dst[2]  = 0;
  dst[3]  = 0;

  dst[4]  = 0;
  dst[5]  = f;
  dst[6]  = 0;
  dst[7]  = 0;

  dst[8]  = 0;
  dst[9]  = 0;
  dst[10] = (zNear + zFar) * rangeInv;
  dst[11] = -1;

  dst[12] = 0;
  dst[13] = 0;
  dst[14] = zNear * zFar * rangeInv * 2;
  dst[15] = 0;

  return dst;
};


/**
 * Computes a 4-by-4 othogonal transformation matrix given the left, right,
 * bottom, and top dimensions of the near clipping plane as well as the
 * near and far clipping plane distances.
 * @param {tdl.fast.Matrix4} dst Output matrix.
 * @param {number} left Left side of the near clipping plane viewport.
 * @param {number} right Right side of the near clipping plane viewport.
 * @param {number} top Top of the near clipping plane viewport.
 * @param {number} bottom Bottom of the near clipping plane viewport.
 * @param {number} near The depth (negative z coordinate)
 *     of the near clipping plane.
 * @param {number} far The depth (negative z coordinate)
 *     of the far clipping plane.
 * @return {tdl.fast.Matrix4} The perspective matrix.
 */
tdl.fast.matrix4.ortho = function(dst, left, right, bottom, top, near, far) {


  dst[0]  = 2 / (right - left);
  dst[1]  = 0;
  dst[2]  = 0;
  dst[3]  = 0;

  dst[4]  = 0;
  dst[5]  = 2 / (top - bottom);
  dst[6]  = 0;
  dst[7]  = 0;

  dst[8]  = 0;
  dst[9]  = 0;
  dst[10] = -1 / (far - near);
  dst[11] = 0;

  dst[12] = (right + left) / (left - right);
  dst[13] = (top + bottom) / (bottom - top);
  dst[14] = -near / (near - far);
  dst[15] = 1;

  return dst;
}

/**
 * Computes a 4-by-4 perspective transformation matrix given the left, right,
 * top, bottom, near and far clipping planes. The arguments define a frustum
 * extending in the negative z direction. The arguments near and far are the
 * distances to the near and far clipping planes. Note that near and far are not
 * z coordinates, but rather they are distances along the negative z-axis. The
 * matrix generated sends the viewing frustum to the unit box. We assume a unit
 * box extending from -1 to 1 in the x and y dimensions and from 0 to 1 in the z
 * dimension.
 * @param {number} left The x coordinate of the left plane of the box.
 * @param {number} right The x coordinate of the right plane of the box.
 * @param {number} bottom The y coordinate of the bottom plane of the box.
 * @param {number} top The y coordinate of the right plane of the box.
 * @param {number} near The negative z coordinate of the near plane of the box.
 * @param {number} far The negative z coordinate of the far plane of the box.
 * @return {tdl.fast.Matrix4} The perspective projection matrix.
 */
tdl.fast.matrix4.frustum = function(dst, left, right, bottom, top, near, far) {
  var dx = (right - left);
  var dy = (top - bottom);
  var dz = (near - far);

  dst[ 0] = 2 * near / dx;
  dst[ 1] = 0;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = 2 * near / dy;
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = (left + right) / dx;
  dst[ 9] = (top + bottom) / dy;
  dst[10] = far / dz;
  dst[11] = -1;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = near * far / dz;
  dst[15] = 0;

  return dst;
};

/**
 * Computes a 4-by-4 look-at transformation.  The transformation generated is
 * an orthogonal rotation matrix with translation component.  The translation
 * component sends the eye to the origin.  The rotation component sends the
 * vector pointing from the eye to the target to a vector pointing in the
 * negative z direction, and also sends the up vector into the upper half of
 * the yz plane.
 * @param {tdl.fast.Matrix4} dst matrix.
 * @param {tdl.fast.Vector3} eye The
 *     position of the eye.
 * @param {tdl.fast.Vector3} target The
 *     position meant to be viewed.
 * @param {tdl.fast.Vector3} up A vector
 *     pointing up.
 * @return {tdl.fast.Matrix4} The look-at matrix.
 */
tdl.fast.matrix4.lookAt = function(dst, eye, target, up) {
  var t0 = tdl.fast.temp0v3_;
  var t1 = tdl.fast.temp1v3_;
  var t2 = tdl.fast.temp2v3_;

  var vz = tdl.fast.normalize(t0, tdl.fast.subVector(t0, eye, target));
  var vx = tdl.fast.normalize(t1, tdl.fast.cross(t1, up, vz));
  var vy = tdl.fast.cross(t2, vz, vx);

  dst[ 0] = vx[0];
  dst[ 1] = vy[0];
  dst[ 2] = vz[0];
  dst[ 3] = 0;
  dst[ 4] = vx[1];
  dst[ 5] = vy[1];
  dst[ 6] = vz[1];
  dst[ 7] = 0;
  dst[ 8] = vx[2];
  dst[ 9] = vy[2];
  dst[10] = vz[2];
  dst[11] = 0;
  dst[12] = -tdl.fast.dot(vx, eye);
  dst[13] = -tdl.fast.dot(vy, eye);
  dst[14] = -tdl.fast.dot(vz, eye);
  dst[15] = 1;

  return dst;
};

/**
 * Computes a 4-by-4 camera look-at transformation. This is the
 * inverse of lookAt The transformation generated is an
 * orthogonal rotation matrix with translation component.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} eye The position
 *     of the eye.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} target The
 *     position meant to be viewed.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} up A vector
 *     pointing up.
 * @return {tdl.fast.Matrix4} The camera look-at matrix.
 */
tdl.fast.matrix4.cameraLookAt = function(dst, eye, target, up) {
  var t0 = tdl.fast.temp0v3_;
  var t1 = tdl.fast.temp1v3_;
  var t2 = tdl.fast.temp2v3_;

  var vz = tdl.fast.normalize(t0, tdl.fast.subVector(t0, eye, target));
  var vx = tdl.fast.normalize(t1, tdl.fast.cross(t1, up, vz));
  var vy = tdl.fast.cross(t2, vz, vx);

  dst[ 0] = vx[0];
  dst[ 1] = vx[1];
  dst[ 2] = vx[2];
  dst[ 3] = 0;
  dst[ 4] = vy[0];
  dst[ 5] = vy[1];
  dst[ 6] = vy[2];
  dst[ 7] = 0;
  dst[ 8] = vz[0];
  dst[ 9] = vz[1];
  dst[10] = vz[2];
  dst[11] = 0;
  dst[12] = eye[0];
  dst[13] = eye[1];
  dst[14] = eye[2];
  dst[15] = 1;

  return dst;
};

/**
 * Creates a 4-by-4 matrix which translates by the given vector v.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} v The vector by
 *     which to translate.
 * @return {tdl.fast.Matrix4} The translation matrix.
 */
tdl.fast.matrix4.translation = function(dst, v) {
  dst[ 0] = 1;
  dst[ 1] = 0;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = 1;
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = 0;
  dst[ 9] = 0;
  dst[10] = 1;
  dst[11] = 0;
  dst[12] = v[0];
  dst[13] = v[1];
  dst[14] = v[2];
  dst[15] = 1;
  return dst;
};

/**
 * Modifies the given 4-by-4 matrix by translation by the given vector v.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} v The vector by
 *     which to translate.
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.translate = function(m, v) {
  var v0 = v[0];
  var v1 = v[1];
  var v2 = v[2];
  var m00 = m[0];
  var m01 = m[1];
  var m02 = m[2];
  var m03 = m[3];
  var m10 = m[1 * 4 + 0];
  var m11 = m[1 * 4 + 1];
  var m12 = m[1 * 4 + 2];
  var m13 = m[1 * 4 + 3];
  var m20 = m[2 * 4 + 0];
  var m21 = m[2 * 4 + 1];
  var m22 = m[2 * 4 + 2];
  var m23 = m[2 * 4 + 3];
  var m30 = m[3 * 4 + 0];
  var m31 = m[3 * 4 + 1];
  var m32 = m[3 * 4 + 2];
  var m33 = m[3 * 4 + 3];

  m[12] = m00 * v0 + m10 * v1 + m20 * v2 + m30;
  m[13] = m01 * v0 + m11 * v1 + m21 * v2 + m31;
  m[14] = m02 * v0 + m12 * v1 + m22 * v2 + m32;
  m[15] = m03 * v0 + m13 * v1 + m23 * v2 + m33;

  return m;
};

tdl.fast.matrix4.transpose = tdl.fast.transpose4;

/**
 * Creates a 4-by-4 matrix which rotates around the x-axis by the given angle.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} The rotation matrix.
 */
tdl.fast.matrix4.rotationX = function(dst, angle) {
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  dst[ 0] = 1;
  dst[ 1] = 0;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = c;
  dst[ 6] = s;
  dst[ 7] = 0;
  dst[ 8] = 0;
  dst[ 9] = -s;
  dst[10] = c;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;

  return dst;
};

/**
 * Modifies the given 4-by-4 matrix by a rotation around the x-axis by the given
 * angle.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.rotateX = function(m, angle) {
  var m10 = m[4];
  var m11 = m[5];
  var m12 = m[6];
  var m13 = m[7];
  var m20 = m[8];
  var m21 = m[9];
  var m22 = m[10];
  var m23 = m[11];
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  m[4]  = c * m10 + s * m20;
  m[5]  = c * m11 + s * m21;
  m[6]  = c * m12 + s * m22;
  m[7]  = c * m13 + s * m23;
  m[8]  = c * m20 - s * m10;
  m[9]  = c * m21 - s * m11;
  m[10] = c * m22 - s * m12;
  m[11] = c * m23 - s * m13;

  return m;
};

/**
 * Creates a 4-by-4 matrix which rotates around the y-axis by the given angle.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} The rotation matrix.
 */
tdl.fast.matrix4.rotationY = function(dst, angle) {
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  dst[ 0] = c;
  dst[ 1] = 0;
  dst[ 2] = -s;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = 1;
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = s;
  dst[ 9] = 0;
  dst[10] = c;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;

  return dst;
};

/**
 * Modifies the given 4-by-4 matrix by a rotation around the y-axis by the given
 * angle.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.rotateY = function(m, angle) {
  var m00 = m[0*4+0];
  var m01 = m[0*4+1];
  var m02 = m[0*4+2];
  var m03 = m[0*4+3];
  var m20 = m[2*4+0];
  var m21 = m[2*4+1];
  var m22 = m[2*4+2];
  var m23 = m[2*4+3];
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  m[ 0] = c * m00 - s * m20;
  m[ 1] = c * m01 - s * m21;
  m[ 2] = c * m02 - s * m22;
  m[ 3] = c * m03 - s * m23;
  m[ 8] = c * m20 + s * m00;
  m[ 9] = c * m21 + s * m01;
  m[10] = c * m22 + s * m02;
  m[11] = c * m23 + s * m03;

  return m;
};

/**
 * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} The rotation matrix.
 */
tdl.fast.matrix4.rotationZ = function(dst, angle) {
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  dst[ 0] = c;
  dst[ 1] = s;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = -s;
  dst[ 5] = c;
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = 0;
  dst[ 9] = 0;
  dst[10] = 1;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;

  return dst;
};

/**
 * Modifies the given 4-by-4 matrix by a rotation around the z-axis by the given
 * angle.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.rotateZ = function(m, angle) {
  var m00 = m[0*4+0];
  var m01 = m[0*4+1];
  var m02 = m[0*4+2];
  var m03 = m[0*4+3];
  var m10 = m[1*4+0];
  var m11 = m[1*4+1];
  var m12 = m[1*4+2];
  var m13 = m[1*4+3];
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  m[ 0] = c * m00 + s * m10;
  m[ 1] = c * m01 + s * m11;
  m[ 2] = c * m02 + s * m12;
  m[ 3] = c * m03 + s * m13;
  m[ 4] = c * m10 - s * m00;
  m[ 5] = c * m11 - s * m01;
  m[ 6] = c * m12 - s * m02;
  m[ 7] = c * m13 - s * m03;

  return m;
};

/**
 * Creates a 4-by-4 matrix which rotates around the given axis by the given
 * angle.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} axis The axis
 *     about which to rotate.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} A matrix which rotates angle radians
 *     around the axis.
 */
tdl.fast.matrix4.axisRotation = function(dst, axis, angle) {
  var x = axis[0];
  var y = axis[1];
  var z = axis[2];
  var n = Math.sqrt(x * x + y * y + z * z);
  x /= n;
  y /= n;
  z /= n;
  var xx = x * x;
  var yy = y * y;
  var zz = z * z;
  var c = Math.cos(angle);
  var s = Math.sin(angle);
  var oneMinusCosine = 1 - c;

  dst[ 0] = xx + (1 - xx) * c;
  dst[ 1] = x * y * oneMinusCosine + z * s;
  dst[ 2] = x * z * oneMinusCosine - y * s;
  dst[ 3] = 0;
  dst[ 4] = x * y * oneMinusCosine - z * s;
  dst[ 5] = yy + (1 - yy) * c;
  dst[ 6] = y * z * oneMinusCosine + x * s;
  dst[ 7] = 0;
  dst[ 8] = x * z * oneMinusCosine + y * s;
  dst[ 9] = y * z * oneMinusCosine - x * s;
  dst[10] = zz + (1 - zz) * c;
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;

  return dst;
};

/**
 * Modifies the given 4-by-4 matrix by rotation around the given axis by the
 * given angle.
 * @param {tdl.fast.Matrix4} m The matrix.
 * @param {(tdl.fast.Vector3|tdl.fast.Vector4)} axis The axis
 *     about which to rotate.
 * @param {number} angle The angle by which to rotate (in radians).
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.axisRotate = function(m, axis, angle) {
  var x = axis[0];
  var y = axis[1];
  var z = axis[2];
  var n = Math.sqrt(x * x + y * y + z * z);
  x /= n;
  y /= n;
  z /= n;
  var xx = x * x;
  var yy = y * y;
  var zz = z * z;
  var c = Math.cos(angle);
  var s = Math.sin(angle);
  var oneMinusCosine = 1 - c;

  var r00 = xx + (1 - xx) * c;
  var r01 = x * y * oneMinusCosine + z * s;
  var r02 = x * z * oneMinusCosine - y * s;
  var r10 = x * y * oneMinusCosine - z * s;
  var r11 = yy + (1 - yy) * c;
  var r12 = y * z * oneMinusCosine + x * s;
  var r20 = x * z * oneMinusCosine + y * s;
  var r21 = y * z * oneMinusCosine - x * s;
  var r22 = zz + (1 - zz) * c;

  var m00 = m[0];
  var m01 = m[1];
  var m02 = m[2];
  var m03 = m[3];
  var m10 = m[4];
  var m11 = m[5];
  var m12 = m[6];
  var m13 = m[7];
  var m20 = m[8];
  var m21 = m[9];
  var m22 = m[10];
  var m23 = m[11];
  var m30 = m[12];
  var m31 = m[13];
  var m32 = m[14];
  var m33 = m[15];

  m[ 0] = r00 * m00 + r01 * m10 + r02 * m20;
  m[ 1] = r00 * m01 + r01 * m11 + r02 * m21;
  m[ 2] = r00 * m02 + r01 * m12 + r02 * m22;
  m[ 3] = r00 * m03 + r01 * m13 + r02 * m23;
  m[ 4] = r10 * m00 + r11 * m10 + r12 * m20;
  m[ 5] = r10 * m01 + r11 * m11 + r12 * m21;
  m[ 6] = r10 * m02 + r11 * m12 + r12 * m22;
  m[ 7] = r10 * m03 + r11 * m13 + r12 * m23;
  m[ 8] = r20 * m00 + r21 * m10 + r22 * m20;
  m[ 9] = r20 * m01 + r21 * m11 + r22 * m21;
  m[10] = r20 * m02 + r21 * m12 + r22 * m22;
  m[11] = r20 * m03 + r21 * m13 + r22 * m23;

  return m;
};

/**
 * Creates a 4-by-4 matrix which scales in each dimension by an amount given by
 * the corresponding entry in the given vector; assumes the vector has three
 * entries.
 * @param {tdl.fast.Vector3} v A vector of
 *     three entries specifying the factor by which to scale in each dimension.
 * @return {tdl.fast.Matrix4} The scaling matrix.
 */
tdl.fast.matrix4.scaling = function(dst, v) {
  dst[ 0] = v[0];
  dst[ 1] = 0;
  dst[ 2] = 0;
  dst[ 3] = 0;
  dst[ 4] = 0;
  dst[ 5] = v[1];
  dst[ 6] = 0;
  dst[ 7] = 0;
  dst[ 8] = 0;
  dst[ 9] = 0;
  dst[10] = v[2];
  dst[11] = 0;
  dst[12] = 0;
  dst[13] = 0;
  dst[14] = 0;
  dst[15] = 1;
  return dst;
};

/**
 * Modifies the given 4-by-4 matrix, scaling in each dimension by an amount
 * given by the corresponding entry in the given vector; assumes the vector has
 * three entries.
 * @param {tdl.fast.Matrix4} m The matrix to be modified.
 * @param {tdl.fast.Vector3} v A vector of three entries specifying the
 *     factor by which to scale in each dimension.
 * @return {tdl.fast.Matrix4} m once modified.
 */
tdl.fast.matrix4.scale = function(m, v) {
  var v0 = v[0];
  var v1 = v[1];
  var v2 = v[2];

  m[0] = v0 * m[0*4+0];
  m[1] = v0 * m[0*4+1];
  m[2] = v0 * m[0*4+2];
  m[3] = v0 * m[0*4+3];
  m[4] = v1 * m[1*4+0];
  m[5] = v1 * m[1*4+1];
  m[6] = v1 * m[1*4+2];
  m[7] = v1 * m[1*4+3];
  m[8] = v2 * m[2*4+0];
  m[9] = v2 * m[2*4+1];
  m[10] = v2 * m[2*4+2];
  m[11] = v2 * m[2*4+3];

  return m;
};

/**
 * Sets each function in the namespace tdl.fast to the row major
 * version in tdl.fast.rowMajor (provided such a function exists in
 * tdl.fast.rowMajor).  Call this function to establish the row major
 * convention.
 */
tdl.fast.installRowMajorFunctions = function() {
  for (var f in tdl.fast.rowMajor) {
    tdl.fast[f] = tdl.fast.rowMajor[f];
  }
};

/**
 * Sets each function in the namespace tdl.fast to the column major
 * version in tdl.fast.columnMajor (provided such a function exists in
 * tdl.fast.columnMajor).  Call this function to establish the column
 * major convention.
 */
tdl.fast.installColumnMajorFunctions = function() {
  for (var f in tdl.fast.columnMajor) {
    tdl.fast[f] = tdl.fast.columnMajor[f];
  }
};

// By default, install the row-major functions.
tdl.fast.installRowMajorFunctions();

return tdl.fast;
});


================================================
FILE: tdl/fps.js
================================================
/*
 * Copyright 2009, 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 objects to measure frames
 *               per second.
 */
define(['./base-rs'], function(BaseRS) {

tdl.provide('tdl.fps');
/**
 * A module for fps.
 * @namespace
 */
tdl.fps = tdl.fps || {};

/**
 * Number of frames to average over for computing FPS.
 * @type {number}
 */
tdl.fps.NUM_FRAMES_TO_AVERAGE = 16;

/**
 * Measures frames per second.
 * @constructor
 */
tdl.fps.FPSTimer = function() {
  // total time spent for last N frames.
  this.totalTime_ = tdl.fps.NUM_FRAMES_TO_AVERAGE;

  // elapsed time for last N frames.
  this.timeTable_ = [];

  // where to record next elapsed time.
  this.timeTableCursor_ = 0;

  // Initialize the FPS elapsed time history table.
  for (var tt = 0; tt < tdl.fps.NUM_FRAMES_TO_AVERAGE; ++tt) {
    this.timeTable_[tt] = 1.0;
  }

  /**
   * The instantaneous FPS
   * @type {number}
   */
  this.instantaneousFPS = 0;
  /**
   * The average FPS
   * @type {number}
   */
  this.averageFPS = 0;
};

/**
 * Updates the fps measurement. You must call this in your
 * render loop.
 *
 * @param {number} elapsedTime The elasped time in seconds
 *     since the last frame.
 */
tdl.fps.FPSTimer.prototype.update = function(elapsedTime) {
  // Keep the total time and total active time for the last N frames.
  this.totalTime_ += elapsedTime - this.timeTable_[this.timeTableCursor_];

  // Save off the elapsed time for this frame so we can subtract it later.
  this.timeTable_[this.timeTableCursor_] = elapsedTime;

  // Wrap the place to store the next time sample.
  ++this.timeTableCursor_;
  if (this.timeTableCursor_ == tdl.fps.NUM_FRAMES_TO_AVERAGE) {
    this.timeTableCursor_ = 0;
  }

  this.instantaneousFPS = Math.floor(1.0 / elapsedTime + 0.5);
  this.averageFPS = Math.floor(
      (1.0 / (this.totalTime_ / tdl.fps.NUM_FRAMES_TO_AVERAGE)) + 0.5);
};

return tdl.fps;
});



================================================
FILE: tdl/framebuffers.js
================================================
/*
 * Copyright 2009, 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 objects to manage
 *               framebuffers.
 */
define(['./base-rs', './textures'], function(BaseRS, Textures) {

tdl.provide('tdl.framebuffers');
/**
 * A module for textures.
 * @namespace
 */
tdl.framebuffers = tdl.framebuffers || {};

/**
 * Creates a framebuffer
 * @param {number} width width of framebuffer.
 * @param {number} height height of framebuffer.
 * @param {boolean?} opt_depth true = make a depth attachment
 * @return {tdl.Framebuffer} the created framebuffer.
 */
tdl.framebuffers.createFramebuffer = function(width, height, opt_depth) {
  return new tdl.framebuffers.Framebuffer(width, height, opt_depth);
};

/**
 * Creates a cubemap framebuffer
 * @param {number} size size of edge of cube.
 * @param {boolean?} opt_depth true = make a depth attachment
 * @return {tdl.CubeFramebuffer} the created framebuffer.
 */
tdl.framebuffers.createCubeFramebuffer = function(size, opt_depth) {
  return new tdl.framebuffers.CubeFramebuffer(size, opt_depth);
};

/**
 * A class to represent the backbuffer (the canvas)
 * @constructor
 */
tdl.framebuffers.BackBuffer = function() {
  this.depth = true;
  this.buffer = null;
};

/**
 * Binds the backbuffer as the current render target.
 */
tdl.framebuffers.BackBuffer.prototype.bind = function() {
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, this.width, this.height);
};

if (Object.prototype.__defineSetter__) {
tdl.framebuffers.BackBuffer.prototype.__defineGetter__(
    'width',
    function () {
      return gl.drawingBufferWidth || gl.canvas.width;
    }
);

tdl.framebuffers.BackBuffer.prototype.__defineGetter__(
    'height',
    function () {
      return gl.drawingBufferHeight || gl.canvas.height;
    }
);
}

/**
 * Get a FrameBuffer for the backbuffer.
 * Use this where you need to pass in a framebuffer, but you really
 * mean the backbuffer, so that binding it works as expected.
 * @return {tdl.BackBuffer} the created BackBuffer.
 */
tdl.framebuffers.getBackBuffer = function() {
  return new tdl.framebuffers.BackBuffer();
};

/**
 * Represnets a WebGLFramebuffer
 * @constructor
 * @param {number} width width of framebuffer.
 * @param {number} height height of framebuffer.
 * @param {boolean?} opt_depth true = create a depth attachment
 */
tdl.framebuffers.Framebuffer = function(width, height, opt_depth) {
  this.width = width;
  this.height = height;
  this.depth = opt_depth;
  var tex = new tdl.textures.SolidTexture([0,0,0,0]);
  this.initializeTexture(tex);

  var fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  gl.framebufferTexture2D(
      gl.FRAMEBUFFER,
      gl.COLOR_ATTACHMENT0,
      gl.TEXTURE_2D,
      tex.texture,
      0);

  if (this.depth) {
    if (gl.tdl.depthTexture) {
      var dt = new tdl.textures.DepthTexture(this.width, this.height);
      gl.framebufferTexture2D(
          gl.FRAMEBUFFER,
          gl.DEPTH_ATTACHMENT,
          gl.TEXTURE_2D,
          dt.texture,
          0);
      this.depthTexture = dt;
    } else {
      var db = gl.createRenderbuffer();
      gl.bindRenderbuffer(gl.RENDERBUFFER, db);
      gl.renderbufferStorage(
          gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.width, this.height);
      gl.framebufferRenderbuffer(
          gl.FRAMEBUFFER,
          gl.DEPTH_ATTACHMENT,
          gl.RENDERBUFFER,
          db);
      gl.bindRenderbuffer(gl.RENDERBUFFER, null);
      this.depthRenderbuffer = db;
    }
  }

  var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  if (status != gl.FRAMEBUFFER_COMPLETE && !gl.isContextLost()) {
    throw("gl.checkFramebufferStatus() returned " +
          tdl.webgl.glEnumToString(status));
  }
  this.framebuffer = fb;
  this.texture = tex;
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};

/**
 * Bind this framebuffer as the current render target.
 */
tdl.framebuffers.Framebuffer.prototype.bind = function() {
  gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
  gl.viewport(0, 0, this.width, this.height);
};

/**
 * Unbinds this framebuffer as the current render target
 */
tdl.framebuffers.Framebuffer.prototype.unbind = function() {
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(
      0, 0,
      gl.drawingBufferWidth || gl.canvas.width,
      gl.drawingBufferHeight || gl.canvas.height);
};

tdl.framebuffers.Framebuffer.prototype.initializeTexture = function(tex) {
  gl.bindTexture(gl.TEXTURE_2D, tex.texture);
  tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texImage2D(gl.TEXTURE_2D,
                0,                 // level
                gl.RGBA,           // internalFormat
                this.width,        // width
                this.height,       // height
                0,                 // border
                gl.RGBA,           // format
                gl.UNSIGNED_BYTE,  // type
                null);             // data
};

/**
 * Represnents a Cube Map framebuffer
 * @constructor
 * @param {number} size size of edge of cube.
 * @param {boolean?} opt_depth true = make a depth attachment
 */
tdl.framebuffers.CubeFramebuffer = function(size, opt_depth) {
  this.size = size;
  this.depth = opt_depth;
  var tex = new tdl.textures.CubeMap(this.size);
  gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex.texture);
  tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  for (var ff = 0; ff < 6; ++ff) {
    gl.texImage2D(tdl.textures.CubeMap.faceTargets[ff],
                  0,                 // level
                  gl.RGBA,           // internalFormat
                  this.size,         // width
                  this.size,         // height
                  0,                 // border
                  gl.RGBA,           // format
                  gl.UNSIGNED_BYTE,  // type
                  null);             // data
  }
  if (this.depth) {
    var db = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, db);
    gl.renderbufferStorage(
        gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.size, this.size);
  }
  this.framebuffers = [];
  for (var ff = 0; ff < 6; ++ff) {
    var fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferTexture2D(
        gl.FRAMEBUFFER,
        gl.COLOR_ATTACHMENT0,
        tdl.textures.CubeMap.faceTargets[ff],
        tex.texture,
        0);
    if (this.depth) {
      gl.framebufferRenderbuffer(
          gl.FRAMEBUFFER,
          gl.DEPTH_ATTACHMENT,
          gl.RENDERBUFFER,
          db);
    }
    var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
    if (status != gl.FRAMEBUFFER_COMPLETE) {
      throw("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status));
    }
    this.framebuffers.push(fb);
  }
  gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  this.texture = tex;
};

/**
 * Binds a face as the current render target.
 * @param {number} face The face to use as the render target.
 */
tdl.framebuffers.CubeFramebuffer.prototype.bind = function(face) {
  gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[face]);
  gl.viewport(0, 0, this.size, this.size);
};

/**
 * Unbinds this framebuffer as the current render target.
 */
tdl.framebuffers.CubeFramebuffer.prototype.unbind = function() {
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(
      0, 0,
      gl.drawingBufferWidth || gl.canvas.width,
      gl.drawingBufferHeight || gl.canvas.height);
};

/**
 * A framebuffer with a Float32RGBA texture.
 * @param {number} width width of framebuffer.
 * @param {number} height height of framebuffer.
 * @param {boolean?} opt_depth true = create a depth attachment
 */
tdl.framebuffers.Float32Framebuffer = function(width, height, opt_depth) {
  if (!gl.getExtension("OES_texture_float")) {
    throw("Requires OES_texture_float extension");
  }
  tdl.framebuffers.Framebuffer.call(this, width, height, opt_depth);
};

tdl.base.inherit(tdl.framebuffers.Float32Framebuffer, tdl.framebuffers.Framebuffer);

tdl.framebuffers.Float32Framebuffer.prototype.initializeTexture = function(tex) {
  gl.bindTexture(gl.TEXTURE_2D, tex.texture);
  tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texImage2D(gl.TEXTURE_2D,
                0,                 // level
                gl.RGBA,           // internalFormat
                this.width,        // width
                this.height,       // height
                0,                 // border
                gl.RGBA,           // format
                gl.FLOAT,          // type
                null);             // data
};

return tdl.framebuffers;
});


================================================
FILE: tdl/fullscreen.js
================================================
/*
 * Copyright 2009, 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 misc functions to deal with
 *               fullscreen.
 */
define(['./base-rs'], function(BaseRS) {

/**
 * A module for misc.
 * @namespace
 */
tdl.provide('tdl.fullscreen');
tdl.fullscreen = tdl.fullscreen || {};

tdl.fullscreen.requestFullScreen = function(element) {
  if (element.requestFullscreen) {
    element.requestFullscreen();
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen();
  } else if (element.webkitRequestFullScreen) {
    element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen();
  }
};

tdl.fullscreen.cancelFullScreen = function(element) {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen();
  } else if (document.webkitCancelFullScreen) {
    document.webkitCancelFullScreen();
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
  }
};

tdl.fullscreen.onFullScreenChange = function(element, callback) {
  var isFullScreen = function() {
    return document.fullscreenElement || document.mozFullScreenElement ||
           document.webkitFullscreenElement || document.msFullscreenElement ||
           document.mozFullScreen || document.webkitIsFullScreen;
  };
  document.addEventListener('fullscreenchange', function(event) {
      callback(isFullScreen());
    });
  element.addEventListener('webkitfullscreenchange', function(event) {
      callback(isFullScreen());
    });
  document.addEventListener('mozfullscreenchange', function(event) {
      callback(isFullScreen());
    });
};

return tdl.fullscreen;
});


================================================
FILE: tdl/io.js
================================================
/*
 * Copyright 2009, 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 various functions and class for io.
 */
define(['./base-rs'], function(BaseRS) {

tdl.provide('tdl.io');
/**
 * A Module with various io functions and classes.
 * @namespace
 */
tdl.io = tdl.io || {};

/**
 * Creates a LoadInfo object.
 * @param {XMLHttpRequest} opt_request
 *     The request to watch.
 * @return {!tdl.io.LoadInfo} The new LoadInfo.
 * @see tdl.io.LoadInfo
 */
tdl.io.createLoadInfo = function(opt_request) {
  return new tdl.io.LoadInfo(opt_request);
};

/**
 * A class to help with progress reporting for most loading utilities.
 *
 * @example
 * var g_loadInfo = null;
 * g_id = window.setInterval(statusUpdate, 500);
 * g_loadInfo = tdl.scene.loadScene('http://google.com/somescene.js',
 *                                  callback);
 *
 * function callback(exception) {
 *   g_loadInfo = null;
 *   window.clearInterval(g_id);
 *   if (!exception) {
 *     // do something with scene just loaded
 *   }
 * }
 *
 * function statusUpdate() {
 *   if (g_loadInfo) {
 *     var progress = g_loadInfo.getKnownProgressInfoSoFar();
 *     document.getElementById('loadstatus').innerHTML = progress.percent;
 *   }
 * }
 *
 * @constructor
 * @param {XMLHttpRequest?} opt_request
 *     The request to watch.
 * @see tdl.loader.Loader
 */
tdl.io.LoadInfo = function(opt_request) {
  this.request_ = opt_request;
  this.streamLength_ = 0;  // because the request may have been freed.
  this.children_ = [];
};

/**
 * Adds another LoadInfo as a child of this LoadInfo so they can be
 * managed as a group.
 * @param {!tdl.io.LoadInfo} loadInfo The child LoadInfo.
 */
tdl.io.LoadInfo.prototype.addChild = function(loadInfo) {
  this.children_.push(loadInfo);
};

/**
 * Marks this LoadInfo as finished.
 */
tdl.io.LoadInfo.prototype.finish = function() {
  if (this.request_) {
    if (this.hasStatus_) {
      this.streamLength_ = this.request_.streamLength;
    }
    this.request_ = null;
  }
};

/**
 * Gets the total bytes that will be streamed known so far.
 *
 * If you are only streaming 1 file then this will be the info for that file but
 * if you have queued up many files using a `tdl.loader.Loader`
 * only a couple of files are streamed at a time meaning that
 * the size is not known for files that have yet started to
 * download.
 *
 * If you are downloading many files for your application and you want to
 * provide a progress status you have about 4 options
 *
 * 1.  Use `LoadInfo.getTotalBytesDownloaded()` /
 *     `LoadInfo.getTotalKnownBytesToStreamSoFar()` and just be
 *     aware the bar will grown and then shrink as new files
 *     start to download and their lengths become known.
 *
 * 2.  Use `LoadInfo.getTotalRequestsDownloaded()` /
 *     `LoadInfo.getTotalKnownRequestsToStreamSoFar()` and be
 *     aware the granularity is not all that great since it only
 *     reports fully downloaded files. If you are downloading a
 *     bunch of small files this might be ok.
 *
 * 3.  Put all your files in one archive. Then there will be
 *     only one file and method 1 will work well.
 *
 * 4.  Figure out the total size in bytes of the files you will
 *     download and put that number in your application, then use
 *     `LoadInfo.getTotalBytesDownloaded()` /
 *     `MY_APPS_TOTAL_BYTES_TO_DOWNLOAD`.
 *
 * @return {number} The total number of currently known bytes to be streamed.
 */
tdl.io.LoadInfo.prototype.getTotalKnownBytesToStreamSoFar = function() {
  //if (!this.streamLength_ && this.request_ && this.hasStatus_) {
  //  //
  //  //this.streamLength_ = this.request_.streamLength;
  //}
  var total = this.streamLength_;
  for (var cc = 0; cc < this.children_.length; ++cc) {
    total += this.children_[cc].getTotalKnownBytesToStreamSoFar();
  }
  return total;
};

/**
 * Gets the total bytes downloaded so far.
 * @return {number} The total number of currently known bytes to be streamed.
 */
tdl.io.LoadInfo.prototype.getTotalBytesDownloaded = function() {
  var total = (this.request_ && this.hasStatus_) ?
              this.request_.bytesReceived : this.streamLength_;
  for (var cc = 0; cc < this.children_.length; ++cc) {
    total += this.children_[cc].getTotalBytesDownloaded();
  }
  return total;
};

/**
 * Gets the total streams that will be download known so far.
 * We can't know all the streams since you could use an tdl.loader.Loader
 * object, request some streams, then call this function, then request some
 * more.
 *
 * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
 * @return {number} The total number of requests currently known to be streamed.
 * @see tdl.io.LoadInfo.getTotalKnownBytesToStreamSoFar
 */
tdl.io.LoadInfo.prototype.getTotalKnownRequestsToStreamSoFar = function() {
  var total = 1;
  for (var cc = 0; cc < this.children_.length; ++cc) {
    total += this.children_[cc].getTotalKnownRequestToStreamSoFar();
  }
  return total;
};

/**
 * Gets the total requests downloaded so far.
 * @return {number} The total requests downloaded so far.
 */
tdl.io.LoadInfo.prototype.getTotalRequestsDownloaded = function() {
  var total = this.request_ ? 0 : 1;
  for (var cc = 0; cc < this.children_.length; ++cc) {
    total += this.children_[cc].getTotalRequestsDownloaded();
  }
  return total;
};

/**
 * Gets progress info.
 * This is commonly formatted version of the information available from a
 * LoadInfo.
 *
 * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
 * @return {{percent: number, downloaded: string, totalBytes: string,
 *     base: number, suffix: string}} progress info.
 * @see tdl.io.LoadInfo.getTotalKnownBytesToStreamSoFar
 */
tdl.io.LoadInfo.prototype.getKnownProgressInfoSoFar = function() {
  var percent = 0;
  var bytesToDownload = this.getTotalKnownBytesToStreamSoFar();
  var bytesDownloaded = this.getTotalBytesDownloaded();
  if (bytesToDownload > 0) {
    percent = Math.floor(bytesDownloaded / bytesToDownload * 100);
  }

  var base = (bytesToDownload < 1024 * 1024) ? 1024 : (1024 * 1024);

  return {
    percent: percent,
    downloaded: (bytesDownloaded / base).toFixed(2),
    totalBytes: (bytesToDownload / base).toFixed(2),
    base: base,
    suffix: (base == 1024 ? 'kb' : 'mb')}

};

/**
 * Loads text from an external file. This function is synchronous.
 * @param {string} url The url of the external file.
 * @return {string} the loaded text if the request is synchronous.
 */
tdl.io.loadTextFileSynchronous = function(url) {
  var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
  var request;
  if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
    if (request.overrideMimeType) {
      request.overrideMimeType('text/plain');
    }
  } else if (window.ActiveXObject) {
    request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
  } else {
    throw 'XMLHttpRequest is disabled';
  }
  request.open('GET', url, false);
  request.send(null);
  if (request.readyState != 4) {
    throw error;
  }
  return request.responseText;
};

/**
 * Loads text from an external file. This function is asynchronous.
 * @param {string} url The url of the external file.
 * @param {function(string, *): void} callback A callback passed the loaded
 *     string and an exception which will be null on success.
 * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
 */
tdl.io.loadTextFile = function(url, callback) {
  var error = 'loadTextFile failed to load url "' + url + '"';
  var request;
  if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
    if (request.overrideMimeType) {
      request.overrideMimeType('text/plain; charset=utf-8');
    }
  } else if (window.ActiveXObject) {
    request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
  } else {
    throw 'XMLHttpRequest is disabled';
  }
  var loadInfo = tdl.io.createLoadInfo(request, false);
  request.open('GET', url, true);
  var finish = function() {
    if (request.readyState == 4) {
      var text = '';
      // HTTP reports success with a 200 status. The file protocol reports
      // success with zero. HTTP does not use zero as a status code (they
      // start at 100).
      // https://developer.mozilla.org/En/Using_XMLHttpRequest
      var success = request.status == 200 || request.status == 0;
      if (success) {
        text = request.responseText;
      }
      loadInfo.finish();
      callback(text, success ? null : 'could not load: ' + url);
    }
  };
  request.onreadystatechange = finish;
  request.send(null);
  return loadInfo;
};

/**
 * Loads a file from an external file. This function is
 * asynchronous.
 * @param {string} url The url of the external file.
 * @param {function(string, *): void} callback A callback passed the loaded
 *     ArrayBuffer and an exception which will be null on
 *     success.
 * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
 */
tdl.io.loadArrayBuffer = function(url, callback) {
  var error = 'loadArrayBuffer failed to load url "' + url + '"';
  var request;
  if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();
  } else {
    throw 'XMLHttpRequest is disabled';
  }
  var loadInfo = tdl.io.
Download .txt
gitextract_7m630dcz/

├── .gitignore
├── Gruntfile.js
├── README.md
├── bower.json
├── docs.md
├── example/
│   ├── example-requirejs.html
│   ├── example-requirejs.js
│   ├── example.html
│   ├── example2.html
│   ├── line.html
│   └── picking.html
├── js/
│   └── require.js
├── jsdoc.conf.json
├── package.json
└── tdl/
    ├── base-rs.js
    ├── base.js
    ├── buffers.js
    ├── clock.js
    ├── fast.js
    ├── fps.js
    ├── framebuffers.js
    ├── fullscreen.js
    ├── io.js
    ├── loader.js
    ├── log.js
    ├── math.js
    ├── misc.js
    ├── models.js
    ├── particles.js
    ├── primitives.js
    ├── programs.js
    ├── quaternions.js
    ├── screenshot.js
    ├── shader.js
    ├── string.js
    ├── sync.js
    ├── textures.js
    └── webgl.js
Download .txt
SYMBOL INDEX (34 symbols across 7 files)

FILE: example/example-requirejs.js
  function ValidateNoneOfTheArgsAreUndefined (line 29) | function ValidateNoneOfTheArgsAreUndefined(functionName, args) {
  function Log (line 38) | function Log(msg) {
  function LogGLCall (line 44) | function LogGLCall(functionName, args) {
  function createProgramFromTags (line 52) | function createProgramFromTags(vertexTagId, fragmentTagId) {
  function setupSphere (line 61) | function setupSphere() {
  function initialize (line 72) | function initialize() {

FILE: js/require.js
  function G (line 7) | function G(b){return"[object Function]"===M.call(b)}
  function H (line 7) | function H(b){return"[object Array]"===M.call(b)}
  function v (line 7) | function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+...
  function U (line 7) | function U(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b))...
  function s (line 7) | function s(b,c){return ga.call(b,c)}
  function j (line 7) | function j(b,c){return s(b,c)&&b[c]}
  function B (line 7) | function B(b,c){for(var d in b)if(s(b,d)&&c(b[d],d))break}
  function V (line 7) | function V(b,c,d,g){c&&B(c,function(c,h){if(d||!s(b,h))g&&"object"===typ...
  function t (line 8) | function t(b,c){return function(){return c.apply(b,arguments)}}
  function da (line 8) | function da(b){throw b;}
  function ea (line 8) | function ea(b){if(!b)return b;var c=ca;v(b.split("."),function(b){c=c[b]...
  function C (line 8) | function C(b,c,d,g){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"...
  function ha (line 8) | function ha(b){function c(a,e,b){var f,n,c,d,g,h,i,I=e&&e.split("/");n=I...

FILE: tdl/base.js
  function visitNode (line 315) | function visitNode(path) {
  function define (line 570) | function define() {

FILE: tdl/primitives.js
  function roundVector (line 320) | function roundVector(v) {
  function tangentFrameKey (line 326) | function tangentFrameKey(position, normal) {
  function addTangentFrame (line 333) | function addTangentFrame(position, normal, tangent, binormal) {
  function getTangentFrame (line 346) | function getTangentFrame(position, normal) {
  function createArc (line 734) | function createArc(arcRadius, x, normalMult, normalAdd, uMult, uAdd) {
  function createSurface (line 768) | function createSurface(leftArcOffset, rightArcOffset) {

FILE: tdl/programs.js
  function flatten (line 236) | function flatten(array){
  function createSetters (line 245) | function createSetters(program) {

FILE: tdl/string.js
  function objToString (line 109) | function objToString(obj, opt_prefix) {

FILE: tdl/webgl.js
  function handleCreationError (line 107) | function handleCreationError(msg) {
  function returnFalse (line 179) | function returnFalse() {
  function makeErrorWrapper (line 491) | function makeErrorWrapper(ctx, functionName) {
  function makePropertyWrapper (line 511) | function makePropertyWrapper(wrapper, original, propertyName) {
Condensed preview — 38 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (495K chars).
[
  {
    "path": ".gitignore",
    "chars": 285,
    "preview": "docs\n*.Makefile\n*.mk\n*.ncb\n*.ninja\n*.props\n*.pyc\n*.rules\n*.scons\n*.sdf\n*.sln\n*.suo\n*.targets\n*.user\n*.vcproj\n*.vcxproj\n*"
  },
  {
    "path": "Gruntfile.js",
    "chars": 1371,
    "preview": "\"use strict\";\n\nmodule.exports = function(grunt) {\n\n  grunt.initConfig({\n    jsdoc: {\n      tdl: {\n        src: ['tdl/*.j"
  },
  {
    "path": "README.md",
    "chars": 3535,
    "preview": "TDL\n===\n\nPlease check out [TWGL](http://twgljs.org). It's arguably the spiritual successor to TDL.\n\nTDL is a **low-level"
  },
  {
    "path": "bower.json",
    "chars": 684,
    "preview": "{\n  \"name\": \"tdl\",\n  \"version\": \"0.0.8\",\n  \"authors\": [\n    {\n      \"name\": \"Gregg Tavares\",\n      \"email\": \"github@greg"
  },
  {
    "path": "docs.md",
    "chars": 3727,
    "preview": "TDL Docs\n========\nI hope the code is pretty straight forward. There's some simple examples here\n\n<a href=\"http://greggma"
  },
  {
    "path": "example/example-requirejs.html",
    "chars": 4672,
    "preview": "<!--\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms,"
  },
  {
    "path": "example/example-requirejs.js",
    "chars": 7348,
    "preview": "var main = function(\n   TDLBuffers,\n   TDLFast,\n   TDLFps,\n   TDLLog,\n   TDLMath,\n   TDLModels,\n   TDLPrimitives,\n   TDL"
  },
  {
    "path": "example/example.html",
    "chars": 11771,
    "preview": "<!--\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms,"
  },
  {
    "path": "example/example2.html",
    "chars": 11204,
    "preview": "<!--\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms,"
  },
  {
    "path": "example/line.html",
    "chars": 11161,
    "preview": "<!--\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wit"
  },
  {
    "path": "example/picking.html",
    "chars": 17778,
    "preview": "<!--\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms,"
  },
  {
    "path": "js/require.js",
    "chars": 15234,
    "preview": "/*\n RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.\n Available via the MIT or new BSD"
  },
  {
    "path": "jsdoc.conf.json",
    "chars": 738,
    "preview": "{\r\n\t\"tags\"      : {\r\n\t\t\"allowUnknownTags\" : false\r\n\t},\r\n\t\"plugins\"   : [\"plugins/markdown\"],\r\n\t\"templates\" : {\r\n\t\t\"cleve"
  },
  {
    "path": "package.json",
    "chars": 692,
    "preview": "{\n  \"name\": \"tdl\",\n  \"version\": \"0.0.8\",\n  \"description\": \"Some WebGL Library\",\n  \"main\": \"tdl/base.js\",\n  \"directories\""
  },
  {
    "path": "tdl/base-rs.js",
    "chars": 6314,
    "preview": "/*\n * Copyright 2014, Gregg Tavares.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "tdl/base.js",
    "chars": 16764,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/buffers.js",
    "chars": 5152,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/clock.js",
    "chars": 3991,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/fast.js",
    "chars": 46818,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/fps.js",
    "chars": 3430,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/framebuffers.js",
    "chars": 10601,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/fullscreen.js",
    "chars": 3279,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/io.js",
    "chars": 14905,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/loader.js",
    "chars": 4946,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/log.js",
    "chars": 2781,
    "preview": "/*\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "tdl/math.js",
    "chars": 74674,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/misc.js",
    "chars": 4577,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/models.js",
    "chars": 6431,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/particles.js",
    "chars": 47228,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/primitives.js",
    "chars": 47096,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/programs.js",
    "chars": 15930,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/quaternions.js",
    "chars": 15484,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/screenshot.js",
    "chars": 2133,
    "preview": "/*\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "tdl/shader.js",
    "chars": 5987,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/string.js",
    "chars": 4362,
    "preview": "/*\r\n * Copyright 2009, Google Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, w"
  },
  {
    "path": "tdl/sync.js",
    "chars": 4490,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/textures.js",
    "chars": 18720,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  },
  {
    "path": "tdl/webgl.js",
    "chars": 18515,
    "preview": "/*\n * Copyright 2009, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with "
  }
]

About this extraction

This page contains the full source code of the greggman/tdl GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 38 files (463.7 KB), approximately 140.4k tokens, and a symbol index with 34 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!