├── .gitignore ├── Gruntfile.js ├── README.md ├── bower.json ├── docs.md ├── example ├── assets │ └── sometexture.png ├── 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 ├── error.jpg ├── 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 /.gitignore: -------------------------------------------------------------------------------- 1 | docs 2 | *.Makefile 3 | *.mk 4 | *.ncb 5 | *.ninja 6 | *.props 7 | *.pyc 8 | *.rules 9 | *.scons 10 | *.sdf 11 | *.sln 12 | *.suo 13 | *.targets 14 | *.user 15 | *.vcproj 16 | *.vcxproj 17 | *.vcxproj.filters 18 | *.vpj 19 | *.vpw 20 | *.vpwhistu 21 | *.vtg 22 | *.xcodeproj 23 | *~ 24 | .*.sw? 25 | .DS_Store 26 | .cproject 27 | .gdb_history 28 | .gdbinit 29 | .metadata 30 | .project 31 | tags 32 | Thumbs.db 33 | v8.log 34 | node_modules 35 | 36 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function(grunt) { 4 | 5 | grunt.initConfig({ 6 | jsdoc: { 7 | tdl: { 8 | src: ['tdl/*.js'], 9 | options: { 10 | destination: 'docs/gen', 11 | configure: 'jsdoc.conf.json', 12 | template: 'node_modules/ink-docstrap/template', 13 | private: false, 14 | }, 15 | }, 16 | }, 17 | clean: [ 18 | 'docs/gen', 19 | ], 20 | uglify: { 21 | my_target: { 22 | files: { 23 | 'build/tdl.min.js': [ 24 | 'tdl/base.js', 25 | 'tdl/buffers.js', 26 | 'tdl/clock.js', 27 | 'tdl/fast.js', 28 | 'tdl/fps.js', 29 | 'tdl/framebuffers.js', 30 | 'tdl/fullscreen.js', 31 | 'tdl/io.js', 32 | 'tdl/loader.js', 33 | 'tdl/log.js', 34 | 'tdl/math.js', 35 | 'tdl/misc.js', 36 | 'tdl/models.js', 37 | 'tdl/particles.js', 38 | 'tdl/primitives.js', 39 | 'tdl/programs.js', 40 | 'tdl/quaternions.js', 41 | 'tdl/screenshot.js', 42 | 'tdl/shader.js', 43 | 'tdl/string.js', 44 | 'tdl/sync.js', 45 | 'tdl/textures.js', 46 | 'tdl/webgl.js', 47 | ], 48 | }, 49 | }, 50 | }, 51 | }); 52 | 53 | grunt.loadNpmTasks('grunt-contrib-clean'); 54 | grunt.loadNpmTasks('grunt-jsdoc'); 55 | grunt.loadNpmTasks('grunt-contrib-uglify'); 56 | 57 | grunt.registerTask('default', ['clean', 'jsdoc', 'uglify']); 58 | }; 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TDL 2 | === 3 | 4 | Please check out [TWGL](http://twgljs.org). It's arguably the spiritual successor to TDL. 5 | 6 | TDL is a **low-level** library for WebGL apps. It currently focuses on speed of rendering rather than ease of use. 7 | 8 | Some [terse docs can be found at here](docs.md) 9 | 10 | Note: By **low-level** I mean TDL doesn't currently provide any 3D knowledge. 11 | There are almost no built in shaders. There is no scene graph. There are just some objects for wrapping WebGL 12 | shaders and helping to easily associate vertex data with attributes and update uniforms. 13 | 14 | Example: Assuming a shaders like this. 15 | 16 | 30 | 31 | 39 | 40 | In WebGL you'd do this 41 | 42 | // At init time: 43 | var program = UtilToCompileShaders("vshader", "fshader"); 44 | var positionLoc = gl.getAttribLocation(program, "position"); 45 | var texcoordLoc = gl.getAttribLocation(program, "texcoord"); 46 | var worldMatLoc = gl.getUniformLocation(program, "u_worldMatrix"); 47 | var projectionMatLoc = gl.getUniformLocation(program, "u_projectionMatrix"); 48 | var textureLoc = gl.getUniformLocation(program, "u_texture"); 49 | 50 | var positions = gl.createBuffer(); 51 | gl.bindBuffer(gl.ARRAY_BUFFER, positions); 52 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positionData), gl.STATIC_DRAW); 53 | 54 | var tecoords = gl.createBuffer(); 55 | gl.bindBuffer(gl.ARRAY_BUFFER, texcoords); 56 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoordData), gl.STATIC_DRAW); 57 | 58 | var texture = gl.createTexture(); 59 | gl.bindTexture(gl.TEXTURE_2D, texture); 60 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, someImage); 61 | 62 | 63 | // At draw time 64 | gl.bindBuffer(gl.ARRAY_BUFFER, positions); 65 | gl.enableVertexAttribArray(programLoc); 66 | gl.vertexAttribPointer(programLoc, 3, gl.FLOAT, false, 0, 0); 67 | 68 | gl.bindBuffer(gl.ARRAY_BUFFER, positions); 69 | gl.enableVertexAttribArray(texcoordLoc); 70 | gl.vertexAttribPointer(tecoordLoc, 2, gl.FLOAT, false, 0, 0); 71 | 72 | gl.useProgram(program); 73 | gl.uniformMatrix4f(projectionMatLoc, false, projectionMatrix); 74 | 75 | for (var i = 0; i < 3; ++i) 76 | { 77 | gl.uniformMatrix4f(worldMatLoc, false, computeWorldMatrix(i)); 78 | gl.drawArrays(gl.TRIANGLES, 0, num); 79 | } 80 | 81 | In TDL that would be shortened to 82 | 83 | // At init time. 84 | var program = tdl.programs.loadProgramFromScriptTags("vshader", "fshader"); 85 | var arrays = { 86 | position: new tdl.primitives.AttribBuffer(3, positionData), 87 | texcoord: new tdl.primitives.AttribBuffer(2, texcoordData), 88 | }; 89 | var textures = { 90 | u_texture: new tdl.textures.loadTexture(someImage), 91 | } 92 | var model = new tdl.models.Model(program, arrays, textures); 93 | 94 | 95 | // At Draw time 96 | var sharedUniforms = { 97 | u_projectionMatrix: projectionMatrix, 98 | }; 99 | var perObjectUniforms = { 100 | u_worldMatrix: worldMatrix, 101 | }; 102 | 103 | model.drawPrep(sharedUniforms); 104 | 105 | for (var i = 0; i < 3; ++i) 106 | { 107 | perObjectUnifirms.u_worldMatrix = computeWorldMatrix(i); 108 | model.draw(perObjectuniforms); 109 | } 110 | 111 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tdl", 3 | "version": "0.0.8", 4 | "authors": [ 5 | { 6 | "name": "Gregg Tavares", 7 | "email": "github@greggman.com", 8 | "homepage": "http://games.greggman.com" 9 | } 10 | ], 11 | "description": "A JavaScript library for WebGL", 12 | "main": "tdl/base.js", 13 | "moduleType": [ 14 | "amd" 15 | ], 16 | "keywords": [ 17 | "webgl", 18 | "tdl" 19 | ], 20 | "license": "MIT", 21 | "homepage": "https://github.com/greggman/tdl", 22 | "repository": "git://github.com/greggman/tdl.git", 23 | "ignore": [ 24 | "**/.*", 25 | "*.md", 26 | "Gruntfile.js", 27 | "package.json", 28 | "bower.json", 29 | "node_modules", 30 | "docs", 31 | "build", 32 | "example", 33 | "js", 34 | "bower_components", 35 | "test", 36 | "tests" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /docs.md: -------------------------------------------------------------------------------- 1 | TDL Docs 2 | ======== 3 | I hope the code is pretty straight forward. There's some simple examples here 4 | 5 | http://greggman.github.com/tdl/example/example.html 6 | 7 | http://greggman.github.com/tdl/example/example2.html 8 | 9 | http://greggman.github.com/tdl/example/picking.html 10 | 11 | More complex samples can be found at http://webglsamples.googlecode.com 12 | 13 | Briefly... 14 | 15 | Your startup code should look like this 16 | 17 | canvas = document.getElementById("canvas"); 18 | gl = tdl.webgl.setupWebGL(canvas); 19 | if (!gl) { 20 | return; // Do nothing 21 | } 22 | 23 | Where "canvas" is the id of the canvas you want to draw into. 24 | tdl.webgl.setupWebGL will replace the contents of the containing div 25 | with a link to getting a WebGL capable browser if the user's browser 26 | does not support WebGL. 27 | 28 | Otherwise... 29 | 30 | Loading Shaders 31 | --------------- 32 | 33 | var program = tdl.programs.loadProgram(vertexShaderSource, fragmentShaderSource); 34 | 35 | Compiles your shaders and creates a Program object. 36 | 37 | Loading Textures 38 | ---------------- 39 | 40 | var textures = { 41 | name1: tdl.textures.loadTexture(url), 42 | name2: tdl.textures.loadTexture(url) 43 | }; 44 | 45 | Loads your textures. The property names must match whatever you called the samplers 46 | in your shaders. loadTexture can take `[url]` for an image, `[r,g,b,a]` for solid 47 | texture. `[url,url,url,url,url,url]` for a cubemap and also `[url]` for a cubemap 48 | where all 6 faces are in a cross. It can also take an img or canvas tag. 49 | 50 | Create Vertices or a Mesh 51 | ------------------------- 52 | 53 | var arrays = tdl.primitives.createSphere(1, 10, 10); 54 | 55 | Creates vertices 56 | 57 | The tdl.primitives functions return an object like this 58 | 59 | { 60 | position: AttribBuffer, 61 | normal: AttribBuffer, 62 | texCoord: AttribBuffer 63 | }; 64 | 65 | The property names must match the attributes in your vertex shader if you want to 66 | add more. 67 | 68 | A call to tdl.primitives.addTangentsAndBinormals adds the fields "tangent" and 69 | "binormal" 70 | 71 | Create a Model 72 | -------------- 73 | 74 | Once you have a program, a texture object and an arrays object you make a new 75 | model with 76 | 77 | var model = new tdl.models.Model(program, array, textures); 78 | 79 | 80 | Rendering 81 | --------- 82 | 83 | To draw the model there are 2 functions, `model.drawPrep(uniformMap)` and 84 | `model.draw(uniformMap)`. 85 | 86 | Both of them take an object with uniformName/value pairs. 87 | 88 | model.drawPrep binds the program, binds all the textures and attributes and 89 | sets whatever uniforms you pass in. 90 | 91 | model.draw sets any more uniforms you pass in and then calls gl.drawElements. 92 | The idea is you call `model.drawPrep` once and then `model.draw` to draw a 93 | bunch of the same model, changing as few uniforms as possible. This is the 94 | fastest way to use WebGL. 95 | 96 | Your rendering loop should look something like this 97 | 98 | function render() { 99 | var time = tdl.webgl.animationTime(); 100 | model.drawPrep({...}); 101 | model.draw({...}); 102 | tdl.webgl.requestAnimationFrame(render, canvas); 103 | } 104 | render(); // call the first render manually to start it off. 105 | 106 | 107 | Math 108 | ---- 109 | 110 | The math is a little funky. There are 2 math libraries, math.js and fast.js. 111 | math.js comes from O3D and uses `JavaScript` arrays. A Matrix in that 112 | library is a an array of numbers. fast.js uses `Float32Array` for its storage 113 | and most functions take a destination object as the first argument. 114 | Theoretically this is faster because you can avoid a certain number of 115 | allocations. It also means the numbers in the array do not have to be queried 116 | and converted from `JavaScript` Number to floats before calling glUniform. 117 | -------------------------------------------------------------------------------- /example/assets/sometexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greggman/tdl/6b633052599e8ee95245b6bfa17c645a935e16ae/example/assets/sometexture.png -------------------------------------------------------------------------------- /example/example-requirejs.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | WebGL TDL Example 36 | 78 | 79 | 80 | 81 |
tdl.js - example
82 |
83 |
fps:
84 |
85 |
86 | 87 |
88 | 89 | 113 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /example/example-requirejs.js: -------------------------------------------------------------------------------- 1 | var main = function( 2 | TDLBuffers, 3 | TDLFast, 4 | TDLFps, 5 | TDLLog, 6 | TDLMath, 7 | TDLModels, 8 | TDLPrimitives, 9 | TDLPrograms, 10 | TDLTextures, 11 | TDLWebGL) { 12 | // globals 13 | var gl; // the gl context. 14 | var canvas; // the canvas 15 | var math; // the math lib. 16 | var fast; // the fast math lib. 17 | var g_fpsTimer; // object to measure frames per second; 18 | var g_logGLCalls = true; // whether or not to log webgl calls 19 | var g_debug = false; // whether or not to debug. 20 | var g_drawOnce = false; // draw just one frame. 21 | 22 | //g_drawOnce = true; 23 | //g_debug = true; 24 | 25 | var g_eyeSpeed = 0.5; 26 | var g_eyeHeight = 2; 27 | var g_eyeRadius = 9; 28 | 29 | function ValidateNoneOfTheArgsAreUndefined(functionName, args) { 30 | for (var ii = 0; ii < args.length; ++ii) { 31 | if (args[ii] === undefined) { 32 | TDLLog.error("undefined passed to gl." + functionName + "(" + 33 | TDLWebGL.glFunctionArgsToString(functionName, args) + ")"); 34 | } 35 | } 36 | } 37 | 38 | function Log(msg) { 39 | if (g_logGLCalls) { 40 | TDLLog.log(msg); 41 | } 42 | } 43 | 44 | function LogGLCall(functionName, args) { 45 | if (g_logGLCalls) { 46 | ValidateNoneOfTheArgsAreUndefined(functionName, args) 47 | TDLLog.log("gl." + functionName + "(" + 48 | TDLWebGL.glFunctionArgsToString(functionName, args) + ")"); 49 | } 50 | } 51 | 52 | function createProgramFromTags(vertexTagId, fragmentTagId) { 53 | return TDLPrograms.loadProgram( 54 | document.getElementById(vertexTagId).text, 55 | document.getElementById(fragmentTagId).text); 56 | } 57 | 58 | /** 59 | * Sets up Planet. 60 | */ 61 | function setupSphere() { 62 | var textures = { 63 | diffuseSampler: TDLTextures.loadTexture('assets/sometexture.png')}; 64 | var program = createProgramFromTags( 65 | 'sphereVertexShader', 66 | 'sphereFragmentShader'); 67 | var arrays = TDLPrimitives.createSphere(0.4, 10, 12); 68 | 69 | return new TDLModels.Model(program, arrays, textures); 70 | } 71 | 72 | function initialize() { 73 | math = TDLMath; 74 | fast = TDLFast; 75 | canvas = document.getElementById("canvas"); 76 | g_fpsTimer = new TDLFps.FPSTimer(); 77 | 78 | gl = TDLWebGL.setupWebGL(canvas); 79 | if (!gl) { 80 | return false; 81 | } 82 | if (g_debug) { 83 | gl = TDLWebGL.makeDebugContext(gl, undefined, LogGLCall); 84 | } 85 | 86 | Log("--Setup Sphere---------------------------------------"); 87 | var sphere = setupSphere(); 88 | 89 | var then = 0.0; 90 | var clock = 0.0; 91 | var fpsElem = document.getElementById("fps"); 92 | 93 | // pre-allocate a bunch of arrays 94 | var projection = new Float32Array(16); 95 | var view = new Float32Array(16); 96 | var world = new Float32Array(16); 97 | var worldInverse = new Float32Array(16); 98 | var worldInverseTranspose = new Float32Array(16); 99 | var viewProjection = new Float32Array(16); 100 | var worldViewProjection = new Float32Array(16); 101 | var viewInverse = new Float32Array(16); 102 | var viewProjectionInverse = new Float32Array(16); 103 | var eyePosition = new Float32Array(3); 104 | var target = new Float32Array(3); 105 | var up = new Float32Array([0,1,0]); 106 | var lightWorldPos = new Float32Array(3); 107 | var v3t0 = new Float32Array(3); 108 | var v3t1 = new Float32Array(3); 109 | var v3t2 = new Float32Array(3); 110 | var v3t3 = new Float32Array(3); 111 | var m4t0 = new Float32Array(16); 112 | var m4t1 = new Float32Array(16); 113 | var m4t2 = new Float32Array(16); 114 | var m4t3 = new Float32Array(16); 115 | var zero4 = new Float32Array(4); 116 | var one4 = new Float32Array([1,1,1,1]); 117 | 118 | // Sphere uniforms. 119 | var sphereConst = { 120 | viewInverse: viewInverse, 121 | lightWorldPos: lightWorldPos, 122 | specular: one4, 123 | shininess: 50, 124 | specularFactor: 0.2}; 125 | var spherePer = { 126 | lightColor: new Float32Array([0,0,0,1]), 127 | world: world, 128 | worldViewProjection: worldViewProjection, 129 | worldInverse: worldInverse, 130 | worldInverseTranspose: worldInverseTranspose}; 131 | 132 | var frameCount = 0; 133 | function render() { 134 | ++frameCount; 135 | if (!g_drawOnce) { 136 | TDLWebGL.requestAnimationFrame(render, canvas); 137 | } 138 | var now = (new Date()).getTime() * 0.001; 139 | var elapsedTime; 140 | if(then == 0.0) { 141 | elapsedTime = 0.0; 142 | } else { 143 | elapsedTime = now - then; 144 | } 145 | then = now; 146 | 147 | g_fpsTimer.update(elapsedTime); 148 | fpsElem.innerHTML = g_fpsTimer.averageFPS; 149 | 150 | clock += elapsedTime; 151 | eyePosition[0] = Math.sin(clock * g_eyeSpeed) * g_eyeRadius; 152 | eyePosition[1] = g_eyeHeight; 153 | eyePosition[2] = Math.cos(clock * g_eyeSpeed) * g_eyeRadius; 154 | 155 | gl.colorMask(true, true, true, true); 156 | gl.depthMask(true); 157 | gl.clearColor(0,0,0,0); 158 | gl.clearDepth(1); 159 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); 160 | 161 | gl.enable(gl.CULL_FACE); 162 | gl.enable(gl.DEPTH_TEST); 163 | 164 | fast.matrix4.perspective( 165 | projection, 166 | math.degToRad(60), 167 | canvas.clientWidth / canvas.clientHeight, 168 | 1, 169 | 5000); 170 | fast.matrix4.lookAt( 171 | view, 172 | eyePosition, 173 | target, 174 | up); 175 | fast.matrix4.mul(viewProjection, view, projection); 176 | fast.matrix4.inverse(viewInverse, view); 177 | fast.matrix4.inverse(viewProjectionInverse, viewProjection); 178 | 179 | fast.matrix4.getAxis(v3t0, viewInverse, 0); // x 180 | fast.matrix4.getAxis(v3t1, viewInverse, 1); // y; 181 | fast.matrix4.getAxis(v3t2, viewInverse, 2); // z; 182 | fast.mulScalarVector(v3t0, 10, v3t0); 183 | fast.mulScalarVector(v3t1, 10, v3t1); 184 | fast.mulScalarVector(v3t2, 10, v3t2); 185 | fast.addVector(lightWorldPos, eyePosition, v3t0); 186 | fast.addVector(lightWorldPos, lightWorldPos, v3t1); 187 | fast.addVector(lightWorldPos, lightWorldPos, v3t2); 188 | 189 | // view: view, 190 | // projection: projection, 191 | // viewProjection: viewProjection, 192 | 193 | Log("--Draw sphere---------------------------------------"); 194 | sphere.drawPrep(sphereConst); 195 | var across = 6; 196 | var lightColor = spherePer.lightColor; 197 | var half = (across - 1) * 0.5; 198 | for (var xx = 0; xx < across; ++xx) { 199 | for (var yy = 0; yy < across; ++yy) { 200 | for (var zz = 0; zz < across; ++zz) { 201 | lightColor[0] = xx / across; 202 | lightColor[1] = yy / across; 203 | lightColor[2] = zz / across; 204 | var scale = (xx + yy + zz) % 4 / 4 + 0.5; 205 | fast.matrix4.scaling(m4t0, [scale, scale, scale]); 206 | fast.matrix4.translation(m4t1, [xx - half, yy - half, zz - half]); 207 | fast.matrix4.mul(world, m4t0, m4t1); 208 | fast.matrix4.mul(worldViewProjection, world, viewProjection); 209 | fast.matrix4.inverse(worldInverse, world); 210 | fast.matrix4.transpose(worldInverseTranspose, worldInverse); 211 | sphere.draw(spherePer); 212 | } 213 | } 214 | } 215 | 216 | // Set the alpha to 255. 217 | gl.colorMask(false, false, false, true); 218 | gl.clearColor(0,0,0,1); 219 | gl.clear(gl.COLOR_BUFFER_BIT); 220 | 221 | // turn off logging after 1 frame. 222 | g_logGLCalls = false; 223 | } 224 | render(); 225 | return true; 226 | } 227 | initialize(); 228 | } 229 | 230 | requirejs( 231 | [ '../tdl/buffers', 232 | '../tdl/fast', 233 | '../tdl/fps', 234 | '../tdl/log', 235 | '../tdl/math', 236 | '../tdl/models', 237 | '../tdl/primitives', 238 | '../tdl/programs', 239 | '../tdl/textures', 240 | '../tdl/webgl', 241 | ], 242 | main); 243 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | WebGL TDL Example 36 | 78 | 79 | 308 | 309 | 310 |
tdl.js - example
311 |
312 |
fps:
313 |
314 |
315 | 316 |
317 | 318 | 342 | 377 | 378 | 379 | 380 | -------------------------------------------------------------------------------- /example/example2.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | WebGL TDL Example 36 | 52 | 53 | 286 | 287 | 288 |

WebGL Spheres

289 |
290 |
291 |
fps:
292 |
293 |
294 | 295 |
296 |
297 | 298 | 322 | 356 | 357 | 358 | 359 | -------------------------------------------------------------------------------- /example/line.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | WebGL TDL Example 36 | 78 | 79 | 313 | 314 | 315 |
tdl.js - example
316 |
317 |
fps:
318 |
319 |
320 | 321 |
322 | 323 | 344 | 377 | 378 | 379 | 380 | -------------------------------------------------------------------------------- /js/require.js: -------------------------------------------------------------------------------- 1 | /* 2 | RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. 3 | Available via the MIT or new BSD license. 4 | see: http://github.com/jrburke/requirejs for details 5 | */ 6 | var requirejs,require,define; 7 | (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;dthis.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&& 19 | (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= 20 | 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); 21 | 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", 22 | "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, 23 | 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, 24 | 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, 25 | 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= 26 | !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!== 27 | d&&(!("."===g||".."===g)||1g.attachEvent.toString().indexOf("[native code"))&&!Z?(O=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)): 34 | (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= 35 | 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|| 36 | (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); 37 | -------------------------------------------------------------------------------- /jsdoc.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags" : { 3 | "allowUnknownTags" : false 4 | }, 5 | "plugins" : ["plugins/markdown"], 6 | "templates" : { 7 | "cleverLinks" : false, 8 | "monospaceLinks" : false, 9 | "dateFormat" : "ddd MMM Do YYYY", 10 | "outputSourceFiles" : false, 11 | "outputSourcePath" : false, 12 | "systemName" : "ThreeDLibrary", 13 | "footer" : "", 14 | "copyright" : "copyright Google, Greggman", 15 | "navType" : "vertical", 16 | "theme" : "cerulean", 17 | "linenums" : true, 18 | "collapseSymbols" : false, 19 | "inverseNav" : true, 20 | "highlightTutorialCode" : true 21 | }, 22 | "markdown" : { 23 | "parser" : "gfm", 24 | "hardwrap" : true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tdl", 3 | "version": "0.0.8", 4 | "description": "Some WebGL Library", 5 | "main": "tdl/base.js", 6 | "directories": { 7 | "doc": "docs", 8 | "example": "example" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/greggman/tdl.git" 16 | }, 17 | "keywords": [ 18 | "WebGL" 19 | ], 20 | "author": "Greggman", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/greggman/tdl/issues" 24 | }, 25 | "homepage": "https://github.com/greggman/tdl", 26 | "devDependencies": { 27 | "grunt": "^0.4.5", 28 | "grunt-contrib-clean": "^0.6.0", 29 | "grunt-contrib-uglify": "^0.7.0", 30 | "grunt-jsdoc": "^0.5.7" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tdl/base-rs.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014, Gregg Tavares. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are 7 | * met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following disclaimer 13 | * in the documentation and/or other materials provided with the 14 | * distribution. 15 | * * Neither the name of Gregg Tavares. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // emulate tdl/base.js for require.js 33 | 34 | define(function() { 35 | 36 | // Was base.js already included? 37 | var haveBaseJS = (this.tdl !== undefined); 38 | if (haveBaseJS) { 39 | tdl.provide('tdl.base-rs'); 40 | return; 41 | } 42 | 43 | this.tdl = {base:{}}; 44 | this.goog = {}; 45 | 46 | var noop = function() {}; 47 | 48 | // Let's assume if the user is using require JS they don't need tdl.require 49 | // If that's not the case we'd need provide a version of tdl.require that 50 | // ignores the tdl files but not the user's files. Probably hooked into requirejs 51 | tdl.require = noop; 52 | tdl.provide = noop; 53 | 54 | 55 | /** 56 | * Determine whether a value is an array. Do not use instanceof because that 57 | * will not work for V8 arrays (the browser thinks they are Objects). 58 | * @param {*} value A value. 59 | * @return {boolean} Whether the value is an array. 60 | */ 61 | tdl.base.isArray = function(value) { 62 | var valueAsObject = /** @type {!Object} */ (value); 63 | return typeof(value) === 'object' && value !== null && 64 | 'length' in valueAsObject && 'splice' in valueAsObject; 65 | }; 66 | 67 | /** 68 | * A stub for later optionally converting obfuscated names 69 | * @private 70 | * @param {string} name Name to un-obfuscate. 71 | * @return {string} un-obfuscated name. 72 | */ 73 | tdl.base.maybeDeobfuscateFunctionName_ = function(name) { 74 | return name; 75 | }; 76 | 77 | /** 78 | * Makes one class inherit from another. 79 | * @param {!Object} subClass Class that wants to inherit. 80 | * @param {!Object} superClass Class to inherit from. 81 | */ 82 | tdl.base.inherit = function(subClass, superClass) { 83 | /** 84 | * TmpClass. 85 | * @ignore 86 | * @constructor 87 | */ 88 | var TmpClass = function() { }; 89 | TmpClass.prototype = superClass.prototype; 90 | subClass.prototype = new TmpClass(); 91 | }; 92 | 93 | /** 94 | * Parses an error stack from an exception 95 | * @param {!Exception} excp The exception to get a stack trace from. 96 | * @return {!Array.} An array of strings of the stack trace. 97 | */ 98 | tdl.base.parseErrorStack = function(excp) { 99 | var stack = []; 100 | var name; 101 | var line; 102 | 103 | if (!excp || !excp.stack) { 104 | return stack; 105 | } 106 | 107 | var stacklist = excp.stack.split('\n'); 108 | 109 | for (var i = 0; i < stacklist.length - 1; i++) { 110 | var framedata = stacklist[i]; 111 | 112 | name = framedata.match(/^([a-zA-Z0-9_$]*)/)[1]; 113 | if (name) { 114 | name = tdl.base.maybeDeobfuscateFunctionName_(name); 115 | } else { 116 | name = 'anonymous'; 117 | } 118 | 119 | var result = framedata.match(/(.*:[0-9]+)$/); 120 | line = result && result[1]; 121 | 122 | if (!line) { 123 | line = '(unknown)'; 124 | } 125 | 126 | stack[stack.length] = name + ' : ' + line 127 | } 128 | 129 | // remove top level anonymous functions to match IE 130 | var omitRegexp = /^anonymous :/; 131 | while (stack.length && omitRegexp.exec(stack[stack.length - 1])) { 132 | stack.length = stack.length - 1; 133 | } 134 | 135 | return stack; 136 | }; 137 | 138 | /** 139 | * Gets a function name from a function object. 140 | * @param {!function(...): *} aFunction The function object to try to get a 141 | * name from. 142 | * @return {string} function name or 'anonymous' if not found. 143 | */ 144 | tdl.base.getFunctionName = function(aFunction) { 145 | var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/); 146 | if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) { 147 | return tdl.base.maybeDeobfuscateFunctionName_(regexpResult[2]); 148 | } 149 | return 'anonymous'; 150 | }; 151 | 152 | /** 153 | * Pretty prints an exception's stack, if it has one. 154 | * @param {Array.} stack An array of errors. 155 | * @return {string} The pretty stack. 156 | */ 157 | tdl.base.formatErrorStack = function(stack) { 158 | var result = ''; 159 | for (var i = 0; i < stack.length; i++) { 160 | result += '> ' + stack[i] + '\n'; 161 | } 162 | return result; 163 | }; 164 | 165 | /** 166 | * Gets a stack trace as a string. 167 | * @param {number} stripCount The number of entries to strip from the top of the 168 | * stack. Example: Pass in 1 to remove yourself from the stack trace. 169 | * @return {string} The stack trace. 170 | */ 171 | tdl.base.getStackTrace = function(stripCount) { 172 | var result = ''; 173 | 174 | if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA 175 | for (var a = arguments.caller; a != null; a = a.caller) { 176 | result += '> ' + tdl.base.getFunctionName(a.callee) + '\n'; 177 | if (a.caller == a) { 178 | result += '*'; 179 | break; 180 | } 181 | } 182 | } else { // Mozilla, not ECMA 183 | // fake an exception so we can get Mozilla's error stack 184 | var testExcp; 185 | try { 186 | eval('var var;'); 187 | } catch (testExcp) { 188 | var stack = tdl.base.parseErrorStack(testExcp); 189 | result += tdl.base.formatErrorStack(stack.slice(3 + stripCount, 190 | stack.length)); 191 | } 192 | } 193 | 194 | return result; 195 | }; 196 | 197 | /** 198 | * Returns true if the user's browser is Microsoft IE. 199 | * @return {boolean} true if the user's browser is Microsoft IE. 200 | */ 201 | tdl.base.IsMSIE = function() { 202 | var ua = navigator.userAgent.toLowerCase(); 203 | var msie = /msie/.test(ua) && !/opera/.test(ua); 204 | return msie; 205 | }; 206 | 207 | return {}; 208 | }); 209 | -------------------------------------------------------------------------------- /tdl/base.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009, Google Inc. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are 7 | * met: 8 | * 9 | * * Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above 12 | * copyright notice, this list of conditions and the following disclaimer 13 | * in the documentation and/or other materials provided with the 14 | * distribution. 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | 33 | /** 34 | * @fileoverview Base for all tdl sample utilties. 35 | * 36 | * The main point of this module is to provide a central place to 37 | * have an init function to register an tdl namespace object because many other 38 | * modules need access to it. 39 | */ 40 | 41 | /** 42 | * A namespace for all the tdl utility libraries. 43 | * @namespace 44 | */ 45 | var tdl = tdl || {}; 46 | 47 | /** 48 | * Define this because the Google internal JSCompiler needs goog.typedef below. 49 | */ 50 | var goog = goog || {}; 51 | 52 | 53 | if (!window.Int32Array) { 54 | window.Int32Array = function() { }; 55 | window.Float32Array = function() { }; 56 | window.Uint16Array = function() { }; 57 | } 58 | 59 | /** 60 | * A macro for defining composite types. 61 | * 62 | * By assigning goog.typedef to a name, this tells Google internal JSCompiler 63 | * that this is not the name of a class, but rather it's the name of a composite 64 | * type. 65 | * 66 | * For example, 67 | * /** @type {Array|NodeList} / goog.ArrayLike = goog.typedef; 68 | * will tell JSCompiler to replace all appearances of goog.ArrayLike in type 69 | * definitions with the union of Array and NodeList. 70 | * 71 | * Does nothing in uncompiled code. 72 | */ 73 | goog.typedef = true; 74 | 75 | /** 76 | * Reference to the global context. In most cases this will be 'window'. 77 | */ 78 | tdl.global = this; 79 | 80 | /** 81 | * Some javascripts don't support __defineGetter__ or __defineSetter__ 82 | * so we define some here so at least we don't get compile errors. 83 | * We expect the initialzation code will check and complain. This stubs 84 | * are just here to make sure we can actually get to the initialization code. 85 | */ 86 | //if (!Object.prototype.__defineSetter__) { 87 | // Object.prototype.__defineSetter__ = function() {} 88 | // Object.prototype.__defineGetter__ = function() {} 89 | //} 90 | // 91 | /** 92 | * Flag used to force a function to run in the browser when it is called 93 | * from V8. 94 | * @type {boolean} 95 | */ 96 | tdl.BROWSER_ONLY = true; 97 | 98 | /** 99 | * Array of namespaces that have been provided. 100 | * @private 101 | * @type {!Array.} 102 | */ 103 | tdl.provided_ = []; 104 | 105 | /** 106 | * Creates object stubs for a namespace. When present in a file, 107 | * tdl.provide also indicates that the file defines the indicated 108 | * object. 109 | * @param {string} name name of the object that this file defines. 110 | */ 111 | tdl.provide = function(name) { 112 | // Ensure that the same namespace isn't provided twice. 113 | if (tdl.getObjectByName(name) && 114 | !tdl.implicitNamespaces_[name]) { 115 | throw 'Namespace "' + name + '" already declared.'; 116 | } 117 | 118 | var namespace = name; 119 | while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { 120 | tdl.implicitNamespaces_[namespace] = true; 121 | } 122 | 123 | tdl.exportPath_(name); 124 | tdl.provided_.push(name); 125 | }; 126 | 127 | 128 | /** 129 | * Namespaces implicitly defined by tdl.provide. For example, 130 | * tdl.provide('tdl.events.Event') implicitly declares 131 | * that 'tdl' and 'tdl.events' must be namespaces. 132 | * 133 | * @type {Object} 134 | * @private 135 | */ 136 | tdl.implicitNamespaces_ = {}; 137 | 138 | /** 139 | * Builds an object structure for the provided namespace path, 140 | * ensuring that names that already exist are not overwritten. For 141 | * example: 142 | * "a.b.c" -> a = {};a.b={};a.b.c={}; 143 | * Used by tdl.provide and tdl.exportSymbol. 144 | * @param {string} name name of the object that this file defines. 145 | * @param {Object} opt_object the object to expose at the end of the path. 146 | * @param {Object} opt_objectToExportTo The object to add the path to; default 147 | * is |tdl.global|. 148 | * @private 149 | */ 150 | tdl.exportPath_ = function(name, opt_object, opt_objectToExportTo) { 151 | var parts = name.split('.'); 152 | var cur = opt_objectToExportTo || tdl.global; 153 | var part; 154 | 155 | // Internet Explorer exhibits strange behavior when throwing errors from 156 | // methods externed in this manner. See the testExportSymbolExceptions in 157 | // base_test.html for an example. 158 | if (!(parts[0] in cur) && cur.execScript) { 159 | cur.execScript('var ' + parts[0]); 160 | } 161 | 162 | // Parentheses added to eliminate strict JS warning in Firefox. 163 | while (parts.length && (part = parts.shift())) { 164 | if (!parts.length && tdl.isDef(opt_object)) { 165 | // last part and we have an object; use it. 166 | cur[part] = opt_object; 167 | } else if (cur[part]) { 168 | cur = cur[part]; 169 | } else { 170 | cur = cur[part] = {}; 171 | } 172 | } 173 | }; 174 | 175 | 176 | /** 177 | * Returns an object based on its fully qualified external name. If you are 178 | * using a compilation pass that renames property names beware that using this 179 | * function will not find renamed properties. 180 | * 181 | * @param {string} name The fully qualified name. 182 | * @param {Object} opt_obj The object within which to look; default is 183 | * |tdl.global|. 184 | * @return {Object} The object or, if not found, null. 185 | */ 186 | tdl.getObjectByName = function(name, opt_obj) { 187 | var parts = name.split('.'); 188 | var cur = opt_obj || tdl.global; 189 | for (var pp = 0; pp < parts.length; ++pp) { 190 | var part = parts[pp]; 191 | if (cur[part]) { 192 | cur = cur[part]; 193 | } else { 194 | return null; 195 | } 196 | } 197 | return cur; 198 | }; 199 | 200 | 201 | /** 202 | * Implements a system for the dynamic resolution of dependencies. 203 | * @param {string} rule Rule to include, in the form tdl.package.part. 204 | */ 205 | tdl.require = function(rule) { 206 | // TODO(gman): For some unknown reason, when we call 207 | // tdl.util.getScriptTagText_ it calls 208 | // document.getElementsByTagName('script') and for some reason the scripts do 209 | // not always show up. Calling it here seems to fix that as long as we 210 | // actually ask for the length, at least in FF 3.5.1 It would be nice to 211 | // figure out why. 212 | var dummy = document.getElementsByTagName('script').length; 213 | // if the object already exists we do not need do do anything 214 | if (tdl.getObjectByName(rule)) { 215 | return; 216 | } 217 | var path = tdl.getPathFromRule_(rule); 218 | if (path) { 219 | tdl.included_[path] = true; 220 | tdl.writeScripts_(); 221 | } else { 222 | throw new Error('tdl.require could not find: ' + rule); 223 | } 224 | }; 225 | 226 | 227 | /** 228 | * Path for included scripts. 229 | * @type {string} 230 | */ 231 | tdl.basePath = ''; 232 | 233 | 234 | /** 235 | * Object used to keep track of urls that have already been added. This 236 | * record allows the prevention of circular dependencies. 237 | * @type {Object} 238 | * @private 239 | */ 240 | tdl.included_ = {}; 241 | 242 | 243 | /** 244 | * This object is used to keep track of dependencies and other data that is 245 | * used for loading scripts. 246 | * @private 247 | * @type {Object} 248 | */ 249 | tdl.dependencies_ = { 250 | visited: {}, // used when resolving dependencies to prevent us from 251 | // visiting the file twice. 252 | written: {} // used to keep track of script files we have written. 253 | }; 254 | 255 | 256 | /** 257 | * Tries to detect the base path of the tdl-base.js script that 258 | * bootstraps the tdl libraries. 259 | * @private 260 | */ 261 | tdl.findBasePath_ = function() { 262 | var doc = tdl.global.document; 263 | if (typeof doc == 'undefined') { 264 | return; 265 | } 266 | if (tdl.global.BASE_PATH) { 267 | tdl.basePath = tdl.global.BASE_PATH; 268 | return; 269 | } else { 270 | // HACKHACK to hide compiler warnings :( 271 | tdl.global.BASE_PATH = null; 272 | } 273 | var expectedBase = 'tdl/base.js'; 274 | var scripts = doc.getElementsByTagName('script'); 275 | for (var script, i = 0; script = scripts[i]; i++) { 276 | var src = script.src; 277 | var l = src.length; 278 | if (src.substr(l - expectedBase.length) == expectedBase) { 279 | tdl.basePath = src.substr(0, l - expectedBase.length); 280 | return; 281 | } 282 | } 283 | }; 284 | 285 | 286 | /** 287 | * Writes a script tag if, and only if, that script hasn't already been added 288 | * to the document. (Must be called at execution time.) 289 | * @param {string} src Script source. 290 | * @private 291 | */ 292 | tdl.writeScriptTag_ = function(src) { 293 | var doc = tdl.global.document; 294 | if (typeof doc != 'undefined' && 295 | !tdl.dependencies_.written[src]) { 296 | tdl.dependencies_.written[src] = true; 297 | var html = '