├── tdl
├── error.jpg
├── screenshot.js
├── log.js
├── fullscreen.js
├── fps.js
├── clock.js
├── string.js
├── sync.js
├── misc.js
├── loader.js
├── buffers.js
├── shader.js
├── base-rs.js
├── models.js
├── framebuffers.js
├── io.js
├── quaternions.js
├── programs.js
└── base.js
├── example
├── assets
│ └── sometexture.png
├── example-requirejs.html
├── example-requirejs.js
├── example2.html
├── line.html
└── example.html
├── .gitignore
├── package.json
├── bower.json
├── jsdoc.conf.json
├── Gruntfile.js
├── README.md
├── docs.md
└── js
└── require.js
/tdl/error.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/greggman/tdl/HEAD/tdl/error.jpg
--------------------------------------------------------------------------------
/example/assets/sometexture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/greggman/tdl/HEAD/example/assets/sometexture.png
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tdl/screenshot.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 This file contains various functions for taking a screenshot
35 | */
36 | define(['./base-rs', './io'], function(BaseRS, IO) {
37 |
38 | tdl.provide('tdl.screenshot');
39 |
40 | /**
41 | * @namespace
42 | */
43 | tdl.screenshot = tdl.screenshot || {};
44 |
45 | /**
46 | * takes a screenshot of a canvas. Sends it to the server to be saved.
47 | */
48 | tdl.screenshot.takeScreenshot = function(canvas) {
49 | tdl.io.sendJSON(
50 | this.url,
51 | {cmd: 'screenshot', dataURL: canvas.toDataURL()},
52 | function() {});
53 | };
54 |
55 | return tdl.screenshot;
56 | });
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tdl/log.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 This file contains objects to deal with logging.
35 | */
36 | define(['./base-rs', './string'], function(BaseRS, Strings) {
37 |
38 | tdl.provide('tdl.log');
39 | /**
40 | * A module for log.
41 | * @namespace
42 | */
43 |
44 | /**
45 | * Wrapped logging function.
46 | * @param {*} msg The message to log.
47 | */
48 | tdl.log = function() {
49 | var str = tdl.string.argsToString(arguments);
50 | if (window.console && window.console.log) {
51 | window.console.log(str);
52 | } else if (window.dump) {
53 | window.dump(str + "\n");
54 | }
55 | };
56 |
57 | /**
58 | * Wrapped logging function.
59 | * @param {*} msg The message to log.
60 | */
61 | tdl.error = function() {
62 | var str = tdl.string.argsToString(arguments);
63 | if (window.console) {
64 | if (window.console.error) {
65 | window.console.error(str);
66 | } else if (window.console.log) {
67 | window.console.log(str);
68 | }
69 | } else if (window.dump) {
70 | window.dump(str + "\n");
71 | }
72 | };
73 |
74 | /**
75 | * Dumps an object to the console.
76 | *
77 | * @param {!Object} obj Object to dump.
78 | * @param {string} opt_prefix string to prefix each value with.
79 | */
80 | tdl.dumpObj = function(obj, opt_prefix) {
81 | tdl.log(tdl.string.objToString(obj, opt_prefix));
82 | };
83 |
84 | return tdl;
85 | });
86 |
--------------------------------------------------------------------------------
/tdl/fullscreen.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 This file contains misc functions to deal with
35 | * fullscreen.
36 | */
37 | define(['./base-rs'], function(BaseRS) {
38 |
39 | /**
40 | * A module for misc.
41 | * @namespace
42 | */
43 | tdl.provide('tdl.fullscreen');
44 | tdl.fullscreen = tdl.fullscreen || {};
45 |
46 | tdl.fullscreen.requestFullScreen = function(element) {
47 | if (element.requestFullscreen) {
48 | element.requestFullscreen();
49 | } else if (element.msRequestFullscreen) {
50 | element.msRequestFullscreen();
51 | } else if (element.webkitRequestFullScreen) {
52 | element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
53 | } else if (element.mozRequestFullScreen) {
54 | element.mozRequestFullScreen();
55 | }
56 | };
57 |
58 | tdl.fullscreen.cancelFullScreen = function(element) {
59 | if (document.exitFullscreen) {
60 | document.exitFullscreen();
61 | } else if (document.msExitFullscreen) {
62 | document.msExitFullscreen();
63 | } else if (document.webkitCancelFullScreen) {
64 | document.webkitCancelFullScreen();
65 | } else if (document.mozCancelFullScreen) {
66 | document.mozCancelFullScreen();
67 | }
68 | };
69 |
70 | tdl.fullscreen.onFullScreenChange = function(element, callback) {
71 | var isFullScreen = function() {
72 | return document.fullscreenElement || document.mozFullScreenElement ||
73 | document.webkitFullscreenElement || document.msFullscreenElement ||
74 | document.mozFullScreen || document.webkitIsFullScreen;
75 | };
76 | document.addEventListener('fullscreenchange', function(event) {
77 | callback(isFullScreen());
78 | });
79 | element.addEventListener('webkitfullscreenchange', function(event) {
80 | callback(isFullScreen());
81 | });
82 | document.addEventListener('mozfullscreenchange', function(event) {
83 | callback(isFullScreen());
84 | });
85 | };
86 |
87 | return tdl.fullscreen;
88 | });
89 |
--------------------------------------------------------------------------------
/tdl/fps.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 This file contains objects to measure frames
35 | * per second.
36 | */
37 | define(['./base-rs'], function(BaseRS) {
38 |
39 | tdl.provide('tdl.fps');
40 | /**
41 | * A module for fps.
42 | * @namespace
43 | */
44 | tdl.fps = tdl.fps || {};
45 |
46 | /**
47 | * Number of frames to average over for computing FPS.
48 | * @type {number}
49 | */
50 | tdl.fps.NUM_FRAMES_TO_AVERAGE = 16;
51 |
52 | /**
53 | * Measures frames per second.
54 | * @constructor
55 | */
56 | tdl.fps.FPSTimer = function() {
57 | // total time spent for last N frames.
58 | this.totalTime_ = tdl.fps.NUM_FRAMES_TO_AVERAGE;
59 |
60 | // elapsed time for last N frames.
61 | this.timeTable_ = [];
62 |
63 | // where to record next elapsed time.
64 | this.timeTableCursor_ = 0;
65 |
66 | // Initialize the FPS elapsed time history table.
67 | for (var tt = 0; tt < tdl.fps.NUM_FRAMES_TO_AVERAGE; ++tt) {
68 | this.timeTable_[tt] = 1.0;
69 | }
70 |
71 | /**
72 | * The instantaneous FPS
73 | * @type {number}
74 | */
75 | this.instantaneousFPS = 0;
76 | /**
77 | * The average FPS
78 | * @type {number}
79 | */
80 | this.averageFPS = 0;
81 | };
82 |
83 | /**
84 | * Updates the fps measurement. You must call this in your
85 | * render loop.
86 | *
87 | * @param {number} elapsedTime The elasped time in seconds
88 | * since the last frame.
89 | */
90 | tdl.fps.FPSTimer.prototype.update = function(elapsedTime) {
91 | // Keep the total time and total active time for the last N frames.
92 | this.totalTime_ += elapsedTime - this.timeTable_[this.timeTableCursor_];
93 |
94 | // Save off the elapsed time for this frame so we can subtract it later.
95 | this.timeTable_[this.timeTableCursor_] = elapsedTime;
96 |
97 | // Wrap the place to store the next time sample.
98 | ++this.timeTableCursor_;
99 | if (this.timeTableCursor_ == tdl.fps.NUM_FRAMES_TO_AVERAGE) {
100 | this.timeTableCursor_ = 0;
101 | }
102 |
103 | this.instantaneousFPS = Math.floor(1.0 / elapsedTime + 0.5);
104 | this.averageFPS = Math.floor(
105 | (1.0 / (this.totalTime_ / tdl.fps.NUM_FRAMES_TO_AVERAGE)) + 0.5);
106 | };
107 |
108 | return tdl.fps;
109 | });
110 |
111 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tdl/clock.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 This file contains various functions for managing a clock
35 | */
36 | define(['./base-rs', './io', './log'], function(BaseRS, IO, Log) {
37 |
38 | tdl.provide('tdl.clock');
39 | /**
40 | * Clock related stuff
41 | * @namespace
42 | */
43 | tdl.clock = tdl.clock || {};
44 |
45 | /**
46 | * Creates a clock. Optionally synced to a server
47 | * @param {number} opt_syncRate. If passed, this is the number of seconds
48 | * between syncing to the server. If not passed the local clock is used.
49 | * Note: If the client is faster than the server this means it's possible
50 | * the clock will report a certain time and then later a previous time.
51 | */
52 | tdl.clock.createClock = function(opt_syncRate, opt_url) {
53 | if (opt_syncRate) {
54 | return new tdl.clock.SyncedClock(opt_syncRate, opt_url);
55 | } else {
56 | return new tdl.clock.LocalClock();
57 | }
58 | };
59 |
60 | /**
61 | * A clock that gets the local current time in seconds.
62 | * @constructor
63 | * @private
64 | */
65 | tdl.clock.LocalClock = function() {
66 | }
67 |
68 | /**
69 | * Gets the current time in seconds.
70 | * @return {number} current time in seconds
71 | */
72 | tdl.clock.LocalClock.prototype.getTime = function() {
73 | return (new Date()).getTime() * 0.001;
74 | }
75 |
76 | /**
77 | * A clock that gets the current time in seconds attempting to eep the clock
78 | * synced to the server.
79 | * @constructor
80 | * @private
81 | */
82 | tdl.clock.SyncedClock = function(opt_syncRate, opt_url) {
83 | this.url = opt_url || window.location.href;
84 | this.syncRate = opt_syncRate || 10;
85 | this.timeOffset = 0;
86 | this.syncToServer();
87 | }
88 |
89 | tdl.clock.SyncedClock.prototype.getLocalTime_ = function() {
90 | return (new Date()).getTime() * 0.001;
91 | }
92 |
93 | tdl.clock.SyncedClock.prototype.syncToServer = function() {
94 | var that = this;
95 | var sendTime = this.getLocalTime_();
96 | tdl.io.sendJSON(this.url, {cmd: 'time'}, function(obj, exception) {
97 | if (exception) {
98 | tdl.log("error: syncToServer: " + exception);
99 | } else {
100 | var receiveTime = that.getLocalTime_();
101 | var duration = receiveTime - sendTime;
102 | var serverTime = obj.time + duration * 0.5;
103 | that.timeOffset = serverTime - receiveTime;
104 | tdl.log("new timeoffset: " + that.timeOffset);
105 | }
106 | setTimeout(function() {
107 | that.syncToServer();
108 | }, that.syncRate * 1000);
109 | });
110 | };
111 |
112 | /**
113 | * Gets the current time in seconds.
114 | * @return {number} current time in seconds
115 | */
116 | tdl.clock.SyncedClock.prototype.getTime = function() {
117 | return (new Date()).getTime() * 0.001 + this.timeOffset;
118 | }
119 |
120 | return tdl.clock;
121 | });
122 |
--------------------------------------------------------------------------------
/tdl/string.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 This file contains objects strings.
35 | */
36 | define(['./base-rs'], function(BaseRS) {
37 |
38 | tdl.provide('tdl.string');
39 | /**
40 | * A module for string.
41 | * @namespace
42 | */
43 | tdl.string = tdl.string || {};
44 |
45 | /**
46 | * Whether a haystack ends with a needle.
47 | * @param {string} haystack String to search
48 | * @param {string} needle String to search for.
49 | * @return {boolean} True if haystack ends with needle.
50 | */
51 | tdl.string.endsWith = function(haystack, needle) {
52 | return haystack.substr(haystack.length - needle.length) === needle;
53 | };
54 |
55 | /**
56 | * Whether a haystack starts with a needle.
57 | * @param {string} haystack String to search
58 | * @param {string} needle String to search for.
59 | * @return {boolean} True if haystack starts with needle.
60 | */
61 | tdl.string.startsWith = function(haystack, needle) {
62 | return haystack.substr(0, needle.length) === needle;
63 | };
64 |
65 | /**
66 | * Converts a non-homogenious array into a string.
67 | * @param {Array.<*>} args Args to turn into a string
68 | * @return {string} string representing args
69 | */
70 | tdl.string.argsToString = function(args) {
71 | var lastArgWasNumber = false;
72 | var numArgs = args.length;
73 | var strs = [];
74 | for (var ii = 0; ii < numArgs; ++ii) {
75 | var arg = args[ii];
76 | if (arg === undefined) {
77 | strs.push('undefined');
78 | } else if (typeof arg == 'number') {
79 | if (lastArgWasNumber) {
80 | strs.push(", ");
81 | }
82 | if (arg == Math.floor(arg)) {
83 | strs.push(arg.toFixed(0));
84 | } else {
85 | strs.push(arg.toFixed(3));
86 | }
87 | lastArgWasNumber = true;
88 | } else if (window.Float32Array && arg instanceof Float32Array) {
89 | // TODO(gman): Make this handle other types of arrays.
90 | strs.push(tdl.string.argsToString(arg));
91 | } else {
92 | strs.push(arg.toString());
93 | lastArgWasNumber = false;
94 | }
95 | }
96 | return strs.join("");
97 | };
98 |
99 | /**
100 | * Converts an object into a string. Similar to JSON.stringify but just used
101 | * for debugging.
102 | * @param {*} obj object to stringify.
103 | * @param {string?} opt_prefix optional prefix
104 | * @return {string} stringified object
105 | */
106 | tdl.string.objToString = function(obj, opt_prefix) {
107 | var strs = [];
108 |
109 | function objToString(obj, opt_prefix) {
110 | opt_prefix = opt_prefix || "";
111 | if (typeof obj == 'object') {
112 | if (obj.length !== undefined) {
113 | for (var ii = 0; ii < obj.length; ++ii) {
114 | objToString(obj[ii], opt_prefix + "[" + ii + "]");
115 | }
116 | } else {
117 | for (var name in obj) {
118 | objToString(obj[name], opt_prefix + "." + name);
119 | }
120 | }
121 | } else {
122 | strs.push(tdl.string.argsToString([opt_prefix, ": ", obj]));
123 | }
124 | }
125 |
126 | objToString(obj);
127 |
128 | return strs.join("\n");
129 | };
130 |
131 | return tdl.string;
132 | });
133 |
134 |
--------------------------------------------------------------------------------
/tdl/sync.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 This file contains objects to sync app settings across
35 | * browsers.
36 | */
37 | define(
38 | [ './base-rs',
39 | './log',
40 | './io',
41 | './misc',
42 | ], function(
43 | BaseRS,
44 | Log,
45 | IO,
46 | Misc) {
47 |
48 | tdl.provide('tdl.sync');
49 | /**
50 | * A module for sync.
51 | * @namespace
52 | */
53 | tdl.sync = tdl.sync || {};
54 |
55 | /**
56 | * Manages synchronizing settings across browsers. Requires a server
57 | * running to support it. Note that even if you don't want to sync
58 | * across browsers you can still use the SyncManager.
59 | *
60 | * @constructor
61 | * @param {!Object} settings The object that contains the settings you
62 | * want kept in sync.
63 | */
64 | tdl.sync.SyncManager = function(settings, opt_callback) {
65 | this.settings = settings;
66 | this.putCount = 0;
67 | this.getCount = 0;
68 | this.callback = opt_callback || function() {};
69 |
70 | // This probably should not be here.
71 | tdl.misc.applyUrlSettings(settings);
72 | }
73 |
74 | /**
75 | * Initialize the sync manager to start syncing settings with a server.
76 | * @param {string} url Url of server.
77 | * @param {boolean} slave true if this page is a slave. Slaves only receive
78 | * settings from the server. Non slaves send settings the server.
79 | */
80 | tdl.sync.SyncManager.prototype.init = function(url, slave) {
81 | var that = this;
82 | this.sync = true;
83 | this.slave = slave;
84 | this.socket = new WebSocket(url);
85 | this.opened = false;
86 | this.queued = [];
87 | this.socket.onopen = function(event) {
88 | tdl.log("SOCKET OPENED!");
89 | that.opened = true;
90 | for (var ii = 0; ii < that.queued.length; ++ii) {
91 | var settings = that.queued[ii];
92 | ++that.putCount;
93 | tdl.log("--PUT:[", that.putCount, "]-------------");
94 | tdl.log(settings);
95 | that.socket.send(settings);
96 | }
97 | that.queued = [];
98 | };
99 | this.socket.onerror = function(event) {
100 | tdl.log("SOCKET ERROR!");
101 | };
102 | this.socket.onclose = function(event) {
103 | tdl.log("SOCKET CLOSED!");
104 | };
105 | this.socket.onmessage = function(event) {
106 | ++that.getCount;
107 | tdl.log("--GET:[", that.getCount, ":", event.type, "]-------------");
108 | var obj = JSON.parse(event.data);
109 | tdl.dumpObj(obj);
110 | tdl.misc.copyProperties(obj, that.settings);
111 | that.callback(obj);
112 | };
113 | };
114 |
115 | /**
116 | * Sets the settings.
117 | *
118 | * If we are synchronizing settings the settings are sent to the server.
119 | * Otherwise they are applied directy.
120 | *
121 | * @param {!Object} settings Object with new settings.
122 | */
123 | tdl.sync.SyncManager.prototype.setSettings = function(settings) {
124 | if (this.sync) {
125 | if (!this.slave) {
126 | if (this.socket) {
127 | if (!this.opened) {
128 | this.queued.push(JSON.stringify(settings));
129 | } else {
130 | ++this.putCount;
131 | tdl.log("--PUT:[", this.putCount, "]-------------");
132 | tdl.dumpObj(settings);
133 | this.socket.send(JSON.stringify(settings));
134 | }
135 | }
136 | }
137 | } else {
138 | tdl.misc.copyProperties(settings, this.settings);
139 | this.callback(settings);
140 | }
141 | };
142 |
143 | return tdl.sync;
144 | });
145 |
146 |
--------------------------------------------------------------------------------
/tdl/misc.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 This file contains misc functions that don't fit elsewhere.
35 | */
36 | define(['./base-rs', './log'], function(BaseRS, Log) {
37 |
38 | tdl.provide('tdl.misc');
39 | /**
40 | * A module for misc.
41 | * @namespace
42 | */
43 | tdl.misc = tdl.misc || {};
44 |
45 | /**
46 | * Lets you parse JS object literal has JSON.
47 | *
48 | * JSON requires property names be quoted, js object literal
49 | * does not.
50 | *
51 | * @example
52 | * var o = tdl.misc.parseUnquoteJSObjectString('{a:"b",c:123}');
53 | * @param {string} str js object literal string.
54 | */
55 | tdl.misc.parseUnquotedJSObjectString = function(str) {
56 | // NOTE: does not handle strings with : in them.
57 | var quoted = str.replace(/([a-zA-Z0-9_]+):/g,'"$1":')
58 | return JSON.parse(quoted);
59 | };
60 |
61 | /**
62 | * Applies part of the query string to an object.
63 | * @param {object} object to apply properties to
64 | * @param {string?} name of query parameter that has settings.
65 | * Default = 'settings'
66 | * @example
67 | * // Assuming the current URL is
68 | * // http://foo.com?settings={a:123,b:"hello",c:[1,2]}
69 | * // then
70 | * var o = {};
71 | * tdl.misc.applyUrlSettings(o);
72 | * console.log(JSON.stringify(o, undefined, " "));
73 | *
74 | * // should print
75 | * {
76 | * "a": 123,
77 | * "b": "hello",
78 | * "c": [1, 2]
79 | * }
80 | */
81 | tdl.misc.applyUrlSettings = function(obj, opt_argumentName) {
82 | var argumentName = opt_argumentName || 'settings';
83 | try {
84 | var s = window.location.href;
85 | var q = s.indexOf("?");
86 | var e = s.indexOf("#");
87 | if (e < 0) {
88 | e = s.length;
89 | }
90 | var query = s.substring(q + 1, e);
91 | //tdl.log("query:", query);
92 | var pairs = query.split("&");
93 | //tdl.log("pairs:", pairs.length);
94 | for (var ii = 0; ii < pairs.length; ++ii) {
95 | var keyValue = pairs[ii].split("=");
96 | var key = keyValue[0];
97 | var value = decodeURIComponent(keyValue[1]);
98 | //tdl.log(ii, ":", key, "=", value);
99 | switch (key) {
100 | case argumentName:
101 | //tdl.log(value);
102 | var settings = tdl.misc.parseUnquotedJSObjectString(value)
103 | //tdl.log("settings:", settings);
104 | tdl.misc.copyProperties(settings, obj);
105 | break;
106 | }
107 | }
108 | } catch (e) {
109 | tdl.error(e);
110 | tdl.error("settings:", settings);
111 | return;
112 | }
113 | };
114 |
115 | /**
116 | * Copies properties from obj to dst recursively.
117 | * @private
118 | * @param {!Object} obj Object with new settings.
119 | * @param {!Object} dst Object to receive new settings.
120 | */
121 | tdl.misc.copyProperties = function(obj, dst) {
122 | for (var name in obj) {
123 | var value = obj[name];
124 | if (value instanceof Array) {
125 | //tdl.log("apply->: ", name, "[]");
126 | var newDst = dst[name];
127 | if (!newDst) {
128 | newDst = [];
129 | dst[name] = newDst;
130 | }
131 | tdl.misc.copyProperties(value, newDst);
132 | } else if (typeof value == 'object') {
133 | //tdl.log("apply->: ", name);
134 | var newDst = dst[name];
135 | if (!newDst) {
136 | newDst = {};
137 | dst[name] = newDst;
138 | }
139 | tdl.misc.copyProperties(value, newDst);
140 | } else {
141 | //tdl.log("apply: ", name, "=", value);
142 | dst[name] = value;
143 | }
144 | }
145 | };
146 |
147 | return tdl.misc;
148 | });
149 |
--------------------------------------------------------------------------------
/example/example-requirejs.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 | WebGL TDL Example
36 |
78 |
79 |
80 |
81 |
82 |
85 |
86 |
87 |
88 |
89 |
113 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/tdl/loader.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 This file contains a loader class for helping to load
35 | * muliple assets in an asynchronous manner.
36 | */
37 | define(['./base-rs', './io'], function(BaseRS, IO) {
38 |
39 | tdl.provide('tdl.loader');
40 | /**
41 | * A Module with a loader class for helping to load muliple assets in an
42 | * asynchronous manner.
43 | * @namespace
44 | */
45 | tdl.loader = tdl.loader || {};
46 |
47 | /**
48 | * @callback Loader~Finished
49 | * @memberOf tdl.loader
50 | */
51 | /**
52 | * A simple Loader class to call some callback when everything has loaded.
53 | * @constructor
54 | * @param {tdl.loader.Loader~Finished} onFinished Function to call when
55 | * final item has loaded.
56 | */
57 | tdl.loader.Loader = function(onFinished) {
58 | this.count_ = 1;
59 | this.onFinished_ = onFinished;
60 |
61 | /**
62 | * The LoadInfo for this loader you can use to track progress.
63 | * @type {!tdl.io.LoadInfo}
64 | */
65 | this.loadInfo = tdl.io.createLoadInfo();
66 | };
67 |
68 | /**
69 | * Creates a Loader for helping to load a bunch of items asychronously.
70 | *
71 | * The way you use this is as follows.
72 | *
73 | * @example
74 | * var loader = tdl.loader.createLoader(myFinishedCallback);
75 | * loader.loadTextFile(text1Url, callbackForText);
76 | * loader.loadTextFile(text2Url, callbackForText);
77 | * loader.loadTextFile(text3Url, callbackForText);
78 | * loader.finish();
79 | *
80 | * The loader guarantees that myFinishedCallback will be called after
81 | * all the items have been loaded.
82 | *
83 | * @param {tdl.loader.Loader~Finished} onFinished Function to call when
84 | * final item has loaded.
85 | * @return {tdl.loader.Loader} A Loader Object.
86 | */
87 | tdl.loader.createLoader = function(onFinished) {
88 | return new tdl.loader.Loader(onFinished);
89 | };
90 |
91 | /**
92 | * @callback Loader~Text
93 | * @param {string?} str contents of file
94 | * @param {error?} error or null of no error.
95 | */
96 |
97 | /**
98 | * Loads a text file.
99 | * @param {string} url URL of scene to load.
100 | * @param {Loader~Text} onTextLoaded
101 | * Function to call when the file is loaded. It will be
102 | * passed the contents of the file as a string and an
103 | * exception which is null on success.
104 | */
105 | tdl.loader.Loader.prototype.loadTextFile = function(url, onTextLoaded) {
106 | var that = this; // so the function below can see "this".
107 | ++this.count_;
108 | var loadInfo = tdl.io.loadTextFile(url, function(string, exception) {
109 | onTextLoaded(string, exception);
110 | that.countDown_();
111 | });
112 | this.loadInfo.addChild(loadInfo);
113 | };
114 |
115 | /**
116 | * Creates a loader that is tracked by this loader so that when the new loader
117 | * is finished it will be reported to this loader.
118 | * @param {tdl.loader.Loader~Finished} onFinished Function
119 | * to be called when everything loaded with this loader has
120 | * finished.
121 | * @return {tdl.loader.Loader} The new Loader.
122 | */
123 | tdl.loader.Loader.prototype.createLoader = function(onFinished) {
124 | var that = this;
125 | ++this.count_;
126 | var loader = tdl.loader.createLoader(function() {
127 | onFinished();
128 | that.countDown_();
129 | });
130 | this.loadInfo.addChild(loader.loadInfo);
131 | return loader;
132 | };
133 |
134 | /**
135 | * Counts down the internal count and if it gets to zero calls the callback.
136 | * @private
137 | */
138 | tdl.loader.Loader.prototype.countDown_ = function() {
139 | --this.count_;
140 | if (this.count_ === 0) {
141 | this.onFinished_();
142 | }
143 | };
144 |
145 | /**
146 | * Finishes the loading process.
147 | * Actually this just calls countDown_ to account for the count starting at 1.
148 | * @private
149 | */
150 | tdl.loader.Loader.prototype.finish = function() {
151 | this.countDown_();
152 | };
153 |
154 | return tdl.loader;
155 | });
156 |
--------------------------------------------------------------------------------
/tdl/buffers.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 This file contains objects to deal with WebGL
35 | * buffers.
36 | */
37 | define(['./base-rs'], function(BaseRS) {
38 |
39 | tdl.provide('tdl.buffers');
40 | /**
41 | * A module for buffers.
42 | * @namespace
43 | */
44 | tdl.buffers = tdl.buffers || {};
45 |
46 | /**
47 | * A Buffer represnets a WebGL buffer.
48 | * @constructor
49 | * @param {tdl.primitives.AttribBuffer} array AttribBuffer with
50 | * data.
51 | * @param {number?} opt_target Assumes gl.ARRAY_BUFFER
52 | */
53 | tdl.buffers.Buffer = function(array, opt_target) {
54 | var target = opt_target || gl.ARRAY_BUFFER;
55 | var buf = gl.createBuffer();
56 | this.target = target;
57 | this.buf = buf;
58 | this.set(array);
59 | };
60 |
61 | /**
62 | * Sets the contents of this buffer from the contents of the
63 | * given AttribBuffer.
64 | * @param {tdl.primitives.AttribBuffer} array AttribBuffer with
65 | * data.
66 | * @param {number?} opt_usage GL buffer usage. Defaults to
67 | * gl.STATIC_DRAW.
68 | */
69 | tdl.buffers.Buffer.prototype.set = function(array, opt_usage) {
70 | this.numComponents_ = array.numComponents;
71 | this.numElements_ = array.numElements;
72 | this.totalComponents_ = this.numComponents_ * this.numElements_;
73 | if (array.buffer instanceof Float32Array) {
74 | this.type_ = gl.FLOAT;
75 | this.normalize_ = false;
76 | } else if (array.buffer instanceof Uint8Array) {
77 | this.type_ = gl.UNSIGNED_BYTE;
78 | this.normalize_ = true;
79 | } else if (array.buffer instanceof Int8Array) {
80 | this.type_ = gl.BYTE;
81 | this.normalize_ = true;
82 | } else if (array.buffer instanceof Uint16Array) {
83 | this.type_ = gl.UNSIGNED_SHORT;
84 | this.normalize_ = true;
85 | } else if (array.buffer instanceof Int16Array) {
86 | this.type_ = gl.SHORT;
87 | this.normalize_ = true;
88 | } else {
89 | throw("unhandled type:" + (typeof array.buffer));
90 | }
91 | gl.bindBuffer(this.target, this.buf);
92 | gl.bufferData(this.target, array.buffer, opt_usage || gl.STATIC_DRAW);
93 | }
94 |
95 | /**
96 | * Sets part of a buffer.
97 | * @param {ArrayBufferView} array some typed array buffer view
98 | * @param {number} the offset in bytes into the buffer to copy
99 | * the array.
100 | */
101 | tdl.buffers.Buffer.prototype.setRange = function(array, offset) {
102 | gl.bindBuffer(this.target, this.buf);
103 | gl.bufferSubData(this.target, offset, array);
104 | };
105 |
106 | /**
107 | * Gets the type of the buffer. Eg. `gl.FLOAT`
108 | * @return {number}
109 | */
110 | tdl.buffers.Buffer.prototype.type = function() {
111 | return this.type_;
112 | };
113 |
114 | /**
115 | * Gets the number of components per element of buffer.
116 | * @return {number} num components per element in buffer
117 | */
118 | tdl.buffers.Buffer.prototype.numComponents = function() {
119 | return this.numComponents_;
120 | };
121 |
122 | /**
123 | * Gets the number of elements in the buffer
124 | * @return {number} num elements in buffer
125 | */
126 | tdl.buffers.Buffer.prototype.numElements = function() {
127 | return this.numElements_;
128 | };
129 |
130 | /**
131 | * Gets the total components in the buffer.
132 | * @return {number} Basically this is numComponents *
133 | * numElements
134 | */
135 | tdl.buffers.Buffer.prototype.totalComponents = function() {
136 | return this.totalComponents_;
137 | };
138 |
139 | /**
140 | * Get the WebGLBuffer for this buffer.
141 | * @return {WebGLBuffer} the WebGLBuffer for this buffer.
142 | */
143 | tdl.buffers.Buffer.prototype.buffer = function() {
144 | return this.buf;
145 | };
146 |
147 | /**
148 | * Get the stride?
149 | * @return {number} stride.
150 | */
151 | tdl.buffers.Buffer.prototype.stride = function() {
152 | return 0;
153 | };
154 |
155 | /**
156 | * Gets whether the data in this buffer should be normalized.
157 | * @return {boolean} normalizaiton.
158 | */
159 | tdl.buffers.Buffer.prototype.normalize = function() {
160 | return this.normalize_;
161 | }
162 |
163 | /**
164 | * Get the offset?
165 | * @return {number} offset.
166 | */
167 | tdl.buffers.Buffer.prototype.offset = function() {
168 | return 0;
169 | };
170 |
171 | return tdl.buffers;
172 | });
173 |
--------------------------------------------------------------------------------
/tdl/shader.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 This file contains a class which assists with the
35 | * loading of GLSL shaders.
36 | */
37 | define(['./base-rs'], function(BaseRS) {
38 |
39 | tdl.provide('tdl.shader');
40 | /**
41 | * A module for shaders.
42 | * @namespace
43 | */
44 | tdl.shader = tdl.shader || {};
45 |
46 | /**
47 |
48 | * Loads a shader from vertex and fragment programs specified in
49 | * "script" nodes in the HTML page. This provides a convenient
50 | * mechanism for writing GLSL snippets without the burden of
51 | * additional syntax like per-line quotation marks.
52 | * @param {WebGLRenderingContext} gl The WebGLRenderingContext
53 | * into which the shader will be loaded.
54 | * @param {string} vertexScriptName The name of the HTML Script node
55 | * containing the vertex program.
56 | * @param {string} fragmentScriptName The name of the HTML Script node
57 | * containing the fragment program.
58 | */
59 | tdl.shader.loadFromScriptNodes = function(gl,
60 | vertexScriptName,
61 | fragmentScriptName) {
62 | var vertexScript = document.getElementById(vertexScriptName);
63 | var fragmentScript = document.getElementById(fragmentScriptName);
64 | if (!vertexScript || !fragmentScript)
65 | return null;
66 | return new tdl.shader.Shader(gl,
67 | vertexScript.text,
68 | fragmentScript.text);
69 | }
70 |
71 | /**
72 | * Helper which convers GLSL names to JavaScript names.
73 | * @private
74 | */
75 | tdl.shader.glslNameToJs_ = function(name) {
76 | return name.replace(/_(.)/g, function(_, p1) { return p1.toUpperCase(); });
77 | }
78 |
79 | /**
80 | * Creates a new Shader object, loading and linking the given vertex
81 | * and fragment shaders into a program.
82 | * @param {WebGLRenderingContext} gl The WebGLRenderingContext
83 | * into which the shader will be loaded.
84 | * @param {string} vertex The vertex shader.
85 | * @param {string} fragment The fragment shader.
86 | */
87 | tdl.shader.Shader = function(gl, vertex, fragment) {
88 | this.program = gl.createProgram();
89 | this.gl = gl;
90 |
91 | var vs = this.loadShader(this.gl.VERTEX_SHADER, vertex);
92 | if (!vs) {
93 | tdl.log("couldn't load shader")
94 | }
95 | this.gl.attachShader(this.program, vs);
96 | this.gl.deleteShader(vs);
97 |
98 | var fs = this.loadShader(this.gl.FRAGMENT_SHADER, fragment);
99 | if (!fs) {
100 | tdl.log("couldn't load shader")
101 | }
102 | this.gl.attachShader(this.program, fs);
103 | this.gl.deleteShader(fs);
104 |
105 | this.gl.linkProgram(this.program);
106 | this.gl.useProgram(this.program);
107 |
108 | // Check the link status
109 | var linked = this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS);
110 | if (!linked && !this.gl.isContextLost()) {
111 | var infoLog = this.gl.getProgramInfoLog(this.program);
112 | tdl.error("Error linking program:\n" + infoLog);
113 | this.gl.deleteProgram(this.program);
114 | this.program = null;
115 | return;
116 | }
117 |
118 | // find uniforms and attributes
119 | var re = /(uniform|attribute)\s+\S+\s+(\S+)\s*;/g;
120 | var match = null;
121 | while ((match = re.exec(vertex + '\n' + fragment)) != null) {
122 | var glslName = match[2];
123 | var jsName = tdl.shader.glslNameToJs_(glslName);
124 | var loc = -1;
125 | if (match[1] == "uniform") {
126 | this[jsName + "Loc"] = this.getUniform(glslName);
127 | } else if (match[1] == "attribute") {
128 | this[jsName + "Loc"] = this.getAttribute(glslName);
129 | }
130 | if (loc >= 0) {
131 | this[jsName + "Loc"] = loc;
132 | }
133 | }
134 | }
135 |
136 | /**
137 | * Binds the shader's program.
138 | */
139 | tdl.shader.Shader.prototype.bind = function() {
140 | this.gl.useProgram(this.program);
141 | }
142 |
143 | /**
144 | * Helper for loading a shader.
145 | * @private
146 | */
147 | tdl.shader.Shader.prototype.loadShader = function(type, shaderSrc) {
148 | var shader = this.gl.createShader(type);
149 | if (shader == null) {
150 | return null;
151 | }
152 |
153 | // Load the shader source
154 | this.gl.shaderSource(shader, shaderSrc);
155 | // Compile the shader
156 | this.gl.compileShader(shader);
157 | // Check the compile status
158 | if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
159 | var infoLog = this.gl.getShaderInfoLog(shader);
160 | tdl.error("Error compiling shader:\n" + infoLog);
161 | this.gl.deleteShader(shader);
162 | return null;
163 | }
164 | return shader;
165 | }
166 |
167 | /**
168 | * Helper for looking up an attribute's location.
169 | * @private
170 | */
171 | tdl.shader.Shader.prototype.getAttribute = function(name) {
172 | return this.gl.getAttribLocation(this.program, name);
173 | };
174 |
175 | /**
176 | * Helper for looking up an attribute's location.
177 | * @private
178 | */
179 | tdl.shader.Shader.prototype.getUniform = function(name) {
180 | return this.gl.getUniformLocation(this.program, name);
181 | }
182 |
183 | return tdl.shader;
184 | });
185 |
--------------------------------------------------------------------------------
/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/models.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 This file contains objects to manage models.
35 | */
36 | define(['./base-rs', './buffers'], function(BaseRS, Buffers) {
37 |
38 | tdl.provide('tdl.models');
39 | /**
40 | * A module for models.
41 | * @namespace
42 | */
43 | tdl.models = tdl.models || {};
44 |
45 | /**
46 | * Manages a program, buffers and textures for easier drawing.
47 | * @constructor
48 | * @param {tdl.programs.Program} program The program to render
49 | * this model with
50 | * @param {Object.} arrays The
51 | * AttribBuffers to bind to draw this model.
52 | * @param {Object.} textures The textures to
53 | * bind to draw this model.
54 | * @param {number} opt_mode Mode to call drawElements with. Default =
55 | * gl.TRIANGLES
56 | */
57 | tdl.models.Model = function(program, arrays, textures, opt_mode) {
58 | this.buffers = { };
59 | this.setBuffers(arrays);
60 |
61 | var textureUnits = { }
62 | var unit = 0;
63 | for (var texture in program.textures) {
64 | textureUnits[texture] = unit++;
65 | }
66 |
67 | this.mode = (opt_mode === undefined) ? gl.TRIANGLES : opt_mode;
68 | this.textures = textures;
69 | this.textureUnits = textureUnits;
70 | this.setProgram(program);
71 | }
72 |
73 | /**
74 | * Sets the program for this model
75 | * @param {tdl.programs.Program} program The new program for
76 | * this model.
77 | */
78 | tdl.models.Model.prototype.setProgram = function(program) {
79 | this.program = program;
80 | }
81 |
82 | /**
83 | * Sets a buffer on this model
84 | * @param {string} name The name of the buffer to set.
85 | * @param {tdl.primitives.AttribBuffer} array The AttribBuffer
86 | * to set on this model.
87 | * @param {boolean?} true if a new WebGLBuffer should be
88 | * created.
89 | */
90 | tdl.models.Model.prototype.setBuffer = function(name, array, opt_newBuffer) {
91 | var target = (name == 'indices') ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
92 | var b = this.buffers[name];
93 | if (!b || opt_newBuffer) {
94 | b = new tdl.buffers.Buffer(array, target);
95 | } else {
96 | b.set(array);
97 | }
98 | this.buffers[name] = b;
99 | };
100 |
101 | /**
102 | * Sets the buffers on this model
103 | * @param {Object.} arrays The
104 | * AttribBuffers to bind to draw this model.
105 | * @param {boolean?} true if new WebGLBuffers should be created.
106 | */
107 | tdl.models.Model.prototype.setBuffers = function(arrays, opt_newBuffers) {
108 | var that = this;
109 | for (var name in arrays) {
110 | this.setBuffer(name, arrays[name], opt_newBuffers);
111 | }
112 | if (this.buffers.indices) {
113 | this.baseBuffer = this.buffers.indices;
114 | this.drawFunc = function(totalComponents, startOffset) {
115 | gl.drawElements(that.mode, totalComponents, gl.UNSIGNED_SHORT, startOffset);
116 | }
117 | } else {
118 | for (var key in this.buffers) {
119 | this.baseBuffer = this.buffers[key];
120 | break;
121 | }
122 | this.drawFunc = function(totalComponents, startOffset) {
123 | gl.drawArrays(that.mode, startOffset, totalComponents);
124 | }
125 | }
126 | };
127 |
128 | tdl.models.Model.prototype.applyUniforms_ = function(opt_uniforms) {
129 | if (opt_uniforms) {
130 | this.program.applyUniforms(opt_uniforms);
131 | }
132 | };
133 |
134 | /**
135 | * Sets up the shared parts of drawing this model. Uses the
136 | * program, binds the buffers, sets the textures.
137 | *
138 | * @param {...Object.} opt_uniforms An object of
139 | * names to values to set on this models uniforms.
140 | */
141 | tdl.models.Model.prototype.drawPrep = function(opt_uniforms) {
142 | var program = this.program;
143 | var buffers = this.buffers;
144 | var textures = this.textures;
145 |
146 | program.use();
147 | for (var buffer in buffers) {
148 | var b = buffers[buffer];
149 | if (buffer == 'indices') {
150 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, b.buffer());
151 | } else {
152 | var attrib = program.attrib[buffer];
153 | if (attrib) {
154 | attrib(b);
155 | }
156 | }
157 | }
158 |
159 | this.applyUniforms_(textures);
160 | for (var ii = 0; ii < arguments.length; ++ii) {
161 | this.applyUniforms_(arguments[ii]);
162 | }
163 | };
164 |
165 | /**
166 | * Draws this model.
167 | *
168 | * After calling tdl.models.Model.drawPrep you can call this
169 | * function multiple times to draw this model.
170 | *
171 | * @param {Object.} opt_uniforms An object of names to
172 | * values to set on this models uniforms.
173 | * @param {Object.} opt_textures An object of names to
174 | * textures to set on this models uniforms.
175 | */
176 | tdl.models.Model.prototype.draw = function() {
177 | var buffers = this.buffers;
178 | // if no indices buffer then assume drawFunc is drawArrays and thus
179 | // totalComponents is the number of vertices (not indices).
180 | var totalComponents = buffers.indices? buffers.indices.totalComponents(): buffers.position.numElements();
181 | var startOffset = 0;
182 | for (var ii = 0; ii < arguments.length; ++ii) {
183 | var arg = arguments[ii];
184 | if (typeof arg == 'number') {
185 | switch (ii) {
186 | case 0:
187 | totalComponents = arg;
188 | break;
189 | case 1:
190 | startOffset = arg;
191 | break;
192 | default:
193 | throw 'unvalid argument';
194 | }
195 | } else {
196 | this.applyUniforms_(arg);
197 | }
198 | }
199 |
200 | this.drawFunc(totalComponents, startOffset);
201 | };
202 |
203 | return tdl.models;
204 | });
205 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tdl/framebuffers.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 This file contains objects to manage
35 | * framebuffers.
36 | */
37 | define(['./base-rs', './textures'], function(BaseRS, Textures) {
38 |
39 | tdl.provide('tdl.framebuffers');
40 | /**
41 | * A module for textures.
42 | * @namespace
43 | */
44 | tdl.framebuffers = tdl.framebuffers || {};
45 |
46 | /**
47 | * Creates a framebuffer
48 | * @param {number} width width of framebuffer.
49 | * @param {number} height height of framebuffer.
50 | * @param {boolean?} opt_depth true = make a depth attachment
51 | * @return {tdl.Framebuffer} the created framebuffer.
52 | */
53 | tdl.framebuffers.createFramebuffer = function(width, height, opt_depth) {
54 | return new tdl.framebuffers.Framebuffer(width, height, opt_depth);
55 | };
56 |
57 | /**
58 | * Creates a cubemap framebuffer
59 | * @param {number} size size of edge of cube.
60 | * @param {boolean?} opt_depth true = make a depth attachment
61 | * @return {tdl.CubeFramebuffer} the created framebuffer.
62 | */
63 | tdl.framebuffers.createCubeFramebuffer = function(size, opt_depth) {
64 | return new tdl.framebuffers.CubeFramebuffer(size, opt_depth);
65 | };
66 |
67 | /**
68 | * A class to represent the backbuffer (the canvas)
69 | * @constructor
70 | */
71 | tdl.framebuffers.BackBuffer = function() {
72 | this.depth = true;
73 | this.buffer = null;
74 | };
75 |
76 | /**
77 | * Binds the backbuffer as the current render target.
78 | */
79 | tdl.framebuffers.BackBuffer.prototype.bind = function() {
80 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
81 | gl.viewport(0, 0, this.width, this.height);
82 | };
83 |
84 | if (Object.prototype.__defineSetter__) {
85 | tdl.framebuffers.BackBuffer.prototype.__defineGetter__(
86 | 'width',
87 | function () {
88 | return gl.drawingBufferWidth || gl.canvas.width;
89 | }
90 | );
91 |
92 | tdl.framebuffers.BackBuffer.prototype.__defineGetter__(
93 | 'height',
94 | function () {
95 | return gl.drawingBufferHeight || gl.canvas.height;
96 | }
97 | );
98 | }
99 |
100 | /**
101 | * Get a FrameBuffer for the backbuffer.
102 | * Use this where you need to pass in a framebuffer, but you really
103 | * mean the backbuffer, so that binding it works as expected.
104 | * @return {tdl.BackBuffer} the created BackBuffer.
105 | */
106 | tdl.framebuffers.getBackBuffer = function() {
107 | return new tdl.framebuffers.BackBuffer();
108 | };
109 |
110 | /**
111 | * Represnets a WebGLFramebuffer
112 | * @constructor
113 | * @param {number} width width of framebuffer.
114 | * @param {number} height height of framebuffer.
115 | * @param {boolean?} opt_depth true = create a depth attachment
116 | */
117 | tdl.framebuffers.Framebuffer = function(width, height, opt_depth) {
118 | this.width = width;
119 | this.height = height;
120 | this.depth = opt_depth;
121 | var tex = new tdl.textures.SolidTexture([0,0,0,0]);
122 | this.initializeTexture(tex);
123 |
124 | var fb = gl.createFramebuffer();
125 | gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
126 | gl.framebufferTexture2D(
127 | gl.FRAMEBUFFER,
128 | gl.COLOR_ATTACHMENT0,
129 | gl.TEXTURE_2D,
130 | tex.texture,
131 | 0);
132 |
133 | if (this.depth) {
134 | if (gl.tdl.depthTexture) {
135 | var dt = new tdl.textures.DepthTexture(this.width, this.height);
136 | gl.framebufferTexture2D(
137 | gl.FRAMEBUFFER,
138 | gl.DEPTH_ATTACHMENT,
139 | gl.TEXTURE_2D,
140 | dt.texture,
141 | 0);
142 | this.depthTexture = dt;
143 | } else {
144 | var db = gl.createRenderbuffer();
145 | gl.bindRenderbuffer(gl.RENDERBUFFER, db);
146 | gl.renderbufferStorage(
147 | gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.width, this.height);
148 | gl.framebufferRenderbuffer(
149 | gl.FRAMEBUFFER,
150 | gl.DEPTH_ATTACHMENT,
151 | gl.RENDERBUFFER,
152 | db);
153 | gl.bindRenderbuffer(gl.RENDERBUFFER, null);
154 | this.depthRenderbuffer = db;
155 | }
156 | }
157 |
158 | var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
159 | if (status != gl.FRAMEBUFFER_COMPLETE && !gl.isContextLost()) {
160 | throw("gl.checkFramebufferStatus() returned " +
161 | tdl.webgl.glEnumToString(status));
162 | }
163 | this.framebuffer = fb;
164 | this.texture = tex;
165 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
166 | };
167 |
168 | /**
169 | * Bind this framebuffer as the current render target.
170 | */
171 | tdl.framebuffers.Framebuffer.prototype.bind = function() {
172 | gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
173 | gl.viewport(0, 0, this.width, this.height);
174 | };
175 |
176 | /**
177 | * Unbinds this framebuffer as the current render target
178 | */
179 | tdl.framebuffers.Framebuffer.prototype.unbind = function() {
180 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
181 | gl.viewport(
182 | 0, 0,
183 | gl.drawingBufferWidth || gl.canvas.width,
184 | gl.drawingBufferHeight || gl.canvas.height);
185 | };
186 |
187 | tdl.framebuffers.Framebuffer.prototype.initializeTexture = function(tex) {
188 | gl.bindTexture(gl.TEXTURE_2D, tex.texture);
189 | tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.LINEAR);
190 | tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
191 | tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
192 | tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
193 | gl.texImage2D(gl.TEXTURE_2D,
194 | 0, // level
195 | gl.RGBA, // internalFormat
196 | this.width, // width
197 | this.height, // height
198 | 0, // border
199 | gl.RGBA, // format
200 | gl.UNSIGNED_BYTE, // type
201 | null); // data
202 | };
203 |
204 | /**
205 | * Represnents a Cube Map framebuffer
206 | * @constructor
207 | * @param {number} size size of edge of cube.
208 | * @param {boolean?} opt_depth true = make a depth attachment
209 | */
210 | tdl.framebuffers.CubeFramebuffer = function(size, opt_depth) {
211 | this.size = size;
212 | this.depth = opt_depth;
213 | var tex = new tdl.textures.CubeMap(this.size);
214 | gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex.texture);
215 | tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.LINEAR);
216 | tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
217 | tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
218 | tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
219 | for (var ff = 0; ff < 6; ++ff) {
220 | gl.texImage2D(tdl.textures.CubeMap.faceTargets[ff],
221 | 0, // level
222 | gl.RGBA, // internalFormat
223 | this.size, // width
224 | this.size, // height
225 | 0, // border
226 | gl.RGBA, // format
227 | gl.UNSIGNED_BYTE, // type
228 | null); // data
229 | }
230 | if (this.depth) {
231 | var db = gl.createRenderbuffer();
232 | gl.bindRenderbuffer(gl.RENDERBUFFER, db);
233 | gl.renderbufferStorage(
234 | gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.size, this.size);
235 | }
236 | this.framebuffers = [];
237 | for (var ff = 0; ff < 6; ++ff) {
238 | var fb = gl.createFramebuffer();
239 | gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
240 | gl.framebufferTexture2D(
241 | gl.FRAMEBUFFER,
242 | gl.COLOR_ATTACHMENT0,
243 | tdl.textures.CubeMap.faceTargets[ff],
244 | tex.texture,
245 | 0);
246 | if (this.depth) {
247 | gl.framebufferRenderbuffer(
248 | gl.FRAMEBUFFER,
249 | gl.DEPTH_ATTACHMENT,
250 | gl.RENDERBUFFER,
251 | db);
252 | }
253 | var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
254 | if (status != gl.FRAMEBUFFER_COMPLETE) {
255 | throw("gl.checkFramebufferStatus() returned " + WebGLDebugUtils.glEnumToString(status));
256 | }
257 | this.framebuffers.push(fb);
258 | }
259 | gl.bindRenderbuffer(gl.RENDERBUFFER, null);
260 | this.texture = tex;
261 | };
262 |
263 | /**
264 | * Binds a face as the current render target.
265 | * @param {number} face The face to use as the render target.
266 | */
267 | tdl.framebuffers.CubeFramebuffer.prototype.bind = function(face) {
268 | gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[face]);
269 | gl.viewport(0, 0, this.size, this.size);
270 | };
271 |
272 | /**
273 | * Unbinds this framebuffer as the current render target.
274 | */
275 | tdl.framebuffers.CubeFramebuffer.prototype.unbind = function() {
276 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
277 | gl.viewport(
278 | 0, 0,
279 | gl.drawingBufferWidth || gl.canvas.width,
280 | gl.drawingBufferHeight || gl.canvas.height);
281 | };
282 |
283 | /**
284 | * A framebuffer with a Float32RGBA texture.
285 | * @param {number} width width of framebuffer.
286 | * @param {number} height height of framebuffer.
287 | * @param {boolean?} opt_depth true = create a depth attachment
288 | */
289 | tdl.framebuffers.Float32Framebuffer = function(width, height, opt_depth) {
290 | if (!gl.getExtension("OES_texture_float")) {
291 | throw("Requires OES_texture_float extension");
292 | }
293 | tdl.framebuffers.Framebuffer.call(this, width, height, opt_depth);
294 | };
295 |
296 | tdl.base.inherit(tdl.framebuffers.Float32Framebuffer, tdl.framebuffers.Framebuffer);
297 |
298 | tdl.framebuffers.Float32Framebuffer.prototype.initializeTexture = function(tex) {
299 | gl.bindTexture(gl.TEXTURE_2D, tex.texture);
300 | tex.setParameter(gl.TEXTURE_MIN_FILTER, gl.NEAREST);
301 | tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.NEAREST);
302 | tex.setParameter(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
303 | tex.setParameter(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
304 | gl.texImage2D(gl.TEXTURE_2D,
305 | 0, // level
306 | gl.RGBA, // internalFormat
307 | this.width, // width
308 | this.height, // height
309 | 0, // border
310 | gl.RGBA, // format
311 | gl.FLOAT, // type
312 | null); // data
313 | };
314 |
315 | return tdl.framebuffers;
316 | });
317 |
--------------------------------------------------------------------------------
/example/example2.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 | WebGL TDL Example
36 |
52 |
53 |
286 |
287 |
288 | WebGL Spheres
289 |
290 |
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 |
316 |
319 |
320 |
321 |
322 |
323 |
344 |
377 |
378 |
379 |
380 |
--------------------------------------------------------------------------------
/example/example.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 | WebGL TDL Example
36 |
78 |
79 |
308 |
309 |
310 |
311 |
314 |
315 |
316 |
317 |
318 |
342 |
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 |
--------------------------------------------------------------------------------
/tdl/io.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 This file contains various functions and class for io.
35 | */
36 | define(['./base-rs'], function(BaseRS) {
37 |
38 | tdl.provide('tdl.io');
39 | /**
40 | * A Module with various io functions and classes.
41 | * @namespace
42 | */
43 | tdl.io = tdl.io || {};
44 |
45 | /**
46 | * Creates a LoadInfo object.
47 | * @param {XMLHttpRequest} opt_request
48 | * The request to watch.
49 | * @return {!tdl.io.LoadInfo} The new LoadInfo.
50 | * @see tdl.io.LoadInfo
51 | */
52 | tdl.io.createLoadInfo = function(opt_request) {
53 | return new tdl.io.LoadInfo(opt_request);
54 | };
55 |
56 | /**
57 | * A class to help with progress reporting for most loading utilities.
58 | *
59 | * @example
60 | * var g_loadInfo = null;
61 | * g_id = window.setInterval(statusUpdate, 500);
62 | * g_loadInfo = tdl.scene.loadScene('http://google.com/somescene.js',
63 | * callback);
64 | *
65 | * function callback(exception) {
66 | * g_loadInfo = null;
67 | * window.clearInterval(g_id);
68 | * if (!exception) {
69 | * // do something with scene just loaded
70 | * }
71 | * }
72 | *
73 | * function statusUpdate() {
74 | * if (g_loadInfo) {
75 | * var progress = g_loadInfo.getKnownProgressInfoSoFar();
76 | * document.getElementById('loadstatus').innerHTML = progress.percent;
77 | * }
78 | * }
79 | *
80 | * @constructor
81 | * @param {XMLHttpRequest?} opt_request
82 | * The request to watch.
83 | * @see tdl.loader.Loader
84 | */
85 | tdl.io.LoadInfo = function(opt_request) {
86 | this.request_ = opt_request;
87 | this.streamLength_ = 0; // because the request may have been freed.
88 | this.children_ = [];
89 | };
90 |
91 | /**
92 | * Adds another LoadInfo as a child of this LoadInfo so they can be
93 | * managed as a group.
94 | * @param {!tdl.io.LoadInfo} loadInfo The child LoadInfo.
95 | */
96 | tdl.io.LoadInfo.prototype.addChild = function(loadInfo) {
97 | this.children_.push(loadInfo);
98 | };
99 |
100 | /**
101 | * Marks this LoadInfo as finished.
102 | */
103 | tdl.io.LoadInfo.prototype.finish = function() {
104 | if (this.request_) {
105 | if (this.hasStatus_) {
106 | this.streamLength_ = this.request_.streamLength;
107 | }
108 | this.request_ = null;
109 | }
110 | };
111 |
112 | /**
113 | * Gets the total bytes that will be streamed known so far.
114 | *
115 | * If you are only streaming 1 file then this will be the info for that file but
116 | * if you have queued up many files using a `tdl.loader.Loader`
117 | * only a couple of files are streamed at a time meaning that
118 | * the size is not known for files that have yet started to
119 | * download.
120 | *
121 | * If you are downloading many files for your application and you want to
122 | * provide a progress status you have about 4 options
123 | *
124 | * 1. Use `LoadInfo.getTotalBytesDownloaded()` /
125 | * `LoadInfo.getTotalKnownBytesToStreamSoFar()` and just be
126 | * aware the bar will grown and then shrink as new files
127 | * start to download and their lengths become known.
128 | *
129 | * 2. Use `LoadInfo.getTotalRequestsDownloaded()` /
130 | * `LoadInfo.getTotalKnownRequestsToStreamSoFar()` and be
131 | * aware the granularity is not all that great since it only
132 | * reports fully downloaded files. If you are downloading a
133 | * bunch of small files this might be ok.
134 | *
135 | * 3. Put all your files in one archive. Then there will be
136 | * only one file and method 1 will work well.
137 | *
138 | * 4. Figure out the total size in bytes of the files you will
139 | * download and put that number in your application, then use
140 | * `LoadInfo.getTotalBytesDownloaded()` /
141 | * `MY_APPS_TOTAL_BYTES_TO_DOWNLOAD`.
142 | *
143 | * @return {number} The total number of currently known bytes to be streamed.
144 | */
145 | tdl.io.LoadInfo.prototype.getTotalKnownBytesToStreamSoFar = function() {
146 | //if (!this.streamLength_ && this.request_ && this.hasStatus_) {
147 | // //
148 | // //this.streamLength_ = this.request_.streamLength;
149 | //}
150 | var total = this.streamLength_;
151 | for (var cc = 0; cc < this.children_.length; ++cc) {
152 | total += this.children_[cc].getTotalKnownBytesToStreamSoFar();
153 | }
154 | return total;
155 | };
156 |
157 | /**
158 | * Gets the total bytes downloaded so far.
159 | * @return {number} The total number of currently known bytes to be streamed.
160 | */
161 | tdl.io.LoadInfo.prototype.getTotalBytesDownloaded = function() {
162 | var total = (this.request_ && this.hasStatus_) ?
163 | this.request_.bytesReceived : this.streamLength_;
164 | for (var cc = 0; cc < this.children_.length; ++cc) {
165 | total += this.children_[cc].getTotalBytesDownloaded();
166 | }
167 | return total;
168 | };
169 |
170 | /**
171 | * Gets the total streams that will be download known so far.
172 | * We can't know all the streams since you could use an tdl.loader.Loader
173 | * object, request some streams, then call this function, then request some
174 | * more.
175 | *
176 | * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
177 | * @return {number} The total number of requests currently known to be streamed.
178 | * @see tdl.io.LoadInfo.getTotalKnownBytesToStreamSoFar
179 | */
180 | tdl.io.LoadInfo.prototype.getTotalKnownRequestsToStreamSoFar = function() {
181 | var total = 1;
182 | for (var cc = 0; cc < this.children_.length; ++cc) {
183 | total += this.children_[cc].getTotalKnownRequestToStreamSoFar();
184 | }
185 | return total;
186 | };
187 |
188 | /**
189 | * Gets the total requests downloaded so far.
190 | * @return {number} The total requests downloaded so far.
191 | */
192 | tdl.io.LoadInfo.prototype.getTotalRequestsDownloaded = function() {
193 | var total = this.request_ ? 0 : 1;
194 | for (var cc = 0; cc < this.children_.length; ++cc) {
195 | total += this.children_[cc].getTotalRequestsDownloaded();
196 | }
197 | return total;
198 | };
199 |
200 | /**
201 | * Gets progress info.
202 | * This is commonly formatted version of the information available from a
203 | * LoadInfo.
204 | *
205 | * See LoadInfo.getTotalKnownBytesToStreamSoFar for details.
206 | * @return {{percent: number, downloaded: string, totalBytes: string,
207 | * base: number, suffix: string}} progress info.
208 | * @see tdl.io.LoadInfo.getTotalKnownBytesToStreamSoFar
209 | */
210 | tdl.io.LoadInfo.prototype.getKnownProgressInfoSoFar = function() {
211 | var percent = 0;
212 | var bytesToDownload = this.getTotalKnownBytesToStreamSoFar();
213 | var bytesDownloaded = this.getTotalBytesDownloaded();
214 | if (bytesToDownload > 0) {
215 | percent = Math.floor(bytesDownloaded / bytesToDownload * 100);
216 | }
217 |
218 | var base = (bytesToDownload < 1024 * 1024) ? 1024 : (1024 * 1024);
219 |
220 | return {
221 | percent: percent,
222 | downloaded: (bytesDownloaded / base).toFixed(2),
223 | totalBytes: (bytesToDownload / base).toFixed(2),
224 | base: base,
225 | suffix: (base == 1024 ? 'kb' : 'mb')}
226 |
227 | };
228 |
229 | /**
230 | * Loads text from an external file. This function is synchronous.
231 | * @param {string} url The url of the external file.
232 | * @return {string} the loaded text if the request is synchronous.
233 | */
234 | tdl.io.loadTextFileSynchronous = function(url) {
235 | var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
236 | var request;
237 | if (window.XMLHttpRequest) {
238 | request = new XMLHttpRequest();
239 | if (request.overrideMimeType) {
240 | request.overrideMimeType('text/plain');
241 | }
242 | } else if (window.ActiveXObject) {
243 | request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
244 | } else {
245 | throw 'XMLHttpRequest is disabled';
246 | }
247 | request.open('GET', url, false);
248 | request.send(null);
249 | if (request.readyState != 4) {
250 | throw error;
251 | }
252 | return request.responseText;
253 | };
254 |
255 | /**
256 | * Loads text from an external file. This function is asynchronous.
257 | * @param {string} url The url of the external file.
258 | * @param {function(string, *): void} callback A callback passed the loaded
259 | * string and an exception which will be null on success.
260 | * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
261 | */
262 | tdl.io.loadTextFile = function(url, callback) {
263 | var error = 'loadTextFile failed to load url "' + url + '"';
264 | var request;
265 | if (window.XMLHttpRequest) {
266 | request = new XMLHttpRequest();
267 | if (request.overrideMimeType) {
268 | request.overrideMimeType('text/plain; charset=utf-8');
269 | }
270 | } else if (window.ActiveXObject) {
271 | request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
272 | } else {
273 | throw 'XMLHttpRequest is disabled';
274 | }
275 | var loadInfo = tdl.io.createLoadInfo(request, false);
276 | request.open('GET', url, true);
277 | var finish = function() {
278 | if (request.readyState == 4) {
279 | var text = '';
280 | // HTTP reports success with a 200 status. The file protocol reports
281 | // success with zero. HTTP does not use zero as a status code (they
282 | // start at 100).
283 | // https://developer.mozilla.org/En/Using_XMLHttpRequest
284 | var success = request.status == 200 || request.status == 0;
285 | if (success) {
286 | text = request.responseText;
287 | }
288 | loadInfo.finish();
289 | callback(text, success ? null : 'could not load: ' + url);
290 | }
291 | };
292 | request.onreadystatechange = finish;
293 | request.send(null);
294 | return loadInfo;
295 | };
296 |
297 | /**
298 | * Loads a file from an external file. This function is
299 | * asynchronous.
300 | * @param {string} url The url of the external file.
301 | * @param {function(string, *): void} callback A callback passed the loaded
302 | * ArrayBuffer and an exception which will be null on
303 | * success.
304 | * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
305 | */
306 | tdl.io.loadArrayBuffer = function(url, callback) {
307 | var error = 'loadArrayBuffer failed to load url "' + url + '"';
308 | var request;
309 | if (window.XMLHttpRequest) {
310 | request = new XMLHttpRequest();
311 | } else {
312 | throw 'XMLHttpRequest is disabled';
313 | }
314 | var loadInfo = tdl.io.createLoadInfo(request, false);
315 | request.open('GET', url, true);
316 | var finish = function() {
317 | if (request.readyState == 4) {
318 | var text = '';
319 | // HTTP reports success with a 200 status. The file protocol reports
320 | // success with zero. HTTP does not use zero as a status code (they
321 | // start at 100).
322 | // https://developer.mozilla.org/En/Using_XMLHttpRequest
323 | var success = request.status == 200 || request.status == 0;
324 | if (success) {
325 | arrayBuffer = request.response;
326 | }
327 | loadInfo.finish();
328 | callback(arrayBuffer, success ? null : 'could not load: ' + url);
329 | }
330 | };
331 | request.onreadystatechange = finish;
332 | if (request.responseType === undefined) {
333 | throw 'no support for binary files';
334 | }
335 | request.responseType = "arraybuffer";
336 | request.send(null);
337 | return loadInfo;
338 | };
339 |
340 | /**
341 | * Loads JSON from an external file. This function is asynchronous.
342 | * @param {string} url The url of the external file.
343 | * @param {function(jsonObject, *): void} callback A callback passed the loaded
344 | * json and an exception which will be null on success.
345 | * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
346 | */
347 | tdl.io.loadJSON = function(url, callback) {
348 | var error = 'loadJSON failed to load url "' + url + '"';
349 | var request;
350 | if (window.XMLHttpRequest) {
351 | request = new XMLHttpRequest();
352 | if (request.overrideMimeType) {
353 | request.overrideMimeType('text/plain');
354 | }
355 | } else if (window.ActiveXObject) {
356 | request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
357 | } else {
358 | throw 'XMLHttpRequest is disabled';
359 | }
360 | var loadInfo = tdl.io.createLoadInfo(request, false);
361 | request.open('GET', url, true);
362 | var finish = function() {
363 | if (request.readyState == 4) {
364 | var json = undefined;
365 | // HTTP reports success with a 200 status. The file protocol reports
366 | // success with zero. HTTP does not use zero as a status code (they
367 | // start at 100).
368 | // https://developer.mozilla.org/En/Using_XMLHttpRequest
369 | var success = request.status == 200 || request.status == 0;
370 | if (success) {
371 | try {
372 | json = JSON.parse(request.responseText);
373 | } catch (e) {
374 | success = false;
375 | }
376 | }
377 | loadInfo.finish();
378 | callback(json, success ? null : 'could not load: ' + url);
379 | }
380 | };
381 | try {
382 | request.onreadystatechange = finish;
383 | request.send(null);
384 | } catch (e) {
385 | callback(null, 'could not load: ' + url);
386 | }
387 | return loadInfo;
388 | };
389 |
390 | /**
391 | * Sends an object. This function is asynchronous.
392 | * @param {string} url The url of the external file.
393 | * @param {function(jsonObject, *): void} callback A callback passed the loaded
394 | * json and an exception which will be null on success.
395 | * @return {tdl.io.LoadInfo} A LoadInfo to track progress.
396 | */
397 | tdl.io.sendJSON = function(url, jsonObject, callback) {
398 | var error = 'sendJSON failed to load url "' + url + '"';
399 | var request;
400 | if (window.XMLHttpRequest) {
401 | request = new XMLHttpRequest();
402 | if (request.overrideMimeType) {
403 | request.overrideMimeType('text/plain');
404 | }
405 | } else if (window.ActiveXObject) {
406 | request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
407 | } else {
408 | throw 'XMLHttpRequest is disabled';
409 | }
410 | var loadInfo = tdl.io.createLoadInfo(request, false);
411 | request.open('POST', url, true);
412 | var js = JSON.stringify(jsonObject);
413 | var finish = function() {
414 | if (request.readyState == 4) {
415 | var json = undefined;
416 | // HTTP reports success with a 200 status. The file protocol reports
417 | // success with zero. HTTP does not use zero as a status code (they
418 | // start at 100).
419 | // https://developer.mozilla.org/En/Using_XMLHttpRequest
420 | var success = request.status == 200 || request.status == 0;
421 | if (success) {
422 | try {
423 | json = JSON.parse(request.responseText);
424 | } catch (e) {
425 | success = false;
426 | }
427 | }
428 | loadInfo.finish();
429 | callback(json, success ? null : 'could not load: ' + url);
430 | }
431 | };
432 | try {
433 | request.onreadystatechange = finish;
434 | request.setRequestHeader("Content-type", "application/json");
435 | request.send(js);
436 | } catch (e) {
437 | callback(null, 'could not load: ' + url);
438 | }
439 | return loadInfo;
440 | };
441 |
442 | return tdl.io;
443 | });
444 |
--------------------------------------------------------------------------------
/tdl/quaternions.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 | * @fileoverview This file contains various functions for quaternion arithmetic
34 | * and converting between rotation matrices and quaternions. It adds them to
35 | * the "quaternions" module on the tdl object. Javascript arrays with
36 | * four entries are used to represent quaternions, and functions are provided
37 | * for doing operations on those.
38 | *
39 | * Operations are done assuming quaternions are of the form:
40 | * `q[0] + q[1]i + q[2]j + q[3]k` and using the hamiltonian
41 | * rules for multiplication as described on Brougham Bridge:
42 | * `i^2 = j^2 = k^2 = ijk = -1`.
43 | *
44 | */
45 |
46 | define(['./base-rs'], function(BaseRS) {
47 |
48 | tdl.provide('tdl.quaternions');
49 | /**
50 | * A Module for quaternion math.
51 | * @namespace
52 | */
53 | tdl.quaternions = tdl.quaternions || {};
54 |
55 | /**
56 | * A Quaternion.
57 | * @typedef {number[]} tdl.quaternions.Quaternion
58 | */
59 |
60 | /**
61 | * Quickly determines if the object a is a scalar or a quaternion;
62 | * assumes that the argument is either a number (scalar), or an array of
63 | * numbers.
64 | * @param {(number|tdl.quaternions.Quaternion)} a A number or array the type
65 | * of which is in question.
66 | * @return {string} Either the string 'Scalar' or 'Quaternion'.
67 | */
68 | tdl.quaternions.mathType = function(a) {
69 | if (typeof(a) === 'number')
70 | return 'Scalar';
71 | return 'Quaternion';
72 | };
73 |
74 | /**
75 | * Creates an identity quaternion.
76 | * @return {tdl.quaternions.Quaternion} The identity quaternion.
77 | */
78 | tdl.quaternions.identity = function() {
79 | return [ 0, 0, 0, 1 ];
80 | };
81 |
82 | /**
83 | * Copies a quaternion.
84 | * @param {tdl.quaternions.Quaternion} q The quaternion.
85 | * @return {tdl.quaternions.Quaternion} A new quaternion identical to q.
86 | */
87 | tdl.quaternions.copy = function(q) {
88 | return q.slice();
89 | };
90 |
91 | /**
92 | * Negates a quaternion.
93 | * @param {tdl.quaternions.Quaternion} q The quaternion.
94 | * @return {tdl.quaternions.Quaternion} -q.
95 | */
96 | tdl.quaternions.negative = function(q) {
97 | return [-q[0], -q[1], -q[2], -q[3]];
98 | };
99 |
100 | /**
101 | * Adds two Quaternions.
102 | * @param {tdl.quaternions.Quaternion} a Operand Quaternion.
103 | * @param {tdl.quaternions.Quaternion} b Operand Quaternion.
104 | * @return {tdl.quaternions.Quaternion} The sum of a and b.
105 | */
106 | tdl.quaternions.addQuaternionQuaternion = function(a, b) {
107 | return [a[0] + b[0],
108 | a[1] + b[1],
109 | a[2] + b[2],
110 | a[3] + b[3]];
111 | };
112 |
113 | /**
114 | * Adds a quaternion to a scalar.
115 | * @param {tdl.quaternions.Quaternion} a Operand Quaternion.
116 | * @param {number} b Operand Scalar.
117 | * @return {tdl.quaternions.Quaternion} The sum of a and b.
118 | */
119 | tdl.quaternions.addQuaternionScalar = function(a, b) {
120 | return a.slice(0, 3).concat(a[3] + b);
121 | };
122 |
123 | /**
124 | * Adds a scalar to a quaternion.
125 | * @param {number} a Operand scalar.
126 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
127 | * @return {tdl.quaternions.Quaternion} The sum of a and b.
128 | */
129 | tdl.quaternions.addScalarQuaternion = function(a, b) {
130 | return b.slice(0, 3).concat(a + b[3]);
131 | };
132 |
133 | /**
134 | * Subtracts two quaternions.
135 | * @param {tdl.quaternions.Quaternion} a Operand quaternion.
136 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
137 | * @return {tdl.quaternions.Quaternion} The difference a - b.
138 | */
139 | tdl.quaternions.subQuaternionQuaternion = function(a, b) {
140 | return [a[0] - b[0],
141 | a[1] - b[1],
142 | a[2] - b[2],
143 | a[3] - b[3]];
144 | };
145 |
146 | /**
147 | * Subtracts a scalar from a quaternion.
148 | * @param {tdl.quaternions.Quaternion} a Operand quaternion.
149 | * @param {number} b Operand scalar.
150 | * @return {tdl.quaternions.Quaternion} The difference a - b.
151 | */
152 | tdl.quaternions.subQuaternionScalar = function(a, b) {
153 | return a.slice(0, 3).concat(a[3] - b);
154 | };
155 |
156 | /**
157 | * Subtracts a quaternion from a scalar.
158 | * @param {number} a Operand scalar.
159 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
160 | * @return {tdl.quaternions.Quaternion} The difference a - b.
161 | */
162 | tdl.quaternions.subScalarQuaternion = function(a, b) {
163 | return [-b[0], -b[1], -b[2], a - b[3]];
164 | };
165 |
166 | /**
167 | * Multiplies a scalar by a quaternion.
168 | * @param {number} k The scalar.
169 | * @param {tdl.quaternions.Quaternion} q The quaternion.
170 | * @return {tdl.quaternions.Quaternion} The product of k and q.
171 | */
172 | tdl.quaternions.mulScalarQuaternion = function(k, q) {
173 | return [k * q[0], k * q[1], k * q[2], k * q[3]];
174 | };
175 |
176 | /**
177 | * Multiplies a quaternion by a scalar.
178 | * @param {tdl.quaternions.Quaternion} q The Quaternion.
179 | * @param {number} k The scalar.
180 | * @return {tdl.quaternions.Quaternion} The product of k and v.
181 | */
182 | tdl.quaternions.mulQuaternionScalar = function(q, k) {
183 | return [k * q[0], k * q[1], k * q[2], k * q[3]];
184 | };
185 |
186 | /**
187 | * Multiplies two quaternions.
188 | * @param {tdl.quaternions.Quaternion} a Operand quaternion.
189 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
190 | * @return {tdl.quaternions.Quaternion} The quaternion product a * b.
191 | */
192 | tdl.quaternions.mulQuaternionQuaternion = function(a, b) {
193 | var aX = a[0];
194 | var aY = a[1];
195 | var aZ = a[2];
196 | var aW = a[3];
197 | var bX = b[0];
198 | var bY = b[1];
199 | var bZ = b[2];
200 | var bW = b[3];
201 |
202 | return [
203 | aW * bX + aX * bW + aY * bZ - aZ * bY,
204 | aW * bY + aY * bW + aZ * bX - aX * bZ,
205 | aW * bZ + aZ * bW + aX * bY - aY * bX,
206 | aW * bW - aX * bX - aY * bY - aZ * bZ];
207 | };
208 |
209 | /**
210 | * Divides two quaternions; assumes the convention that a/b = a*(1/b).
211 | * @param {tdl.quaternions.Quaternion} a Operand quaternion.
212 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
213 | * @return {tdl.quaternions.Quaternion} The quaternion quotient a / b.
214 | */
215 | tdl.quaternions.divQuaternionQuaternion = function(a, b) {
216 | var aX = a[0];
217 | var aY = a[1];
218 | var aZ = a[2];
219 | var aW = a[3];
220 | var bX = b[0];
221 | var bY = b[1];
222 | var bZ = b[2];
223 | var bW = b[3];
224 |
225 | var d = 1 / (bW * bW + bX * bX + bY * bY + bZ * bZ);
226 | return [
227 | (aX * bW - aW * bX - aY * bZ + aZ * bY) * d,
228 | (aX * bZ - aW * bY + aY * bW - aZ * bX) * d,
229 | (aY * bX + aZ * bW - aW * bZ - aX * bY) * d,
230 | (aW * bW + aX * bX + aY * bY + aZ * bZ) * d];
231 | };
232 |
233 | /**
234 | * Divides a Quaternion by a scalar.
235 | * @param {tdl.quaternions.Quaternion} q The quaternion.
236 | * @param {number} k The scalar.
237 | * @return {tdl.quaternions.Quaternion} q The quaternion q divided by k.
238 | */
239 | tdl.quaternions.divQuaternionScalar = function(q, k) {
240 | return [q[0] / k, q[1] / k, q[2] / k, q[3] / k];
241 | };
242 |
243 | /**
244 | * Divides a scalar by a quaternion.
245 | * @param {number} a Operand scalar.
246 | * @param {tdl.quaternions.Quaternion} b Operand quaternion.
247 | * @return {tdl.quaternions.Quaternion} The quaternion product.
248 | */
249 | tdl.quaternions.divScalarQuaternion = function(a, b) {
250 | var b0 = b[0];
251 | var b1 = b[1];
252 | var b2 = b[2];
253 | var b3 = b[3];
254 |
255 | var d = 1 / (b0 * b0 + b1 * b1 + b2 * b2 + b3 * b3);
256 | return [-a * b0 * d, -a * b1 * d, -a * b2 * d, a * b3 * d];
257 | };
258 |
259 | /**
260 | * Computes the multiplicative inverse of a quaternion.
261 | * @param {tdl.quaternions.Quaternion} q The quaternion.
262 | * @return {tdl.quaternions.Quaternion} The multiplicative inverse of q.
263 | */
264 | tdl.quaternions.inverse = function(q) {
265 | var q0 = q[0];
266 | var q1 = q[1];
267 | var q2 = q[2];
268 | var q3 = q[3];
269 |
270 | var d = 1 / (q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
271 | return [-q0 * d, -q1 * d, -q2 * d, q3 * d];
272 | };
273 |
274 | /**
275 | * Multiplies two objects which are either scalars or quaternions.
276 | * @param {(tdl.quaternions.Quaternion|number)} a Operand.
277 | * @param {(tdl.quaternions.Quaternion|number)} b Operand.
278 | * @return {(tdl.quaternions.Quaternion|number)} The product of a and b.
279 | */
280 | tdl.quaternions.mul = function(a, b) {
281 | return tdl.quaternions['mul' + tdl.quaternions.mathType(a) +
282 | tdl.quaternions.mathType(b)](a, b);
283 | };
284 |
285 | /**
286 | * Divides two objects which are either scalars or quaternions.
287 | * @param {(tdl.quaternions.Quaternion|number)} a Operand.
288 | * @param {(tdl.quaternions.Quaternion|number)} b Operand.
289 | * @return {(tdl.quaternions.Quaternion|number)} The quotient of a and b.
290 | */
291 | tdl.quaternions.div = function(a, b) {
292 | return tdl.quaternions['div' + tdl.quaternions.mathType(a) +
293 | tdl.quaternions.mathType(b)](a, b);
294 | };
295 |
296 | /**
297 | * Adds two objects which are either scalars or quaternions.
298 | * @param {(tdl.quaternions.Quaternion|number)} a Operand.
299 | * @param {(tdl.quaternions.Quaternion|number)} b Operand.
300 | * @return {(tdl.quaternions.Quaternion|number)} The sum of a and b.
301 | */
302 | tdl.quaternions.add = function(a, b) {
303 | return tdl.quaternions['add' + tdl.quaternions.mathType(a) +
304 | tdl.quaternions.mathType(b)](a, b);
305 | };
306 |
307 | /**
308 | * Subtracts two objects which are either scalars or quaternions.
309 | * @param {(tdl.quaternions.Quaternion|number)} a Operand.
310 | * @param {(tdl.quaternions.Quaternion|number)} b Operand.
311 | * @return {(tdl.quaternions.Quaternion|number)} The difference of a and b.
312 | */
313 | tdl.quaternions.sub = function(a, b) {
314 | return tdl.quaternions['sub' + tdl.quaternions.mathType(a) +
315 | tdl.quaternions.mathType(b)](a, b);
316 | };
317 |
318 | /**
319 | * Computes the length of a Quaternion, i.e. the square root of the
320 | * sum of the squares of the coefficients.
321 | * @param {tdl.quaternions.Quaternion} a The Quaternion.
322 | * @return {number} The length of a.
323 | */
324 | tdl.quaternions.length = function(a) {
325 | return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]);
326 | };
327 |
328 | /**
329 | * Computes the square of the length of a quaternion, i.e. the sum of the
330 | * squares of the coefficients.
331 | * @param {tdl.quaternions.Quaternion} a The quaternion.
332 | * @return {number} The square of the length of a.
333 | */
334 | tdl.quaternions.lengthSquared = function(a) {
335 | return a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
336 | };
337 |
338 | /**
339 | * Divides a Quaternion by its length and returns the quotient.
340 | * @param {tdl.quaternions.Quaternion} a The Quaternion.
341 | * @return {tdl.quaternions.Quaternion} A unit length quaternion pointing in
342 | * the same direction as a.
343 | */
344 | tdl.quaternions.normalize = function(a) {
345 | var d = 1 / Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]);
346 | return [a[0] * d, a[1] * d, a[2] * d, a[3] * d];
347 | };
348 |
349 | /**
350 | * Computes the conjugate of the given quaternion.
351 | * @param {tdl.quaternions.Quaternion} q The quaternion.
352 | * @return {tdl.quaternions.Quaternion} The conjugate of q.
353 | */
354 | tdl.quaternions.conjugate = function(q) {
355 | return [-q[0], -q[1], -q[2], q[3]];
356 | };
357 |
358 |
359 | /**
360 | * Creates a quaternion which rotates around the x-axis by the given angle.
361 | * @param {number} angle The angle by which to rotate (in radians).
362 | * @return {tdl.quaternions.Quaternion} The quaternion.
363 | */
364 | tdl.quaternions.rotationX = function(angle) {
365 | return [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
366 | };
367 |
368 | /**
369 | * Creates a quaternion which rotates around the y-axis by the given angle.
370 | * @param {number} angle The angle by which to rotate (in radians).
371 | * @return {tdl.quaternions.Quaternion} The quaternion.
372 | */
373 | tdl.quaternions.rotationY = function(angle) {
374 | return [0, Math.sin(angle / 2), 0, Math.cos(angle / 2)];
375 | };
376 |
377 | /**
378 | * Creates a quaternion which rotates around the z-axis by the given angle.
379 | * @param {number} angle The angle by which to rotate (in radians).
380 | * @return {tdl.quaternions.Quaternion} The quaternion.
381 | */
382 | tdl.quaternions.rotationZ = function(angle) {
383 | return [0, 0, Math.sin(angle / 2), Math.cos(angle / 2)];
384 | };
385 |
386 | /**
387 | * Creates a quaternion which rotates around the given axis by the given
388 | * angle.
389 | * @param {tdl.math.Vector3} axis The axis about which to rotate.
390 | * @param {number} angle The angle by which to rotate (in radians).
391 | * @return {tdl.quaternions.Quaternion} A quaternion which rotates angle
392 | * radians around the axis.
393 | */
394 | tdl.quaternions.axisRotation = function(axis, angle) {
395 | var d = 1 / Math.sqrt(axis[0] * axis[0] +
396 | axis[1] * axis[1] +
397 | axis[2] * axis[2]);
398 | var sin = Math.sin(angle / 2);
399 | var cos = Math.cos(angle / 2);
400 | return [sin * axis[0] * d, sin * axis[1] * d, sin * axis[2] * d, cos];
401 | };
402 |
403 | /**
404 | * Computes a 4-by-4 rotation matrix (with trivial translation component)
405 | * given a quaternion. We assume the convention that to rotate a vector v by
406 | * a quaternion r means to express that vector as a quaternion q by letting
407 | * `q = [v[0], v[1], v[2], 0]` and then obtain the rotated
408 | * vector by evaluating the expression `(r * q) / r`.
409 | * @param {tdl.quaternions.Quaternion} q The quaternion.
410 | * @return {tdl.math.Matrix4} A 4-by-4 rotation matrix.
411 | */
412 | tdl.quaternions.quaternionToRotation = function(q) {
413 | var qX = q[0];
414 | var qY = q[1];
415 | var qZ = q[2];
416 | var qW = q[3];
417 |
418 | var qWqW = qW * qW;
419 | var qWqX = qW * qX;
420 | var qWqY = qW * qY;
421 | var qWqZ = qW * qZ;
422 | var qXqW = qX * qW;
423 | var qXqX = qX * qX;
424 | var qXqY = qX * qY;
425 | var qXqZ = qX * qZ;
426 | var qYqW = qY * qW;
427 | var qYqX = qY * qX;
428 | var qYqY = qY * qY;
429 | var qYqZ = qY * qZ;
430 | var qZqW = qZ * qW;
431 | var qZqX = qZ * qX;
432 | var qZqY = qZ * qY;
433 | var qZqZ = qZ * qZ;
434 |
435 | var d = qWqW + qXqX + qYqY + qZqZ;
436 |
437 | return [
438 | (qWqW + qXqX - qYqY - qZqZ) / d,
439 | 2 * (qWqZ + qXqY) / d,
440 | 2 * (qXqZ - qWqY) / d, 0,
441 |
442 | 2 * (qXqY - qWqZ) / d,
443 | (qWqW - qXqX + qYqY - qZqZ) / d,
444 | 2 * (qWqX + qYqZ) / d, 0,
445 |
446 | 2 * (qWqY + qXqZ) / d,
447 | 2 * (qYqZ - qWqX) / d,
448 | (qWqW - qXqX - qYqY + qZqZ) / d, 0,
449 |
450 | 0, 0, 0, 1];
451 | };
452 |
453 | /**
454 | * Computes a quaternion whose rotation is equivalent to the given matrix.
455 | * @param {(tdl.math.Matrix4|tdl.math.Matrix3)} m A 3-by-3 or 4-by-4
456 | * rotation matrix.
457 | * @return {tdl.quaternions.Quaternion} A quaternion q such that
458 | * quaternions.quaternionToRotation(q) is m.
459 | */
460 | tdl.quaternions.rotationToQuaternion = function(m) {
461 | var u;
462 | var v;
463 | var w;
464 |
465 | // Choose u, v, and w such that u is the index of the biggest diagonal entry
466 | // of m, and u v w is an even permutation of 0 1 and 2.
467 | if (m[0*4+0] > m[1*4+1] && m[0*4+0] > m[2*4+2]) {
468 | u = 0;
469 | v = 1;
470 | w = 2;
471 | } else if (m[1*4+1] > m[0*4+0] && m[1*4+1] > m[2*4+2]) {
472 | u = 1;
473 | v = 2;
474 | w = 0;
475 | } else {
476 | u = 2;
477 | v = 0;
478 | w = 1;
479 | }
480 |
481 | var r = Math.sqrt(1 + m[u*4+u] - m[v*4+v] - m[w*4+w]);
482 | var q = [];
483 | q[u] = 0.5 * r;
484 | q[v] = 0.5 * (m[v*4+u] + m[u*4+v]) / r;
485 | q[w] = 0.5 * (m[u*4+w] + m[w*4+u]) / r;
486 | q[3] = 0.5 * (m[v*4+w] - m[w*4+v]) / r;
487 |
488 | return q;
489 | };
490 |
491 | return tdl.quaternions;
492 | });
493 |
494 |
--------------------------------------------------------------------------------
/tdl/programs.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 This file contains objects to deal with WebGL
35 | * programs.
36 | */
37 | define(
38 | [ './base-rs',
39 | './log',
40 | './string',
41 | './webgl',
42 | ], function(
43 | BaseRS,
44 | Log,
45 | Strings,
46 | WebGL) {
47 |
48 | tdl.provide('tdl.programs');
49 | /**
50 | * A module for programs.
51 | * @namespace
52 | */
53 | tdl.programs = tdl.programs || {};
54 |
55 | /**
56 | * Loads a program from script tags.
57 | * @param {string} vertexShaderId The id of the script tag that contains the
58 | * vertex shader source.
59 | * @param {string} fragmentShaderId The id of the script tag that contains the
60 | * fragment shader source.
61 | * @return {tdl.programs.Program} The created program.
62 | */
63 | tdl.programs.loadProgramFromScriptTags = function(
64 | vertexShaderId, fragmentShaderId) {
65 | var vertElem = document.getElementById(vertexShaderId);
66 | var fragElem = document.getElementById(fragmentShaderId);
67 | if (!vertElem) {
68 | throw("Can't find vertex program tag: " + vertexShaderId);
69 | }
70 | if (!fragElem) {
71 | throw("Can't find fragment program tag: " + fragmentShaderId);
72 | }
73 | return tdl.programs.loadProgram(
74 | document.getElementById(vertexShaderId).text,
75 | document.getElementById(fragmentShaderId).text);
76 | };
77 |
78 | tdl.programs.makeProgramId = function(vertexShader, fragmentShader) {
79 | return vertexShader + fragmentShader;
80 | };
81 |
82 | /**
83 | * Loads a program.
84 | * @param {string} vertexShader The vertex shader source.
85 | * @param {string} fragmentShader The fragment shader source.
86 | * @param {function(error)) opt_asyncCallback. Called with
87 | * undefined if success or string if failure.
88 | * @return {tdl.programs.Program} The created program.
89 | */
90 | tdl.programs.loadProgram = function(vertexShader, fragmentShader, opt_asyncCallback) {
91 | var id = tdl.programs.makeProgramId(vertexShader, fragmentShader);
92 | tdl.programs.init_();
93 | var program = gl.tdl.programs.programDB[id];
94 | if (program) {
95 | if (opt_asyncCallback) {
96 | setTimeout(function() { opt_asyncCallback(); }, 1);
97 | }
98 | return program;
99 | }
100 | try {
101 | program = new tdl.programs.Program(vertexShader, fragmentShader, opt_asyncCallback);
102 | } catch (e) {
103 | tdl.error(e);
104 | return null;
105 | }
106 | if (!opt_asyncCallback) {
107 | gl.tdl.programs.programDB[id] = program;
108 | }
109 | return program;
110 | };
111 |
112 | /**
113 | * A object to manage a WebGLProgram.
114 | * @constructor
115 | * @param {string} vertexShader The vertex shader source.
116 | * @param {string} fragmentShader The fragment shader source.
117 | * @param {function(error)) opt_asyncCallback. Called with
118 | * undefined if success or string if failure.
119 | */
120 | tdl.programs.Program = function(vertexShader, fragmentShader, opt_asyncCallback) {
121 | var that = this;
122 | this.programId = tdl.programs.makeProgramId(vertexShader, fragmentShader);
123 | this.asyncCallback = opt_asyncCallback;
124 |
125 | var shaderId;
126 | var program;
127 | var vs;
128 | var fs;
129 |
130 | /**
131 | * Loads a shader.
132 | * @private
133 | * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
134 | * @param {string} shaderSource The shader source.
135 | * @param {number} shaderType The type of shader.
136 | * @return {WebGLShader} The created shader.
137 | */
138 | var loadShader = function(gl, shaderSource, shaderType) {
139 | shaderId = shaderSource + shaderType;
140 | tdl.programs.init_();
141 | var shader = gl.tdl.programs.shaderDB[shaderId];
142 | if (shader) {
143 | return shader;
144 | }
145 |
146 | // Create the shader object
147 | var shader = gl.createShader(shaderType);
148 |
149 | // Load the shader source
150 | gl.shaderSource(shader, shaderSource);
151 |
152 | // Compile the shader
153 | gl.compileShader(shader);
154 |
155 | // Check the compile status
156 | if (!that.asyncCallback) {
157 | checkShader(shader);
158 | }
159 | return shader;
160 | }
161 |
162 | var checkShader = function(shader) {
163 | var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
164 | if (!compiled && !gl.isContextLost()) {
165 | // Something went wrong during compilation; get the error
166 | tdl.programs.lastError = gl.getShaderInfoLog(shader);
167 | gl.deleteShader(shader);
168 | throw("*** Error compiling shader :" + tdl.programs.lastError);
169 | }
170 | gl.tdl.programs.shaderDB[shaderId] = shader;
171 | };
172 |
173 | /**
174 | * Loads shaders from script tags, creates a program, attaches the shaders and
175 | * links.
176 | * @private
177 | * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
178 | * @param {string} vertexShader The vertex shader.
179 | * @param {string} fragmentShader The fragment shader.
180 | * @return {WebGLProgram} The created program.
181 | */
182 | var loadProgram = function(gl, vertexShader, fragmentShader) {
183 | var e;
184 | try {
185 | vs = loadShader(gl, vertexShader, gl.VERTEX_SHADER);
186 | fs = loadShader(gl, fragmentShader, gl.FRAGMENT_SHADER);
187 | program = gl.createProgram();
188 | gl.attachShader(program, vs);
189 | gl.attachShader(program, fs);
190 | linkProgram(gl, program);
191 | } catch (e) {
192 | deleteAll(e);
193 | }
194 | return program;
195 | };
196 |
197 | var deleteAll = function(e) {
198 | if (vs) { gl.deleteShader(vs) }
199 | if (fs) { gl.deleteShader(fs) }
200 | if (program) { gl.deleteProgram(program) }
201 | throw e;
202 | };
203 |
204 | /**
205 | * Links a WebGL program, throws if there are errors.
206 | * @private
207 | * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
208 | * @param {WebGLProgram} program The WebGLProgram to link.
209 | */
210 | var linkProgram = function(gl, program) {
211 | // Link the program
212 | gl.linkProgram(program);
213 |
214 | // Check the link status
215 | if (!that.asyncCallback) {
216 | checkProgram(program);
217 | }
218 | };
219 |
220 | var checkProgram = function(program) {
221 | var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
222 | if (!linked && !gl.isContextLost()) {
223 | // something went wrong with the link
224 | tdl.programs.lastError = gl.getProgramInfoLog (program);
225 | throw("*** Error in program linking:" + tdl.programs.lastError);
226 | }
227 | };
228 |
229 | // Compile shaders
230 | var program = loadProgram(gl, vertexShader, fragmentShader);
231 | if (!program && !gl.isContextLost()) {
232 | throw ("could not compile program");
233 | }
234 |
235 | // TODO(gman): remove the need for this.
236 | function flatten(array){
237 | var flat = [];
238 | for (var i = 0, l = array.length; i < l; i++) {
239 | var type = Object.prototype.toString.call(array[i]).split(' ').pop().split(']').shift().toLowerCase();
240 | if (type) { flat = flat.concat(/^(array|collection|arguments|object)$/.test(type) ? flatten(array[i]) : array[i]); }
241 | }
242 | return flat;
243 | }
244 |
245 | function createSetters(program) {
246 | // Look up attribs.
247 | var attribs = {
248 | };
249 | // Also make a plain table of the locs.
250 | var attribLocs = {
251 | };
252 |
253 | function createAttribSetter(info, index) {
254 | if (info.size != 1) {
255 | throw("arrays of attribs not handled");
256 | }
257 | return function(b) {
258 | gl.bindBuffer(gl.ARRAY_BUFFER, b.buffer());
259 | gl.enableVertexAttribArray(index);
260 | gl.vertexAttribPointer(
261 | index, b.numComponents(), b.type(), b.normalize(), b.stride(), b.offset());
262 | };
263 | }
264 |
265 | var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
266 | for (var ii = 0; ii < numAttribs; ++ii) {
267 | var info = gl.getActiveAttrib(program, ii);
268 | if (!info) {
269 | break;
270 | }
271 | var name = info.name;
272 | if (tdl.string.endsWith(name, "[0]")) {
273 | name = name.substr(0, name.length - 3);
274 | }
275 | var index = gl.getAttribLocation(program, info.name);
276 | attribs[name] = createAttribSetter(info, index);
277 | attribLocs[name] = index
278 | }
279 |
280 | // Look up uniforms
281 | var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
282 | var uniforms = {
283 | };
284 | var textureUnit = 0;
285 |
286 | function createUniformSetter(info) {
287 | var loc = gl.getUniformLocation(program, info.name);
288 | var type = info.type;
289 | if (info.size > 1 && tdl.string.endsWith(info.name, "[0]")) {
290 | // It's an array.
291 | if (type == gl.FLOAT)
292 | return function(v) { gl.uniform1fv(loc, v); };
293 | if (type == gl.FLOAT_VEC2)
294 | return function(v) { gl.uniform2fv(loc, v); };
295 | if (type == gl.FLOAT_VEC3)
296 | return function(v) { gl.uniform3fv(loc, v); };
297 | if (type == gl.FLOAT_VEC4)
298 | return function(v) { gl.uniform4fv(loc, v); };
299 | if (type == gl.INT)
300 | return function(v) { gl.uniform1iv(loc, v); };
301 | if (type == gl.INT_VEC2)
302 | return function(v) { gl.uniform2iv(loc, v); };
303 | if (type == gl.INT_VEC3)
304 | return function(v) { gl.uniform3iv(loc, v); };
305 | if (type == gl.INT_VEC4)
306 | return function(v) { gl.uniform4iv(loc, v); };
307 | if (type == gl.BOOL)
308 | return function(v) { gl.uniform1iv(loc, v); };
309 | if (type == gl.BOOL_VEC2)
310 | return function(v) { gl.uniform2iv(loc, v); };
311 | if (type == gl.BOOL_VEC3)
312 | return function(v) { gl.uniform3iv(loc, v); };
313 | if (type == gl.BOOL_VEC4)
314 | return function(v) { gl.uniform4iv(loc, v); };
315 | if (type == gl.FLOAT_MAT2)
316 | return function(v) { gl.uniformMatrix2fv(loc, false, v); };
317 | if (type == gl.FLOAT_MAT3)
318 | return function(v) { gl.uniformMatrix3fv(loc, false, v); };
319 | if (type == gl.FLOAT_MAT4)
320 | return function(v) { gl.uniformMatrix4fv(loc, false, v); };
321 | if (type == gl.SAMPLER_2D || type == gl.SAMPLER_CUBE) {
322 | var units = [];
323 | for (var ii = 0; ii < info.size; ++ii) {
324 | units.push(textureUnit++);
325 | }
326 | return function(units) {
327 | return function(v) {
328 | gl.uniform1iv(loc, units);
329 | v.forEach(function(t, index) {
330 | t.bindToUnit(units[index]);
331 | });
332 | };
333 | }(units);
334 | }
335 | throw ("unknown type: 0x" + type.toString(16));
336 | } else {
337 | if (type == gl.FLOAT)
338 | return function(v) { gl.uniform1f(loc, v); };
339 | if (type == gl.FLOAT_VEC2)
340 | return function(v) { gl.uniform2fv(loc, v); };
341 | if (type == gl.FLOAT_VEC3)
342 | return function(v) { gl.uniform3fv(loc, v); };
343 | if (type == gl.FLOAT_VEC4)
344 | return function(v) { gl.uniform4fv(loc, v); };
345 | if (type == gl.INT)
346 | return function(v) { gl.uniform1i(loc, v); };
347 | if (type == gl.INT_VEC2)
348 | return function(v) { gl.uniform2iv(loc, v); };
349 | if (type == gl.INT_VEC3)
350 | return function(v) { gl.uniform3iv(loc, v); };
351 | if (type == gl.INT_VEC4)
352 | return function(v) { gl.uniform4iv(loc, v); };
353 | if (type == gl.BOOL)
354 | return function(v) { gl.uniform1i(loc, v); };
355 | if (type == gl.BOOL_VEC2)
356 | return function(v) { gl.uniform2iv(loc, v); };
357 | if (type == gl.BOOL_VEC3)
358 | return function(v) { gl.uniform3iv(loc, v); };
359 | if (type == gl.BOOL_VEC4)
360 | return function(v) { gl.uniform4iv(loc, v); };
361 | if (type == gl.FLOAT_MAT2)
362 | return function(v) { gl.uniformMatrix2fv(loc, false, v); };
363 | if (type == gl.FLOAT_MAT3)
364 | return function(v) { gl.uniformMatrix3fv(loc, false, v); };
365 | if (type == gl.FLOAT_MAT4)
366 | return function(v) { gl.uniformMatrix4fv(loc, false, v); };
367 | if (type == gl.SAMPLER_2D || type == gl.SAMPLER_CUBE) {
368 | return function(unit) {
369 | return function(v) {
370 | gl.uniform1i(loc, unit);
371 | v.bindToUnit(unit);
372 | };
373 | }(textureUnit++);
374 | }
375 | throw ("unknown type: 0x" + type.toString(16));
376 | }
377 | }
378 |
379 | var textures = {};
380 |
381 | for (var ii = 0; ii < numUniforms; ++ii) {
382 | var info = gl.getActiveUniform(program, ii);
383 | if (!info) {
384 | break;
385 | }
386 | name = info.name;
387 | if (tdl.string.endsWith(name, "[0]")) {
388 | name = name.substr(0, name.length - 3);
389 | }
390 | var setter = createUniformSetter(info);
391 | uniforms[name] = setter;
392 | if (info.type == gl.SAMPLER_2D || info.type == gl.SAMPLER_CUBE) {
393 | textures[name] = setter;
394 | }
395 | }
396 |
397 | that.textures = textures;
398 | that.attrib = attribs;
399 | that.attribLoc = attribLocs;
400 | that.uniform = uniforms;
401 | }
402 | createSetters(program);
403 |
404 | this.loadNewShaders = function(vertexShaderSource, fragmentShaderSource) {
405 | var program = loadProgram(gl, vertexShaderSource, fragmentShaderSource);
406 | if (!program && !gl.isContextLost()) {
407 | throw ("could not compile program");
408 | }
409 | that.program = program;
410 | createSetters();
411 | };
412 |
413 | this.program = program;
414 | this.good = this.asyncCallback ? false : true;
415 |
416 | var checkLater = function() {
417 | var e;
418 | try {
419 | checkShader(vs);
420 | checkShader(fs);
421 | checkProgram(program);
422 | } catch (e) {
423 | that.asyncCallback(e.toString());
424 | return;
425 | }
426 | gl.tdl.programs.programDB[that.programId] = this;
427 | that.asyncCallback();
428 | };
429 | if (this.asyncCallback) {
430 | setTimeout(checkLater, 1000);
431 | }
432 | };
433 |
434 | tdl.programs.handleContextLost_ = function() {
435 | if (gl.tdl && gl.tdl.programs && gl.tdl.programs.shaderDB) {
436 | delete gl.tdl.programs.shaderDB;
437 | delete gl.tdl.programs.programDB;
438 | }
439 | };
440 |
441 | tdl.programs.init_ = function() {
442 | if (!gl.tdl.programs) {
443 | gl.tdl.programs = { };
444 | tdl.webgl.registerContextLostHandler(gl.canvas, tdl.programs.handleContextLost_, true);
445 | }
446 | if (!gl.tdl.programs.shaderDB) {
447 | gl.tdl.programs.shaderDB = { };
448 | gl.tdl.programs.programDB = { };
449 | }
450 | };
451 |
452 | /**
453 | * Uses the current program (calls `gl.useProgram`)
454 | */
455 | tdl.programs.Program.prototype.use = function() {
456 | gl.useProgram(this.program);
457 | };
458 |
459 | //function dumpValue(msg, name, value) {
460 | // var str;
461 | // if (value.length) {
462 | // str = value[0].toString();
463 | // for (var ii = 1; ii < value.length; ++ii) {
464 | // str += "," + value[ii];
465 | // }
466 | // } else {
467 | // str = value.toString();
468 | // }
469 | // tdl.log(msg + name + ": " + str);
470 | //}
471 |
472 | /**
473 | * Sets a uniform to a value
474 | * @param {string} uniform name of uniform to set
475 | * @param {*} value value that is compatible with type of
476 | * uniform.
477 | */
478 | tdl.programs.Program.prototype.setUniform = function(uniform, value) {
479 | var func = this.uniform[uniform];
480 | if (func) {
481 | //dumpValue("SET UNI:", uniform, value);
482 | func(value);
483 | }
484 | };
485 |
486 | /**
487 | * Sets a bunch of uniforms
488 | * @param {Object.} uniforms uniform name value
489 | * pairs.
490 | */
491 | tdl.programs.Program.prototype.applyUniforms = function(uniforms) {
492 | for (var uniform in uniforms) {
493 | this.setUniform(uniform, uniforms[uniform]);
494 | }
495 | };
496 |
497 | return tdl.programs;
498 | });
499 |
500 |
--------------------------------------------------------------------------------
/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 = '