├── .gitignore ├── .npmignore ├── Gruntfile.js ├── README.md ├── build ├── kami.js └── kami.min.js ├── demos └── build │ ├── bundle.js │ └── kami.min.js ├── docs ├── api.js ├── assets │ ├── css │ │ ├── external-small.png │ │ ├── logo.png │ │ └── main.css │ ├── favicon.png │ ├── img │ │ └── spinner.gif │ ├── index.html │ ├── js │ │ ├── api-filter.js │ │ ├── api-list.js │ │ ├── api-search.js │ │ ├── apidocs.js │ │ └── yui-prettify.js │ └── vendor │ │ └── prettify │ │ ├── CHANGES.html │ │ ├── COPYING │ │ ├── README.html │ │ ├── prettify-min.css │ │ └── prettify-min.js ├── classes │ ├── BaseBatch.html │ ├── FrameBuffer.html │ ├── Mesh.html │ ├── ShaderProgram.html │ ├── SpriteBatch.html │ ├── Texture.html │ ├── WebGLContext.html │ └── index.html ├── data.json ├── files │ ├── index.html │ ├── lib_BaseBatch.js.html │ ├── lib_SpriteBatch.js.html │ ├── lib_Texture.js.html │ ├── lib_TextureRegion.js.html │ ├── lib_WebGLContext.js.html │ ├── lib_glutils_FrameBuffer.js.html │ ├── lib_glutils_Mesh.js.html │ ├── lib_glutils_ShaderProgram.js.html │ ├── lib_index-umd.js.html │ └── lib_index.js.html ├── index.html └── modules │ ├── index.html │ └── kami.html ├── lib ├── BaseBatch.js ├── SpriteBatch.js ├── Texture.js ├── TextureRegion.js ├── WebGLContext.js ├── glutils │ ├── FrameBuffer.js │ ├── Mesh.js │ └── ShaderProgram.js ├── index-umd.js └── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | .DS_Store 4 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | .DS_Store 4 | build/ 5 | demos/ 6 | Gruntfile.js 7 | docs/ -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | module.exports = function(grunt) { 5 | 6 | require('load-grunt-tasks')(grunt); 7 | 8 | grunt.initConfig({ 9 | 10 | pkg: grunt.file.readJSON('package.json'), 11 | 12 | dirs: { 13 | build: 'build', 14 | src: 'lib', 15 | demos: 'demos', 16 | demo_src: 'demos/src', 17 | demo_build: 'demos/build', 18 | docs: 'docs' 19 | }, 20 | 21 | browserify: { 22 | //We include a UMD build for non-Node people... 23 | umd: { 24 | src: ['<%= dirs.src %>/index-umd.js'], 25 | dest: '<%= dirs.build %>/kami.js', 26 | 27 | options: { 28 | standalone: "kami", 29 | debug: true 30 | } 31 | }, 32 | 33 | demos: { 34 | src: ['<%= dirs.src %>/index.js'], 35 | dest: '<%= dirs.demo_build %>/bundle.js', 36 | 37 | options: { 38 | debug: true, 39 | alias: [ 40 | '<%= dirs.src %>/index.js:kami', 41 | 'signals', //externalize, 42 | 'number-util' 43 | ] 44 | } 45 | } 46 | }, 47 | 48 | watch: { 49 | demos: { 50 | //Watch for changes... 51 | files: ['<%= dirs.src %>/**/*.js', 52 | '<%= dirs.demo_src %>/**/*.js', 53 | '<%= dirs.demos %>/**/*.html', 54 | 'Gruntfile.js'], 55 | tasks: ['browserify:demos', 'yuidoc'], 56 | options: { 57 | livereload: true 58 | }, 59 | }, 60 | }, 61 | 62 | 63 | uglify: { 64 | umd: { 65 | files: { 66 | '<%= dirs.build %>/kami.min.js': ['<%= dirs.build %>/kami.js'] 67 | } 68 | }, 69 | demos: { 70 | files: { 71 | '<%= dirs.demo_build %>/kami.min.js': ['<%= dirs.build %>/kami.js'] 72 | } 73 | } 74 | }, 75 | 76 | //Builds the documentation; do not run this task directly 77 | yuidoc: { 78 | compile: { 79 | name: '<%= pkg.name %>', 80 | description: '<%= pkg.description %>', 81 | version: '<%= pkg.version %>', 82 | url: '<%= pkg.homepage %>', 83 | options: { 84 | paths: '<%= dirs.src %>', 85 | outdir: '<%= dirs.docs %>', 86 | 87 | //nocode: true, 88 | } 89 | } 90 | }, 91 | 92 | //We use a little grunt plugin to write out the index.js file. 93 | //This also builds a UMD-specific index file, which is then browserified. 94 | autoindex: { 95 | umd: { 96 | options: { 97 | banner: "/**\n" + 98 | " Auto-generated Kami index file.\n" + 99 | " Dependencies are placed on the top-level namespace, for convenience.\n" + 100 | " Created on <%= grunt.template.today('yyyy-mm-dd') %>.\n" + 101 | "*/", 102 | 103 | // Options for our dependency modules... 104 | modules: { 105 | 106 | //Export this module with the name 'Class' 107 | 'klasse': { 108 | standalone: 'Class' 109 | }, 110 | 111 | //We want to export the NumberUtils too.. 112 | //we'll use the same naming style as the rest of Kami 113 | 'number-util': { 114 | standalone: 'NumberUtil' 115 | } 116 | } 117 | }, 118 | dest: '<%= dirs.src %>/index-umd.js', 119 | src: '<%= dirs.src %>' 120 | }, 121 | 122 | core: { 123 | options: { 124 | banner: "/**\n" + 125 | " Auto-generated Kami index file.\n" + 126 | " Created on <%= grunt.template.today('yyyy-mm-dd') %>.\n" + 127 | "*/", 128 | 129 | // only core modules 130 | dependencies: [], 131 | // ignore the UMD file if it's present 132 | file_ignores: ['<%= dirs.src %>/index-umd.js'], 133 | }, 134 | dest: '<%= dirs.src %>/index.js', 135 | src: '<%= dirs.src %>' 136 | } 137 | } 138 | }); 139 | 140 | //Builds core library 141 | grunt.registerTask('build-umd', ['autoindex:umd', 'browserify:umd', 'uglify:umd']); 142 | 143 | //Depends on build-umd 144 | grunt.registerTask('build-demos', ['browserify:demos', 'uglify:demos']) 145 | 146 | 147 | grunt.registerTask('build', ['autoindex:core', 'build-umd', 'build-demos', 'yuidoc']); 148 | grunt.registerTask('default', ['build']); 149 | 150 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Upcoming v1.0.0 Changes 2 | 3 | Kami is now breaking into small and composable modules that will be published separately to NPM. Most new work is under the [stackgl](https://github.com/stackgl) ecosystem. However, some higher-level 2D game abstractions may be eventually built on top of these modules under the kami namespace. 4 | 5 | ## kami 6 | 7 | Kami is a fast and lightweight WebGL sprite rendering framework. 8 | 9 | It is ideal for tinkering with WebGL, building your game engine on top of, or writing applications that require low-level control over vertex data, textures, and so forth. 10 | 11 | **This library is still in development.** 12 | 13 | ## Docs 14 | 15 | [Kami API Docs](http://mattdesl.github.io/kami/docs/) 16 | 17 | ## Usage 18 | 19 | Here is an example using Node style requires and browserify: 20 | 21 | ```javascript 22 | //require the necessary classes from the 'kami' module 23 | var AssetManager = require('kami').AssetManager; 24 | var SpriteBatch = require('kami').SpriteBatch; 25 | 26 | var WebGLContext = require('kami').WebGLContext; 27 | 28 | var width = 256; 29 | var height = 256; 30 | 31 | //create our webGL context.. 32 | //this will manage viewport and context loss/restore 33 | var context = new WebGLContext(width, height); 34 | 35 | //add the GL canvas to the DOM 36 | document.body.appendChild(context.view); 37 | 38 | //Create a new batcher for 2D sprites 39 | var batch = new SpriteBatch(context); 40 | 41 | //Create a new texture. This will load the URL asynchronously 42 | var tex0 = new Texture(context, "img/mysprite.png"); 43 | 44 | //kami aliases some Texture GLenums for convenience 45 | tex0.setFilter(Texture.Filter.LINEAR); 46 | 47 | //Start our render loop 48 | requestAnimationFrame(render); 49 | 50 | function render() { 51 | requestAnimationFrame(render); 52 | 53 | var gl = context.gl; 54 | 55 | //clear the GL canvas 56 | gl.clear(gl.COLOR_BUFFER_BIT); 57 | 58 | //start the batch... 59 | batch.begin(); 60 | 61 | //draw the texture at (75, 75) with a size of 100x100 62 | batch.draw(tex0, 75, 75, 100, 100); 63 | 64 | //draw it some other places 65 | batch.draw(tex0, 0, 0, 15, 25); 66 | batch.draw(tex0, 100, 100); 67 | 68 | //flush sprites to GPU 69 | batch.end(); 70 | } 71 | ``` 72 | 73 | ## demos 74 | 75 | The demos are hosted in another package, see here: 76 | https://github.com/mattdesl/kami-demos 77 | 78 | ## Using without Node 79 | 80 | If you aren't using Node and `require()` statements, you can grab the UMD build at `build/kami.js`. 81 | 82 | Most of the code looks exactly the same, except all of Kami's objects are exported onto a global `kami` namespace. The dependencies are also exported on the namespace, for convenience. See here: 83 | 84 | ```html 85 | 86 | 99 | ``` 100 | 101 | ## Road Map / TODOs 102 | 103 | - WebGL2 utils: compressed textures (done, see kami-demos), texture arrays, float textures, instanced draws, etc. 104 | - Cube maps and other Texture utils 105 | - clean up asset loading and kami-assets 106 | - MRTs for FrameBuffer utility (WebGL2) 107 | - SpriteBatch should use matrices (projeciton/transform) 108 | - SpriteBatch needs rotation -------------------------------------------------------------------------------- /docs/api.js: -------------------------------------------------------------------------------- 1 | YUI.add("yuidoc-meta", function(Y) { 2 | Y.YUIDoc = { meta: { 3 | "classes": [ 4 | "BaseBatch", 5 | "FrameBuffer", 6 | "Mesh", 7 | "ShaderProgram", 8 | "SpriteBatch", 9 | "Texture", 10 | "WebGLContext" 11 | ], 12 | "modules": [ 13 | "kami" 14 | ], 15 | "allModules": [ 16 | { 17 | "displayName": "kami", 18 | "name": "kami" 19 | } 20 | ] 21 | } }; 22 | }); -------------------------------------------------------------------------------- /docs/assets/css/external-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattdesl/kami/9a429563a4a2939f8aa4ff44abeb5330f74fe573/docs/assets/css/external-small.png -------------------------------------------------------------------------------- /docs/assets/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattdesl/kami/9a429563a4a2939f8aa4ff44abeb5330f74fe573/docs/assets/css/logo.png -------------------------------------------------------------------------------- /docs/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattdesl/kami/9a429563a4a2939f8aa4ff44abeb5330f74fe573/docs/assets/favicon.png -------------------------------------------------------------------------------- /docs/assets/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattdesl/kami/9a429563a4a2939f8aa4ff44abeb5330f74fe573/docs/assets/img/spinner.gif -------------------------------------------------------------------------------- /docs/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/assets/js/api-filter.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-filter', function (Y) { 2 | 3 | Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], { 4 | // -- Initializer ---------------------------------------------------------- 5 | initializer: function () { 6 | this._bindUIACBase(); 7 | this._syncUIACBase(); 8 | }, 9 | getDisplayName: function(name) { 10 | 11 | Y.each(Y.YUIDoc.meta.allModules, function(i) { 12 | if (i.name === name && i.displayName) { 13 | name = i.displayName; 14 | } 15 | }); 16 | 17 | return name; 18 | } 19 | 20 | }, { 21 | // -- Attributes ----------------------------------------------------------- 22 | ATTRS: { 23 | resultHighlighter: { 24 | value: 'phraseMatch' 25 | }, 26 | 27 | // May be set to "classes" or "modules". 28 | queryType: { 29 | value: 'classes' 30 | }, 31 | 32 | source: { 33 | valueFn: function() { 34 | var self = this; 35 | return function(q) { 36 | var data = Y.YUIDoc.meta[self.get('queryType')], 37 | out = []; 38 | Y.each(data, function(v) { 39 | if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) { 40 | out.push(v); 41 | } 42 | }); 43 | return out; 44 | }; 45 | } 46 | } 47 | } 48 | }); 49 | 50 | }, '3.4.0', {requires: [ 51 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources' 52 | ]}); 53 | -------------------------------------------------------------------------------- /docs/assets/js/api-list.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-list', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | YArray = Y.Array, 5 | 6 | APIList = Y.namespace('APIList'), 7 | 8 | classesNode = Y.one('#api-classes'), 9 | inputNode = Y.one('#api-filter'), 10 | modulesNode = Y.one('#api-modules'), 11 | tabviewNode = Y.one('#api-tabview'), 12 | 13 | tabs = APIList.tabs = {}, 14 | 15 | filter = APIList.filter = new Y.APIFilter({ 16 | inputNode : inputNode, 17 | maxResults: 1000, 18 | 19 | on: { 20 | results: onFilterResults 21 | } 22 | }), 23 | 24 | search = APIList.search = new Y.APISearch({ 25 | inputNode : inputNode, 26 | maxResults: 100, 27 | 28 | on: { 29 | clear : onSearchClear, 30 | results: onSearchResults 31 | } 32 | }), 33 | 34 | tabview = APIList.tabview = new Y.TabView({ 35 | srcNode : tabviewNode, 36 | panelNode: '#api-tabview-panel', 37 | render : true, 38 | 39 | on: { 40 | selectionChange: onTabSelectionChange 41 | } 42 | }), 43 | 44 | focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, { 45 | circular : true, 46 | descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a', 47 | keys : {next: 'down:40', previous: 'down:38'} 48 | }).focusManager, 49 | 50 | LIST_ITEM_TEMPLATE = 51 | '
  • ' + 52 | '{displayName}' + 53 | '
  • '; 54 | 55 | // -- Init --------------------------------------------------------------------- 56 | 57 | // Duckpunch FocusManager's key event handling to prevent it from handling key 58 | // events when a modifier is pressed. 59 | Y.before(function (e, activeDescendant) { 60 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 61 | return new Y.Do.Prevent(); 62 | } 63 | }, focusManager, '_focusPrevious', focusManager); 64 | 65 | Y.before(function (e, activeDescendant) { 66 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 67 | return new Y.Do.Prevent(); 68 | } 69 | }, focusManager, '_focusNext', focusManager); 70 | 71 | // Create a mapping of tabs in the tabview so we can refer to them easily later. 72 | tabview.each(function (tab, index) { 73 | var name = tab.get('label').toLowerCase(); 74 | 75 | tabs[name] = { 76 | index: index, 77 | name : name, 78 | tab : tab 79 | }; 80 | }); 81 | 82 | // Switch tabs on Ctrl/Cmd-Left/Right arrows. 83 | tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); 84 | 85 | // Focus the filter input when the `/` key is pressed. 86 | Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); 87 | 88 | // Keep the Focus Manager up to date. 89 | inputNode.on('focus', function () { 90 | focusManager.set('activeDescendant', inputNode); 91 | }); 92 | 93 | // Update all tabview links to resolved URLs. 94 | tabview.get('panelNode').all('a').each(function (link) { 95 | link.setAttribute('href', link.get('href')); 96 | }); 97 | 98 | // -- Private Functions -------------------------------------------------------- 99 | function getFilterResultNode() { 100 | return filter.get('queryType') === 'classes' ? classesNode : modulesNode; 101 | } 102 | 103 | // -- Event Handlers ----------------------------------------------------------- 104 | function onFilterResults(e) { 105 | var frag = Y.one(Y.config.doc.createDocumentFragment()), 106 | resultNode = getFilterResultNode(), 107 | typePlural = filter.get('queryType'), 108 | typeSingular = typePlural === 'classes' ? 'class' : 'module'; 109 | 110 | if (e.results.length) { 111 | YArray.each(e.results, function (result) { 112 | frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { 113 | rootPath : APIList.rootPath, 114 | displayName : filter.getDisplayName(result.highlighted), 115 | name : result.text, 116 | typePlural : typePlural, 117 | typeSingular: typeSingular 118 | })); 119 | }); 120 | } else { 121 | frag.append( 122 | '
  • ' + 123 | 'No ' + typePlural + ' found.' + 124 | '
  • ' 125 | ); 126 | } 127 | 128 | resultNode.empty(true); 129 | resultNode.append(frag); 130 | 131 | focusManager.refresh(); 132 | } 133 | 134 | function onSearchClear(e) { 135 | 136 | focusManager.refresh(); 137 | } 138 | 139 | function onSearchKey(e) { 140 | var target = e.target; 141 | 142 | if (target.test('input,select,textarea') 143 | || target.get('isContentEditable')) { 144 | return; 145 | } 146 | 147 | e.preventDefault(); 148 | 149 | inputNode.focus(); 150 | focusManager.refresh(); 151 | } 152 | 153 | function onSearchResults(e) { 154 | var frag = Y.one(Y.config.doc.createDocumentFragment()); 155 | 156 | if (e.results.length) { 157 | YArray.each(e.results, function (result) { 158 | frag.append(result.display); 159 | }); 160 | } else { 161 | frag.append( 162 | '
  • ' + 163 | 'No results found. Maybe you\'ll have better luck with a ' + 164 | 'different query?' + 165 | '
  • ' 166 | ); 167 | } 168 | 169 | 170 | focusManager.refresh(); 171 | } 172 | 173 | function onTabSelectionChange(e) { 174 | var tab = e.newVal, 175 | name = tab.get('label').toLowerCase(); 176 | 177 | tabs.selected = { 178 | index: tab.get('index'), 179 | name : name, 180 | tab : tab 181 | }; 182 | 183 | switch (name) { 184 | case 'classes': // fallthru 185 | case 'modules': 186 | filter.setAttrs({ 187 | minQueryLength: 0, 188 | queryType : name 189 | }); 190 | 191 | search.set('minQueryLength', -1); 192 | 193 | // Only send a request if this isn't the initially-selected tab. 194 | if (e.prevVal) { 195 | filter.sendRequest(filter.get('value')); 196 | } 197 | break; 198 | 199 | case 'everything': 200 | filter.set('minQueryLength', -1); 201 | search.set('minQueryLength', 1); 202 | 203 | if (search.get('value')) { 204 | search.sendRequest(search.get('value')); 205 | } else { 206 | inputNode.focus(); 207 | } 208 | break; 209 | 210 | default: 211 | // WTF? We shouldn't be here! 212 | filter.set('minQueryLength', -1); 213 | search.set('minQueryLength', -1); 214 | } 215 | 216 | if (focusManager) { 217 | setTimeout(function () { 218 | focusManager.refresh(); 219 | }, 1); 220 | } 221 | } 222 | 223 | function onTabSwitchKey(e) { 224 | var currentTabIndex = tabs.selected.index; 225 | 226 | if (!(e.ctrlKey || e.metaKey)) { 227 | return; 228 | } 229 | 230 | e.preventDefault(); 231 | 232 | switch (e.keyCode) { 233 | case 37: // left arrow 234 | if (currentTabIndex > 0) { 235 | tabview.selectChild(currentTabIndex - 1); 236 | inputNode.focus(); 237 | } 238 | break; 239 | 240 | case 39: // right arrow 241 | if (currentTabIndex < (Y.Object.size(tabs) - 2)) { 242 | tabview.selectChild(currentTabIndex + 1); 243 | inputNode.focus(); 244 | } 245 | break; 246 | } 247 | } 248 | 249 | }, '3.4.0', {requires: [ 250 | 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' 251 | ]}); 252 | -------------------------------------------------------------------------------- /docs/assets/js/api-search.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-search', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | Node = Y.Node, 5 | YArray = Y.Array; 6 | 7 | Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], { 8 | // -- Public Properties ---------------------------------------------------- 9 | RESULT_TEMPLATE: 10 | '
  • ' + 11 | '' + 12 | '

    {name}

    ' + 13 | '{resultType}' + 14 | '
    {description}
    ' + 15 | '{class}' + 16 | '
    ' + 17 | '
  • ', 18 | 19 | // -- Initializer ---------------------------------------------------------- 20 | initializer: function () { 21 | this._bindUIACBase(); 22 | this._syncUIACBase(); 23 | }, 24 | 25 | // -- Protected Methods ---------------------------------------------------- 26 | _apiResultFilter: function (query, results) { 27 | // Filter components out of the results. 28 | return YArray.filter(results, function (result) { 29 | return result.raw.resultType === 'component' ? false : result; 30 | }); 31 | }, 32 | 33 | _apiResultFormatter: function (query, results) { 34 | return YArray.map(results, function (result) { 35 | var raw = Y.merge(result.raw), // create a copy 36 | desc = raw.description || ''; 37 | 38 | // Convert description to text and truncate it if necessary. 39 | desc = Node.create('
    ' + desc + '
    ').get('text'); 40 | 41 | if (desc.length > 65) { 42 | desc = Y.Escape.html(desc.substr(0, 65)) + ' …'; 43 | } else { 44 | desc = Y.Escape.html(desc); 45 | } 46 | 47 | raw['class'] || (raw['class'] = ''); 48 | raw.description = desc; 49 | 50 | // Use the highlighted result name. 51 | raw.name = result.highlighted; 52 | 53 | return Lang.sub(this.RESULT_TEMPLATE, raw); 54 | }, this); 55 | }, 56 | 57 | _apiTextLocator: function (result) { 58 | return result.displayName || result.name; 59 | } 60 | }, { 61 | // -- Attributes ----------------------------------------------------------- 62 | ATTRS: { 63 | resultFormatter: { 64 | valueFn: function () { 65 | return this._apiResultFormatter; 66 | } 67 | }, 68 | 69 | resultFilters: { 70 | valueFn: function () { 71 | return this._apiResultFilter; 72 | } 73 | }, 74 | 75 | resultHighlighter: { 76 | value: 'phraseMatch' 77 | }, 78 | 79 | resultListLocator: { 80 | value: 'data.results' 81 | }, 82 | 83 | resultTextLocator: { 84 | valueFn: function () { 85 | return this._apiTextLocator; 86 | } 87 | }, 88 | 89 | source: { 90 | value: '/api/v1/search?q={query}&count={maxResults}' 91 | } 92 | } 93 | }); 94 | 95 | }, '3.4.0', {requires: [ 96 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources', 97 | 'escape' 98 | ]}); 99 | -------------------------------------------------------------------------------- /docs/assets/js/apidocs.js: -------------------------------------------------------------------------------- 1 | YUI().use( 2 | 'yuidoc-meta', 3 | 'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax', 4 | function (Y) { 5 | 6 | var win = Y.config.win, 7 | localStorage = win.localStorage, 8 | 9 | bdNode = Y.one('#bd'), 10 | 11 | pjax, 12 | defaultRoute, 13 | 14 | classTabView, 15 | selectedTab; 16 | 17 | // Kill pjax functionality unless serving over HTTP. 18 | if (!Y.getLocation().protocol.match(/^https?\:/)) { 19 | Y.Router.html5 = false; 20 | } 21 | 22 | // Create the default route with middleware which enables syntax highlighting 23 | // on the loaded content. 24 | defaultRoute = Y.Pjax.defaultRoute.concat(function (req, res, next) { 25 | prettyPrint(); 26 | bdNode.removeClass('loading'); 27 | 28 | next(); 29 | }); 30 | 31 | pjax = new Y.Pjax({ 32 | container : '#docs-main', 33 | contentSelector: '#docs-main > .content', 34 | linkSelector : '#bd a', 35 | titleSelector : '#xhr-title', 36 | 37 | navigateOnHash: true, 38 | root : '/', 39 | routes : [ 40 | // -- / ---------------------------------------------------------------- 41 | { 42 | path : '/(index.html)?', 43 | callbacks: defaultRoute 44 | }, 45 | 46 | // -- /classes/* ------------------------------------------------------- 47 | { 48 | path : '/classes/:class.html*', 49 | callbacks: [defaultRoute, 'handleClasses'] 50 | }, 51 | 52 | // -- /files/* --------------------------------------------------------- 53 | { 54 | path : '/files/*file', 55 | callbacks: [defaultRoute, 'handleFiles'] 56 | }, 57 | 58 | // -- /modules/* ------------------------------------------------------- 59 | { 60 | path : '/modules/:module.html*', 61 | callbacks: defaultRoute 62 | } 63 | ] 64 | }); 65 | 66 | // -- Utility Functions -------------------------------------------------------- 67 | 68 | pjax.checkVisibility = function (tab) { 69 | tab || (tab = selectedTab); 70 | 71 | if (!tab) { return; } 72 | 73 | var panelNode = tab.get('panelNode'), 74 | visibleItems; 75 | 76 | // If no items are visible in the tab panel due to the current visibility 77 | // settings, display a message to that effect. 78 | visibleItems = panelNode.all('.item,.index-item').some(function (itemNode) { 79 | if (itemNode.getComputedStyle('display') !== 'none') { 80 | return true; 81 | } 82 | }); 83 | 84 | panelNode.all('.no-visible-items').remove(); 85 | 86 | if (!visibleItems) { 87 | if (Y.one('#index .index-item')) { 88 | panelNode.append( 89 | '
    ' + 90 | '

    ' + 91 | 'Some items are not shown due to the current visibility ' + 92 | 'settings. Use the checkboxes at the upper right of this ' + 93 | 'page to change the visibility settings.' + 94 | '

    ' + 95 | '
    ' 96 | ); 97 | } else { 98 | panelNode.append( 99 | '
    ' + 100 | '

    ' + 101 | 'This class doesn\'t provide any methods, properties, ' + 102 | 'attributes, or events.' + 103 | '

    ' + 104 | '
    ' 105 | ); 106 | } 107 | } 108 | 109 | // Hide index sections without any visible items. 110 | Y.all('.index-section').each(function (section) { 111 | var items = 0, 112 | visibleItems = 0; 113 | 114 | section.all('.index-item').each(function (itemNode) { 115 | items += 1; 116 | 117 | if (itemNode.getComputedStyle('display') !== 'none') { 118 | visibleItems += 1; 119 | } 120 | }); 121 | 122 | section.toggleClass('hidden', !visibleItems); 123 | section.toggleClass('no-columns', visibleItems < 4); 124 | }); 125 | }; 126 | 127 | pjax.initClassTabView = function () { 128 | if (!Y.all('#classdocs .api-class-tab').size()) { 129 | return; 130 | } 131 | 132 | if (classTabView) { 133 | classTabView.destroy(); 134 | selectedTab = null; 135 | } 136 | 137 | classTabView = new Y.TabView({ 138 | srcNode: '#classdocs', 139 | 140 | on: { 141 | selectionChange: pjax.onTabSelectionChange 142 | } 143 | }); 144 | 145 | pjax.updateTabState(); 146 | classTabView.render(); 147 | }; 148 | 149 | pjax.initLineNumbers = function () { 150 | var hash = win.location.hash.substring(1), 151 | container = pjax.get('container'), 152 | hasLines, node; 153 | 154 | // Add ids for each line number in the file source view. 155 | container.all('.linenums>li').each(function (lineNode, index) { 156 | lineNode.set('id', 'l' + (index + 1)); 157 | lineNode.addClass('file-line'); 158 | hasLines = true; 159 | }); 160 | 161 | // Scroll to the desired line. 162 | if (hasLines && /^l\d+$/.test(hash)) { 163 | if ((node = container.getById(hash))) { 164 | win.scroll(0, node.getY()); 165 | } 166 | } 167 | }; 168 | 169 | pjax.initRoot = function () { 170 | var terminators = /^(?:classes|files|modules)$/, 171 | parts = pjax._getPathRoot().split('/'), 172 | root = [], 173 | i, len, part; 174 | 175 | for (i = 0, len = parts.length; i < len; i += 1) { 176 | part = parts[i]; 177 | 178 | if (part.match(terminators)) { 179 | // Makes sure the path will end with a "/". 180 | root.push(''); 181 | break; 182 | } 183 | 184 | root.push(part); 185 | } 186 | 187 | pjax.set('root', root.join('/')); 188 | }; 189 | 190 | pjax.updateTabState = function (src) { 191 | var hash = win.location.hash.substring(1), 192 | defaultTab, node, tab, tabPanel; 193 | 194 | function scrollToNode() { 195 | if (node.hasClass('protected')) { 196 | Y.one('#api-show-protected').set('checked', true); 197 | pjax.updateVisibility(); 198 | } 199 | 200 | if (node.hasClass('private')) { 201 | Y.one('#api-show-private').set('checked', true); 202 | pjax.updateVisibility(); 203 | } 204 | 205 | setTimeout(function () { 206 | // For some reason, unless we re-get the node instance here, 207 | // getY() always returns 0. 208 | var node = Y.one('#classdocs').getById(hash); 209 | win.scrollTo(0, node.getY() - 70); 210 | }, 1); 211 | } 212 | 213 | if (!classTabView) { 214 | return; 215 | } 216 | 217 | if (src === 'hashchange' && !hash) { 218 | defaultTab = 'index'; 219 | } else { 220 | if (localStorage) { 221 | defaultTab = localStorage.getItem('tab_' + pjax.getPath()) || 222 | 'index'; 223 | } else { 224 | defaultTab = 'index'; 225 | } 226 | } 227 | 228 | if (hash && (node = Y.one('#classdocs').getById(hash))) { 229 | if ((tabPanel = node.ancestor('.api-class-tabpanel', true))) { 230 | if ((tab = Y.one('#classdocs .api-class-tab.' + tabPanel.get('id')))) { 231 | if (classTabView.get('rendered')) { 232 | Y.Widget.getByNode(tab).set('selected', 1); 233 | } else { 234 | tab.addClass('yui3-tab-selected'); 235 | } 236 | } 237 | } 238 | 239 | // Scroll to the desired element if this is a hash URL. 240 | if (node) { 241 | if (classTabView.get('rendered')) { 242 | scrollToNode(); 243 | } else { 244 | classTabView.once('renderedChange', scrollToNode); 245 | } 246 | } 247 | } else { 248 | tab = Y.one('#classdocs .api-class-tab.' + defaultTab); 249 | 250 | // When the `defaultTab` node isn't found, `localStorage` is stale. 251 | if (!tab && defaultTab !== 'index') { 252 | tab = Y.one('#classdocs .api-class-tab.index'); 253 | } 254 | 255 | if (classTabView.get('rendered')) { 256 | Y.Widget.getByNode(tab).set('selected', 1); 257 | } else { 258 | tab.addClass('yui3-tab-selected'); 259 | } 260 | } 261 | }; 262 | 263 | pjax.updateVisibility = function () { 264 | var container = pjax.get('container'); 265 | 266 | container.toggleClass('hide-inherited', 267 | !Y.one('#api-show-inherited').get('checked')); 268 | 269 | container.toggleClass('show-deprecated', 270 | Y.one('#api-show-deprecated').get('checked')); 271 | 272 | container.toggleClass('show-protected', 273 | Y.one('#api-show-protected').get('checked')); 274 | 275 | container.toggleClass('show-private', 276 | Y.one('#api-show-private').get('checked')); 277 | 278 | pjax.checkVisibility(); 279 | }; 280 | 281 | // -- Route Handlers ----------------------------------------------------------- 282 | 283 | pjax.handleClasses = function (req, res, next) { 284 | var status = res.ioResponse.status; 285 | 286 | // Handles success and local filesystem XHRs. 287 | if (!status || (status >= 200 && status < 300)) { 288 | pjax.initClassTabView(); 289 | } 290 | 291 | next(); 292 | }; 293 | 294 | pjax.handleFiles = function (req, res, next) { 295 | var status = res.ioResponse.status; 296 | 297 | // Handles success and local filesystem XHRs. 298 | if (!status || (status >= 200 && status < 300)) { 299 | pjax.initLineNumbers(); 300 | } 301 | 302 | next(); 303 | }; 304 | 305 | // -- Event Handlers ----------------------------------------------------------- 306 | 307 | pjax.onNavigate = function (e) { 308 | var hash = e.hash, 309 | originTarget = e.originEvent && e.originEvent.target, 310 | tab; 311 | 312 | if (hash) { 313 | tab = originTarget && originTarget.ancestor('.yui3-tab', true); 314 | 315 | if (hash === win.location.hash) { 316 | pjax.updateTabState('hashchange'); 317 | } else if (!tab) { 318 | win.location.hash = hash; 319 | } 320 | 321 | e.preventDefault(); 322 | return; 323 | } 324 | 325 | // Only scroll to the top of the page when the URL doesn't have a hash. 326 | this.set('scrollToTop', !e.url.match(/#.+$/)); 327 | 328 | bdNode.addClass('loading'); 329 | }; 330 | 331 | pjax.onOptionClick = function (e) { 332 | pjax.updateVisibility(); 333 | }; 334 | 335 | pjax.onTabSelectionChange = function (e) { 336 | var tab = e.newVal, 337 | tabId = tab.get('contentBox').getAttribute('href').substring(1); 338 | 339 | selectedTab = tab; 340 | 341 | // If switching from a previous tab (i.e., this is not the default tab), 342 | // replace the history entry with a hash URL that will cause this tab to 343 | // be selected if the user navigates away and then returns using the back 344 | // or forward buttons. 345 | if (e.prevVal && localStorage) { 346 | localStorage.setItem('tab_' + pjax.getPath(), tabId); 347 | } 348 | 349 | pjax.checkVisibility(tab); 350 | }; 351 | 352 | // -- Init --------------------------------------------------------------------- 353 | 354 | pjax.on('navigate', pjax.onNavigate); 355 | 356 | pjax.initRoot(); 357 | pjax.upgrade(); 358 | pjax.initClassTabView(); 359 | pjax.initLineNumbers(); 360 | pjax.updateVisibility(); 361 | 362 | Y.APIList.rootPath = pjax.get('root'); 363 | 364 | Y.one('#api-options').delegate('click', pjax.onOptionClick, 'input'); 365 | 366 | Y.on('hashchange', function (e) { 367 | pjax.updateTabState('hashchange'); 368 | }, win); 369 | 370 | }); 371 | -------------------------------------------------------------------------------- /docs/assets/js/yui-prettify.js: -------------------------------------------------------------------------------- 1 | YUI().use('node', function(Y) { 2 | var code = Y.all('.prettyprint.linenums'); 3 | if (code.size()) { 4 | code.each(function(c) { 5 | var lis = c.all('ol li'), 6 | l = 1; 7 | lis.each(function(n) { 8 | n.prepend(''); 9 | l++; 10 | }); 11 | }); 12 | var h = location.hash; 13 | location.hash = ''; 14 | h = h.replace('LINE_', 'LINENUM_'); 15 | location.hash = h; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/CHANGES.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Change Log 5 | 6 | 7 | README 8 | 9 |

    Known Issues

    10 | 22 | 23 |

    Change Log

    24 |

    29 March 2007

    25 | 56 |

    4 Jul 2008

    57 | 63 |

    5 Jul 2008

    64 | 67 |

    14 Jul 2008

    68 | 76 |

    6 Jan 2009

    77 | 93 |

    21 May 2009

    94 | 101 |

    14 August 2009

    102 | 105 |

    3 October 2009

    106 | 109 |

    19 July 2010

    110 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/README.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Javascript code prettifier 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | Languages : CH 20 |

    Javascript code prettifier

    21 | 22 |

    Setup

    23 |
      24 |
    1. Download a distribution 25 |
    2. Include the script and stylesheets in your document 26 | (you will need to make sure the css and js file are on your server, and 27 | adjust the paths in the script and link tag) 28 |
       29 | <link href="prettify.css" type="text/css" rel="stylesheet" />
       30 | <script type="text/javascript" src="prettify.js"></script>
      31 |
    3. Add onload="prettyPrint()" to your 32 | document's body tag. 33 |
    4. Modify the stylesheet to get the coloring you prefer
    5. 34 |
    35 | 36 |

    Usage

    37 |

    Put code snippets in 38 | <pre class="prettyprint">...</pre> 39 | or <code class="prettyprint">...</code> 40 | and it will automatically be pretty printed. 41 | 42 | 43 | 44 | 47 |
    The original 45 | Prettier 46 |
    class Voila {
     49 | public:
     50 |   // Voila
     51 |   static const string VOILA = "Voila";
     52 | 
     53 |   // will not interfere with embedded tags.
     54 | }
    55 | 56 |
    class Voila {
     57 | public:
     58 |   // Voila
     59 |   static const string VOILA = "Voila";
     60 | 
     61 |   // will not interfere with embedded tags.
     62 | }
    63 |
    64 | 65 |

    FAQ

    66 |

    Which languages does it work for?

    67 |

    The comments in prettify.js are authoritative but the lexer 68 | should work on a number of languages including C and friends, 69 | Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles. 70 | It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl 71 | and Ruby, but, because of commenting conventions, doesn't work on 72 | Smalltalk, or CAML-like languages.

    73 | 74 |

    LISPy languages are supported via an extension: 75 | lang-lisp.js.

    77 |

    And similarly for 78 | CSS, 80 | Haskell, 82 | Lua, 84 | OCAML, SML, F#, 86 | Visual Basic, 88 | SQL, 90 | Protocol Buffers, and 92 | WikiText.. 94 | 95 |

    If you'd like to add an extension for your favorite language, please 96 | look at src/lang-lisp.js and file an 97 | issue including your language extension, and a testcase.

    99 | 100 |

    How do I specify which language my code is in?

    101 |

    You don't need to specify the language since prettyprint() 102 | will guess. You can specify a language by specifying the language extension 103 | along with the prettyprint class like so:

    104 |
    <pre class="prettyprint lang-html">
    106 |   The lang-* class specifies the language file extensions.
    107 |   File extensions supported by default include
    108 |     "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
    109 |     "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
    110 |     "xhtml", "xml", "xsl".
    111 | </pre>
    112 | 113 |

    It doesn't work on <obfuscated code sample>?

    114 |

    Yes. Prettifying obfuscated code is like putting lipstick on a pig 115 | — i.e. outside the scope of this tool.

    116 | 117 |

    Which browsers does it work with?

    118 |

    It's been tested with IE 6, Firefox 1.5 & 2, and Safari 2.0.4. 119 | Look at the test page to see if it 120 | works in your browser.

    121 | 122 |

    What's changed?

    123 |

    See the change log

    124 | 125 |

    Why doesn't Prettyprinting of strings work on WordPress?

    126 |

    Apparently wordpress does "smart quoting" which changes close quotes. 127 | This causes end quotes to not match up with open quotes. 128 |

    This breaks prettifying as well as copying and pasting of code samples. 129 | See 130 | WordPress's help center for info on how to stop smart quoting of code 132 | snippets.

    133 | 134 |

    How do I put line numbers in my code?

    135 |

    You can use the linenums class to turn on line 136 | numbering. If your code doesn't start at line number 1, you can 137 | add a colon and a line number to the end of that class as in 138 | linenums:52. 139 | 140 |

    For example 141 |

    <pre class="prettyprint linenums:4"
    142 | >// This is line 4.
    143 | foo();
    144 | bar();
    145 | baz();
    146 | boo();
    147 | far();
    148 | faz();
    149 | <pre>
    150 | produces 151 |
    // This is line 4.
    153 | foo();
    154 | bar();
    155 | baz();
    156 | boo();
    157 | far();
    158 | faz();
    159 | 
    160 | 161 |

    How do I prevent a portion of markup from being marked as code?

    162 |

    You can use the nocode class to identify a span of markup 163 | that is not code. 164 |

    <pre class=prettyprint>
    165 | int x = foo();  /* This is a comment  <span class="nocode">This is not code</span>
    166 |   Continuation of comment */
    167 | int y = bar();
    168 | </pre>
    169 | produces 170 |
    171 | int x = foo();  /* This is a comment  This is not code
    172 |   Continuation of comment */
    173 | int y = bar();
    174 | 
    175 | 176 |

    For a more complete example see the issue22 177 | testcase.

    178 | 179 |

    I get an error message "a is not a function" or "opt_whenDone is not a function"

    180 |

    If you are calling prettyPrint via an event handler, wrap it in a function. 181 | Instead of doing 182 |

    183 | addEventListener('load', prettyPrint, false); 185 |
    186 | wrap it in a closure like 187 |
    188 | addEventListener('load', function (event) { prettyPrint() }, false); 190 |
    191 | so that the browser does not pass an event object to prettyPrint which 192 | will confuse it. 193 | 194 |


    195 | 196 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/prettify-min.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/prettify-min.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;var prettyPrintOne;var prettyPrint;(function(){var O=window;var j=["break,continue,do,else,for,if,return,while"];var v=[j,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var q=[v,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var m=[q,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var y=[q,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var T=[y,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"];var s="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes";var x=[q,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var t="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var J=[j,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var g=[j,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var I=[j,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var B=[m,T,x,t+J,g,I];var f=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var D="str";var A="kwd";var k="com";var Q="typ";var H="lit";var M="pun";var G="pln";var n="tag";var F="dec";var K="src";var R="atn";var o="atv";var P="nocode";var N="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function l(ab){var af=0;var U=false;var ae=false;for(var X=0,W=ab.length;X122)){if(!(am<65||ai>90)){ah.push([Math.max(65,ai)|32,Math.min(am,90)|32])}if(!(am<97||ai>122)){ah.push([Math.max(97,ai)&~32,Math.min(am,122)&~32])}}}}ah.sort(function(aw,av){return(aw[0]-av[0])||(av[1]-aw[1])});var ak=[];var aq=[];for(var at=0;atau[0]){if(au[1]+1>au[0]){ao.push("-")}ao.push(V(au[1]))}}ao.push("]");return ao.join("")}function Y(an){var al=an.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var aj=al.length;var ap=[];for(var am=0,ao=0;am=2&&ak==="["){al[am]=Z(ai)}else{if(ak!=="\\"){al[am]=ai.replace(/[a-zA-Z]/g,function(aq){var ar=aq.charCodeAt(0);return"["+String.fromCharCode(ar&~32,ar|32)+"]"})}}}}return al.join("")}var ac=[];for(var X=0,W=ab.length;X=0;){U[ae.charAt(ag)]=aa}}var ah=aa[1];var ac=""+ah;if(!ai.hasOwnProperty(ac)){aj.push(ah);ai[ac]=null}}aj.push(/[\0-\uffff]/);X=l(aj)})();var Z=V.length;var Y=function(aj){var ab=aj.sourceCode,aa=aj.basePos;var af=[aa,G];var ah=0;var ap=ab.match(X)||[];var al={};for(var ag=0,at=ap.length;ag=5&&"lang-"===ar.substring(0,5);if(ao&&!(ak&&typeof ak[1]==="string")){ao=false;ar=K}if(!ao){al[ai]=ar}}var ad=ah;ah+=ai.length;if(!ao){af.push(aa+ad,ar)}else{var an=ak[1];var am=ai.indexOf(an);var ae=am+an.length;if(ak[2]){ae=ai.length-ak[2].length;am=ae-an.length}var au=ar.substring(5);C(aa+ad,ai.substring(0,am),Y,af);C(aa+ad+am,an,r(au,an),af);C(aa+ad+ae,ai.substring(ae),Y,af)}}aj.decorations=af};return Y}function i(V){var Y=[],U=[];if(V.tripleQuotedStrings){Y.push([D,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(V.multiLineStrings){Y.push([D,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{Y.push([D,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(V.verbatimStrings){U.push([D,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var ab=V.hashComments;if(ab){if(V.cStyleComments){if(ab>1){Y.push([k,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{Y.push([k,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}U.push([D,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{Y.push([k,/^#[^\r\n]*/,null,"#"])}}if(V.cStyleComments){U.push([k,/^\/\/[^\r\n]*/,null]);U.push([k,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(V.regexLiterals){var aa=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");U.push(["lang-regex",new RegExp("^"+N+"("+aa+")")])}var X=V.types;if(X){U.push([Q,X])}var W=(""+V.keywords).replace(/^ | $/g,"");if(W.length){U.push([A,new RegExp("^(?:"+W.replace(/[\s,]+/g,"|")+")\\b"),null])}Y.push([G,/^\s+/,null," \r\n\t\xA0"]);var Z=/^.[^\s\w\.$@\'\"\`\/\\]*/;U.push([H,/^@[a-z_$][a-z_$@0-9]*/i,null],[Q,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[G,/^[a-z_$][a-z_$@0-9]*/i,null],[H,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[G,/^\\[\s\S]?/,null],[M,Z,null]);return h(Y,U)}var L=i({keywords:B,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function S(W,ah,aa){var V=/(?:^|\s)nocode(?:\s|$)/;var ac=/\r\n?|\n/;var ad=W.ownerDocument;var ag=ad.createElement("li");while(W.firstChild){ag.appendChild(W.firstChild)}var X=[ag];function af(am){switch(am.nodeType){case 1:if(V.test(am.className)){break}if("br"===am.nodeName){ae(am);if(am.parentNode){am.parentNode.removeChild(am)}}else{for(var ao=am.firstChild;ao;ao=ao.nextSibling){af(ao)}}break;case 3:case 4:if(aa){var an=am.nodeValue;var ak=an.match(ac);if(ak){var aj=an.substring(0,ak.index);am.nodeValue=aj;var ai=an.substring(ak.index+ak[0].length);if(ai){var al=am.parentNode;al.insertBefore(ad.createTextNode(ai),am.nextSibling)}ae(am);if(!aj){am.parentNode.removeChild(am)}}}break}}function ae(al){while(!al.nextSibling){al=al.parentNode;if(!al){return}}function aj(am,at){var ar=at?am.cloneNode(false):am;var ap=am.parentNode;if(ap){var aq=aj(ap,1);var ao=am.nextSibling;aq.appendChild(ar);for(var an=ao;an;an=ao){ao=an.nextSibling;aq.appendChild(an)}}return ar}var ai=aj(al.nextSibling,0);for(var ak;(ak=ai.parentNode)&&ak.nodeType===1;){ai=ak}X.push(ai)}for(var Z=0;Z=U){aj+=2}if(Y>=ar){ac+=2}}}finally{if(au){au.style.display=ak}}}var u={};function d(W,X){for(var U=X.length;--U>=0;){var V=X[U];if(!u.hasOwnProperty(V)){u[V]=W}else{if(O.console){console.warn("cannot override language handler %s",V)}}}}function r(V,U){if(!(V&&u.hasOwnProperty(V))){V=/^\s*]*(?:>|$)/],[k,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[M,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);d(h([[G,/^[\s]+/,null," \t\r\n"],[o,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[n,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[R,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[M,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);d(h([],[[o,/^[\s\S]+/]]),["uq.val"]);d(i({keywords:m,hashComments:true,cStyleComments:true,types:f}),["c","cc","cpp","cxx","cyc","m"]);d(i({keywords:"null,true,false"}),["json"]);d(i({keywords:T,hashComments:true,cStyleComments:true,verbatimStrings:true,types:f}),["cs"]);d(i({keywords:y,cStyleComments:true}),["java"]);d(i({keywords:I,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);d(i({keywords:J,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);d(i({keywords:t,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);d(i({keywords:g,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);d(i({keywords:x,cStyleComments:true,regexLiterals:true}),["js"]);d(i({keywords:s,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);d(h([],[[D,/^[\s\S]+/]]),["regex"]);function e(X){var W=X.langExtension;try{var U=b(X.sourceNode,X.pre);var V=U.sourceCode;X.sourceCode=V;X.spans=U.spans;X.basePos=0;r(W,V)(X);E(X)}catch(Y){if(O.console){console.log(Y&&Y.stack?Y.stack:Y)}}}function z(Y,X,W){var U=document.createElement("pre");U.innerHTML=Y;if(W){S(U,W,true)}var V={langExtension:X,numberLines:W,sourceNode:U,pre:1};e(V);return U.innerHTML}function c(aj){function ab(al){return document.getElementsByTagName(al)}var ah=[ab("pre"),ab("code"),ab("xmp")];var V=[];for(var ae=0;ae]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); -------------------------------------------------------------------------------- /docs/classes/Mesh.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mesh - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    Mesh Class

    100 |
    101 | 102 | 103 | 104 | 105 | 106 |
    107 | Defined in: lib/glutils/Mesh.js:8 108 |
    109 | 110 | 111 | 112 | 113 | Module: kami 114 | 115 | 116 | 117 | 118 |
    119 | 120 | 121 | 122 |
    123 |

    A mesh class that wraps VBO and IBO.

    124 | 125 |
    126 | 127 | 128 | 129 |
    130 | 140 | 141 |
    142 |
    143 |

    Item Index

    144 | 145 | 146 | 147 | 148 |
    149 |

    Properties

    150 | 151 |
      152 | 153 |
    • 154 | dirty 155 | 156 | 157 | 158 |
    • 159 | 160 |
    • 161 | 162 | 163 | 164 | 165 |
    • 166 | 167 |
    • 168 | vertexStride 169 | 170 | 171 | 172 |
    • 173 | 174 |
    175 |
    176 | 177 | 178 | 179 | 180 | 181 |
    182 | 183 | 184 | 185 | 186 |
    187 |

    Properties

    188 | 189 | 190 |
    191 |

    dirty

    192 | Boolean 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 |
    203 | 204 | 205 | 206 |

    207 | 208 | Defined in 209 | 210 | 211 | 212 | 213 | lib/glutils/Mesh.js:16 214 | 215 |

    216 | 217 | 218 | 219 | 220 |
    221 | 222 |
    223 |

    A write-only property which sets both vertices and indices 224 | flag to dirty or not.

    225 | 226 |
    227 | 228 | 229 | 230 | 231 | 232 | 233 |
    234 | 235 | 236 |
    237 |

    238 | Unknown 239 | 240 | 241 | 242 | 243 | private 244 | 245 | 246 | 247 | 248 | 249 | 250 |
    251 | 252 | 253 | 254 |

    255 | 256 | Defined in 257 | 258 | 259 | 260 | 261 | lib/glutils/Mesh.js:70 262 | 263 |

    264 | 265 | 266 | 267 | 268 |
    269 | 270 |
    271 | 272 |
    273 | 274 | 275 | 276 | 277 | 278 | 279 |
    280 | 281 | 282 |
    283 |

    vertexStride

    284 | Number 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 |
    295 | 296 | 297 | 298 |

    299 | 300 | Defined in 301 | 302 | 303 | 304 | 305 | lib/glutils/Mesh.js:76 306 | 307 |

    308 | 309 | 310 | 311 | 312 |
    313 | 314 |
    315 |

    The stride for one vertex in bytes.

    316 | 317 |
    318 | 319 | 320 | 321 | 322 | 323 | 324 |
    325 | 326 | 327 |
    328 | 329 | 330 | 331 | 332 | 333 |
    334 |
    335 | 336 |
    337 |
    338 |
    339 |
    340 |
    341 |
    342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | -------------------------------------------------------------------------------- /docs/classes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/files/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/files/lib_TextureRegion.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/TextureRegion.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/TextureRegion.js

    100 | 101 |
    102 |
    103 | var Class = require('klasse');
    104 | 
    105 | //This is a GL-specific texture region, employing tangent space normalized coordinates U and V.
    106 | //A canvas-specific region would really just be a lightweight object with { x, y, width, height }
    107 | //in pixels.
    108 | var TextureRegion = new Class({
    109 | 
    110 | 	initialize: function TextureRegion(texture, x, y, width, height) {
    111 | 		this.texture = texture;
    112 | 		this.setRegion(x, y, width, height);
    113 | 	},
    114 | 
    115 | 	setUVs: function(u, v, u2, v2) {
    116 | 		this.regionWidth = Math.round(Math.abs(u2 - u) * this.texture.width);
    117 |         this.regionHeight = Math.round(Math.abs(v2 - v) * this.texture.height);
    118 | 
    119 |         // From LibGDX TextureRegion.java -- 
    120 | 		// For a 1x1 region, adjust UVs toward pixel center to avoid filtering artifacts on AMD GPUs when drawing very stretched.
    121 | 		if (this.regionWidth == 1 && this.regionHeight == 1) {
    122 | 			var adjustX = 0.25 / this.texture.width;
    123 | 			u += adjustX;
    124 | 			u2 -= adjustX;
    125 | 			var adjustY = 0.25 / this.texture.height;
    126 | 			v += adjustY;
    127 | 			v2 -= adjustY;
    128 | 		}
    129 | 
    130 | 		this.u = u;
    131 | 		this.v = v;
    132 | 		this.u2 = u2;
    133 | 		this.v2 = v2;
    134 | 	},
    135 | 
    136 | 	setRegion: function(x, y, width, height) {
    137 | 		x = x || 0;
    138 | 		y = y || 0;
    139 | 		width = (width===0 || width) ? width : this.texture.width;
    140 | 		height = (height===0 || height) ? height : this.texture.height;
    141 | 
    142 | 		var invTexWidth = 1 / this.texture.width;
    143 | 		var invTexHeight = 1 / this.texture.height;
    144 | 		this.setUVs(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
    145 | 		this.regionWidth = Math.abs(width);
    146 | 		this.regionHeight = Math.abs(height);
    147 | 	},
    148 | 
    149 | 	/** Sets the texture to that of the specified region and sets the coordinates relative to the specified region. */
    150 | 	setFromRegion: function(region, x, y, width, height) {
    151 | 		this.texture = region.texture;
    152 | 		this.set(region.getRegionX() + x, region.getRegionY() + y, width, height);
    153 | 	},
    154 | 
    155 | 
    156 | 	//TODO: add setters for regionX/Y and regionWidth/Height
    157 | 
    158 | 	regionX: {
    159 | 		get: function() {
    160 | 			return Math.round(this.u * this.texture.width);
    161 | 		} 
    162 | 	},
    163 | 
    164 | 	regionY: {
    165 | 		get: function() {
    166 | 			return Math.round(this.v * this.texture.height);
    167 | 		}
    168 | 	},
    169 | 
    170 | 	flip: function(x, y) {
    171 | 		var temp;
    172 | 		if (x) {
    173 | 			temp = this.u;
    174 | 			this.u = this.u2;
    175 | 			this.u2 = temp;
    176 | 		}
    177 | 		if (y) {
    178 | 			temp = this.v;
    179 | 			this.v = this.v2;
    180 | 			this.v2 = temp;
    181 | 		}
    182 | 	}
    183 | });
    184 | 
    185 | module.exports = TextureRegion;
    186 |     
    187 |
    188 | 189 |
    190 |
    191 |
    192 |
    193 |
    194 |
    195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /docs/files/lib_WebGLContext.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/WebGLContext.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/WebGLContext.js

    100 | 101 |
    102 |
    103 | /**
    104 |  * @module kami
    105 |  */
    106 | 
    107 | var Class = require('klasse');
    108 | var Signal = require('signals');
    109 | 
    110 | /**
    111 |  * A thin wrapper around WebGLRenderingContext which handles
    112 |  * context loss and restore with various rendering objects (textures,
    113 |  * shaders and buffers). This also handles general viewport management.
    114 |  *
    115 |  * If the view is not specified, a canvas will be created.
    116 |  *
    117 |  * If the `view` parameter is an instanceof WebGLRenderingContext,
    118 |  * we will use its canvas and context without fetching another through `getContext`.
    119 |  * Passing a canvas that has already had `getContext('webgl')` called will not cause
    120 |  * errors, but in certain debuggers (e.g. Chrome WebGL Inspector) only the latest
    121 |  * context will be traced.
    122 |  * 
    123 |  * @class  WebGLContext
    124 |  * @constructor
    125 |  * @param {Number} width the width of the GL canvas
    126 |  * @param {Number} height the height of the GL canvas
    127 |  * @param {HTMLCanvasElement} view the optional DOM canvas element
    128 |  * @param {Object} contextAttribuets an object containing context attribs which
    129 |  *                                   will be used during GL initialization
    130 |  */
    131 | var WebGLContext = new Class({
    132 | 	
    133 | 	initialize: function WebGLContext(width, height, view, contextAttributes) {
    134 | 		/**
    135 | 		 * The list of rendering objects (shaders, VBOs, textures, etc) which are 
    136 | 		 * currently being managed. Any object with a "create" method can be added
    137 | 		 * to this list. Upon destroying the rendering object, it should be removed.
    138 | 		 * See addManagedObject and removeManagedObject.
    139 | 		 * 
    140 | 		 * @property {Array} managedObjects
    141 | 		 */
    142 | 		this.managedObjects = [];
    143 | 
    144 | 		/**
    145 | 		 * The actual GL context. You can use this for
    146 | 		 * raw GL calls or to access GLenum constants. This
    147 | 		 * will be updated on context restore. While the WebGLContext
    148 | 		 * is not `valid`, you should not try to access GL state.
    149 | 		 * 
    150 | 		 * @property gl
    151 | 		 * @type {WebGLRenderingContext}
    152 | 		 */
    153 | 		this.gl = null;
    154 | 
    155 | 		if (view && typeof window.WebGLRenderingContext !== "undefined"
    156 | 				 && view instanceof window.WebGLRenderingContext) {
    157 | 			view = view.canvas;
    158 | 			this.gl = view;
    159 | 			this.valid = true;
    160 | 			contextAttributes = undefined; //just ignore new attribs...
    161 | 		}
    162 | 
    163 | 		/**
    164 | 		 * The canvas DOM element for this context.
    165 | 		 * @property {Number} view
    166 | 		 */
    167 | 		this.view = view || document.createElement("canvas");
    168 | 
    169 | 		//default size as per spec:
    170 | 		//http://www.w3.org/TR/2012/WD-html5-author-20120329/the-canvas-element.html#the-canvas-element
    171 | 		
    172 | 		/**
    173 | 		 * The width of this canvas.
    174 | 		 *
    175 | 		 * @property width
    176 | 		 * @type {Number}
    177 | 		 */
    178 | 		this.width = this.view.width = width || 300;
    179 | 
    180 | 		/**
    181 | 		 * The height of this canvas.
    182 | 		 * @property height
    183 | 		 * @type {Number}
    184 | 		 */
    185 | 		this.height = this.view.height = height || 150;
    186 | 
    187 | 
    188 | 		/**
    189 | 		 * The context attributes for initializing the GL state. This might include
    190 | 		 * anti-aliasing, alpha settings, verison, and so forth.
    191 | 		 * 
    192 | 		 * @property {Object} contextAttributes 
    193 | 		 */
    194 | 		this.contextAttributes = contextAttributes;
    195 | 		
    196 | 		/**
    197 | 		 * Whether this context is 'valid', i.e. renderable. A context that has been lost
    198 | 		 * (and not yet restored) or destroyed is invalid.
    199 | 		 * 
    200 | 		 * @property {Boolean} valid
    201 | 		 */
    202 | 		this.valid = false;
    203 | 
    204 | 		/**
    205 | 		 * A signal dispatched when GL context is lost. 
    206 | 		 * 
    207 | 		 * The first argument passed to the listener is the WebGLContext
    208 | 		 * managing the context loss.
    209 | 		 * 
    210 | 		 * @event {Signal} lost
    211 | 		 */
    212 | 		this.lost = new Signal();
    213 | 
    214 | 		/**
    215 | 		 * A signal dispatched when GL context is restored, after all the managed
    216 | 		 * objects have been recreated.
    217 | 		 *
    218 | 		 * The first argument passed to the listener is the WebGLContext
    219 | 		 * which managed the restoration.
    220 | 		 *
    221 | 		 * This does not gaurentee that all objects will be renderable.
    222 | 		 * For example, a Texture with an ImageProvider may still be loading
    223 | 		 * asynchronously.	 
    224 | 		 * 
    225 | 		 * @event {Signal} restored
    226 | 		 */
    227 | 		this.restored = new Signal();	
    228 | 		
    229 | 		//setup context lost and restore listeners
    230 | 		this.view.addEventListener("webglcontextlost", function (ev) {
    231 | 			ev.preventDefault();
    232 | 			this._contextLost(ev);
    233 | 		}.bind(this));
    234 | 		this.view.addEventListener("webglcontextrestored", function (ev) {
    235 | 			ev.preventDefault();
    236 | 			this._contextRestored(ev);
    237 | 		}.bind(this));
    238 | 			
    239 | 		if (!this.valid) //would only be valid if WebGLRenderingContext was passed 
    240 | 			this._initContext();
    241 | 
    242 | 		this.resize(this.width, this.height);
    243 | 	},
    244 | 	
    245 | 	_initContext: function() {
    246 | 		var err = "";
    247 | 		this.valid = false;
    248 | 
    249 | 		try {
    250 | 			this.gl = (this.view.getContext('webgl', this.contextAttributes) 
    251 | 						|| this.view.getContext('experimental-webgl', this.contextAttributes));
    252 | 		} catch (e) {
    253 | 			this.gl = null;
    254 | 		}
    255 | 
    256 | 		if (this.gl) {
    257 | 			this.valid = true;
    258 | 		} else {
    259 | 			throw "WebGL Context Not Supported -- try enabling it or using a different browser";
    260 | 		}	
    261 | 	},
    262 | 
    263 | 	/**
    264 | 	 * Updates the width and height of this WebGL context, resizes
    265 | 	 * the canvas view, and calls gl.viewport() with the new size.
    266 | 	 * 
    267 | 	 * @param  {Number} width  the new width
    268 | 	 * @param  {Number} height the new height
    269 | 	 */
    270 | 	resize: function(width, height) {
    271 | 		this.width = width;
    272 | 		this.height = height;
    273 | 
    274 | 		this.view.width = width;
    275 | 		this.view.height = height;
    276 | 
    277 | 		var gl = this.gl;
    278 | 		gl.viewport(0, 0, this.width, this.height);
    279 | 	},
    280 | 
    281 | 	/**
    282 | 	 * (internal use)
    283 | 	 * A managed object is anything with a "create" function, that will
    284 | 	 * restore GL state after context loss. 
    285 | 	 * 
    286 | 	 * @param {[type]} tex [description]
    287 | 	 */
    288 | 	addManagedObject: function(obj) {
    289 | 		this.managedObjects.push(obj);
    290 | 	},
    291 | 
    292 | 	/**
    293 | 	 * (internal use)
    294 | 	 * Removes a managed object from the cache. This is useful to destroy
    295 | 	 * a texture or shader, and have it no longer re-load on context restore.
    296 | 	 *
    297 | 	 * Returns the object that was removed, or null if it was not found in the cache.
    298 | 	 * 
    299 | 	 * @param  {Object} obj the object to be managed
    300 | 	 * @return {Object}     the removed object, or null
    301 | 	 */
    302 | 	removeManagedObject: function(obj) {
    303 | 		var idx = this.managedObjects.indexOf(obj);
    304 | 		if (idx > -1) {
    305 | 			this.managedObjects.splice(idx, 1);
    306 | 			return obj;
    307 | 		} 
    308 | 		return null;
    309 | 	},
    310 | 
    311 | 	/**
    312 | 	 * Calls destroy() on each managed object, then removes references to these objects
    313 | 	 * and the GL rendering context. This also removes references to the view and sets
    314 | 	 * the context's width and height to zero.
    315 | 	 *
    316 | 	 * Attempting to use this WebGLContext or the GL rendering context after destroying it
    317 | 	 * will lead to undefined behaviour.
    318 | 	 */
    319 | 	destroy: function() {
    320 | 		for (var i=0; i<this.managedObjects.length; i++) {
    321 | 			var obj = this.managedObjects[i];
    322 | 			if (obj && typeof obj.destroy === "function")
    323 | 				obj.destroy();
    324 | 		}
    325 | 		this.managedObjects.length = 0;
    326 | 		this.valid = false;
    327 | 		this.gl = null;
    328 | 		this.view = null;
    329 | 		this.width = this.height = 0;
    330 | 	},
    331 | 
    332 | 	_contextLost: function(ev) {
    333 | 		//all textures/shaders/buffers/FBOs have been deleted... 
    334 | 		//we need to re-create them on restore
    335 | 		this.valid = false;
    336 | 
    337 | 		this.lost.dispatch(this);
    338 | 	},
    339 | 
    340 | 	_contextRestored: function(ev) {
    341 | 		//first, initialize the GL context again
    342 | 		this._initContext();
    343 | 
    344 | 		//now we recreate our shaders and textures
    345 | 		for (var i=0; i<this.managedObjects.length; i++) {
    346 | 			this.managedObjects[i].create();
    347 | 		}
    348 | 
    349 | 		//update GL viewport
    350 | 		this.resize(this.width, this.height);
    351 | 
    352 | 		this.restored.dispatch(this);
    353 | 	}
    354 | });
    355 | 
    356 | module.exports = WebGLContext;
    357 |     
    358 |
    359 | 360 |
    361 |
    362 |
    363 |
    364 |
    365 |
    366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | -------------------------------------------------------------------------------- /docs/files/lib_glutils_FrameBuffer.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/glutils/FrameBuffer.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/glutils/FrameBuffer.js

    100 | 101 |
    102 |
    103 | var Class = require('klasse');
    104 | var Texture = require('../Texture');
    105 | 
    106 | 
    107 | var FrameBuffer = new Class({
    108 | 
    109 | 	/**
    110 | 	 * Creates a new Frame Buffer Object with the given width and height.
    111 | 	 *
    112 | 	 * If width and height are non-numbers, this method expects the
    113 | 	 * first parameter to be a Texture object which should be acted upon. 
    114 | 	 * In this case, the FrameBuffer does not "own" the texture, and so it
    115 | 	 * won't dispose of it upon destruction. This is an advanced version of the
    116 | 	 * constructor that assumes the user is giving us a valid Texture that can be bound (i.e.
    117 | 	 * no async Image textures).
    118 | 	 *
    119 | 	 * @class  FrameBuffer
    120 | 	 * @constructor
    121 | 	 * @param  {[type]} width  [description]
    122 | 	 * @param  {[type]} height [description]
    123 | 	 * @param  {[type]} filter [description]
    124 | 	 * @return {[type]}        [description]
    125 | 	 */
    126 | 	initialize: function FrameBuffer(context, width, height, format) { //TODO: depth component
    127 | 		if (typeof context !== "object")
    128 | 			throw "GL context not specified to FrameBuffer";
    129 | 	
    130 | 
    131 | 		/**
    132 | 		 * The underlying ID of the GL frame buffer object.
    133 | 		 *
    134 | 		 * @property {WebGLFramebuffer} id
    135 | 		 */		
    136 | 		this.id = null;
    137 | 
    138 | 		/**
    139 | 		 * The WebGLContext backed by this frame buffer.
    140 | 		 *
    141 | 		 * @property {WebGLContext} context
    142 | 		 */
    143 | 		this.context = context;
    144 | 
    145 | 		/**
    146 | 		 * The Texture backed by this frame buffer.
    147 | 		 *
    148 | 		 * @property {Texture} Texture
    149 | 		 */
    150 | 		//this Texture is now managed.
    151 | 		this.texture = new Texture(context, width, height, format);
    152 | 
    153 | 		//This is maanged by WebGLContext
    154 | 		this.context.addManagedObject(this);
    155 | 		this.create();
    156 | 	},
    157 | 
    158 | 	/**
    159 | 	 * A read-only property which returns the width of the backing texture. 
    160 | 	 * 
    161 | 	 * @readOnly
    162 | 	 * @property width
    163 | 	 * @type {Number}
    164 | 	 */
    165 | 	width: {
    166 | 		get: function() {
    167 | 			return this.texture.width
    168 | 		}
    169 | 	},
    170 | 
    171 | 	/**
    172 | 	 * A read-only property which returns the height of the backing texture. 
    173 | 	 * 
    174 | 	 * @readOnly
    175 | 	 * @property height
    176 | 	 * @type {Number}
    177 | 	 */
    178 | 	height: {
    179 | 		get: function() {
    180 | 			return this.texture.height;
    181 | 		}
    182 | 	},
    183 | 
    184 | 
    185 | 	/**
    186 | 	 * Called during initialization to setup the frame buffer; also called on
    187 | 	 * context restore. Users will not need to call this directly.
    188 | 	 * 
    189 | 	 * @method create
    190 | 	 */
    191 | 	create: function() {
    192 | 		this.gl = this.context.gl; 
    193 | 		var gl = this.gl;
    194 | 
    195 | 		var tex = this.texture;
    196 | 
    197 | 		//we assume the texture has already had create() called on it
    198 | 		//since it was added as a managed object prior to this FrameBuffer
    199 | 		tex.bind();
    200 |  
    201 | 		this.id = gl.createFramebuffer();
    202 | 		gl.bindFramebuffer(gl.FRAMEBUFFER, this.id);
    203 | 
    204 | 		gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex.target, tex.id, 0);
    205 | 
    206 | 		var result = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
    207 | 		if (result != gl.FRAMEBUFFER_COMPLETE) {
    208 | 			this.destroy(); //destroy our resources before leaving this function..
    209 | 
    210 | 			var err = "Framebuffer not complete";
    211 | 			switch (result) {
    212 | 				case gl.FRAMEBUFFER_UNSUPPORTED:
    213 | 					throw new Error(err + ": unsupported");
    214 | 				case gl.INCOMPLETE_DIMENSIONS:
    215 | 					throw new Error(err + ": incomplete dimensions");
    216 | 				case gl.INCOMPLETE_ATTACHMENT:
    217 | 					throw new Error(err + ": incomplete attachment");
    218 | 				case gl.INCOMPLETE_MISSING_ATTACHMENT:
    219 | 					throw new Error(err + ": missing attachment");
    220 | 				default:
    221 | 					throw new Error(err);
    222 | 			}
    223 | 		}
    224 | 		gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    225 | 	},
    226 | 
    227 | 
    228 | 	/**
    229 | 	 * Destroys this frame buffer. Using this object after destroying it will have
    230 | 	 * undefined results. 
    231 | 	 * @method destroy
    232 | 	 */
    233 | 	destroy: function() {
    234 | 		var gl = this.gl;
    235 | 
    236 | 		if (this.texture)
    237 | 			this.texture.destroy();
    238 | 		if (this.id && this.gl)
    239 | 			this.gl.deleteFramebuffer(this.id);
    240 | 		if (this.context)
    241 | 			this.context.removeManagedObject(this);
    242 | 
    243 | 		this.id = null;
    244 | 		this.gl = null;
    245 | 		this.texture = null;
    246 | 		this.context = null;
    247 | 	},
    248 | 
    249 | 	/**
    250 | 	 * Binds this framebuffer and sets the viewport to the expected size.
    251 | 	 * @method begin
    252 | 	 */
    253 | 	begin: function() {
    254 | 		var gl = this.gl;
    255 | 		gl.viewport(0, 0, this.texture.width, this.texture.height);
    256 | 		gl.bindFramebuffer(gl.FRAMEBUFFER, this.id);
    257 | 	},
    258 | 
    259 | 	/**
    260 | 	 * Binds the default frame buffer (the screen) and sets the viewport back
    261 | 	 * to the size of the WebGLContext.
    262 | 	 * 
    263 | 	 * @method end
    264 | 	 */
    265 | 	end: function() {
    266 | 		var gl = this.gl;
    267 | 		gl.viewport(0, 0, this.context.width, this.context.height);
    268 | 		gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    269 | 	}
    270 | });
    271 | 
    272 | module.exports = FrameBuffer;
    273 |     
    274 |
    275 | 276 |
    277 |
    278 |
    279 |
    280 |
    281 |
    282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /docs/files/lib_glutils_Mesh.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/glutils/Mesh.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/glutils/Mesh.js

    100 | 101 |
    102 |
    103 | /**
    104 |  * @module kami
    105 |  */
    106 | 
    107 | var Class = require('klasse');
    108 | 
    109 | //TODO: decouple into VBO + IBO utilities 
    110 | /**
    111 |  * A mesh class that wraps VBO and IBO.
    112 |  *
    113 |  * @class  Mesh
    114 |  */
    115 | var Mesh = new Class({
    116 | 
    117 | 
    118 | 	/**
    119 | 	 * A write-only property which sets both vertices and indices 
    120 | 	 * flag to dirty or not. 
    121 | 	 *
    122 | 	 * @property dirty
    123 | 	 * @type {Boolean}
    124 | 	 * @writeOnly
    125 | 	 */
    126 | 	dirty: {
    127 | 		set: function(val) {
    128 | 			this.verticesDirty = val;
    129 | 			this.indicesDirty = val;
    130 | 		}
    131 | 	},
    132 | 
    133 | 	/**
    134 | 	 * Creates a new Mesh with the provided parameters.
    135 | 	 *
    136 | 	 * If numIndices is 0 or falsy, no index buffer will be used
    137 | 	 * and indices will be an empty ArrayBuffer and a null indexBuffer.
    138 | 	 * 
    139 | 	 * If isStatic is true, then vertexUsage and indexUsage will
    140 | 	 * be set to gl.STATIC_DRAW. Otherwise they will use gl.DYNAMIC_DRAW.
    141 | 	 * You may want to adjust these after initialization for further control.
    142 | 	 * 
    143 | 	 * @param  {WebGLContext}  context the context for management
    144 | 	 * @param  {Boolean} isStatic      a hint as to whether this geometry is static
    145 | 	 * @param  {[type]}  numVerts      [description]
    146 | 	 * @param  {[type]}  numIndices    [description]
    147 | 	 * @param  {[type]}  vertexAttribs [description]
    148 | 	 * @return {[type]}                [description]
    149 | 	 */
    150 | 	initialize: function Mesh(context, isStatic, numVerts, numIndices, vertexAttribs) {
    151 | 		if (typeof context !== "object")
    152 | 			throw "GL context not specified to Mesh";
    153 | 		if (!numVerts)
    154 | 			throw "numVerts not specified, must be > 0";
    155 | 
    156 | 		this.context = context;
    157 | 		this.gl = context.gl;
    158 | 		
    159 | 		this.numVerts = null;
    160 | 		this.numIndices = null;
    161 | 		
    162 | 		this.vertices = null;
    163 | 		this.indices = null;
    164 | 		this.vertexBuffer = null;
    165 | 		this.indexBuffer = null;
    166 | 
    167 | 		this.verticesDirty = true;
    168 | 		this.indicesDirty = true;
    169 | 		this.indexUsage = null;
    170 | 		this.vertexUsage = null;
    171 | 
    172 | 		/** 
    173 | 		 * @property
    174 | 		 * @private
    175 | 		 */
    176 | 		this._vertexAttribs = null;
    177 | 
    178 | 		/** 
    179 | 		 * The stride for one vertex _in bytes_. 
    180 | 		 * 
    181 | 		 * @property {Number} vertexStride
    182 | 		 */
    183 | 		this.vertexStride = null;
    184 | 
    185 | 		this.numVerts = numVerts;
    186 | 		this.numIndices = numIndices || 0;
    187 | 		this.vertexUsage = isStatic ? this.gl.STATIC_DRAW : this.gl.DYNAMIC_DRAW;
    188 | 		this.indexUsage  = isStatic ? this.gl.STATIC_DRAW : this.gl.DYNAMIC_DRAW;
    189 | 		this._vertexAttribs = vertexAttribs || [];
    190 | 		
    191 | 		this.indicesDirty = true;
    192 | 		this.verticesDirty = true;
    193 | 
    194 | 		//determine the vertex stride based on given attributes
    195 | 		var totalNumComponents = 0;
    196 | 		for (var i=0; i<this._vertexAttribs.length; i++)
    197 | 			totalNumComponents += this._vertexAttribs[i].offsetCount;
    198 | 		this.vertexStride = totalNumComponents * 4; // in bytes
    199 | 
    200 | 		this.vertices = new Float32Array(this.numVerts);
    201 | 		this.indices = new Uint16Array(this.numIndices);
    202 | 
    203 | 		//add this VBO to the managed cache
    204 | 		this.context.addManagedObject(this);
    205 | 
    206 | 		this.create();
    207 | 	},
    208 | 
    209 | 	//recreates the buffers on context loss
    210 | 	create: function() {
    211 | 		this.gl = this.context.gl;
    212 | 		var gl = this.gl;
    213 | 		this.vertexBuffer = gl.createBuffer();
    214 | 
    215 | 		//ignore index buffer if we haven't specified any
    216 | 		this.indexBuffer = this.numIndices > 0
    217 | 					? gl.createBuffer()
    218 | 					: null;
    219 | 
    220 | 		this.dirty = true;
    221 | 	},
    222 | 
    223 | 	destroy: function() {
    224 | 		this.vertices = null;
    225 | 		this.indices = null;
    226 | 		if (this.vertexBuffer && this.gl)
    227 | 			this.gl.deleteBuffer(this.vertexBuffer);
    228 | 		if (this.indexBuffer && this.gl)
    229 | 			this.gl.deleteBuffer(this.indexBuffer);
    230 | 		this.vertexBuffer = null;
    231 | 		this.indexBuffer = null;
    232 | 		if (this.context)
    233 | 			this.context.removeManagedObject(this);
    234 | 		this.gl = null;
    235 | 		this.context = null;
    236 | 	},
    237 | 
    238 | 	_updateBuffers: function(ignoreBind, subDataLength) {
    239 | 		var gl = this.gl;
    240 | 
    241 | 		//bind our index data, if we have any
    242 | 		if (this.numIndices > 0) {
    243 | 			if (!ignoreBind)
    244 | 				gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
    245 | 
    246 | 			//update the index data
    247 | 			if (this.indicesDirty) {
    248 | 				gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, this.indexUsage);
    249 | 				this.indicesDirty = false;
    250 | 			}
    251 | 		}
    252 | 
    253 | 		//bind our vertex data
    254 | 		if (!ignoreBind)
    255 | 			gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
    256 | 
    257 | 		//update our vertex data
    258 | 		if (this.verticesDirty) {
    259 | 			if (subDataLength) {
    260 | 				// TODO: When decoupling VBO/IBO be sure to give better subData support..
    261 | 				var view = this.vertices.subarray(0, subDataLength);
    262 | 				gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
    263 | 			} else {
    264 | 				gl.bufferData(gl.ARRAY_BUFFER, this.vertices, this.vertexUsage);	
    265 | 			}
    266 | 
    267 | 			
    268 | 			this.verticesDirty = false;
    269 | 		}
    270 | 	},
    271 | 
    272 | 	draw: function(primitiveType, count, offset, subDataLength) {
    273 | 		if (count === 0)
    274 | 			return;
    275 | 
    276 | 		var gl = this.gl;
    277 | 		
    278 | 		offset = offset || 0;
    279 | 
    280 | 		//binds and updates our buffers. pass ignoreBind as true
    281 | 		//to avoid binding unnecessarily
    282 | 		this._updateBuffers(true, subDataLength);
    283 | 
    284 | 		if (this.numIndices > 0) { 
    285 | 			gl.drawElements(primitiveType, count, 
    286 | 						gl.UNSIGNED_SHORT, offset * 2); //* Uint16Array.BYTES_PER_ELEMENT
    287 | 		} else
    288 | 			gl.drawArrays(primitiveType, offset, count);
    289 | 	},
    290 | 
    291 | 	//binds this mesh's vertex attributes for the given shader
    292 | 	bind: function(shader) {
    293 | 		var gl = this.gl;
    294 | 
    295 | 		var offset = 0;
    296 | 		var stride = this.vertexStride;
    297 | 
    298 | 		//bind and update our vertex data before binding attributes
    299 | 		this._updateBuffers();
    300 | 
    301 | 		//for each attribtue
    302 | 		for (var i=0; i<this._vertexAttribs.length; i++) {
    303 | 			var a = this._vertexAttribs[i];
    304 | 
    305 | 			//location of the attribute
    306 | 			var loc = a.location === null 
    307 | 					? shader.getAttributeLocation(a.name)
    308 | 					: a.location;
    309 | 
    310 | 			//TODO: We may want to skip unfound attribs
    311 | 			// if (loc!==0 && !loc)
    312 | 			// 	console.warn("WARN:", a.name, "is not enabled");
    313 | 
    314 | 			//first, enable the vertex array
    315 | 			gl.enableVertexAttribArray(loc);
    316 | 
    317 | 			//then specify our vertex format
    318 | 			gl.vertexAttribPointer(loc, a.numComponents, a.type || gl.FLOAT, 
    319 | 								   a.normalize, stride, offset);
    320 | 
    321 | 			//and increase the offset...
    322 | 			offset += a.offsetCount * 4; //in bytes
    323 | 		}
    324 | 	},
    325 | 
    326 | 	unbind: function(shader) {
    327 | 		var gl = this.gl;
    328 | 
    329 | 		//for each attribtue
    330 | 		for (var i=0; i<this._vertexAttribs.length; i++) {
    331 | 			var a = this._vertexAttribs[i];
    332 | 
    333 | 			//location of the attribute
    334 | 			var loc = a.location === null 
    335 | 					? shader.getAttributeLocation(a.name)
    336 | 					: a.location;
    337 | 
    338 | 			//first, enable the vertex array
    339 | 			gl.disableVertexAttribArray(loc);
    340 | 		}
    341 | 	}
    342 | });
    343 | 
    344 | Mesh.Attrib = new Class({
    345 | 
    346 | 	name: null,
    347 | 	numComponents: null,
    348 | 	location: null,
    349 | 	type: null,
    350 | 
    351 | 	/**
    352 | 	 * Location is optional and for advanced users that
    353 | 	 * want vertex arrays to match across shaders. Any non-numerical
    354 | 	 * value will be converted to null, and ignored. If a numerical
    355 | 	 * value is given, it will override the position of this attribute
    356 | 	 * when given to a mesh.
    357 | 	 * 
    358 | 	 * @param  {[type]} name          [description]
    359 | 	 * @param  {[type]} numComponents [description]
    360 | 	 * @param  {[type]} location      [description]
    361 | 	 * @return {[type]}               [description]
    362 | 	 */
    363 | 	initialize: function(name, numComponents, location, type, normalize, offsetCount) {
    364 | 		this.name = name;
    365 | 		this.numComponents = numComponents;
    366 | 		this.location = typeof location === "number" ? location : null;
    367 | 		this.type = type;
    368 | 		this.normalize = Boolean(normalize);
    369 | 		this.offsetCount = typeof offsetCount === "number" ? offsetCount : this.numComponents;
    370 | 	}
    371 | })
    372 | 
    373 | 
    374 | module.exports = Mesh;
    375 |     
    376 |
    377 | 378 |
    379 |
    380 |
    381 |
    382 |
    383 |
    384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /docs/files/lib_index-umd.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/index-umd.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/index-umd.js

    100 | 101 |
    102 |
    103 | /**
    104 |   Auto-generated Kami index file.
    105 |   Dependencies are placed on the top-level namespace, for convenience.
    106 |   Created on 2014-06-11.
    107 | */
    108 | module.exports = {
    109 |     //core classes
    110 |     'BaseBatch':       require('./BaseBatch.js'),
    111 |     'SpriteBatch':     require('./SpriteBatch.js'),
    112 |     'Texture':         require('./Texture.js'),
    113 |     'TextureRegion':   require('./TextureRegion.js'),
    114 |     'WebGLContext':    require('./WebGLContext.js'),
    115 |     'FrameBuffer':     require('./glutils/FrameBuffer.js'),
    116 |     'Mesh':            require('./glutils/Mesh.js'),
    117 |     'ShaderProgram':   require('./glutils/ShaderProgram.js'),
    118 | 
    119 |     //signals dependencies
    120 |     'Signal':          require('signals').Signal,
    121 | 
    122 |     //klasse dependencies
    123 |     'Class':           require('klasse'),
    124 | 
    125 |     //number-util dependencies
    126 |     'NumberUtil':      require('number-util')
    127 | };
    128 |     
    129 |
    130 | 131 |
    132 |
    133 |
    134 |
    135 |
    136 |
    137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/files/lib_index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | lib/index.js - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    File: lib/index.js

    100 | 101 |
    102 |
    103 | /**
    104 |   Auto-generated Kami index file.
    105 |   Created on 2014-06-11.
    106 | */
    107 | module.exports = {
    108 |     //core classes
    109 |     'BaseBatch':       require('./BaseBatch.js'),
    110 |     'SpriteBatch':     require('./SpriteBatch.js'),
    111 |     'Texture':         require('./Texture.js'),
    112 |     'TextureRegion':   require('./TextureRegion.js'),
    113 |     'WebGLContext':    require('./WebGLContext.js'),
    114 |     'FrameBuffer':     require('./glutils/FrameBuffer.js'),
    115 |     'Mesh':            require('./glutils/Mesh.js'),
    116 |     'ShaderProgram':   require('./glutils/ShaderProgram.js')
    117 | };
    118 |     
    119 |
    120 | 121 |
    122 |
    123 |
    124 |
    125 |
    126 |
    127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |
    100 |
    101 |

    102 | Browse to a module or class using the sidebar to view its API documentation. 103 |

    104 | 105 |

    Keyboard Shortcuts

    106 | 107 |
      108 |
    • Press s to focus the API search box.

    • 109 | 110 |
    • Use Up and Down to select classes, modules, and search results.

    • 111 | 112 |
    • With the API search box or sidebar focused, use -Left or -Right to switch sidebar tabs.

    • 113 | 114 |
    • With the API search box or sidebar focused, use Ctrl+Left and Ctrl+Right to switch sidebar tabs.

    • 115 |
    116 |
    117 |
    118 | 119 | 120 | 121 |
    122 |
    123 |
    124 |
    125 |
    126 |
    127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /docs/modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/modules/kami.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | kami - kami 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 0.5.1 23 |
    24 |
    25 |
    26 | 27 |
    28 | 70 |
    71 |
    72 |
    73 | Show: 74 | 78 | 79 | 83 | 84 | 88 | 92 | 93 |
    94 | 95 | 96 |
    97 |
    98 |
    99 |

    kami Module

    100 |
    101 | 102 | 103 | 104 | 105 | 106 |
    107 | Defined in: lib/WebGLContext.js:8 108 |
    109 | 110 | 111 | 112 |
    113 | 114 | 115 | 116 |
    117 | 118 |
    119 | 120 | 121 | 122 |
    123 |
    124 | 125 |

    This module provides the following classes:

    126 | 127 | 172 | 173 |
    174 | 175 |
    176 | 177 |
    178 |
    179 | 180 |
    181 |
    182 |
    183 |
    184 |
    185 |
    186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /lib/BaseBatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The core kami module provides basic 2D sprite batching and 3 | * asset management. 4 | * 5 | * @module kami 6 | */ 7 | 8 | var Class = require('klasse'); 9 | var Mesh = require('./glutils/Mesh'); 10 | 11 | var colorToFloat = require('number-util').colorToFloat; 12 | 13 | /** 14 | * A batcher mixin composed of quads (two tris, indexed). 15 | * 16 | * This is used internally; users should look at 17 | * {{#crossLink "SpriteBatch"}}{{/crossLink}} instead, which inherits from this 18 | * class. 19 | * 20 | * The batcher itself is not managed by WebGLContext; however, it makes 21 | * use of Mesh and Texture which will be managed. For this reason, the batcher 22 | * does not hold a direct reference to the GL state. 23 | * 24 | * Subclasses must implement the following: 25 | * {{#crossLink "BaseBatch/_createShader:method"}}{{/crossLink}} 26 | * {{#crossLink "BaseBatch/_createVertexAttributes:method"}}{{/crossLink}} 27 | * {{#crossLink "BaseBatch/getVertexSize:method"}}{{/crossLink}} 28 | * 29 | * @class BaseBatch 30 | * @constructor 31 | * @param {WebGLContext} context the context this batcher belongs to 32 | * @param {Number} size the optional size of this batch, i.e. max number of quads 33 | * @default 500 34 | */ 35 | var BaseBatch = new Class({ 36 | 37 | //Constructor 38 | initialize: function BaseBatch(context, size) { 39 | if (typeof context !== "object") 40 | throw "GL context not specified to SpriteBatch"; 41 | this.context = context; 42 | 43 | this.size = size || 500; 44 | 45 | // 65535 is max index, so 65535 / 6 = 10922. 46 | if (this.size > 10922) //(you'd have to be insane to try and batch this much with WebGL) 47 | throw "Can't have more than 10922 sprites per batch: " + this.size; 48 | 49 | 50 | 51 | this._blendSrc = this.context.gl.ONE; 52 | this._blendDst = this.context.gl.ONE_MINUS_SRC_ALPHA 53 | this._blendingEnabled = true; 54 | this._shader = this._createShader(); 55 | 56 | /** 57 | * This shader will be used whenever "null" is passed 58 | * as the batch's shader. 59 | * 60 | * @property {ShaderProgram} shader 61 | */ 62 | this.defaultShader = this._shader; 63 | 64 | /** 65 | * By default, a SpriteBatch is created with its own ShaderProgram, 66 | * stored in `defaultShader`. If this flag is true, on deleting the SpriteBatch, its 67 | * `defaultShader` will also be deleted. If this flag is false, no shaders 68 | * will be deleted on destroy. 69 | * 70 | * Note that if you re-assign `defaultShader`, you will need to dispose the previous 71 | * default shader yoursel. 72 | * 73 | * @property ownsShader 74 | * @type {Boolean} 75 | */ 76 | this.ownsShader = true; 77 | 78 | this.idx = 0; 79 | 80 | /** 81 | * Whether we are currently drawing to the batch. Do not modify. 82 | * 83 | * @property {Boolean} drawing 84 | */ 85 | this.drawing = false; 86 | 87 | this.mesh = this._createMesh(this.size); 88 | 89 | 90 | /** 91 | * The ABGR packed color, as a single float. The default 92 | * value is the color white (255, 255, 255, 255). 93 | * 94 | * @property {Number} color 95 | * @readOnly 96 | */ 97 | this.color = colorToFloat(255, 255, 255, 255); 98 | 99 | /** 100 | * Whether to premultiply alpha on calls to setColor. 101 | * This is true by default, so that we can conveniently write: 102 | * 103 | * batch.setColor(1, 0, 0, 0.25); //tints red with 25% opacity 104 | * 105 | * If false, you must premultiply the colors yourself to achieve 106 | * the same tint, like so: 107 | * 108 | * batch.setColor(0.25, 0, 0, 0.25); 109 | * 110 | * @property premultiplied 111 | * @type {Boolean} 112 | * @default true 113 | */ 114 | this.premultiplied = true; 115 | }, 116 | 117 | /** 118 | * A property to enable or disable blending for this sprite batch. If 119 | * we are currently drawing, this will first flush the batch, and then 120 | * update GL_BLEND state (enabled or disabled) with our new value. 121 | * 122 | * @property {Boolean} blendingEnabled 123 | */ 124 | blendingEnabled: { 125 | set: function(val) { 126 | var old = this._blendingEnabled; 127 | if (this.drawing) 128 | this.flush(); 129 | 130 | this._blendingEnabled = val; 131 | 132 | //if we have a new value, update it. 133 | //this is because blend is done in begin() / end() 134 | if (this.drawing && old != val) { 135 | var gl = this.context.gl; 136 | if (val) 137 | gl.enable(gl.BLEND); 138 | else 139 | gl.disable(gl.BLEND); 140 | } 141 | 142 | }, 143 | 144 | get: function() { 145 | return this._blendingEnabled; 146 | } 147 | }, 148 | 149 | /** 150 | * Sets the blend source parameters. 151 | * If we are currently drawing, this will flush the batch. 152 | * 153 | * Setting either src or dst to `null` or a falsy value tells the SpriteBatch 154 | * to ignore gl.blendFunc. This is useful if you wish to use your 155 | * own blendFunc or blendFuncSeparate. 156 | * 157 | * @property {GLenum} blendDst 158 | */ 159 | blendSrc: { 160 | set: function(val) { 161 | if (this.drawing) 162 | this.flush(); 163 | this._blendSrc = val; 164 | }, 165 | 166 | get: function() { 167 | return this._blendSrc; 168 | } 169 | }, 170 | 171 | /** 172 | * Sets the blend destination parameters. 173 | * If we are currently drawing, this will flush the batch. 174 | * 175 | * Setting either src or dst to `null` or a falsy value tells the SpriteBatch 176 | * to ignore gl.blendFunc. This is useful if you wish to use your 177 | * own blendFunc or blendFuncSeparate. 178 | * 179 | * @property {GLenum} blendSrc 180 | */ 181 | blendDst: { 182 | set: function(val) { 183 | if (this.drawing) 184 | this.flush(); 185 | this._blendDst = val; 186 | }, 187 | 188 | get: function() { 189 | return this._blendDst; 190 | } 191 | }, 192 | 193 | /** 194 | * Sets the blend source and destination parameters. This is 195 | * a convenience function for the blendSrc and blendDst setters. 196 | * If we are currently drawing, this will flush the batch. 197 | * 198 | * Setting either to `null` or a falsy value tells the SpriteBatch 199 | * to ignore gl.blendFunc. This is useful if you wish to use your 200 | * own blendFunc or blendFuncSeparate. 201 | * 202 | * @method setBlendFunction 203 | * @param {GLenum} blendSrc the source blend parameter 204 | * @param {GLenum} blendDst the destination blend parameter 205 | */ 206 | setBlendFunction: function(blendSrc, blendDst) { 207 | this.blendSrc = blendSrc; 208 | this.blendDst = blendDst; 209 | }, 210 | 211 | /** 212 | * This is a setter/getter for this batch's current ShaderProgram. 213 | * If this is set when the batch is drawing, the state will be flushed 214 | * to the GPU and the new shader will then be bound. 215 | * 216 | * If `null` or a falsy value is specified, the batch's `defaultShader` will be used. 217 | * 218 | * Note that shaders are bound on batch.begin(). 219 | * 220 | * @property shader 221 | * @type {ShaderProgram} 222 | */ 223 | shader: { 224 | set: function(val) { 225 | var wasDrawing = this.drawing; 226 | 227 | if (wasDrawing) { 228 | this.end(); //unbinds the shader from the mesh 229 | } 230 | 231 | this._shader = val ? val : this.defaultShader; 232 | 233 | if (wasDrawing) { 234 | this.begin(); 235 | } 236 | }, 237 | 238 | get: function() { 239 | return this._shader; 240 | } 241 | }, 242 | 243 | /** 244 | * Sets the color of this sprite batcher, which is used in subsequent draw 245 | * calls. This does not flush the batch. 246 | * 247 | * If r, g, b, are all numbers, this method assumes that RGB 248 | * or RGBA float values (0.0 to 1.0) are being passed. Alpha defaults to one 249 | * if undefined. 250 | * 251 | * If the first three arguments are not numbers, we only consider the first argument 252 | * and assign it to all four components -- this is useful for setting transparency 253 | * in a premultiplied alpha stage. 254 | * 255 | * If the first argument is invalid or not a number, 256 | * the color defaults to (1, 1, 1, 1). 257 | * 258 | * @method setColor 259 | * @param {Number} r the red component, normalized 260 | * @param {Number} g the green component, normalized 261 | * @param {Number} b the blue component, normalized 262 | * @param {Number} a the alpha component, normalized 263 | */ 264 | setColor: function(r, g, b, a) { 265 | var rnum = typeof r === "number"; 266 | if (rnum 267 | && typeof g === "number" 268 | && typeof b === "number") { 269 | //default alpha to one 270 | a = (a || a === 0) ? a : 1.0; 271 | } else { 272 | r = g = b = a = rnum ? r : 1.0; 273 | } 274 | 275 | if (this.premultiplied) { 276 | r *= a; 277 | g *= a; 278 | b *= a; 279 | } 280 | 281 | this.color = colorToFloat( 282 | ~~(r * 255), 283 | ~~(g * 255), 284 | ~~(b * 255), 285 | ~~(a * 255) 286 | ); 287 | }, 288 | 289 | /** 290 | * Called from the constructor to create a new Mesh 291 | * based on the expected batch size. Should set up 292 | * verts & indices properly. 293 | * 294 | * Users should not call this directly; instead, it 295 | * should only be implemented by subclasses. 296 | * 297 | * @method _createMesh 298 | * @param {Number} size the size passed through the constructor 299 | */ 300 | _createMesh: function(size) { 301 | //the total number of floats in our batch 302 | var numVerts = size * 4 * this.getVertexSize(); 303 | //the total number of indices in our batch 304 | var numIndices = size * 6; 305 | var gl = this.context.gl; 306 | 307 | //vertex data 308 | this.vertices = new Float32Array(numVerts); 309 | //index data 310 | this.indices = new Uint16Array(numIndices); 311 | 312 | for (var i=0, j=0; i < numIndices; i += 6, j += 4) 313 | { 314 | this.indices[i + 0] = j + 0; 315 | this.indices[i + 1] = j + 1; 316 | this.indices[i + 2] = j + 2; 317 | this.indices[i + 3] = j + 0; 318 | this.indices[i + 4] = j + 2; 319 | this.indices[i + 5] = j + 3; 320 | } 321 | 322 | var mesh = new Mesh(this.context, false, 323 | numVerts, numIndices, this._createVertexAttributes()); 324 | mesh.vertices = this.vertices; 325 | mesh.indices = this.indices; 326 | mesh.vertexUsage = gl.DYNAMIC_DRAW; 327 | mesh.indexUsage = gl.STATIC_DRAW; 328 | mesh.dirty = true; 329 | return mesh; 330 | }, 331 | 332 | /** 333 | * Returns a shader for this batch. If you plan to support 334 | * multiple instances of your batch, it may or may not be wise 335 | * to use a shared shader to save resources. 336 | * 337 | * This method initially throws an error; so it must be overridden by 338 | * subclasses of BaseBatch. 339 | * 340 | * @method _createShader 341 | * @return {Number} the size of a vertex, in # of floats 342 | */ 343 | _createShader: function() { 344 | throw "_createShader not implemented" 345 | }, 346 | 347 | /** 348 | * Returns an array of vertex attributes for this mesh; 349 | * subclasses should implement this with the attributes 350 | * expected for their batch. 351 | * 352 | * This method initially throws an error; so it must be overridden by 353 | * subclasses of BaseBatch. 354 | * 355 | * @method _createVertexAttributes 356 | * @return {Array} an array of Mesh.VertexAttrib objects 357 | */ 358 | _createVertexAttributes: function() { 359 | throw "_createVertexAttributes not implemented"; 360 | }, 361 | 362 | 363 | /** 364 | * Returns the number of floats per vertex for this batcher. 365 | * 366 | * This method initially throws an error; so it must be overridden by 367 | * subclasses of BaseBatch. 368 | * 369 | * @method getVertexSize 370 | * @return {Number} the size of a vertex, in # of floats 371 | */ 372 | getVertexSize: function() { 373 | throw "getVertexSize not implemented"; 374 | }, 375 | 376 | 377 | /** 378 | * Begins the sprite batch. This will bind the shader 379 | * and mesh. Subclasses may want to disable depth or 380 | * set up blending. 381 | * 382 | * @method begin 383 | */ 384 | begin: function() { 385 | if (this.drawing) 386 | throw "batch.end() must be called before begin"; 387 | this.drawing = true; 388 | 389 | this.shader.bind(); 390 | 391 | //bind the attributes now to avoid redundant calls 392 | this.mesh.bind(this.shader); 393 | 394 | if (this._blendingEnabled) { 395 | var gl = this.context.gl; 396 | gl.enable(gl.BLEND); 397 | } 398 | }, 399 | 400 | /** 401 | * Ends the sprite batch. This will flush any remaining 402 | * data and set GL state back to normal. 403 | * 404 | * @method end 405 | */ 406 | end: function() { 407 | if (!this.drawing) 408 | throw "batch.begin() must be called before end"; 409 | if (this.idx > 0) 410 | this.flush(); 411 | this.drawing = false; 412 | 413 | this.mesh.unbind(this.shader); 414 | 415 | if (this._blendingEnabled) { 416 | var gl = this.context.gl; 417 | gl.disable(gl.BLEND); 418 | } 419 | }, 420 | 421 | /** 422 | * Called before rendering to bind new textures. 423 | * This method does nothing by default. 424 | * 425 | * @method _preRender 426 | */ 427 | _preRender: function() { 428 | }, 429 | 430 | /** 431 | * Flushes the batch by pushing the current data 432 | * to GL. 433 | * 434 | * @method flush 435 | */ 436 | flush: function() { 437 | if (this.idx===0) 438 | return; 439 | 440 | var gl = this.context.gl; 441 | 442 | //premultiplied alpha 443 | if (this._blendingEnabled) { 444 | //set either to null if you want to call your own 445 | //blendFunc or blendFuncSeparate 446 | if (this._blendSrc && this._blendDst) 447 | gl.blendFunc(this._blendSrc, this._blendDst); 448 | } 449 | 450 | this._preRender(); 451 | 452 | //number of sprites in batch 453 | var numComponents = this.getVertexSize(); 454 | var spriteCount = (this.idx / (numComponents * 4)); 455 | 456 | //draw the sprites 457 | this.mesh.verticesDirty = true; 458 | this.mesh.draw(gl.TRIANGLES, spriteCount * 6, 0, this.idx); 459 | 460 | this.idx = 0; 461 | }, 462 | 463 | /** 464 | * Adds a sprite to this batch. 465 | * The specifics depend on the sprite batch implementation. 466 | * 467 | * @method draw 468 | * @param {Texture} texture the texture for this sprite 469 | * @param {Number} x the x position, defaults to zero 470 | * @param {Number} y the y position, defaults to zero 471 | * @param {Number} width the width, defaults to the texture width 472 | * @param {Number} height the height, defaults to the texture height 473 | * @param {Number} u1 the first U coordinate, default zero 474 | * @param {Number} v1 the first V coordinate, default zero 475 | * @param {Number} u2 the second U coordinate, default one 476 | * @param {Number} v2 the second V coordinate, default one 477 | */ 478 | draw: function(texture, x, y, width, height, u1, v1, u2, v2) { 479 | }, 480 | 481 | /** 482 | * Adds a single quad mesh to this sprite batch from the given 483 | * array of vertices. 484 | * The specifics depend on the sprite batch implementation. 485 | * 486 | * @method drawVertices 487 | * @param {Texture} texture the texture we are drawing for this sprite 488 | * @param {Float32Array} verts an array of vertices 489 | * @param {Number} off the offset into the vertices array to read from 490 | */ 491 | drawVertices: function(texture, verts, off) { 492 | }, 493 | 494 | drawRegion: function(region, x, y, width, height) { 495 | this.draw(region.texture, x, y, width, height, region.u, region.v, region.u2, region.v2); 496 | }, 497 | 498 | /** 499 | * Destroys the batch, deleting its buffers and removing it from the 500 | * WebGLContext management. Trying to use this 501 | * batch after destroying it can lead to unpredictable behaviour. 502 | * 503 | * If `ownsShader` is true, this will also delete the `defaultShader` object. 504 | * 505 | * @method destroy 506 | */ 507 | destroy: function() { 508 | this.vertices = null; 509 | this.indices = null; 510 | this.size = this.maxVertices = 0; 511 | 512 | if (this.ownsShader && this.defaultShader) 513 | this.defaultShader.destroy(); 514 | this.defaultShader = null; 515 | this._shader = null; // remove reference to whatever shader is currently being used 516 | 517 | if (this.mesh) 518 | this.mesh.destroy(); 519 | this.mesh = null; 520 | } 521 | }); 522 | 523 | module.exports = BaseBatch; 524 | -------------------------------------------------------------------------------- /lib/SpriteBatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module kami 3 | */ 4 | 5 | // Requires.... 6 | var Class = require('klasse'); 7 | 8 | var BaseBatch = require('./BaseBatch'); 9 | 10 | var Mesh = require('./glutils/Mesh'); 11 | var ShaderProgram = require('./glutils/ShaderProgram'); 12 | 13 | /** 14 | * A basic implementation of a batcher which draws 2D sprites. 15 | * This uses two triangles (quads) with indexed and interleaved 16 | * vertex data. Each vertex holds 5 floats (Position.xy, Color, TexCoord0.xy). 17 | * 18 | * The color is packed into a single float to reduce vertex bandwidth, and 19 | * the data is interleaved for best performance. We use a static index buffer, 20 | * and a dynamic vertex buffer that is updated with bufferSubData. 21 | * 22 | * @example 23 | * var SpriteBatch = require('kami').SpriteBatch; 24 | * 25 | * //create a new batcher 26 | * var batch = new SpriteBatch(context); 27 | * 28 | * function render() { 29 | * batch.begin(); 30 | * 31 | * //draw some sprites in between begin and end... 32 | * batch.draw( texture, 0, 0, 25, 32 ); 33 | * batch.draw( texture1, 0, 25, 42, 23 ); 34 | * 35 | * batch.end(); 36 | * } 37 | * 38 | * @class SpriteBatch 39 | * @uses BaseBatch 40 | * @constructor 41 | * @param {WebGLContext} context the context for this batch 42 | * @param {Number} size the max number of sprites to fit in a single batch 43 | */ 44 | var SpriteBatch = new Class({ 45 | 46 | //inherit some stuff onto this prototype 47 | Mixins: BaseBatch, 48 | 49 | //Constructor 50 | initialize: function SpriteBatch(context, size) { 51 | BaseBatch.call(this, context, size); 52 | 53 | /** 54 | * The projection Float32Array vec2 which is 55 | * used to avoid some matrix calculations. 56 | * 57 | * @property projection 58 | * @type {Float32Array} 59 | */ 60 | this.projection = new Float32Array(2); 61 | 62 | //Sets up a default projection vector so that the batch works without setProjection 63 | this.projection[0] = this.context.width/2; 64 | this.projection[1] = this.context.height/2; 65 | 66 | /** 67 | * The currently bound texture. Do not modify. 68 | * 69 | * @property {Texture} texture 70 | * @readOnly 71 | */ 72 | this.texture = null; 73 | }, 74 | 75 | /** 76 | * This is a convenience function to set the batch's projection 77 | * matrix to an orthographic 2D projection, based on the given screen 78 | * size. This allows users to render in 2D without any need for a camera. 79 | * 80 | * @param {[type]} width [description] 81 | * @param {[type]} height [description] 82 | * @return {[type]} [description] 83 | */ 84 | resize: function(width, height) { 85 | this.setProjection(width/2, height/2); 86 | }, 87 | 88 | /** 89 | * The number of floats per vertex for this batcher 90 | * (Position.xy + Color + TexCoord0.xy). 91 | * 92 | * @method getVertexSize 93 | * @return {Number} the number of floats per vertex 94 | */ 95 | getVertexSize: function() { 96 | return SpriteBatch.VERTEX_SIZE; 97 | }, 98 | 99 | /** 100 | * Used internally to return the Position, Color, and TexCoord0 attributes. 101 | * 102 | * @method _createVertexAttribuets 103 | * @protected 104 | * @return {[type]} [description] 105 | */ 106 | _createVertexAttributes: function() { 107 | var gl = this.context.gl; 108 | 109 | return [ 110 | new Mesh.Attrib(ShaderProgram.POSITION_ATTRIBUTE, 2), 111 | //pack the color using some crazy wizardry 112 | new Mesh.Attrib(ShaderProgram.COLOR_ATTRIBUTE, 4, null, gl.UNSIGNED_BYTE, true, 1), 113 | new Mesh.Attrib(ShaderProgram.TEXCOORD_ATTRIBUTE+"0", 2) 114 | ]; 115 | }, 116 | 117 | 118 | /** 119 | * Sets the projection vector, an x and y 120 | * defining the middle points of your stage. 121 | * 122 | * @method setProjection 123 | * @param {Number} x the x projection value 124 | * @param {Number} y the y projection value 125 | */ 126 | setProjection: function(x, y) { 127 | var oldX = this.projection[0]; 128 | var oldY = this.projection[1]; 129 | this.projection[0] = x; 130 | this.projection[1] = y; 131 | 132 | //we need to flush the batch.. 133 | if (this.drawing && (x != oldX || y != oldY)) { 134 | this.flush(); 135 | this._updateMatrices(); 136 | } 137 | }, 138 | 139 | /** 140 | * Creates a default shader for this batch. 141 | * 142 | * @method _createShader 143 | * @protected 144 | * @return {ShaderProgram} a new instance of ShaderProgram 145 | */ 146 | _createShader: function() { 147 | var shader = new ShaderProgram(this.context, 148 | SpriteBatch.DEFAULT_VERT_SHADER, 149 | SpriteBatch.DEFAULT_FRAG_SHADER); 150 | if (shader.log) 151 | console.warn("Shader Log:\n" + shader.log); 152 | return shader; 153 | }, 154 | 155 | /** 156 | * This is called during rendering to update projection/transform 157 | * matrices and upload the new values to the shader. For example, 158 | * if the user calls setProjection mid-draw, the batch will flush 159 | * and this will be called before continuing to add items to the batch. 160 | * 161 | * You generally should not need to call this directly. 162 | * 163 | * @method updateMatrices 164 | * @protected 165 | */ 166 | updateMatrices: function() { 167 | this.shader.setUniformfv("u_projection", this.projection); 168 | }, 169 | 170 | /** 171 | * Called before rendering, and binds the current texture. 172 | * 173 | * @method _preRender 174 | * @protected 175 | */ 176 | _preRender: function() { 177 | if (this.texture) 178 | this.texture.bind(); 179 | }, 180 | 181 | /** 182 | * Binds the shader, disables depth writing, 183 | * enables blending, activates texture unit 0, and sends 184 | * default matrices and sampler2D uniforms to the shader. 185 | * 186 | * @method begin 187 | */ 188 | begin: function() { 189 | //sprite batch doesn't hold a reference to GL since it is volatile 190 | var gl = this.context.gl; 191 | 192 | //This binds the shader and mesh! 193 | BaseBatch.prototype.begin.call(this); 194 | 195 | this.updateMatrices(); //send projection/transform to shader 196 | 197 | //upload the sampler uniform. not necessary every flush so we just 198 | //do it here. 199 | this.shader.setUniformi("u_texture0", 0); 200 | 201 | //disable depth mask 202 | gl.depthMask(false); 203 | }, 204 | 205 | /** 206 | * Ends the sprite batcher and flushes any remaining data to the GPU. 207 | * 208 | * @method end 209 | */ 210 | end: function() { 211 | //sprite batch doesn't hold a reference to GL since it is volatile 212 | var gl = this.context.gl; 213 | 214 | //just do direct parent call for speed here 215 | //This binds the shader and mesh! 216 | BaseBatch.prototype.end.call(this); 217 | 218 | gl.depthMask(true); 219 | }, 220 | 221 | /** 222 | * Flushes the batch to the GPU. This should be called when 223 | * state changes, such as blend functions, depth or stencil states, 224 | * shaders, and so forth. 225 | * 226 | * @method flush 227 | */ 228 | flush: function() { 229 | //ignore flush if texture is null or our batch is empty 230 | if (!this.texture) 231 | return; 232 | if (this.idx === 0) 233 | return; 234 | BaseBatch.prototype.flush.call(this); 235 | SpriteBatch.totalRenderCalls++; 236 | }, 237 | 238 | /** 239 | * Adds a sprite to this batch. The sprite is drawn in 240 | * screen-space with the origin at the upper-left corner (y-down). 241 | * 242 | * @method draw 243 | * @param {Texture} texture the Texture 244 | * @param {Number} x the x position in pixels, defaults to zero 245 | * @param {Number} y the y position in pixels, defaults to zero 246 | * @param {Number} width the width in pixels, defaults to the texture width 247 | * @param {Number} height the height in pixels, defaults to the texture height 248 | * @param {Number} u1 the first U coordinate, default zero 249 | * @param {Number} v1 the first V coordinate, default zero 250 | * @param {Number} u2 the second U coordinate, default one 251 | * @param {Number} v2 the second V coordinate, default one 252 | */ 253 | draw: function(texture, x, y, width, height, u1, v1, u2, v2) { 254 | if (!this.drawing) 255 | throw "Illegal State: trying to draw a batch before begin()"; 256 | 257 | //don't draw anything if GL tex doesn't exist.. 258 | if (!texture) 259 | return; 260 | 261 | if (this.texture === null || this.texture.id !== texture.id) { 262 | //new texture.. flush previous data 263 | this.flush(); 264 | this.texture = texture; 265 | } else if (this.idx == this.vertices.length) { 266 | this.flush(); //we've reached our max, flush before pushing more data 267 | } 268 | 269 | width = (width===0) ? width : (width || texture.width); 270 | height = (height===0) ? height : (height || texture.height); 271 | x = x || 0; 272 | y = y || 0; 273 | 274 | var x1 = x; 275 | var x2 = x + width; 276 | var y1 = y; 277 | var y2 = y + height; 278 | 279 | u1 = u1 || 0; 280 | u2 = (u2===0) ? u2 : (u2 || 1); 281 | v1 = v1 || 0; 282 | v2 = (v2===0) ? v2 : (v2 || 1); 283 | 284 | var c = this.color; 285 | 286 | //xy 287 | this.vertices[this.idx++] = x1; 288 | this.vertices[this.idx++] = y1; 289 | //color 290 | this.vertices[this.idx++] = c; 291 | //uv 292 | this.vertices[this.idx++] = u1; 293 | this.vertices[this.idx++] = v1; 294 | 295 | //xy 296 | this.vertices[this.idx++] = x2; 297 | this.vertices[this.idx++] = y1; 298 | //color 299 | this.vertices[this.idx++] = c; 300 | //uv 301 | this.vertices[this.idx++] = u2; 302 | this.vertices[this.idx++] = v1; 303 | 304 | //xy 305 | this.vertices[this.idx++] = x2; 306 | this.vertices[this.idx++] = y2; 307 | //color 308 | this.vertices[this.idx++] = c; 309 | //uv 310 | this.vertices[this.idx++] = u2; 311 | this.vertices[this.idx++] = v2; 312 | 313 | //xy 314 | this.vertices[this.idx++] = x1; 315 | this.vertices[this.idx++] = y2; 316 | //color 317 | this.vertices[this.idx++] = c; 318 | //uv 319 | this.vertices[this.idx++] = u1; 320 | this.vertices[this.idx++] = v2; 321 | }, 322 | 323 | /** 324 | * Adds a single quad mesh to this sprite batch from the given 325 | * array of vertices. The sprite is drawn in 326 | * screen-space with the origin at the upper-left corner (y-down). 327 | * 328 | * This reads 20 interleaved floats from the given offset index, in the format 329 | * 330 | * { x, y, color, u, v, 331 | * ... } 332 | * 333 | * @method drawVertices 334 | * @param {Texture} texture the Texture object 335 | * @param {Float32Array} verts an array of vertices 336 | * @param {Number} off the offset into the vertices array to read from 337 | */ 338 | drawVertices: function(texture, verts, off) { 339 | if (!this.drawing) 340 | throw "Illegal State: trying to draw a batch before begin()"; 341 | 342 | //don't draw anything if GL tex doesn't exist.. 343 | if (!texture) 344 | return; 345 | 346 | 347 | if (this.texture != texture) { 348 | //new texture.. flush previous data 349 | this.flush(); 350 | this.texture = texture; 351 | } else if (this.idx == this.vertices.length) { 352 | this.flush(); //we've reached our max, flush before pushing more data 353 | } 354 | 355 | off = off || 0; 356 | //TODO: use a loop here? 357 | //xy 358 | this.vertices[this.idx++] = verts[off++]; 359 | this.vertices[this.idx++] = verts[off++]; 360 | //color 361 | this.vertices[this.idx++] = verts[off++]; 362 | //uv 363 | this.vertices[this.idx++] = verts[off++]; 364 | this.vertices[this.idx++] = verts[off++]; 365 | 366 | //xy 367 | this.vertices[this.idx++] = verts[off++]; 368 | this.vertices[this.idx++] = verts[off++]; 369 | //color 370 | this.vertices[this.idx++] = verts[off++]; 371 | //uv 372 | this.vertices[this.idx++] = verts[off++]; 373 | this.vertices[this.idx++] = verts[off++]; 374 | 375 | //xy 376 | this.vertices[this.idx++] = verts[off++]; 377 | this.vertices[this.idx++] = verts[off++]; 378 | //color 379 | this.vertices[this.idx++] = verts[off++]; 380 | //uv 381 | this.vertices[this.idx++] = verts[off++]; 382 | this.vertices[this.idx++] = verts[off++]; 383 | 384 | //xy 385 | this.vertices[this.idx++] = verts[off++]; 386 | this.vertices[this.idx++] = verts[off++]; 387 | //color 388 | this.vertices[this.idx++] = verts[off++]; 389 | //uv 390 | this.vertices[this.idx++] = verts[off++]; 391 | this.vertices[this.idx++] = verts[off++]; 392 | } 393 | }); 394 | 395 | /** 396 | * The default vertex size, i.e. number of floats per vertex. 397 | * @attribute VERTEX_SIZE 398 | * @static 399 | * @final 400 | * @type {Number} 401 | * @default 5 402 | */ 403 | SpriteBatch.VERTEX_SIZE = 5; 404 | 405 | /** 406 | * Incremented after each draw call, can be used for debugging. 407 | * 408 | * SpriteBatch.totalRenderCalls = 0; 409 | * 410 | * ... draw your scene ... 411 | * 412 | * console.log("Draw calls per frame:", SpriteBatch.totalRenderCalls); 413 | * 414 | * 415 | * @attribute totalRenderCalls 416 | * @static 417 | * @type {Number} 418 | * @default 0 419 | */ 420 | SpriteBatch.totalRenderCalls = 0; 421 | 422 | SpriteBatch.DEFAULT_FRAG_SHADER = [ 423 | "precision mediump float;", 424 | "varying vec2 vTexCoord0;", 425 | "varying vec4 vColor;", 426 | "uniform sampler2D u_texture0;", 427 | 428 | "void main(void) {", 429 | " gl_FragColor = texture2D(u_texture0, vTexCoord0) * vColor;", 430 | "}" 431 | ].join('\n'); 432 | 433 | SpriteBatch.DEFAULT_VERT_SHADER = [ 434 | "attribute vec2 "+ShaderProgram.POSITION_ATTRIBUTE+";", 435 | "attribute vec4 "+ShaderProgram.COLOR_ATTRIBUTE+";", 436 | "attribute vec2 "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;", 437 | 438 | "uniform vec2 u_projection;", 439 | "varying vec2 vTexCoord0;", 440 | "varying vec4 vColor;", 441 | 442 | "void main(void) {", ///TODO: use a projection and transform matrix 443 | " gl_Position = vec4( " 444 | +ShaderProgram.POSITION_ATTRIBUTE 445 | +".x / u_projection.x - 1.0, " 446 | +ShaderProgram.POSITION_ATTRIBUTE 447 | +".y / -u_projection.y + 1.0 , 0.0, 1.0);", 448 | " vTexCoord0 = "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;", 449 | " vColor = "+ShaderProgram.COLOR_ATTRIBUTE+";", 450 | "}" 451 | ].join('\n'); 452 | 453 | module.exports = SpriteBatch; 454 | -------------------------------------------------------------------------------- /lib/TextureRegion.js: -------------------------------------------------------------------------------- 1 | var Class = require('klasse'); 2 | 3 | //This is a GL-specific texture region, employing tangent space normalized coordinates U and V. 4 | //A canvas-specific region would really just be a lightweight object with { x, y, width, height } 5 | //in pixels. 6 | var TextureRegion = new Class({ 7 | 8 | initialize: function TextureRegion(texture, x, y, width, height) { 9 | this.texture = texture; 10 | this.setRegion(x, y, width, height); 11 | }, 12 | 13 | setUVs: function(u, v, u2, v2) { 14 | this.regionWidth = Math.round(Math.abs(u2 - u) * this.texture.width); 15 | this.regionHeight = Math.round(Math.abs(v2 - v) * this.texture.height); 16 | 17 | // From LibGDX TextureRegion.java -- 18 | // For a 1x1 region, adjust UVs toward pixel center to avoid filtering artifacts on AMD GPUs when drawing very stretched. 19 | if (this.regionWidth == 1 && this.regionHeight == 1) { 20 | var adjustX = 0.25 / this.texture.width; 21 | u += adjustX; 22 | u2 -= adjustX; 23 | var adjustY = 0.25 / this.texture.height; 24 | v += adjustY; 25 | v2 -= adjustY; 26 | } 27 | 28 | this.u = u; 29 | this.v = v; 30 | this.u2 = u2; 31 | this.v2 = v2; 32 | }, 33 | 34 | setRegion: function(x, y, width, height) { 35 | x = x || 0; 36 | y = y || 0; 37 | width = (width===0 || width) ? width : this.texture.width; 38 | height = (height===0 || height) ? height : this.texture.height; 39 | 40 | var invTexWidth = 1 / this.texture.width; 41 | var invTexHeight = 1 / this.texture.height; 42 | this.setUVs(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight); 43 | this.regionWidth = Math.abs(width); 44 | this.regionHeight = Math.abs(height); 45 | }, 46 | 47 | /** Sets the texture to that of the specified region and sets the coordinates relative to the specified region. */ 48 | setFromRegion: function(region, x, y, width, height) { 49 | this.texture = region.texture; 50 | this.set(region.getRegionX() + x, region.getRegionY() + y, width, height); 51 | }, 52 | 53 | 54 | //TODO: add setters for regionX/Y and regionWidth/Height 55 | 56 | regionX: { 57 | get: function() { 58 | return Math.round(this.u * this.texture.width); 59 | } 60 | }, 61 | 62 | regionY: { 63 | get: function() { 64 | return Math.round(this.v * this.texture.height); 65 | } 66 | }, 67 | 68 | flip: function(x, y) { 69 | var temp; 70 | if (x) { 71 | temp = this.u; 72 | this.u = this.u2; 73 | this.u2 = temp; 74 | } 75 | if (y) { 76 | temp = this.v; 77 | this.v = this.v2; 78 | this.v2 = temp; 79 | } 80 | } 81 | }); 82 | 83 | module.exports = TextureRegion; -------------------------------------------------------------------------------- /lib/WebGLContext.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module kami 3 | */ 4 | 5 | var Class = require('klasse'); 6 | var Signal = require('signals'); 7 | 8 | /** 9 | * A thin wrapper around WebGLRenderingContext which handles 10 | * context loss and restore with various rendering objects (textures, 11 | * shaders and buffers). This also handles general viewport management. 12 | * 13 | * If the view is not specified, a canvas will be created. 14 | * 15 | * If the `view` parameter is an instanceof WebGLRenderingContext, 16 | * we will use its canvas and context without fetching another through `getContext`. 17 | * Passing a canvas that has already had `getContext('webgl')` called will not cause 18 | * errors, but in certain debuggers (e.g. Chrome WebGL Inspector) only the latest 19 | * context will be traced. 20 | * 21 | * @class WebGLContext 22 | * @constructor 23 | * @param {Number} width the width of the GL canvas 24 | * @param {Number} height the height of the GL canvas 25 | * @param {HTMLCanvasElement} view the optional DOM canvas element 26 | * @param {Object} contextAttribuets an object containing context attribs which 27 | * will be used during GL initialization 28 | */ 29 | var WebGLContext = new Class({ 30 | 31 | initialize: function WebGLContext(width, height, view, contextAttributes) { 32 | /** 33 | * The list of rendering objects (shaders, VBOs, textures, etc) which are 34 | * currently being managed. Any object with a "create" method can be added 35 | * to this list. Upon destroying the rendering object, it should be removed. 36 | * See addManagedObject and removeManagedObject. 37 | * 38 | * @property {Array} managedObjects 39 | */ 40 | this.managedObjects = []; 41 | 42 | /** 43 | * The actual GL context. You can use this for 44 | * raw GL calls or to access GLenum constants. This 45 | * will be updated on context restore. While the WebGLContext 46 | * is not `valid`, you should not try to access GL state. 47 | * 48 | * @property gl 49 | * @type {WebGLRenderingContext} 50 | */ 51 | this.gl = null; 52 | 53 | if (view && typeof window.WebGLRenderingContext !== "undefined" 54 | && view instanceof window.WebGLRenderingContext) { 55 | view = view.canvas; 56 | this.gl = view; 57 | this.valid = true; 58 | contextAttributes = undefined; //just ignore new attribs... 59 | } 60 | 61 | /** 62 | * The canvas DOM element for this context. 63 | * @property {Number} view 64 | */ 65 | this.view = view || document.createElement("canvas"); 66 | 67 | //default size as per spec: 68 | //http://www.w3.org/TR/2012/WD-html5-author-20120329/the-canvas-element.html#the-canvas-element 69 | 70 | /** 71 | * The width of this canvas. 72 | * 73 | * @property width 74 | * @type {Number} 75 | */ 76 | this.width = this.view.width = width || 300; 77 | 78 | /** 79 | * The height of this canvas. 80 | * @property height 81 | * @type {Number} 82 | */ 83 | this.height = this.view.height = height || 150; 84 | 85 | 86 | /** 87 | * The context attributes for initializing the GL state. This might include 88 | * anti-aliasing, alpha settings, verison, and so forth. 89 | * 90 | * @property {Object} contextAttributes 91 | */ 92 | this.contextAttributes = contextAttributes; 93 | 94 | /** 95 | * Whether this context is 'valid', i.e. renderable. A context that has been lost 96 | * (and not yet restored) or destroyed is invalid. 97 | * 98 | * @property {Boolean} valid 99 | */ 100 | this.valid = false; 101 | 102 | /** 103 | * A signal dispatched when GL context is lost. 104 | * 105 | * The first argument passed to the listener is the WebGLContext 106 | * managing the context loss. 107 | * 108 | * @event {Signal} lost 109 | */ 110 | this.lost = new Signal(); 111 | 112 | /** 113 | * A signal dispatched when GL context is restored, after all the managed 114 | * objects have been recreated. 115 | * 116 | * The first argument passed to the listener is the WebGLContext 117 | * which managed the restoration. 118 | * 119 | * This does not gaurentee that all objects will be renderable. 120 | * For example, a Texture with an ImageProvider may still be loading 121 | * asynchronously. 122 | * 123 | * @event {Signal} restored 124 | */ 125 | this.restored = new Signal(); 126 | 127 | //setup context lost and restore listeners 128 | this.view.addEventListener("webglcontextlost", function (ev) { 129 | ev.preventDefault(); 130 | this._contextLost(ev); 131 | }.bind(this)); 132 | this.view.addEventListener("webglcontextrestored", function (ev) { 133 | ev.preventDefault(); 134 | this._contextRestored(ev); 135 | }.bind(this)); 136 | 137 | if (!this.valid) //would only be valid if WebGLRenderingContext was passed 138 | this._initContext(); 139 | 140 | this.resize(this.width, this.height); 141 | }, 142 | 143 | _initContext: function() { 144 | var err = ""; 145 | this.valid = false; 146 | 147 | try { 148 | this.gl = (this.view.getContext('webgl', this.contextAttributes) 149 | || this.view.getContext('experimental-webgl', this.contextAttributes)); 150 | } catch (e) { 151 | this.gl = null; 152 | } 153 | 154 | if (this.gl) { 155 | this.valid = true; 156 | } else { 157 | throw "WebGL Context Not Supported -- try enabling it or using a different browser"; 158 | } 159 | }, 160 | 161 | /** 162 | * Updates the width and height of this WebGL context, resizes 163 | * the canvas view, and calls gl.viewport() with the new size. 164 | * 165 | * @param {Number} width the new width 166 | * @param {Number} height the new height 167 | */ 168 | resize: function(width, height) { 169 | this.width = width; 170 | this.height = height; 171 | 172 | this.view.width = width; 173 | this.view.height = height; 174 | 175 | var gl = this.gl; 176 | gl.viewport(0, 0, this.width, this.height); 177 | }, 178 | 179 | /** 180 | * (internal use) 181 | * A managed object is anything with a "create" function, that will 182 | * restore GL state after context loss. 183 | * 184 | * @param {[type]} tex [description] 185 | */ 186 | addManagedObject: function(obj) { 187 | this.managedObjects.push(obj); 188 | }, 189 | 190 | /** 191 | * (internal use) 192 | * Removes a managed object from the cache. This is useful to destroy 193 | * a texture or shader, and have it no longer re-load on context restore. 194 | * 195 | * Returns the object that was removed, or null if it was not found in the cache. 196 | * 197 | * @param {Object} obj the object to be managed 198 | * @return {Object} the removed object, or null 199 | */ 200 | removeManagedObject: function(obj) { 201 | var idx = this.managedObjects.indexOf(obj); 202 | if (idx > -1) { 203 | this.managedObjects.splice(idx, 1); 204 | return obj; 205 | } 206 | return null; 207 | }, 208 | 209 | /** 210 | * Calls destroy() on each managed object, then removes references to these objects 211 | * and the GL rendering context. This also removes references to the view and sets 212 | * the context's width and height to zero. 213 | * 214 | * Attempting to use this WebGLContext or the GL rendering context after destroying it 215 | * will lead to undefined behaviour. 216 | */ 217 | destroy: function() { 218 | for (var i=0; i 0"; 53 | 54 | this.context = context; 55 | this.gl = context.gl; 56 | 57 | this.numVerts = null; 58 | this.numIndices = null; 59 | 60 | this.vertices = null; 61 | this.indices = null; 62 | this.vertexBuffer = null; 63 | this.indexBuffer = null; 64 | 65 | this.verticesDirty = true; 66 | this.indicesDirty = true; 67 | this.indexUsage = null; 68 | this.vertexUsage = null; 69 | 70 | /** 71 | * @property 72 | * @private 73 | */ 74 | this._vertexAttribs = null; 75 | 76 | /** 77 | * The stride for one vertex _in bytes_. 78 | * 79 | * @property {Number} vertexStride 80 | */ 81 | this.vertexStride = null; 82 | 83 | this.numVerts = numVerts; 84 | this.numIndices = numIndices || 0; 85 | this.vertexUsage = isStatic ? this.gl.STATIC_DRAW : this.gl.DYNAMIC_DRAW; 86 | this.indexUsage = isStatic ? this.gl.STATIC_DRAW : this.gl.DYNAMIC_DRAW; 87 | this._vertexAttribs = vertexAttribs || []; 88 | 89 | this.indicesDirty = true; 90 | this.verticesDirty = true; 91 | 92 | //determine the vertex stride based on given attributes 93 | var totalNumComponents = 0; 94 | for (var i=0; i 0 115 | ? gl.createBuffer() 116 | : null; 117 | 118 | this.dirty = true; 119 | }, 120 | 121 | destroy: function() { 122 | this.vertices = null; 123 | this.indices = null; 124 | if (this.vertexBuffer && this.gl) 125 | this.gl.deleteBuffer(this.vertexBuffer); 126 | if (this.indexBuffer && this.gl) 127 | this.gl.deleteBuffer(this.indexBuffer); 128 | this.vertexBuffer = null; 129 | this.indexBuffer = null; 130 | if (this.context) 131 | this.context.removeManagedObject(this); 132 | this.gl = null; 133 | this.context = null; 134 | }, 135 | 136 | _updateBuffers: function(ignoreBind, subDataLength) { 137 | var gl = this.gl; 138 | 139 | //bind our index data, if we have any 140 | if (this.numIndices > 0) { 141 | if (!ignoreBind) 142 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); 143 | 144 | //update the index data 145 | if (this.indicesDirty) { 146 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, this.indexUsage); 147 | this.indicesDirty = false; 148 | } 149 | } 150 | 151 | //bind our vertex data 152 | if (!ignoreBind) 153 | gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); 154 | 155 | //update our vertex data 156 | if (this.verticesDirty) { 157 | if (subDataLength) { 158 | // TODO: When decoupling VBO/IBO be sure to give better subData support.. 159 | var view = this.vertices.subarray(0, subDataLength); 160 | gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); 161 | } else { 162 | gl.bufferData(gl.ARRAY_BUFFER, this.vertices, this.vertexUsage); 163 | } 164 | 165 | 166 | this.verticesDirty = false; 167 | } 168 | }, 169 | 170 | draw: function(primitiveType, count, offset, subDataLength) { 171 | if (count === 0) 172 | return; 173 | 174 | var gl = this.gl; 175 | 176 | offset = offset || 0; 177 | 178 | //binds and updates our buffers. pass ignoreBind as true 179 | //to avoid binding unnecessarily 180 | this._updateBuffers(true, subDataLength); 181 | 182 | if (this.numIndices > 0) { 183 | gl.drawElements(primitiveType, count, 184 | gl.UNSIGNED_SHORT, offset * 2); //* Uint16Array.BYTES_PER_ELEMENT 185 | } else 186 | gl.drawArrays(primitiveType, offset, count); 187 | }, 188 | 189 | //binds this mesh's vertex attributes for the given shader 190 | bind: function(shader) { 191 | var gl = this.gl; 192 | 193 | var offset = 0; 194 | var stride = this.vertexStride; 195 | 196 | //bind and update our vertex data before binding attributes 197 | this._updateBuffers(); 198 | 199 | //for each attribtue 200 | for (var i=0; i pairs. 13 | * 14 | * _Note:_ Chrome version 31 was giving me issues with attribute locations -- you may 15 | * want to omit this to let the browser pick the locations for you. 16 | * 17 | * @class ShaderProgram 18 | * @constructor 19 | * @param {WebGLContext} context the context to manage this object 20 | * @param {String} vertSource the vertex shader source 21 | * @param {String} fragSource the fragment shader source 22 | * @param {Object} attributeLocations the attribute locations 23 | */ 24 | initialize: function ShaderProgram(context, vertSource, fragSource, attributeLocations) { 25 | if (!vertSource || !fragSource) 26 | throw "vertex and fragment shaders must be defined"; 27 | if (typeof context !== "object") 28 | throw "GL context not specified to ShaderProgram"; 29 | this.context = context; 30 | 31 | this.vertShader = null; 32 | this.fragShader = null; 33 | this.program = null; 34 | this.log = ""; 35 | 36 | this.uniformCache = null; 37 | this.attributeCache = null; 38 | 39 | this.attributeLocations = attributeLocations; 40 | 41 | //We trim (ECMAScript5) so that the GLSL line numbers are 42 | //accurate on shader log 43 | this.vertSource = vertSource.trim(); 44 | this.fragSource = fragSource.trim(); 45 | 46 | //Adds this shader to the context, to be managed 47 | this.context.addManagedObject(this); 48 | 49 | this.create(); 50 | }, 51 | 52 | /** 53 | * This is called during the ShaderProgram constructor, 54 | * and may need to be called again after context loss and restore. 55 | * 56 | * @method create 57 | */ 58 | create: function() { 59 | this.gl = this.context.gl; 60 | this._compileShaders(); 61 | }, 62 | 63 | //Compiles the shaders, throwing an error if the program was invalid. 64 | _compileShaders: function() { 65 | var gl = this.gl; 66 | 67 | this.log = ""; 68 | 69 | this.vertShader = this._loadShader(gl.VERTEX_SHADER, this.vertSource); 70 | this.fragShader = this._loadShader(gl.FRAGMENT_SHADER, this.fragSource); 71 | 72 | if (!this.vertShader || !this.fragShader) 73 | throw "Error returned when calling createShader"; 74 | 75 | this.program = gl.createProgram(); 76 | 77 | gl.attachShader(this.program, this.vertShader); 78 | gl.attachShader(this.program, this.fragShader); 79 | 80 | //TODO: This seems not to be working on my OSX -- maybe a driver bug? 81 | if (this.attributeLocations) { 82 | for (var key in this.attributeLocations) { 83 | if (this.attributeLocations.hasOwnProperty(key)) { 84 | gl.bindAttribLocation(this.program, Math.floor(this.attributeLocations[key]), key); 85 | } 86 | } 87 | } 88 | 89 | gl.linkProgram(this.program); 90 | 91 | this.log += gl.getProgramInfoLog(this.program) || ""; 92 | 93 | if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) { 94 | throw "Error linking the shader program:\n" 95 | + this.log; 96 | } 97 | 98 | this._fetchUniforms(); 99 | this._fetchAttributes(); 100 | }, 101 | 102 | _fetchUniforms: function() { 103 | var gl = this.gl; 104 | 105 | this.uniformCache = {}; 106 | 107 | var len = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS); 108 | if (!len) //null or zero 109 | return; 110 | 111 | for (var i=0; i .. whatever that is ?? 384 | 385 | 386 | ///// 387 | 388 | /** 389 | * A convenience method to set uniformNfv from the given ArrayBuffer. 390 | * We determine which GL call to make based on the length of the array 391 | * buffer (for 1-4 component vectors stored in a Float32Array). To use 392 | * this method to upload data to uniform arrays, you need to specify the 393 | * 'count' parameter; i.e. the data type you are using for that array. If 394 | * specified, this will dictate whether to call uniform1fv, uniform2fv, etc. 395 | * 396 | * @method setUniformfv 397 | * @param {String} name the name of the uniform 398 | * @param {ArrayBuffer} arrayBuffer the array buffer 399 | * @param {Number} count optional, the explicit data type count, e.g. 2 for vec2 400 | */ 401 | setUniformfv: function(name, arrayBuffer, count) { 402 | 'use strict'; 403 | count = count || arrayBuffer.length; 404 | var gl = this.gl; 405 | var loc = this.getUniformLocation(name); 406 | if (loc === null) 407 | return false; 408 | switch (count) { 409 | case 1: gl.uniform1fv(loc, arrayBuffer); return true; 410 | case 2: gl.uniform2fv(loc, arrayBuffer); return true; 411 | case 3: gl.uniform3fv(loc, arrayBuffer); return true; 412 | case 4: gl.uniform4fv(loc, arrayBuffer); return true; 413 | default: 414 | throw "invalid arguments to setUniformf"; 415 | } 416 | }, 417 | 418 | /** 419 | * A convenience method to set uniformNiv from the given ArrayBuffer. 420 | * We determine which GL call to make based on the length of the array 421 | * buffer (for 1-4 component vectors stored in a int array). To use 422 | * this method to upload data to uniform arrays, you need to specify the 423 | * 'count' parameter; i.e. the data type you are using for that array. If 424 | * specified, this will dictate whether to call uniform1fv, uniform2fv, etc. 425 | * 426 | * @method setUniformiv 427 | * @param {String} name the name of the uniform 428 | * @param {ArrayBuffer} arrayBuffer the array buffer 429 | * @param {Number} count optional, the explicit data type count, e.g. 2 for ivec2 430 | */ 431 | setUniformiv: function(name, arrayBuffer, count) { 432 | 'use strict'; 433 | count = count || arrayBuffer.length; 434 | var gl = this.gl; 435 | var loc = this.getUniformLocation(name); 436 | if (loc === null) 437 | return false; 438 | switch (count) { 439 | case 1: gl.uniform1iv(loc, arrayBuffer); return true; 440 | case 2: gl.uniform2iv(loc, arrayBuffer); return true; 441 | case 3: gl.uniform3iv(loc, arrayBuffer); return true; 442 | case 4: gl.uniform4iv(loc, arrayBuffer); return true; 443 | default: 444 | throw "invalid arguments to setUniformf"; 445 | } 446 | }, 447 | 448 | /** 449 | * This is a convenience function to pass a Matrix3 (from vecmath, 450 | * kami's preferred math library) or a Float32Array (e.g. gl-matrix) 451 | * to a shader. If mat is an object with "val", it is considered to be 452 | * a Matrix3, otherwise assumed to be a typed array being passed directly 453 | * to the shader. 454 | * 455 | * @param {String} name the uniform name 456 | * @param {Matrix3|Float32Array} mat a Matrix3 or Float32Array 457 | * @param {Boolean} transpose whether to transpose the matrix, default false 458 | */ 459 | setUniformMatrix3: function(name, mat, transpose) { 460 | 'use strict'; 461 | var arr = typeof mat === "object" && mat.val ? mat.val : mat; 462 | transpose = !!transpose; //to boolean 463 | 464 | var gl = this.gl; 465 | var loc = this.getUniformLocation(name); 466 | if (loc === null) 467 | return false; 468 | gl.uniformMatrix3fv(loc, transpose, arr) 469 | }, 470 | 471 | /** 472 | * This is a convenience function to pass a Matrix4 (from vecmath, 473 | * kami's preferred math library) or a Float32Array (e.g. gl-matrix) 474 | * to a shader. If mat is an object with "val", it is considered to be 475 | * a Matrix4, otherwise assumed to be a typed array being passed directly 476 | * to the shader. 477 | * 478 | * @param {String} name the uniform name 479 | * @param {Matrix4|Float32Array} mat a Matrix4 or Float32Array 480 | * @param {Boolean} transpose whether to transpose the matrix, default false 481 | */ 482 | setUniformMatrix4: function(name, mat, transpose) { 483 | 'use strict'; 484 | var arr = typeof mat === "object" && mat.val ? mat.val : mat; 485 | transpose = !!transpose; //to boolean 486 | 487 | var gl = this.gl; 488 | var loc = this.getUniformLocation(name); 489 | if (loc === null) 490 | return false; 491 | gl.uniformMatrix4fv(loc, transpose, arr) 492 | } 493 | 494 | }); 495 | 496 | //Some default attribute names that parts of kami will use 497 | //when creating a standard shader. 498 | ShaderProgram.POSITION_ATTRIBUTE = "Position"; 499 | ShaderProgram.NORMAL_ATTRIBUTE = "Normal"; 500 | ShaderProgram.COLOR_ATTRIBUTE = "Color"; 501 | ShaderProgram.TEXCOORD_ATTRIBUTE = "TexCoord"; 502 | 503 | module.exports = ShaderProgram; -------------------------------------------------------------------------------- /lib/index-umd.js: -------------------------------------------------------------------------------- 1 | /** 2 | Auto-generated Kami index file. 3 | Dependencies are placed on the top-level namespace, for convenience. 4 | Created on 2014-06-11. 5 | */ 6 | module.exports = { 7 | //core classes 8 | 'BaseBatch': require('./BaseBatch.js'), 9 | 'SpriteBatch': require('./SpriteBatch.js'), 10 | 'Texture': require('./Texture.js'), 11 | 'TextureRegion': require('./TextureRegion.js'), 12 | 'WebGLContext': require('./WebGLContext.js'), 13 | 'FrameBuffer': require('./glutils/FrameBuffer.js'), 14 | 'Mesh': require('./glutils/Mesh.js'), 15 | 'ShaderProgram': require('./glutils/ShaderProgram.js'), 16 | 17 | //signals dependencies 18 | 'Signal': require('signals').Signal, 19 | 20 | //klasse dependencies 21 | 'Class': require('klasse'), 22 | 23 | //number-util dependencies 24 | 'NumberUtil': require('number-util') 25 | }; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | Auto-generated Kami index file. 3 | Created on 2014-06-11. 4 | */ 5 | module.exports = { 6 | //core classes 7 | 'BaseBatch': require('./BaseBatch.js'), 8 | 'SpriteBatch': require('./SpriteBatch.js'), 9 | 'Texture': require('./Texture.js'), 10 | 'TextureRegion': require('./TextureRegion.js'), 11 | 'WebGLContext': require('./WebGLContext.js'), 12 | 'FrameBuffer': require('./glutils/FrameBuffer.js'), 13 | 'Mesh': require('./glutils/Mesh.js'), 14 | 'ShaderProgram': require('./glutils/ShaderProgram.js') 15 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kami", 3 | "version": "0.5.3", 4 | "description": "WebGL utilities for performant and flexible 2D and 3D rendering.", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "signals": "~1.0.0", 13 | "klasse": "~1.0.6", 14 | "number-util": "~1.0.1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/mattdesl/kami.git" 19 | }, 20 | "devDependencies": { 21 | "grunt": "~0.4.1", 22 | "browserify": "~2.35.0", 23 | "grunt-browserify": "~1.2.9", 24 | "grunt-contrib-watch": "~0.5.3", 25 | "load-grunt-tasks": "~0.2.0", 26 | "grunt-contrib-yuidoc": "~0.5.0", 27 | "grunt-contrib-uglify": "~0.2.5", 28 | "grunt-autoindex": "~0.1.1" 29 | } 30 | } 31 | --------------------------------------------------------------------------------