├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── bin
└── jbbc.js
├── compiler.js
├── decoder.js
├── dist
├── jbb-loader.js
├── jbb-loader.min.js
├── jbb.js
└── jbb.min.js
├── doc
├── Bundle Format.md
├── Tutorial 1 - THREEjs
│ ├── Using with THREEjs.md
│ ├── files
│ │ ├── crate.json
│ │ └── crate.png
│ └── img
│ │ ├── 1-blender.png
│ │ └── 2-result.png
├── bundle.json.md
├── jbb-logo.png
├── table_BUF_TYPE.png
├── table_CHUNK.png
├── table_DWS_TYPE.png
├── table_LEN.png
├── table_LN.png
├── table_NUM_TYPE.png
├── table_OP_ARR.png
├── table_OP_BULK_KNOWN.png
├── table_OP_CTL.png
├── table_OP_OBJECT.png
├── table_OP_PRIM.png
├── table_OT.png
├── table_SCALE.png
└── table_S_TYPE.png
├── encoder.js
├── gulpfile.js
├── index.js
├── lib
├── BinaryBundle.js
├── BinaryStream.js
├── DecodeProfile.js
├── EncodeProfile.js
├── Errors.js
└── ProgressManager.js
├── loader.js
├── package.json
└── test
├── media
├── animated.jbbsrc
│ ├── bundle.json
│ ├── flamingo.js
│ ├── horse.js
│ └── monster
│ │ ├── monster.jpg
│ │ └── monster.js
├── heavy.jbbsrc
│ ├── ben.js
│ ├── ben.utf8
│ ├── ben_dds.js
│ ├── bundle.json
│ ├── dds
│ │ ├── James_Body_Lores.dds
│ │ ├── James_EyeLashBotTran.dds
│ │ ├── James_EyeLashTopTran.dds
│ │ ├── James_Eye_Green.dds
│ │ ├── James_Eye_Inner_Green.dds
│ │ ├── James_Face_Color_Hair_Lores.dds
│ │ ├── James_Mouth_Gum_Lores.dds
│ │ ├── James_Tongue_Lores.dds
│ │ ├── MCasShoe1TEX_Lores.dds
│ │ ├── MJeans1TEX_Lores.dds
│ │ ├── MTshirt3TEX_Lores.dds
│ │ └── Nail_Hand_01_Lores.dds
│ ├── hand.jpg
│ ├── hand.js
│ └── hand.utf8
├── md2.jbbsrc
│ ├── bundle.json
│ ├── grasslight-big.jpg
│ └── ratamahatta
│ │ ├── ratamahatta.md2
│ │ ├── skins
│ │ ├── ctf_b.png
│ │ ├── ctf_r.png
│ │ ├── dead.png
│ │ ├── gearwhore.png
│ │ ├── ratamahatta.png
│ │ └── weapon.png
│ │ └── weapon.md2
├── obj.jbbsrc
│ ├── bundle.json
│ └── walt
│ │ ├── WaltHead_bin.bin
│ │ └── WaltHead_bin.js
└── vrml.jbbsrc
│ ├── bundle.json
│ └── house.wrl
├── simple-profile
├── objects.js
├── second-decode.js
├── second-encode.js
├── second.yaml
├── specs-decode.js
├── specs-encode.js
└── specs.yaml
├── test-core.js
├── test-three.js
└── utils
├── common.js
├── compare.js
└── tests.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
29 | *.local
30 | *.local.js
31 |
32 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
29 | *.local
30 | *.local.js
31 |
32 | ############## Ignore Test Files ##############
33 | .travis.yml
34 | test
35 | doc
36 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5.4.1"
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Javascript Binary Bundles
2 |
3 | [](https://www.npmjs.com/package/jbb) [](https://travis-ci.org/wavesoft/jbb) [](https://gitter.im/wavesoft/jbb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | **Why Binary Bundles?** For *faster* loading time due to *fewer* requests and an *optimised* binary format, closely compatible with Javascript internals. It is optimised in balance between size and performance, preferring performance when in doubt.
6 |
7 | [Examples](https://github.com/wavesoft/jbb/wiki#examples) — [Documentation](https://github.com/wavesoft/jbb/wiki) — [Tutorials](https://github.com/wavesoft/jbb/wiki#tutorials) — [Help](https://gitter.im/wavesoft/jbb)
8 |
9 |
10 |
11 | With JBB you can load all of your project's resources in a `node.js` instance and then serialize them in a single file. You can then load this file instead.
12 |
13 | ## Usage - Loading Bundles
14 |
15 | Download the [minified run-time library](https://raw.githubusercontent.com/wavesoft/jbb/master/dist/jbb.min.js) and include it in your project:
16 |
17 | ```html
18 |
19 | ```
20 |
21 | You can then load your bundles like this:
22 |
23 | ```js
24 | var loader = new JBB.BinaryLoader("path/to/bundles");
25 | loader.add("bundle_name.jbb");
26 | loader.load(function(error, database) {
27 | // Handle your data
28 | });
29 | ```
30 |
31 | ### Using npm
32 |
33 | JBB is also available on npm. Both compiler and run-time library is available in the same package:
34 |
35 | ```
36 | npm install --save jbb
37 | ```
38 |
39 | You can then load your bundles like this:
40 |
41 | ```js
42 | var JBBBinaryLoader = require('jbb/decoder');
43 |
44 | var loader = new JBBBinaryLoader("path/to/bundles");
45 | loader.add("bundle_name.jbb");
46 | loader.load(function(error, database) {
47 | // Handle your data
48 | });
49 | ```
50 |
51 | ## Usage - Creating Bundles
52 |
53 | After you have [collected your resources in a source bundle](https://github.com/wavesoft/jbb/wiki/Creating-a-Simple-Source-Bundle-%26-Compiling-it) you can then compile it using the `gulp-jbb` plugin.
54 |
55 | In your `gulpfile.js`:
56 |
57 | ```js
58 | var gulp = require('gulp');
59 | var jbb = require('gulp-jbb');
60 |
61 | // Compile jbb task
62 | gulp.task('jbb', function() {
63 | return gulp
64 | .src([ "your_bundle.jbbsrc" ])
65 | .pipe(jbb({
66 | profile: [ "profile-1", "profile-2" ]
67 | }))
68 | .pipe(gulp.dest( "build/bundles" ));
69 | });
70 | ```
71 |
72 | # License
73 |
74 | ```
75 | Copyright (C) 2015-2016 Ioannis Charalampidis
76 |
77 | Licensed under the Apache License, Version 2.0 (the "License");
78 | you may not use this file except in compliance with the License.
79 | You may obtain a copy of the License at
80 |
81 | http://www.apache.org/licenses/LICENSE-2.0
82 |
83 | Unless required by applicable law or agreed to in writing, software
84 | distributed under the License is distributed on an "AS IS" BASIS,
85 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
86 | See the License for the specific language governing permissions and
87 | limitations under the License.
88 | ```
89 |
--------------------------------------------------------------------------------
/bin/jbbc.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // Override default console functions
4 | var colors = require("colors"), hideWarn = false;
5 | console.warn = function() { if (hideWarn) return; console.log.apply(console, ["WARN:".yellow].concat(Array.prototype.slice.call(arguments)) ); };
6 | console.error = function() { console.log.apply(console, ["ERROR:".red].concat(Array.prototype.slice.call(arguments)) ); };
7 | console.info = function() { console.log.apply(console, ["INFO:".green].concat(Array.prototype.slice.call(arguments)) ); };
8 | console.info("Initializing compiler");
9 |
10 | // Import dependencies
11 | var fs = require('fs');
12 | var path = require('path');
13 | var getopt = require('node-getopt');
14 | var BinaryEncoder = require("../encoder");
15 | var BinaryCompiler = require("../compiler");
16 |
17 | ///////////////////////////////////////////////////////////////////////
18 | // Helper functions
19 | ///////////////////////////////////////////////////////////////////////
20 |
21 | /**
22 | * Create node-getopt object
23 | */
24 | var createOptions = function( profile ) {
25 |
26 | // Extract profile additions
27 | var profile_additions = [];
28 | if (profile && profile.getopt)
29 | profile_additions = profile.getopt();
30 |
31 | // Validate command-line
32 | var opt = getopt.create([
33 | ['p' , 'profile=NAME' , 'Specify the profile to use for the compiler'],
34 | ['o' , 'out=BUNDLE' , 'Specify the name of the bundle'],
35 | ['O' , 'optimise=LEVEL+' , 'Specify optimisation level'],
36 | ['b' , 'basedir=DIR' , 'Specify bundle base directory'],
37 | ].concat( profile_additions ).concat([
38 | ['' , 'log=FLAGS' , 'Enable logging (see flags below)'],
39 | ['s' , 'sparse' , 'Create a sparse bundle rather than a solid one'],
40 | ['h' , 'help' , 'Display this help'],
41 | ['v' , 'version' , 'Show version'],
42 | ]))
43 | .setHelp(
44 | "Usage: jbb -p -o [OPTION] \n" +
45 | "Compile one or more bundles to a binary format.\n" +
46 | "\n" +
47 | "[[OPTIONS]]\n" +
48 | "\n" +
49 | "Logging Flags:\n" +
50 | "\n" +
51 | " p Log primitive opcodes\n" +
52 | " a Log array opcodes\n" +
53 | " c Log array chunk opcodes\n" +
54 | " b Log array bulk operations opcodes\n" +
55 | " s Log string opcodes\n" +
56 | " r Log internal cross-reference\n" +
57 | " R Log external cross-reference\n" +
58 | " o Log object opcodes\n" +
59 | " e Log file embedding opcodes\n" +
60 | " o Log object opcodes\n" +
61 | " O Log plain object opcodes\n" +
62 | " d Log protocol debug operations\n" +
63 | " w Log low-level byte writes\n" +
64 | " - Log everything\n" +
65 | "\n" +
66 | "Installation: npm install three-bundles\n" +
67 | "Respository: https://github.com/wavesoft/three-bundles"
68 | )
69 | .bindHelp() // bind option 'help' to default action
70 | .parseSystem(); // parse command line
71 |
72 | // Return options
73 | return opt;
74 |
75 | }
76 |
77 | /**
78 | * Compile log
79 | */
80 | var getLogFlags = function( logTags ) {
81 |
82 | // If missing return none
83 | if (!logTags)
84 | return 0;
85 |
86 | // Apply logging flags
87 | var logFlags = 0;
88 | for (var i=0; i
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | var BinaryEncoder = require("./encoder");
22 | var BinaryDecoder = require("./decoder");
23 | var BundlesLoader = require("./loader");
24 | var path = require('path');
25 | var fs = require('fs');
26 |
27 | /**
28 | * Wrapper function for the compile function, that first loads the
29 | * bundle specs from the source bundle file specified.
30 | */
31 | function compileFile( sourceBundle, bundleFile, config, callback ) {
32 | var fname = sourceBundle + "/bundle.json";
33 | fs.readFile(fname, 'utf8', function (err,data) {
34 | if (err) {
35 | console.error("Unable to load file",fname);
36 | if (callback) callback( err, null );
37 | return;
38 | }
39 |
40 | // Update path if missing
41 | if (!config['path'])
42 | config['path'] = path.dirname( sourceBundle );
43 |
44 | // Compile
45 | compile( JSON.parse(data), bundleFile, config, callback );
46 |
47 | });
48 | }
49 |
50 | /**
51 | * Compile the specifie bundle data to the specified bundle file.
52 | * Additional information, such as profile or other compile-time parameters
53 | * can be specified through the config object.
54 | */
55 | function compile( bundleData, bundleFile, config, callback ) {
56 | var baseDir = config['path'] || path.dirname(bundleFile);
57 | var encoder, profileEncoder = [], profileLoader = [], bundleLoader;
58 |
59 | // Compile stages
60 | var openBundle = function( cb ) {
61 | return function() {
62 |
63 | // Create encoder
64 | encoder = new BinaryEncoder(
65 | bundleFile,
66 | {
67 | 'name' : bundleData['name'],
68 | 'base_dir' : baseDir,
69 | 'log' : config['log'] || 0x00,
70 | 'sparse' : config['sparse'],
71 | }
72 | );
73 |
74 | // Add profiles
75 | for (var i=0; io;++o)s[o]=pivot+a[o]*n;return s}function o(t,r,e,i){var s=I.FROM[i],n=new m[s](e),a=0;switch(s){case 0:a=t.u8[t.i8++];break;case 1:a=t.s8[t.i8++];break;case 2:a=t.u16[t.i16++];break;case 3:a=t.s16[t.i16++];break;case 4:a=t.u32[t.i32++];break;case 5:a=t.s32[t.i32++];break;case 6:a=t.f32[t.i32++];break;case 7:a=t.f64[t.i64++]}var o=t.readTypedArray(I.TO[i],e-1);n[0]=a;for(var h=0,u=o.length;u>h;++h)a+=o[h],n[h+1]=a;return n}function h(t,r){var e=t.u16[t.i16++],i=t.signature_table[e],s=t.factory_plain_bulk[e];if(void 0===s)throw new w.AssertError("Could not found simple object signature with id #"+e+"!");for(var n=l(t,r),a=n.length/i.length,o=new Array(a),h=0;a>h;++h)o[h]=s(n,h);return o}function u(t,r,e){var i=t.u16[t.i16++],s=t.profile.decode(i),n=s.props,a=0,o=[],h=0,u=0,f=0,c=null,p=0,d=0,v=[],b=[];for(f=65536>e?t.u16[t.i16++]:t.u32[t.i32++],o=Array(f),h=0;f>h;++h)t.iref_table.push(o[h]=s.create());if(f){if(v=l(t,r),void 0===v.length)throw new w.AssertError("Decoded known bulk primitive is not array!");a=v.length/n}var y=new Array(e),g=0,T=void 0;for(h=0;e>h;)if(d=t.u8[t.i8++],(128&d)===k.LREF_7)u=127&d,y[h++]=T=b[u];else if((192&d)===k.DEFINE){for(u=(63&d)+1,p=0;u>p;p++)c=o[g],s.init(c,v,a,g),y[h++]=c,g++;T=c}else if((224&d)===k.REPEAT)for(u=(31&d)+1,p=0;u>p;p++)y[h++]=T;else if((240&d)===k.IREF){if(u=(15&d)<<16|t.u16[t.i16++],u>=t.iref_table.length)throw new w.IRefError("Invalid IREF #"+u+"!");y[h++]=T=t.iref_table[u],b.push(t.iref_table[u])}else if((248&d)===k.LREF_11)u=(7&d)<<8|t.u8[t.i8++],y[h++]=T=b[u];else if(d===k.LREF_16)u=t.u16[t.i16++],y[h++]=T=b[u];else if(d===k.XREF){if(u=t.readStringLT(),void 0===r[u])throw new w.XRefError("Cannot import undefined external reference "+u+"!");y[h++]=T=r[u]}return y}function f(t,r,e,i){for(var s,n,a=t.u8[t.i8++],o=[],h=0,u=!0,f=0,l=0,p=0,d=0,v=0,b=0;e>h;){if(i)if(64===(240&a)){switch(p=1&a,d=a>>1&7,v=p?t.u32[t.i32++]:t.u16[t.i16++],u&&(n=new m[d](e),u=!1),d){case 0:b=t.u8[t.i8++];break;case 1:b=t.s8[t.i8++];break;case 2:b=t.u16[t.i16++];break;case 3:b=t.s16[t.i16++];break;case 4:b=t.u32[t.i32++];break;case 5:b=t.s32[t.i32++];break;case 6:b=t.f32[t.i32++];break;case 7:b=t.f64[t.i64++]}n.fill(b,h,h+v),h+=v}else{if(s=c(t,r,a),void 0===s.length)throw new w.AssertError("Encountered non-array chunk as part of chunked array!");if(u&&(n=new s.constructor(e),u=!1),!(s instanceof n.constructor))throw new w.AssertError("Got is_numeric flag, but chunks are not of the same type (op was "+a+"!");n.set(s,h),h+=s.length}else{if(s=c(t,r,a),void 0===s.length)throw new w.AssertError("Encountered non-array chunk as part of chunked array!");for(u&&(o=new Array(e),u=!1),f=0,l=s.length;l>f;f++,h++)o[h]=s[f]}if(!(e>h))break;a=t.u8[t.i8++]}return i?n:o}function c(t,r,e){var i,s=0,n=0,c=0,p=0,d=[];if(e=255&e,110===e)return h(t,r);if(111===e){for(p=t.u8[t.i8++],d[p-1]=null,s=0;p>s;++s)d[s]=l(t,r);return d}if(126===e)return[];if(127===e)throw new w.AssertError("Encountered PRIM_CHUNK_END outside of chunked array!");if(0===(224&e)){c=1&e,n=e>>1&15,p=c?t.u32[t.i32++]:t.u16[t.i16++],i=t.readTypedArray(E.TO[n],p);var v=new m[E.FROM[n]](i);return v}if(32===(240&e))return c=1&e,n=e>>1&7,p=c?t.u32[t.i32++]:t.u16[t.i16++],o(t,r,p,n);if(48===(240&e))return c=1&e,n=e>>1&7,p=c?t.u32[t.i32++]:t.u16[t.i16++],a(t,r,p,n);if(64===(240&e)){switch(c=1&e,n=e>>1&7,p=c?t.u32[t.i32++]:t.u16[t.i16++],n){case 0:i=t.u8[t.i8++];break;case 1:i=t.s8[t.i8++];break;case 2:i=t.u16[t.i16++];break;case 3:i=t.s16[t.i16++];break;case 4:i=t.u32[t.i32++];break;case 5:i=t.s32[t.i32++];break;case 6:i=t.f32[t.i32++];break;case 7:i=t.f64[t.i64++]}var v=new m[n](p);for(s=0;p>s;++s)v[s]=i;return v}if(80===(240&e))return c=1&e,n=e>>1&7,p=c?t.u32[t.i32++]:t.u16[t.i16++],d=t.readTypedArray(n,p);if(96===(248&e))return n=7&e,p=t.u8[t.i8++],d=t.readTypedArray(n,p);if(104===(254&e)){for(c=1&e,p=c?t.u32[t.i32++]:t.u16[t.i16++],i=l(t,r),d[p-1]=null,s=0;p>s;s++)d[s]=i;return d}if(106===(254&e)){for(c=1&e,p=c?t.u32[t.i32++]:t.u16[t.i16++],d[p-1]=null,s=0;p>s;++s)d[s]=l(t,r);return d}if(120===(252&e))return c=1&e,n=e>>1&1,p=c?t.u32[t.i32++]:t.u16[t.i16++],f(t,r,p,n);if(124===(254&e))return c=1&e,p=c?t.u32[t.i32++]:t.u16[t.i16++],u(t,r,p);throw new w.AssertError("Unknown array op-code 0x"+e.toString(16)+" at offset @"+(t.i8-t.ofs8)+"!")}function l(t,r){var e=t.u8[t.i8++];if(0===(128&e))return c(t,r,127&e);if(128===(192&e))return n(t,r,63&e);if(192===(224&e))return s(t,(24&e)>>3,7&e);if(224===(240&e)){var i=t.u16[t.i16++];if(i=(15&e)<<16|i,i>=t.iref_table.length)throw new w.IRefError("Invalid IREF #"+i+"!");return t.iref_table[i]}if(240===(248&e))switch(7&e){case 0:return t.u8[t.i8++];case 1:return t.s8[t.i8++];case 2:return t.u16[t.i16++];case 3:return t.s16[t.i16++];case 4:return t.u32[t.i32++];case 5:return t.s32[t.i32++];case 6:return t.f32[t.i32++];case 7:return t.f64[t.i64++]}else{if(248===(252&e))return U[3&e];if(252===(254&e))return N[2&e];if(254===(255&e)){var a=t.readStringLT();if(void 0===r[a])throw new w.XRefError("Cannot import undefined external reference "+a+"!");return r[a]}if(255===(255&e))throw new w.AssertError("Encountered RESERVED primitive operator!")}}function p(t,r){for(;!t.eof();){var e=t.u8[t.i8++];switch(e){case 248:var i=t.prefix+t.readStringLT();r[i]=l(t,r);break;default:throw new w.AssertError("Unknown control operator 0x"+e.toString(16)+" at @"+t.i8+"!")}}}function d(t,r,e){var i=t.length,s=Array(i),n=!1;return t.forEach(function(a,o){var h=new XMLHttpRequest;h.open("GET",t[o]),h.responseType="arraybuffer",h.send(),h.addEventListener("progress",function(t){t.lengthComputable&&r.update(h,t.loaded,t.total)}),h.addEventListener("readystatechange",function(){if(4===h.readyState)if(200===h.status)s[o]=h.response,0===--i&&(r.complete(),e(null));else{if(n)return;n=!0,r.complete(),e("Error loading "+t[o]+": "+h.statusText)}})}),s}var v=e(1),b=e(2),y=e(3),w=e(4);const g=0,T=1,A={UINT8:0,INT8:1,UINT16:2,INT16:3,UINT32:4,INT32:5,FLOAT32:6,FLOAT64:7},E={FROM:[A.UINT16,A.INT16,A.UINT32,A.INT32,A.UINT32,A.INT32,A.FLOAT32,A.FLOAT32,A.FLOAT32,A.FLOAT32,A.FLOAT64,A.FLOAT64,A.FLOAT64,A.FLOAT64,A.FLOAT64],TO:[A.UINT8,A.INT8,A.UINT8,A.INT8,A.UINT16,A.INT16,A.UINT8,A.INT8,A.UINT16,A.INT16,A.UINT8,A.INT8,A.UINT16,A.INT16,A.FLOAT32]},I={FROM:[A.UINT16,A.INT16,A.UINT32,A.INT32,A.UINT32,A.INT32],TO:[A.INT8,A.INT8,A.INT8,A.INT8,A.INT16,A.INT16]},_={FROM:[A.FLOAT32,A.FLOAT32,A.FLOAT64,A.FLOAT64],TO:[A.INT8,A.INT16,A.INT8,A.INT16]},m=[Uint8Array,Int8Array,Uint16Array,Int16Array,Uint32Array,Int32Array,Float32Array,Float64Array],k=([A.UINT16,A.UINT32],[A.UINT8,A.UINT16,A.UINT32,A.FLOAT64],{LREF_7:0,LREF_11:240,LREF_16:254,IREF:224,XREF:255,DEFINE:128,REPEAT:192}),U=[void 0,null,!1,!0],N=[NaN];var F=function(t,r){"object"==typeof t&&(r=t,t=""),this.database=r||{},this.baseDir=t||"",this.queuedRequests=[],this.profile=new b,this.progressManager=new y};F.prototype={constructor:F,addProfile:function(t){this.profile.add(t)},add:function(t,r){var e,i="";this.baseDir&&(i=this.baseDir+"/");var s=t.split("?"),n="",a=[];if(s.length>1&&(n="?"+s[1]),".jbbp"===s[0].substr(s[0].length-5).toLowerCase()){var e=i+s[0].substr(0,s[0].length-5);a=[e+".jbbp"+n,e+"_b16.jbbp"+n,e+"_b32.jbbp"+n,e+"_b64.jbbp"+n]}else{var t=s[0];".jbb"!=t.substr(t.length-4)&&(t+=".jbb"),a=[i+t+n]}var o={callback:r,status:g,buffer:void 0,url:a};this.queuedRequests.push(o)},addByBuffer:function(t,r){var e={callback:r,status:T,buffer:t,url:void 0};this.queuedRequests.push(e)},addProgressHandler:function(t){this.progressManager.addHandler(t)},removeProgressHandler:function(t){this.progressManager.removeHandler(t)},load:function(t){this.__process(t)},__process:function(t){var r=this;if(t||(t=function(){}),0===this.queuedRequests.length)return void t(null,this.database);for(var e=!1,i=0;ie;++e)0!==e&&(r+=","),r+="p[i+c*"+e+"]";return new Function("p","i","var c=p.length/"+t+";return ["+r+"]")}var i=function(t,r){this.profile=r,this.prefix="",this.sparse=t instanceof Array;var i,s,n,a=32;if(this.sparse?(this.u8=new Uint8Array(t[0]),this.s8=new Int8Array(t[0]),this.u16=new Uint16Array(t[1]),this.s16=new Int16Array(t[1]),this.u32=new Uint32Array(t[2]),this.s32=new Int32Array(t[2]),this.f32=new Float32Array(t[2]),this.f64=new Float64Array(t[3]),i=new Uint16Array(t[0],0,a/2),s=new Uint32Array(t[0],0,a/4),n=t[0].byteLength):(this.u8=new Uint8Array(t),this.s8=new Int8Array(t),this.u16=new Uint16Array(t),this.s16=new Int16Array(t),this.u32=new Uint32Array(t),this.s32=new Int32Array(t),this.f32=new Float32Array(t),this.f64=new Float64Array(t),i=new Uint16Array(t),s=new Uint32Array(t),n=t.byteLength),this.magic=i[0],this.table_id=i[1],this.version=i[2],this.table_count=i[3],this.ver_major=255&this.version,this.ver_minor=(65280&this.version)>>8,this.max64=s[2],this.max32=s[3],this.max16=s[4],this.max8=s[5],this.lenST=s[6],this.lenOT=s[7],12610==this.magic)throw{name:"EndianessError",message:"Unfortunately the JBB format is currently only compatible with Little-Endian CPUs",toString:function(){return this.name+": "+this.message}};if(16945!=this.magic)throw{name:"DecodingError",message:"This does not look like a JBB archive! (Magic is 0x"+this.magic.toString(16)+")",toString:function(){return this.name+": "+this.message}};if(258!=this.version)throw{name:"DecodingError",message:"Unsupported bundle version v"+this.ver_minor+"."+this.ver_minor,toString:function(){return this.name+": "+this.message}};this.sparse?(this.i64=0,this.i32=0,this.i16=0,this.i8=a,this.iEnd=this.i8+this.max8-this.lenST,this.ofs8=this.i8,this.ofs16=this.i16,this.ofs32=this.i32,this.ofs64=this.i64):(this.i64=a,this.i32=this.i64+this.max64,this.i16=this.i32+this.max32,this.i8=this.i16+this.max16,this.iEnd=this.i8+this.max8-this.lenST,this.ofs8=this.i8,this.ofs16=this.i16,this.ofs32=this.i32,this.ofs64=this.i64,this.i16/=2,this.i32/=4,this.i64/=8);var o=[];if(this.table_count<=1)0!==this.table_id&&o.push(this.table_id);else{if(0!==this.table_id)throw{name:"DecodingError",message:"Invalid header data",toString:function(){return this.name+": "+this.message}};for(var h=0;h0){for(var c=this.i8+this.max8,h=c-this.lenST;c>h;++h){var l=this.u8[h];0===l?(this.string_table.push(u),u="",f=!1):(u+=String.fromCharCode(l),f=!0)}f&&this.string_table.push(u)}var p=[],d=0,v=!1;if(this.signature_table=[],this.lenOT>0){for(var c=2*this.i16+this.max16,h=c-this.lenOT;c>h;h+=2){var l=this.u16[h/2];d--?p.push(this.string_table[l]):(v&&this.signature_table.push(p),p=[],d=l,v=!0)}v&&this.signature_table.push(p)}this.sparse?this.readTypedArray=function(r,e){var i=this.i8,s=2*this.i16,n=4*this.i32,a=8*this.i64;switch(r){case 0:return this.i8+=e,new Uint8Array(t[0],i,e);case 1:return this.i8+=e,new Int8Array(t[0],i,e);case 2:return this.i16+=e,new Uint16Array(t[1],s,e);case 3:return this.i16+=e,new Int16Array(t[1],s,e);case 4:return this.i32+=e,new Uint32Array(t[2],n,e);case 5:return this.i32+=e,new Int32Array(t[2],n,e);case 6:return this.i32+=e,new Float32Array(t[2],n,e);case 7:return this.i64+=e,new Float64Array(t[3],a,e)}}:this.readTypedArray=function(r,e){var i=this.i8,s=2*this.i16,n=4*this.i32,a=8*this.i64;switch(r){case 0:return this.i8+=e,new Uint8Array(t,i,e);case 1:return this.i8+=e,new Int8Array(t,i,e);case 2:return this.i16+=e,new Uint16Array(t,s,e);case 3:return this.i16+=e,new Int16Array(t,s,e);case 4:return this.i32+=e,new Uint32Array(t,n,e);case 5:return this.i32+=e,new Int32Array(t,n,e);case 6:return this.i32+=e,new Float32Array(t,n,e);case 7:return this.i64+=e,new Float64Array(t,a,e)}},this.factory_plain=[],this.factory_plain_bulk=[];for(var h=0;hT;++T)w+="'"+b[T]+"': values["+T+"],",g+="'"+b[T]+"': values[i+c*"+T+"],";w+="}",g+="}",this.factory_plain.push(new Function("values",w)),this.factory_plain_bulk.push(new Function("values","i",g))}this.factory_weave=[function(t,r){return[]}];for(var h=1;16>h;++h)this.factory_weave.push(e(h))};i.prototype.readStringLT=function(){var t=this.u16[this.i16++];if(t>=this.string_table.length)throw{name:"RangeError",message:"String ID is outside than the range of the string lookup table!",toString:function(){return this.name+": "+this.message}};return this.string_table[t]},i.prototype.eof=function(){return this.i8>=this.iEnd},i.prototype.where=function(){console.log("i8=",this.i8-this.ofs8," [U:",this.u8[this.i8],"0x"+this.u8[this.i8].toString(16),"/ S:",this.s8[this.i8],"]"),console.log("i16=",this.i16-this.ofs16/2," [U:",this.u16[this.i16],"/ S:",this.s16[this.i16],"]"),console.log("i32=",this.i32-this.ofs32/4," [U:",this.u32[this.i32],"/ S:",this.s32[this.i32],"/ F:",this.f32[this.i32],"]"),console.log("i64=",this.i64-this.ofs64/8," [F:",this.f64[this.i64],"]")},t.exports=i},function(t,r){"use strict";var e=function(){this.size=0,this._lib=[],this._profiles=[],this._offset=0,this._foffset=0};e.prototype.add=function(t){this._lib.push(t)},e.prototype.use=function(t){if(0!=t.length)for(var r=0,e=t.length;e>r;r++){for(var i=null,s=t[r],n=0,a=this._lib.length;a>n;n++){var o=this._lib[n];if(o.id===s){i=o;break}}if(null===i){var h=(65520&s)>>4,u=15&s;throw{name:"DecodingError",message:"The bundle uses profile 0x"+h.toString(16)+", rev "+u+" but it was not loaded!",toString:function(){return this.name+": "+this.message}}}this.size+=i.size,this._profiles.push([i,this._foffset,this._foffset+i.frequent,this._offset,this._offset+i.size-i.frequent]),this._offset+=i.size-i.frequent,this._foffset+=i.frequent}},e.prototype.decode=function(t){if(32>t)for(var r=0,e=this._profiles.length;e>r;++r){var i=this._profiles[r],s=i[0],n=i[1],a=i[2];if(t>=n&&a>t)return s.decode(t-n)}else{t-=32;for(var r=0,e=this._profiles.length;e>r;++r){var i=this._profiles[r],s=i[0],n=i[3],a=i[4];if(t>=n&&a>t)return s.decode(t-n+32)}}},t.exports=e},function(t,r){"use strict";var e=function(t){this.parent=t,this.objectLookup=[],this.objects=[],this.value=0};e.prototype.update=function(t,r,e){var i=this.objectLookup.indexOf(t);-1===i?(i=this.objectLookup.length,this.objectLookup.push(t),this.objects.push([r,e])):(this.objects[i][0]=r,this.objects[i][1]=e);for(var s=0,n=0,a=0;a
10 |
11 |
Offset
12 |
Region
13 |
14 |
15 |
0x0000
16 |
Header (see below)
17 |
18 |
19 |
0x0018
20 |
64-Bit Elements (Float64)
21 |
22 |
23 |
...
24 |
32-Bit Elements (Float32, Int32, UInt32)
25 |
26 |
27 |
...
28 |
16-Bit Elements (Int16, UInt16)
29 |
30 |
31 |
...
32 |
Object Signatures
33 |
34 |
35 |
...
36 |
8-Bit Elements (Int8, UInt8)
37 |
38 |
39 |
...
40 |
Strings (NULL Terminated)
41 |
42 |
43 |
44 | The entry point of the bundle is the beginning of the 8-bit elements, since all the op-codes are 8-bit long (`UInt8`).
45 |
46 | *NOTE:* When using sparse format, the four streams are separated in four different files that can be loaded in parallel.
47 |
48 | ## Header
49 |
50 | _Revision Notice: The previous version of the protocol was using the 0x4233 magic number in the header._
51 |
52 | The file header is organised as shown below. The `Magic` number is a 16-bit unsigned integer with value `0x4231`, so it's represented as `<31h,42h>` in machines with little-endian architecture or `<42h,31h>` in big-endian. It's therefore possible to detect incompatible endianess before loading the bundle.
53 |
54 | The `Object Table ID` is the ID of the Object Table used to compile this bundle. This table contains the information required to re-construct the objects in the bundle and should be provided by the loader arguments.
55 |
56 |
57 |
58 |
Offset
59 |
+1
60 |
+2
61 |
+3
62 |
+4
63 |
64 |
65 |
0x00
66 |
Magic (0x4231)
67 |
Object Table ID
68 |
69 |
70 |
0x04
71 |
Protocol Version (1)
72 |
Reserved
73 |
74 |
75 |
0x08
76 |
64-Bit Table Size (Bytes)
77 |
78 |
79 |
0x0C
80 |
32-Bit Table Size (Bytes)
81 |
82 |
83 |
0x10
84 |
16-Bit Table Size (Bytes)
85 |
86 |
87 |
0x14
88 |
8-Bit Table Size (Bytes)
89 |
90 |
91 |
0x18
92 |
String Table Size (Bytes)
93 |
94 |
95 |
0x1C
96 |
Object Signature Table Size (Bytes)
97 |
98 |
99 |
100 | ## Primitives
101 |
102 | The binary bundle is a compacted representation of javascript objects, with size and speed optimisations. In addition, it offers a symbol import/export functionality for sharing resources among different bundles.
103 |
104 | The data in a bundle file are organised in _Primitives_, each one being one of the following:
105 |
106 | * __SIMPLE__ - A simple primitive, that being:
107 | - `UNDEFINED` - The value `undefined`
108 | - `NULL` - The value `null`
109 | - `FALSE` - The boolean value `false`
110 | - `TRUE` - The boolean value `true`
111 | - `NAN` - The value `NaN`
112 | * __ARRAY__ - Array of primitives, further specialised as:
113 | - `EMPTY` - Empty Array
114 | - `DELTA` - Delta-Encoded TypedArray
115 | - `REPEATED` - Repeated TypedArray
116 | - `DOWNSCALED` - Downscaled TypedArray
117 | - `SHORT` - Short TypedArray (1-256 numbers)
118 | - `PRIMITIVE` - Primitive Array (further optimised in chunks)
119 | - `RAW` - RAW Typed Array
120 | * __OBJECT__ - A Javascript object, further specialised as:
121 | - `PREDEFINED` - A predefined object from the object table
122 | - `PLAIN` - A plain object
123 | - `PRIMITIVE` - A primitive javascript object, such as `Date`
124 | * __BUFFER__ - Buffered contents, further specialised as:
125 | - `STRING_LATIN` - A string in LATIN-1 (ISO-8859-1) encoding
126 | - `STRING_UTF8` - A string un UTF-8 encoding
127 | - `BUF_IMAGE` - An embedded image (ImageDOMElement)
128 | - `BUF_SCRIPT` - An embedded script (ScriptDOMElement)
129 | - `RESOURCE` - An arbitrary payload embedded as resource
130 | * __NUMBER__ - A single number
131 | * __IMPORT__ - Import a primitive from another bundle
132 | * __REF__ - Reference to a primitive in the same bundle
133 |
134 | The object primitives are composites. Internally the use array primitives to represent the series of property names and the property values. Therefore the object properties can be further optimised by the array optimisation functions.
135 |
136 | ## Optimisations
137 |
138 | There are a series of optimisations used in this file format. The goal is to have the smallest file size possible that will not impact the parsing speed. This means avoiding `for` loops, using TypedArrays when possible and de-duplicating entries in the file. In addition, to further reduce the file size, the type of the TypedArray is chosen dynamically by analysing the values of the array.
139 |
140 | ### Table of Known Objects
141 |
142 | Most of the times, some objects can be represented with less properties than appear in their instance. In addition, to further reduce the amount of information stored in the file, this information is stored in a separate table, called `Object Table`.
143 |
144 | This table is specific to the application and therefore maintained separately from the `jbb` project. For example, have a look on the [jbb-profile-three](https://github.com/wavesoft/jbb-profile-three) profile.
145 |
146 | ### De-duplication
147 |
148 | De-duplication occurs only for the `OBJECT` primitives, by internally referencing same or similar object in the bundle. The detection of the duplicate items is achieved either by reference or by value:
149 |
150 | * __By Reference__ is enabled by default and looks for exact matches of the object in the object table.
151 | * __By Value__ is enabled by the user (because it slows down the compilation time), and looks for exact match of the values of the object in the object table.
152 |
153 | ### Compression
154 |
155 | In addition to de-duplication, there are some cases that we can benefit from numerical type downscaling, with a minor performance loss. Therefore compression occurs only on the `ARRAY` primitives:
156 |
157 | * __Delta Encoding__ is used when the values in the array have a small difference (delta) between them. In this case, they are encoded as an array of smaller type size. For instance `Int32Array` can be encoded as `Int16Array` or even `Int8Array` if the differences are small. This can also be used with `Float32Array` in conjunction with scaled integers (ex. ±`Int16`*0.001).
158 | * __Downscaling__ is used when the values of an array are able to fit on an array with smaller type. Therefore an `Int32Array` can be downscaled to `Int16Array` or event `Int8Array`. The original array type is preserved and restored at decoding.
159 | * __Repeated__ is used when the values of the array is simply a single value repeated.
160 | * __Chunked Primitive__ is used when an array mixes primitives and numerical values. The encoding algorithm will try to split the array in chunks if similar types that can be further optimised with one of the above techniques.
161 |
162 | ## Opcodes
163 |
164 | The following table explains the binary opcodes found in the bundle format:
165 |
166 | ### Control Opcodes
167 | The control opcodes prefix primitives or other control/information data in the file.
168 |
169 |
170 |
171 | ### Primitive Opcodes
172 | The primitive opcodes define the type of the primitive being encoded:
173 |
174 |
175 |
176 | ### Object Opcodes
177 | This is a specialisation of the OBJECT primitive.
178 |
179 |
180 |
181 | ### Array Opcodes
182 | This is a specialisation of the ARRAY primitive.
183 |
184 |
185 |
186 | ### PRIM_BULK_KNOWN Steering OP-Codes
187 | This is a set of steering instructions for the `PRIM_BULK_KNOWN` array.
188 |
189 |
190 |
191 | ### Other Types
192 | The following tables contain the values of other properties of the opcodes.
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
--------------------------------------------------------------------------------
/doc/Tutorial 1 - THREEjs/Using with THREEjs.md:
--------------------------------------------------------------------------------
1 |
2 | # Using `jbb` with `THREE.js`
3 |
4 | The JBB Project was initially started in order to optimally store resources for THREE.js scenes. Therefore it's only natural to have a dedicated guide on how to use it with three.js.
5 |
6 | You can integrate jbb in your pipeline in various ways. In this tutorial we are going to use `gulp-jbb` for steering the creation of bundles, but we are not going to create a gulp-based binary project.
7 |
8 | ## 1. Getting Started
9 |
10 | For the bare minimum requirements you will need to install `node` and a few packages. Start by creating a new directory for our project and install the following packages locally:
11 |
12 | ```
13 | npm install jbb jbb-profile-three gulp gulp-jbb three
14 | ```
15 |
16 | Then create two directories:
17 | * `bundles` - Were the bundle sources are located.
18 | * `build` - Were the built files will be placed.
19 |
20 | ```
21 | mkdir bundles build
22 | ```
23 |
24 | ## 3. Creating a THREE.js scene
25 |
26 | Let's start by creating a new page for our three.js scene. Create a new file `index.html` in the root directory with the following contents:
27 |
28 | ```html
29 |
30 |
31 |
32 | three.js + jbb.js
33 |
34 |
35 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
109 |
110 |
111 | ```
112 |
113 | Open your `index.html` file and check your javascript console. If you see no errors you are ready to continue. Don't worry about the empty black content for now...
114 |
115 | ## 2. Creating a bundle
116 |
117 | For our example we are going to bundle a textured cube. We used [Blender](https://www.blender.org/) and [THREE.js exporter](https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender) to create a very simple crate:
118 |
119 |
120 |
121 | After exporting the cube, we have two files: `crate.json` and `crate.png`. The first contains the cube mesh and the second the diffuse map for the texture. You can find the files [here](https://github.com/wavesoft/jbb/tree/master/doc/Tutorial 1 - THREEjs/files).
122 |
123 | To create a new bundle, we are going to create a new bundle directory in the `bundles` folder and a new specifications file.
124 |
125 | ```
126 | mkdir bundles/crate.jbbsrc
127 | ```
128 |
129 | Move the two files in the `crate.jbbsrc` directory and create an additional new file called `bundle.json` with the following contents:
130 |
131 | ```json
132 | {
133 | "name": "crate",
134 | "exports": {
135 | "THREE.JSONLoader": {
136 | "crate" : "crate.json",
137 | }
138 | }
139 | }
140 | ```
141 |
142 | This is the _index_ file of the bundle and instructs jbb to first load `crate.json` using the `THREE.JSONLoader` and to export it under the name `crate/crate`. The first, `name` argument should be the same as the bundle folder name (without the extension).
143 |
144 | ## 3. Creating a Gulpfile.js
145 |
146 | In order to build our bundles we can either use the `jbb` command-line, or we can create a gulpfile to automate the build process using `gulp`.
147 |
148 | Create a new file called `gulpfile.js` in your root directory with the following contents:
149 |
150 | ```javascript
151 | var gulp = require('gulp');
152 | var jbb = require('gulp-jbb');
153 |
154 | //
155 | // Compile the binary bundles
156 | //
157 | gulp.task('bundles', function() {
158 | return gulp
159 | .src([ "bundles/*.jbbsrc" ])
160 | .pipe(jbb({
161 | profile: 'three'
162 | }))
163 | .pipe(gulp.dest('build/bundles'));
164 | });
165 |
166 | // By default build bundles
167 | gulp.task('default', ['bundles' ]);
168 | ```
169 |
170 | Note the `profile` parameter in the `jbb` group. It instructs jbb to use the [jbb-profile-three](github.com/wavesoft/jbb-profile-three) in order to correctly handle THREE.js objects. Without it `jbb` will complain about unknown object instances.
171 |
172 | You can now build your bundle just by running `gulp`
173 |
174 | ```
175 | $ gulp
176 | [21:07:10] Using gulpfile .. /gulpfile.js
177 | [21:07:10] Starting 'bundles'...
178 | Loader.createMaterial: Unsupported colorAmbient [ 0.64, 0.64, 0.64 ]
179 | Loading .. /bundles/crate.jbbsrc/crate.png
180 | [21:07:10] Finished 'bundles' after
181 | [21:07:10] Starting 'default'...
182 | [21:07:10] Finished 'default' after 115 μs
183 | ```
184 |
185 | You can confirm that `crate.jbb` exists in your `build/bundles` directory.
186 |
187 | ## 4. Loading the bundle in the scene
188 |
189 | Now that we have our bundle, it's time to load it into our THREE.js scene. To do so, we are going to use the `JBBBundleLoader` that was made available when we included the `jbb.min.js` file.
190 |
191 | Change the last part of the init() function like this:
192 |
193 | ```javascript
194 | // TODO : Add something on the scene
195 |
196 | var bundleLoader = new JBBBinaryLoader();
197 | bundleLoader.addProfile( JBBProfileThree );
198 |
199 | // Get model from bundle
200 | bundleLoader.add("build/bundles/crate.jbb");
201 | bundleLoader.load( function(error, database) {
202 |
203 | var geometry = database['crate/crate'];
204 | var materials = database['crate/crate:extra'];
205 |
206 | var mesh = new THREE.Mesh( geometry, materials[0] );
207 | scene.add(mesh);
208 |
209 | });
210 | ```
211 |
212 | Let's see this step-by-step: First, we are creating a new instance to the `JBBBinaryLoader` class. This is responsible for loading and parsing the bundles.
213 |
214 | ```javascript
215 | var bundleLoader = new JBBBinaryLoader();
216 | ```
217 |
218 | Right after, we are adding a decoding profile to the loader using the `.addProfile()` method. Similar to the encoding process, a profile contains the decoding information for the objects.
219 |
220 | We have already loaded `jbb-profile-three.min.js`, that exposes the `JBBProfileThree` global variable, so we can use it right-away:
221 |
222 | ```javascript
223 | bundleLoader.addProfile( JBBProfileThree );
224 | ```
225 |
226 | Then, we request jbb loader to load our crate bundle. We can add more bundles if needed. Additional bundles might also be loaded if a dependency is encountered.
227 |
228 | ```javascript
229 | bundleLoader.add("build/bundles/crate.jbb");
230 | ```
231 |
232 | To actually start loading the bundle we are calling the `.load` function. This will trigger a callback when the operation has completed.
233 |
234 | ```javascript
235 | bundleLoader.load( function(error, database) {
236 | ...
237 | });
238 | ```
239 |
240 | If there was no error while loading the bundle, the `error` argument will be `null` and the `database` argument will be a dictionary-like object with all the loaded objects.
241 |
242 | Therefore, we can easily access the encoded crate like this:
243 |
244 | ```javascript
245 | var geometry = database['crate/crate'];
246 | ```
247 |
248 | Since the cube stored in `crate.json` file is not an object, but just the geometry to the cube, the `THREE.JSONLoader` will create a `THREE.Geometry` object. Since that's the loader's default return value, this geometry will be accessible as `/`.
249 |
250 | However `THREE.JSONLoader` also returns an array of `THREE.Material` instances as a separate argument. Such 'extra' information is available under the `/:extra` name.
251 |
252 | Therefore we have enough information to create a new textured mesh:
253 |
254 | ```javascript
255 | var materials = database['crate/crate:extra'];
256 |
257 | var mesh = new THREE.Mesh( geometry, materials[0] );
258 | scene.add(mesh);
259 | ```
260 |
261 | If everything went as expected, you will see something like this:
262 |
263 |
264 |
265 | If you are using `Chrome` you will need to see this page over `http:`. You can use the minimalistic http server from node to serve your resources locally:
266 |
267 | ```
268 | ~$ npm install http-server
269 | ~$ ./node_modules/http-server/bin/http-server
270 | Starting up http-server, serving ./
271 | Available on:
272 | http://127.0.0.1:8080
273 | ```
274 |
275 | And you can now see your results on [http://127.0.0.1:8080](http://127.0.0.1:8080).
276 |
277 |
--------------------------------------------------------------------------------
/doc/Tutorial 1 - THREEjs/files/crate.json:
--------------------------------------------------------------------------------
1 | {
2 | "normals": [0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,-0.577349,0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,0.577349,0.577349,0.577349,0.577349],
3 | "uvs": [[0,0,1,0,1,1,0,1]],
4 | "name": "CubeGeometry.1",
5 | "materials": [{
6 | "colorDiffuse": [0.64,0.64,0.64],
7 | "DbgIndex": 0,
8 | "colorEmissive": [0,0,0],
9 | "wireframe": false,
10 | "mapDiffuseWrap": ["RepeatWrapping","RepeatWrapping"],
11 | "colorAmbient": [0.64,0.64,0.64],
12 | "specularCoef": 50,
13 | "transparent": false,
14 | "colorSpecular": [0,0,0],
15 | "mapDiffuseAnisotropy": 1,
16 | "opacity": 1,
17 | "blending": "NormalBlending",
18 | "visible": true,
19 | "depthWrite": true,
20 | "DbgName": "Material",
21 | "depthTest": true,
22 | "DbgColor": 15658734,
23 | "mapDiffuse": "crate.png",
24 | "mapDiffuseRepeat": [1,1],
25 | "shading": "phong"
26 | }],
27 | "vertices": [1,-1,-1,1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,0.999999,1,1,-1,1,1,-1,1,-1],
28 | "faces": [43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,7,6,5,0,0,1,2,3,4,5,6,7,43,0,4,5,1,0,0,1,2,3,0,4,7,1,43,1,5,6,2,0,0,1,2,3,1,7,6,2,43,2,6,7,3,0,0,1,2,3,2,6,5,3,43,4,0,3,7,0,0,1,2,3,4,0,3,5],
29 | "metadata": {
30 | "normals": 8,
31 | "uvs": 1,
32 | "materials": 1,
33 | "faces": 6,
34 | "generator": "io_three",
35 | "type": "Geometry",
36 | "vertices": 8,
37 | "version": 3
38 | }
39 | }
--------------------------------------------------------------------------------
/doc/Tutorial 1 - THREEjs/files/crate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/Tutorial 1 - THREEjs/files/crate.png
--------------------------------------------------------------------------------
/doc/Tutorial 1 - THREEjs/img/1-blender.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/Tutorial 1 - THREEjs/img/1-blender.png
--------------------------------------------------------------------------------
/doc/Tutorial 1 - THREEjs/img/2-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/Tutorial 1 - THREEjs/img/2-result.png
--------------------------------------------------------------------------------
/doc/bundle.json.md:
--------------------------------------------------------------------------------
1 | # bundle.json
2 |
3 | The following example describes the full parameter set that you can use
4 | in your own `bundle.json` file:
5 |
6 | ```javascript
7 | {
8 | //
9 | // -= name =-
10 | //
11 | // The name of the bundle, used internally or tagging the contents of
12 | // the bundle. This name SHOULD match the name of the bundle (without
13 | // the extension)
14 | //
15 | // -----------------------------------------------------------------------
16 | // Default : (required)
17 | // Type : string
18 | //
19 | "name" : "bundle-name",
20 |
21 | //
22 | // -= profile =-
23 | //
24 | // The name of jbb profile to use for compiling the contents of this bundle.
25 | // The profile provides the loader functions and the binary specifications
26 | // for the contents. Refer to the bundle you are interested in for more
27 | // details.
28 | //
29 | // The name of the bundle should not include the 'jbb-bndle-' prefix. For
30 | // example, specify 'three' for 'jbb-profile-three'.
31 | //
32 | // If this parameter is missing the profile must be specified at
33 | // compile-time.
34 | //
35 | // -----------------------------------------------------------------------
36 | // Default : ""
37 | // Type : string
38 | //
39 | "profile" : "three",
40 |
41 | //
42 | // -= imports =-
43 | //
44 | // Other bundles this bundle depends on. These bundles will be loaded
45 | // before loading the contents of this bundle.
46 | //
47 | // It's important to provide this information if your bundle has external
48 | // references, in order to properly resolve them at loading time.
49 | //
50 | // You can specify the bundle names as an array of strings. In this case,
51 | // the compiler will try to locate them in the 'path' directory specified
52 | // at compile-time:
53 | //
54 | // "imports": [ "bundle-1", "bundle-2" ]
55 | //
56 | // If you want more control, you can provide the path to the bundle (without
57 | // the extension) yourself:
58 | //
59 | // "imports": {
60 | // "bundle-1": "../bundle-1",
61 | // "bundle-2": "bundles/bundle-2"
62 | // }
63 | //
64 | // -----------------------------------------------------------------------
65 | // Default : []
66 | // Type : array | object
67 | //
68 | "imports" : [ "dependant-module-1", "dependant-module-2" ],
69 |
70 | //
71 | // -= exports =-
72 | //
73 | // This section contains the information for what resources are exposed
74 | // by this bundle. You will need to specify the loader class to use for
75 | // each class of resources.
76 | //
77 | // -----------------------------------------------------------------------
78 | // Default : (required)
79 | // Type : object
80 | //
81 | "exports" : {
82 |
83 | //
84 | // -= (Blob Embeds) =-
85 | //
86 | // Resources that cannot be serialized by the JBB compiler (such as
87 | // images, sounds or other binary resources) can be placed in the
88 | // "blob" (case-insensitive) group.
89 | //
90 | // These files are just embedded as-is in the final bundle and do not
91 | // benefit by any optimisation.
92 | //
93 | "blob": {
94 |
95 | //
96 | // For each binary resource the MIME type will be
97 | // automatically detected base on the extension
98 | //
99 | "background-audio": "sounds/background.mp3",
100 |
101 | //
102 | // You can also override the automatic MIME detection
103 | // by specifying the MIME type yourself
104 | //
105 | "player-sound": [ "sounds/player.mp3", "audio/mpeg" ]
106 |
107 | },
108 |
109 | //
110 | // -= (Loader Class) =-
111 | //
112 | // Specify the loader class that is capapble of loading the resources
113 | // in this group.
114 | //
115 | // This key is profile-specific, therefore you should refer to the
116 | // appropriate jbb profile documentation for more details.
117 | //
118 | "THREE.JSONLoader": {
119 |
120 | //
121 | // -= (Resources) =-
122 | //
123 | // Here you specify your actual resources and the key they will
124 | // be available in the bundle:
125 | //
126 | // "key" : "path/to/resource"
127 | //
128 | // Each loader accepts different kind of parameters, so refer to
129 | // the jbb profile for more details. However in most of the cases
130 | // this is just a string pointing to the resources, relative to
131 | // the bundle folder.
132 | //
133 | // On a more complicated scenarios, the macro ${BUNDLE} is
134 | // provided for convenience, and it expands to the base directory
135 | // of the bundle. Refer on the THREE.MD2CharacterLoader example
136 | // below for an example.
137 | //
138 | "test-model": "${BUNDLE}/models/test.json",
139 |
140 | //
141 | // If the ${BUNDLE} macro is not used, the path to the resources
142 | // should be relative to the bundle directory
143 | //
144 | "another-model": "modeuls/world.json",
145 |
146 | //
147 | // There is no limitation on how many resources you can export
148 | //
149 | "big-model": "models/big.json",
150 | "strong-model": "models/strong.json",
151 | "tall-model": "models/tall.json",
152 | "short-model": "models/short.json",
153 | "thin-model": "models/thin.json",
154 | ...
155 |
156 | },
157 |
158 | //
159 | // Other loaders require more complex configuration
160 | // rather than just a filename.
161 | //
162 | "THREE.MD2CharacterLoader": {
163 |
164 | //
165 | // For example, the MD2CharacterLoader requires detailed
166 | // configuration for various parts (hence the need for // the ${BUNDLE} macro)
167 | //
168 | "ratamahatta": {
169 | "baseUrl": "${BUNDLE}/mesh/ratamahatta/",
170 | "body": "ratamahatta.md2",
171 | "skins": [ "ratamahatta.png", "ctf_b.png", "ctf_r.png", "dead.png", "gearwhore.png" ],
172 | "weapons": [ [ "weapon.md2", "weapon.png" ],
173 | [ "w_bfg.md2", "w_bfg.png" ],
174 | [ "w_blaster.md2", "w_blaster.png" ],
175 | [ "w_chaingun.md2", "w_chaingun.png" ],
176 | [ "w_glauncher.md2", "w_glauncher.png" ],
177 | [ "w_hyperblaster.md2", "w_hyperblaster.png" ],
178 | [ "w_machinegun.md2", "w_machinegun.png" ],
179 | [ "w_railgun.md2", "w_railgun.png" ],
180 | [ "w_rlauncher.md2", "w_rlauncher.png" ],
181 | [ "w_shotgun.md2", "w_shotgun.png" ],
182 | [ "w_sshotgun.md2", "w_sshotgun.png" ]
183 | ]
184 | }
185 |
186 | }
187 |
188 | }
189 | }
190 | ```
--------------------------------------------------------------------------------
/doc/jbb-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/jbb-logo.png
--------------------------------------------------------------------------------
/doc/table_BUF_TYPE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_BUF_TYPE.png
--------------------------------------------------------------------------------
/doc/table_CHUNK.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_CHUNK.png
--------------------------------------------------------------------------------
/doc/table_DWS_TYPE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_DWS_TYPE.png
--------------------------------------------------------------------------------
/doc/table_LEN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_LEN.png
--------------------------------------------------------------------------------
/doc/table_LN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_LN.png
--------------------------------------------------------------------------------
/doc/table_NUM_TYPE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_NUM_TYPE.png
--------------------------------------------------------------------------------
/doc/table_OP_ARR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OP_ARR.png
--------------------------------------------------------------------------------
/doc/table_OP_BULK_KNOWN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OP_BULK_KNOWN.png
--------------------------------------------------------------------------------
/doc/table_OP_CTL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OP_CTL.png
--------------------------------------------------------------------------------
/doc/table_OP_OBJECT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OP_OBJECT.png
--------------------------------------------------------------------------------
/doc/table_OP_PRIM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OP_PRIM.png
--------------------------------------------------------------------------------
/doc/table_OT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_OT.png
--------------------------------------------------------------------------------
/doc/table_SCALE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_SCALE.png
--------------------------------------------------------------------------------
/doc/table_S_TYPE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/doc/table_S_TYPE.png
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var header = require('gulp-header');
3 | var jbb_profile = require('gulp-jbb-profile');
4 | var webpack = require('webpack-stream');
5 | var PROD = JSON.parse(process.env.PROD_DEV || "0");
6 |
7 | //
8 | // Compile test files
9 | //
10 | gulp.task('test/simple-profile', function() {
11 | return gulp
12 | .src([ 'test/simple-profile/specs.yaml' ])
13 | .pipe(jbb_profile())
14 | .pipe(gulp.dest('test/simple-profile'));
15 | });
16 | gulp.task('test/second-profile', function() {
17 | return gulp
18 | .src([ 'test/simple-profile/second.yaml' ])
19 | .pipe(jbb_profile())
20 | .pipe(gulp.dest('test/simple-profile'));
21 | });
22 |
23 | //
24 | // Compile the binary loader
25 | //
26 | gulp.task('dist/jbb', function() {
27 | return gulp.src('decoder.js')
28 | .pipe(webpack({
29 | module: {
30 | loaders: [
31 | { test: /\.json$/, loader: 'json' },
32 | ],
33 | },
34 | node: {
35 | 'fs': 'empty'
36 | },
37 | output: {
38 | // The output filename
39 | filename: PROD ? 'jbb.min.js' : 'jbb.js',
40 | // Export itself to a global var
41 | libraryTarget: 'var',
42 | // Name of the global var: 'JBB.BinaryLoader'
43 | library: [ 'JBB', 'BinaryLoader' ]
44 | },
45 | externals: {
46 | 'three': 'THREE',
47 | },
48 | plugins: ([
49 | new webpack.webpack.optimize.DedupePlugin(),
50 | new webpack.webpack.DefinePlugin({
51 | GULP_BUILD : PROD
52 | })
53 | ]).concat(PROD ? [
54 | new webpack.webpack.optimize.UglifyJsPlugin({
55 | minimize: true
56 | })
57 | ] : [])
58 | }))
59 | .pipe(header("/* JBB Binary Bundle Loader - https://github.com/wavesoft/jbb */\n"))
60 | .pipe(gulp.dest('dist'));
61 | });
62 |
63 | //
64 | // Compile the source loader
65 | //
66 | gulp.task('dist/jbb-loader', function() {
67 | return gulp.src('loader.js')
68 | .pipe(webpack({
69 | module: {
70 | loaders: [
71 | { test: /\.json$/, loader: 'json' },
72 | ],
73 | },
74 | node: {
75 | 'fs': 'empty'
76 | },
77 | output: {
78 | // The output filename
79 | filename: PROD ? 'jbb-loader.min.js' : 'jbb-loader.js',
80 | // Export itself to a global var
81 | libraryTarget: 'var',
82 | // Name of the global var: 'Foo'
83 | library: [ 'JBB', 'SourceLoader' ]
84 | },
85 | externals: {
86 | 'three': 'THREE',
87 | },
88 | plugins: ([
89 | new webpack.webpack.optimize.DedupePlugin(),
90 | new webpack.webpack.DefinePlugin({
91 | GULP_BUILD : PROD
92 | })
93 | ]).concat(PROD ? [
94 | new webpack.webpack.optimize.UglifyJsPlugin({
95 | minimize: true
96 | })
97 | ] : [])
98 | }))
99 | .pipe(header("/* JBB Source Bundle Loader - https://github.com/wavesoft/jbb */\n"))
100 | .pipe(gulp.dest('dist'));
101 | });
102 |
103 | // The files to pack on dist release
104 | gulp.task('dist', [
105 | 'dist/jbb',
106 | 'dist/jbb-loader'
107 | ]);
108 |
109 |
110 | // By default run only script
111 | gulp.task('default', ['dist']);
112 |
113 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * THREE Bundles - Binary Encoder
4 | * Copyright (C) 2015 Ioannis Charalampidis
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License along
17 | * with this program; if not, write to the Free Software Foundation, Inc.,
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 | *
20 | * @author Ioannis Charalampidis / https://github.com/wavesoft
21 | */
22 |
23 | /**
24 | * Export binary encoder
25 | */
26 | module.exports = {
27 |
28 | // Expose binary encoder
29 | 'BinaryEncoder' : require("./encoder.js"),
30 |
31 | // Expose binary decoder
32 | 'BinaryDecoder': require("./decoder.js")
33 |
34 | };
35 |
--------------------------------------------------------------------------------
/lib/BinaryBundle.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * JBB - Javascript Binary Bundles - Binary Decoder
4 | * Copyright (C) 2015 Ioannis Charalampidis
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | /**
22 | * Numerical types
23 | */
24 | var NUMTYPE = {
25 | UINT8: 0, INT8: 1,
26 | UINT16: 2, INT16: 3,
27 | UINT32: 4, INT32: 5,
28 | FLOAT32: 6, FLOAT64: 7
29 | }
30 |
31 | //////////////////////////////////////////////////////////////////
32 | // Local Helper Functions
33 | //////////////////////////////////////////////////////////////////
34 |
35 | /**
36 | * Create a weave property factory
37 | */
38 | function genWeavePropFn( d ) {
39 | var code = "";
40 | for (var i=0; i> 8;
116 |
117 | // Calculate upper bounds
118 | this.max64 = hv32[2];
119 | this.max32 = hv32[3];
120 | this.max16 = hv32[4];
121 | this.max8 = hv32[5];
122 | this.lenST = hv32[6];
123 | this.lenOT = hv32[7];
124 |
125 | // Validate magic
126 | if (this.magic == 0x3142) {
127 | throw {
128 | 'name' : 'EndianessError',
129 | 'message' : 'Unfortunately the JBB format is currently only compatible with Little-Endian CPUs',
130 | toString : function(){return this.name + ": " + this.message;}
131 | }
132 | } else if (this.magic != 0x4231) {
133 | throw {
134 | 'name' : 'DecodingError',
135 | 'message' : 'This does not look like a JBB archive! (Magic is 0x'+this.magic.toString(16)+')',
136 | toString : function(){return this.name + ": " + this.message;}
137 | }
138 | }
139 |
140 | // Validate bundle version number
141 | if (this.version != 0x0102) {
142 | throw {
143 | 'name' : 'DecodingError',
144 | 'message' : 'Unsupported bundle version v'+this.ver_minor+'.'+this.ver_minor,
145 | toString : function(){return this.name + ": " + this.message;}
146 | }
147 | }
148 |
149 | // Setup indices
150 | if (this.sparse) {
151 |
152 | // Setup indices
153 | this.i64 = 0;
154 | this.i32 = 0;
155 | this.i16 = 0;
156 | this.i8 = header_size;
157 | this.iEnd= this.i8 + this.max8 - this.lenST;
158 |
159 | // Offsets of array beginning (for getting array portions)
160 | this.ofs8 = this.i8;
161 | this.ofs16 = this.i16;
162 | this.ofs32 = this.i32;
163 | this.ofs64 = this.i64;
164 |
165 | } else {
166 |
167 | // Setup indices
168 | this.i64 = header_size;
169 | this.i32 = this.i64 + this.max64;
170 | this.i16 = this.i32 + this.max32;
171 | this.i8 = this.i16 + this.max16;
172 | this.iEnd= this.i8 + this.max8 - this.lenST;
173 |
174 | // Offsets of array beginning (for getting array portions)
175 | this.ofs8 = this.i8;
176 | this.ofs16 = this.i16;
177 | this.ofs32 = this.i32;
178 | this.ofs64 = this.i64;
179 |
180 | // Convert to element index
181 | this.i16 /= 2;
182 | this.i32 /= 4;
183 | this.i64 /= 8;
184 |
185 | }
186 |
187 | // Current position of i16 used later
188 | var ci16 = this.i16;
189 |
190 | // Load object tables
191 | var ots = [];
192 | if (this.table_count <= 1) {
193 |
194 | // The bundle can have no profile if needed
195 | if (this.table_id !== 0x00)
196 | ots.push( this.table_id );
197 |
198 | } else if (this.table_id !== 0x00) {
199 | throw {
200 | 'name' : 'DecodingError',
201 | 'message' : 'Invalid header data',
202 | toString : function(){return this.name + ": " + this.message;}
203 | }
204 | } else {
205 | // Read known table IDs
206 | for (var i=0; i 0) {
221 | for (var l=this.i8+this.max8, i=l-this.lenST; i 0) {
239 | for (var l=ci16*2+this.max16, i=l-this.lenOT; i= this.string_table.length) throw {
330 | 'name' : 'RangeError',
331 | 'message' : 'String ID is outside than the range of the string lookup table!',
332 | toString : function(){return this.name + ": " + this.message;}
333 | }
334 | return this.string_table[id];
335 | }
336 |
337 | /**
338 | * Check if we ran out of opcodes
339 | */
340 | BinaryBundle.prototype.eof = function() {
341 | return (this.i8 >= this.iEnd);
342 | }
343 |
344 | /**
345 | * Print the index offsets
346 | */
347 | BinaryBundle.prototype.where = function() {
348 | console.log( "i8=", this.i8 - this.ofs8, " [U:",this.u8[this.i8], "0x"+this.u8[this.i8].toString(16),"/ S:",this.s8[this.i8],"]" );
349 | console.log( "i16=", this.i16 - this.ofs16/2, " [U:",this.u16[this.i16], "/ S:",this.s16[this.i16],"]" );
350 | console.log( "i32=", this.i32 - this.ofs32/4, " [U:",this.u32[this.i32], "/ S:",this.s32[this.i32],"/ F:",this.f32[this.i32],"]" );
351 | console.log( "i64=", this.i64 - this.ofs64/8, " [F:",this.f64[this.i64], "]");
352 | }
353 |
354 | module.exports = BinaryBundle;
355 |
--------------------------------------------------------------------------------
/lib/BinaryStream.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * JBB - Javascript Binary Bundles - Binary Stream Class
4 | * Copyright (C) 2015 Ioannis Charalampidis
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | var fs = require("fs");
22 | var util = require("util");
23 |
24 | //////////////////////////////////////////////////////////////////
25 | // Binary Stream
26 | //////////////////////////////////////////////////////////////////
27 |
28 | /**
29 | * Binary Stream
30 | */
31 | var BinaryStream = function( filename, alignSize, logWrites ) {
32 |
33 | // Local properties
34 | this.offset = 0;
35 | this.blockSize = 1024 * 16;
36 | this.logWrites = logWrites;
37 |
38 | // Private properties
39 | this.__writeChunks = [];
40 | this.__syncOffset = 0;
41 | this.__fd = null;
42 | this.__alignSize = 0;
43 |
44 | // Initialize
45 | this.__alignSize = alignSize || 8;
46 | this.__fd = fs.openSync( filename, 'w+' );
47 |
48 | }
49 |
50 | /**
51 | * Prototype constructor
52 | */
53 | BinaryStream.prototype = {
54 |
55 | 'constructor': BinaryStream,
56 |
57 | /**
58 | * Finalise and close stream
59 | */
60 | 'close': function() {
61 | // Close
62 | fs.closeSync( this.__fd );
63 | },
64 |
65 | /**
66 | * Finalize the stream
67 | */
68 | 'finalize': function() {
69 | // Write alignment padding
70 | var alignOffset = this.offset % this.__alignSize;
71 | if (alignOffset > 0)
72 | this.write( new Buffer(new Uint8Array( this.__alignSize - alignOffset )) );
73 | // Synchronize
74 | this.__sync( true );
75 | },
76 |
77 | /**
78 | * Write a buffer using the compile function
79 | */
80 | 'write': function( buffer ) {
81 | if (this.logWrites) {
82 | var bits = String(this.__alignSize*8);
83 | if (bits.length === 1) bits=" "+bits;
84 | console.log((bits+"b ").yellow+("@"+this.offset/this.__alignSize).bold.yellow+": "+util.inspect(buffer));
85 | }
86 | this.__writeChunks.push( buffer );
87 | this.offset += buffer.length;
88 | this.__sync();
89 | },
90 |
91 | /**
92 | * Write an array of buffers
93 | */
94 | 'writeMany': function( buffers ) {
95 | var bits;
96 | for (var i=0, bl=buffers.length; i
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | /**
22 | * Encoder profile
23 | */
24 | var DecodeProfile = function() {
25 | this.size = 0;
26 | this._lib = [];
27 | this._profiles = [];
28 | this._offset = 0;
29 | this._foffset = 0;
30 | };
31 |
32 | /**
33 | * Combine current profile with the given one
34 | */
35 | DecodeProfile.prototype.add = function( profile ) {
36 | // Add in the library. They will be used
37 | // only when explicitly requested.
38 | this._lib.push( profile );
39 | }
40 |
41 | /**
42 | * From the profiles added, use the ones specified in the list,
43 | * in the order they were given.
44 | */
45 | DecodeProfile.prototype.use = function( ids ) {
46 |
47 | // If empty profile, return
48 | if (ids.length == 0)
49 | return;
50 |
51 | // Pick the profiles of interest
52 | for (var i=0, l=ids.length; i> 4, rev = id & 0xF;
67 | throw {
68 | 'name' : 'DecodingError',
69 | 'message' : 'The bundle uses profile 0x'+pid.toString(16)+', rev '+rev+' but it was not loaded!',
70 | toString : function(){return this.name + ": " + this.message;}
71 | }
72 | }
73 |
74 | // Update size
75 | this.size += profile.size;
76 |
77 | // Keep profiles and bounds for fast segment lookup
78 | this._profiles.push([ profile,
79 | this._foffset, this._foffset + profile.frequent,
80 | this._offset, this._offset + profile.size - profile.frequent ]);
81 |
82 | // Update offsets
83 | this._offset += profile.size - profile.frequent;
84 | this._foffset += profile.frequent;
85 |
86 | }
87 |
88 | }
89 |
90 | /**
91 | * Drop-in replacement for the profile decode function
92 | */
93 | DecodeProfile.prototype.decode = function( eid ) {
94 | if (eid < 32) {
95 | for (var i=0, l=this._profiles.length; i= ofs) && (eid < end))
98 | return p.decode( eid - ofs );
99 | }
100 | } else {
101 | eid -= 32;
102 | for (var i=0, l=this._profiles.length; i= ofs) && (eid < end))
105 | return p.decode( eid - ofs + 32 );
106 | }
107 | }
108 | };
109 |
110 | // Export profile
111 | module.exports = DecodeProfile;
112 |
--------------------------------------------------------------------------------
/lib/EncodeProfile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * JBB - Javascript Binary Bundles - Encoder Multi-Profile Drop-in replacement
4 | * Copyright (C) 2015 Ioannis Charalampidis
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | var Errors = require("./Errors");
22 |
23 | /**
24 | * Encoder profile
25 | */
26 | var EncodeProfile = function() {
27 | this.size = 0;
28 | this.id = 0;
29 | this.count = 0;
30 | this._profiles = [];
31 | this._ioffset = 0;
32 | this._foffset = 0;
33 | };
34 |
35 | /**
36 | * Combine current profile with the given one
37 | */
38 | EncodeProfile.prototype.add = function( profile ) {
39 |
40 | // Update size
41 | this.size += profile.size;
42 |
43 | // Keep profiles and their offsets
44 | this._profiles.push([ this._ioffset, this._foffset, profile ]);
45 | this._ioffset += profile.size - profile.frequent;
46 | this._foffset += profile.frequent;
47 |
48 | // Keep the first ID
49 | if (this.id === 0)
50 | this.id = profile.id;
51 |
52 | // Test for overflow
53 | if (this._foffset > 31) {
54 | throw new Errors.AssertError("Exceeded maximum number of frequent profile items");
55 | }
56 |
57 | // Increment counter
58 | this.count++;
59 |
60 | }
61 |
62 | /**
63 | * Drop-in replacement for the profile encode function
64 | */
65 | EncodeProfile.prototype.encode = function( entity ) {
66 | for (var i=0, l=this._profiles.length; i
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | /**
22 | * Helper to reduce a few bytes on the minified version
23 | */
24 | function _define(inst, message, type) {
25 | var temp = Error.call(inst, message);
26 | temp.name = inst.name = type;
27 | inst.stack = temp.stack;
28 | inst.message = temp.message;
29 | }
30 |
31 | /**
32 | * Encode error is a generic error emmited during encoding
33 | */
34 | var EncodeError = function(message) {
35 | _define(this, message, "EncodeError");
36 | }
37 | EncodeError.prototype = Object.create(Error.prototype);
38 |
39 | /**
40 | * Assert error is generated by integrity checks
41 | */
42 | var AssertError = function(message) {
43 | _define(this, message, "AssertError");
44 | }
45 | AssertError.prototype = Object.create(Error.prototype);
46 |
47 | /**
48 | * Assert error generated by the packing functions
49 | */
50 | var PackError = function(message) {
51 | _define(this, message, "PackError");
52 | }
53 | PackError.prototype = Object.create(Error.prototype);
54 |
55 | /**
56 | * Assert error generated by the loading functions
57 | */
58 | var LoadError = function(message) {
59 | _define(this, message, "LoadError");
60 | }
61 | LoadError.prototype = Object.create(Error.prototype);
62 |
63 | /**
64 | * A value is out of range
65 | */
66 | var RangeError = function(message) {
67 | _define(this, message, "RangeError");
68 | }
69 | RangeError.prototype = Object.create(Error.prototype);
70 |
71 | /**
72 | * Internal referrence error
73 | */
74 | var IRefError = function(message) {
75 | _define(this, message, "IRefError");
76 | }
77 | IRefError.prototype = Object.create(Error.prototype);
78 |
79 | /**
80 | * External referrence error
81 | */
82 | var XRefError = function(message) {
83 | _define(this, message, "XRefError");
84 | }
85 | XRefError.prototype = Object.create(Error.prototype);
86 |
87 | module.exports = {
88 | 'EncodeError': EncodeError,
89 | 'AssertError': AssertError,
90 | 'PackError': PackError,
91 | 'RangeError': RangeError,
92 | 'IRefError': IRefError,
93 | 'XRefError': XRefError,
94 | };
--------------------------------------------------------------------------------
/lib/ProgressManager.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * JBB - Javascript Binary Bundles - Binary Decoder
4 | * Copyright (C) 2015 Ioannis Charalampidis
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | /**
22 | * A partial progress item
23 | */
24 | var ProgressManagerPart = function(parent) {
25 | this.parent = parent;
26 | this.objectLookup = [];
27 | this.objects = [];
28 | this.value = 0;
29 | };
30 |
31 | /**
32 | * Update sub-object progress
33 | */
34 | ProgressManagerPart.prototype.update = function( obj, progress, total ) {
35 |
36 | // Get/Create new object for tracking this object
37 | var id = this.objectLookup.indexOf(obj);
38 | if (id === -1) {
39 | id = this.objectLookup.length;
40 | this.objectLookup.push(obj);
41 | this.objects.push([ progress, total ])
42 | } else {
43 | this.objects[id][0] = progress;
44 | this.objects[id][1] = total;
45 | }
46 |
47 | // Update summary
48 | var prog=0, tot=0;
49 | for (var i=0; i
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | * @author Ioannis Charalampidis / https://github.com/wavesoft
19 | */
20 |
21 | var toposort = require('toposort');
22 | var path = require('path');
23 | var mime = require('mime');
24 |
25 | var IS_BROWSER = true && (new Function("try {return this===window;}catch(e){ return false;}")());
26 |
27 | /**
28 | * Pick MIME type according to filename and known MIME Types
29 | */
30 | function mimeTypeFromFilename( filename ) {
31 | var ext = filename.split(".").pop().toLowerCase();
32 | return mime.lookup(filename) || "application/octet-stream";
33 | }
34 |
35 | /**
36 | * State constants for the
37 | */
38 | const STATE_REQUESTED = 0;
39 | const STATE_SPECS = 1;
40 | const STATE_LOADING = 2;
41 | const STATE_LOADED = 3;
42 | const STATE_FAILED = 4;
43 |
44 | /**
45 | * Apply full path by replacing the ${BUNDLE} macro or
46 | * by prepending the path to the path if config is only a string
47 | */
48 | function applyFullPath( baseDir, suffix, config, skipRelative ) {
49 | if (typeof(config) == "string") {
50 | // Check for macros
51 | if (config.indexOf('${') >= 0) {
52 | config = config.replace(/\${(.+?)}/g, function(match, contents, offset, s)
53 | {
54 | var key = contents.toLowerCase();
55 | if (key === "bundle") {
56 | return baseDir
57 | } else if (key === "suffix") {
58 | return suffix;
59 | } else {
60 | console.warn("Unknown macro '"+key+"' encountered in: "+config);
61 | return "";
62 | }
63 | });
64 | // Check for full path
65 | } else if (!skipRelative && config.substr(0,1) != "/") {
66 | return path.join(baseDir, config) + suffix;
67 | }
68 | // Otherwise we are good
69 | return config;
70 | } else {
71 | if (config.constructor == ({}).constructor) {
72 | var ans = {};
73 | for (var k in config)
74 | ans[k] = applyFullPath( baseDir, suffix, config[k], true );
75 | return ans;
76 | } else if (config.length !== undefined) {
77 | var ans = [];
78 | for (var i=0; i 1) nameParts.pop();
524 | name = nameParts.join(".");
525 | if (urlparts.length > 1) suffix="?"+urlparts[1];
526 | url = urlparts[0];
527 |
528 | // Get/Create bundle queue item
529 | var item = this.__queuedBundle( name );
530 | if (item.state == STATE_REQUESTED) {
531 |
532 | // Add prefix if needed
533 | if (this.baseURL)
534 | url = this.baseURL + '/' + url;
535 |
536 | // Add bundle suffix if not already exists
537 | if (url.substr(-this.bundleSuffix.length) != this.bundleSuffix) {
538 | url += this.bundleSuffix;
539 | }
540 |
541 | // Set URL
542 | item.setURL( url + suffix );
543 |
544 | }
545 |
546 | // Register callback
547 | item.addCallback( callback );
548 |
549 | }
550 |
551 | /**
552 | * Put a bundle in the queue, by it's specifiactions
553 | */
554 | BundlesLoader.prototype.addBySpecs = function( specs, callback ) {
555 |
556 | // Get/Create bundle queue item
557 | var item = this.__queuedBundle( specs['name'] );
558 | if (item.state == STATE_REQUESTED) {
559 | item.setSpecs( specs );
560 | }
561 |
562 | // Register callback
563 | item.addCallback( callback );
564 |
565 | }
566 |
567 | /**
568 | * Load all bundles in queue
569 | */
570 | BundlesLoader.prototype.load = function( callback ) {
571 | // Keep callback in loadCallbacks
572 | this.loadCallbacks.push(callback);
573 | // Start loading
574 | this.__process();
575 | }
576 |
577 | /**
578 | * Load file contents
579 | */
580 | BundlesLoader.prototype.__loadFileContents = function( url, asBlob, callback ) {
581 | if (!IS_BROWSER /* browser exclude */) {
582 | // Node Code
583 | var fs = require('fs');
584 | if (asBlob) {
585 | var buf = fs.readFileSync( url ), // Load Buffer
586 | ab = new ArrayBuffer( buf.length ), // Create an ArrayBuffer to fit the data
587 | view = new Uint8Array(ab); // Create an Uint8Array view
588 |
589 | // Copy buffer into view
590 | for (var i = 0; i < buf.length; ++i)
591 | view[i] = buf[i];
592 | callback(null, view );
593 | } else {
594 | fs.readFile(url, {encoding: 'utf8'}, callback);
595 | }
596 | return;
597 | }
598 |
599 | // Broswer code
600 | var req = new XMLHttpRequest(),
601 | scope = this;
602 |
603 | // Place request
604 | req.open('GET', url);
605 | if (asBlob) {
606 | req.responseType = "arraybuffer";
607 | } else {
608 | req.responseType = "text";
609 | }
610 | req.send();
611 |
612 | // Wait until the file is loaded
613 | req.onreadystatechange = function () {
614 | if (req.readyState !== 4) return;
615 | callback(null, req.response);
616 | }
617 | };
618 |
619 | /**
620 | * Get an item from the queue or express interest for a new item
621 | */
622 | BundlesLoader.prototype.__queuedBundle = function( name ) {
623 |
624 | // Get/Create bundle queue item
625 | var item = this.bundles[name];
626 | if (!item) {
627 |
628 | // Create new item
629 | item = new QueuedBundle( this, name );
630 |
631 | // Put on queue
632 | this.bundles[name] = item;
633 | this.queue.push( item );
634 |
635 | }
636 |
637 | // Return item
638 | return item;
639 |
640 | }
641 |
642 | /**
643 | * Process queue
644 | */
645 | BundlesLoader.prototype.__process = function() {
646 | var self = this;
647 |
648 | // Check if we have at least one item in 'requested' state
649 | var pendingRequested = false;
650 | for (var i=0; i STATE_SPECS
659 | // ----------------------------------------------------
660 | // Download bundle specifications for every bundle
661 | // in pending state.
662 | ////////////////////////////////////////////////////////
663 |
664 | // If there are items pending request, download them in parallel
665 | if (pendingRequested) {
666 |
667 | var context = { 'counter': 0 };
668 | var load_callback = (function( err ) {
669 | // Check fo errors
670 | if (err) {
671 | console.error("Error loading bundle", err);
672 | return;
673 | }
674 |
675 | // When we reached 0, call process again
676 | if (--this.counter == 0) {
677 | setTimeout( self.__process.bind(self), 1 );
678 | }
679 | }).bind(context);
680 |
681 | // Load all items pending
682 | for (var i=0; i STATE_LOADED
717 | // ----------------------------------------------------
718 | // Download bundles that are not part of a dependency
719 | // graph in parallel.
720 | ////////////////////////////////////////////////////////
721 |
722 | // If we have bundles without dependencies, load them in parallel
723 | if (nodepBundles.length > 0) {
724 |
725 | var context = { 'counter': 0 };
726 | var load_callback = (function() {
727 | // When we reached 0, call process again
728 | if (--this.counter == 0) {
729 | setTimeout( self.__process.bind(self), 1 );
730 | }
731 | }).bind(context);
732 |
733 | // Load all items pending
734 | for (var i=0; i STATE_LOADED
757 | // ----------------------------------------------------
758 | // Download cross-referenced bundles in the order they
759 | // appear in the dependency graph.
760 | ////////////////////////////////////////////////////////
761 |
762 | var context = { 'bundles': depBundles };
763 | var load_step = (function() {
764 |
765 | // Get next item
766 | var item = this.bundles.shift();
767 | if (!item) {
768 | // We are done loading the bundle chain, fire callbacks
769 | for (var i=0; i",
19 | "license": "Apache-2.0",
20 | "bugs": {
21 | "url": "https://github.com/wavesoft/jbb/issues"
22 | },
23 | "homepage": "https://github.com/wavesoft/jbb#readme",
24 | "devDependencies": {
25 | "colors": "^1.1.2",
26 | "deep-equal": "^1.0.1",
27 | "gulp-header": "^1.7.1",
28 | "gulp-jbb-profile": "^1.0.2",
29 | "jbb-profile-three": "^1.0.1",
30 | "json-loader": "^0.5.4",
31 | "mocha": "^2.3.4",
32 | "mute": "^2.0.6",
33 | "node-getopt": "^0.2.3",
34 | "seed-random": "^2.2.0",
35 | "webpack-stream": "^3.1.0"
36 | },
37 | "dependencies": {
38 | "binary-search-tree": "^0.2.4",
39 | "colors": "^1.1.2",
40 | "deep-equal": "^1.0.1",
41 | "gulp-jbb-profile": "^1.0.3",
42 | "jbb-profile-three": "^1.0.3",
43 | "mime": "^1.3.4",
44 | "mock-browser": "^0.92.12",
45 | "temp": "^0.8.3",
46 | "toposort": "^1.0.0",
47 | "xmldom": "^0.1.22",
48 | "xmlhttprequest": "^1.8.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/media/animated.jbbsrc/bundle.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "animated",
3 | "exports": {
4 | "THREE.JSONLoader": {
5 | "flamingo" : "flamingo.js",
6 | "horse" : "horse.js",
7 | "monster" : "monster/monster.js"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/test/media/animated.jbbsrc/monster/monster.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/animated.jbbsrc/monster/monster.jpg
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/ben.js:
--------------------------------------------------------------------------------
1 | {
2 | "materials": {
3 | "gums": { "map_Kd": "James_Mouth_Gum_Lores.jpg" },
4 | "tongue": { "map_Kd": "James_Tongue_Lores.jpg" },
5 | "teethbottom": { "Kd": [251, 248, 248] },
6 | "teethtop": { "Kd": [251, 248, 248] },
7 | "topeyelashes": { "Kd": [66, 52, 42], "map_Kd": "James_EyeLashTopTran.png", "d": 0.999 },
8 | "bottomeyelashes": { "Kd": [66, 52, 42], "map_Kd": "James_EyeLashBotTran.png", "d": 0.999 },
9 | "head": { "map_Kd": "James_Face_Color_Hair_Lores.jpg", "Ks": [25,25,25], "Ns": 70 },
10 | "eyetrans": { "Kd": [0, 0, 0] },
11 | "pupil": { "Kd": [1, 1, 1] },
12 | "iris": { "map_Kd": "James_Eye_Inner_Green.jpg" },
13 | "eyeball": { "map_Kd": "James_Eye_Green.jpg" },
14 | "pants": { "map_Kd": "MJeans1TEX_Lores.jpg", "Ks": [30,30,30], "Ns": 20 },
15 | "tshirt3": { "map_Kd": "MTshirt3TEX_Lores.jpg", "Ks": [30,30,30], "Ns": 20 },
16 | "skinbody": { "map_Kd": "James_Body_Lores.jpg", "Ks": [25,25,25], "Ns": 70 },
17 | "fingernails": { "map_Kd": "Nail_Hand_01_Lores.jpg" },
18 | "soleshoe": { "map_Kd": "MCasShoe1TEX_Lores.jpg" },
19 | "sole": { "map_Kd": "MCasShoe1TEX_Lores.jpg" },
20 | "laces": { "map_Kd": "MCasShoe1TEX_Lores.jpg" },
21 | "bow": { "map_Kd": "MCasShoe1TEX_Lores.jpg" }
22 | },
23 | "decodeParams": {
24 | "decodeOffsets": [-2533,-149,-6225,0,0,-511,-511,-511],
25 | "decodeScales": [0.000043,0.000043,0.000043,0.000978,0.000978,0.001957,0.001957,0.001957]
26 | },
27 | "urls": {
28 | "ben.utf8": [
29 | { "material": "bottomeyelashes",
30 | "attribRange": [0, 130],
31 | "codeRange": [1040, 388, 192]
32 | },
33 | { "material": "bow",
34 | "attribRange": [1428, 1848],
35 | "codeRange": [16212, 6457, 3224]
36 | },
37 | { "material": "eyeball",
38 | "attribRange": [22669, 3834],
39 | "codeRange": [53341, 14697, 7284]
40 | },
41 | { "material": "eyetrans",
42 | "attribRange": [68038, 5248],
43 | "codeRange": [110022, 20180, 9964]
44 | },
45 | { "material": "fingernails",
46 | "attribRange": [130202, 1023],
47 | "codeRange": [138386, 2669, 1228]
48 | },
49 | { "material": "gums",
50 | "attribRange": [141055, 1446],
51 | "codeRange": [152623, 5270, 2624]
52 | },
53 | { "material": "head",
54 | "attribRange": [157893, 2219],
55 | "codeRange": [175645, 8353, 4168]
56 | },
57 | { "material": "iris",
58 | "attribRange": [183998, 902],
59 | "codeRange": [191214, 3332, 1664]
60 | },
61 | { "material": "laces",
62 | "attribRange": [194546, 1016],
63 | "codeRange": [202674, 3590, 1792]
64 | },
65 | { "material": "pants",
66 | "attribRange": [206264, 8200],
67 | "codeRange": [271864, 30625, 15293]
68 | },
69 | { "material": "pupil",
70 | "attribRange": [302489, 148],
71 | "codeRange": [303673, 581, 288]
72 | },
73 | { "material": "skinbody",
74 | "attribRange": [304254, 4990],
75 | "codeRange": [344174, 15770, 7830]
76 | },
77 | { "material": "sole",
78 | "attribRange": [359944, 2588],
79 | "codeRange": [380648, 9345, 4668]
80 | },
81 | { "material": "soleshoe",
82 | "attribRange": [389993, 3164],
83 | "codeRange": [415305, 10721, 5352]
84 | },
85 | { "material": "teethbottom",
86 | "attribRange": [426026, 1235],
87 | "codeRange": [435906, 3513, 1656]
88 | },
89 | { "material": "teethtop",
90 | "attribRange": [439419, 1666],
91 | "codeRange": [452747, 3937, 1816]
92 | },
93 | { "material": "tongue",
94 | "attribRange": [456684, 845],
95 | "codeRange": [463444, 3162, 1578]
96 | },
97 | { "material": "topeyelashes",
98 | "attribRange": [466606, 130],
99 | "codeRange": [467646, 388, 192]
100 | },
101 | { "material": "tshirt3",
102 | "attribRange": [468034, 4283],
103 | "codeRange": [502298, 14470, 7216]
104 | }
105 | ]
106 | }
107 | }
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/ben_dds.js:
--------------------------------------------------------------------------------
1 | {
2 | "materials": {
3 | "gums": { "map_Kd": "dds/James_Mouth_Gum_Lores.dds" },
4 | "tongue": { "map_Kd": "dds/James_Tongue_Lores.dds" },
5 | "teethbottom": { "Kd": [251, 248, 248] },
6 | "teethtop": { "Kd": [251, 248, 248] },
7 | "topeyelashes": { "Kd": [66, 52, 42], "map_Kd": "dds/James_EyeLashTopTran.dds", "d": 0.999 },
8 | "bottomeyelashes": { "Kd": [66, 52, 42], "map_Kd": "dds/James_EyeLashBotTran.dds", "d": 0.999 },
9 | "head": { "map_Kd": "dds/James_Face_Color_Hair_Lores.dds", "Ks": [25,25,25], "Ns": 70 },
10 | "eyetrans": { "Kd": [0, 0, 0] },
11 | "pupil": { "Kd": [1, 1, 1] },
12 | "iris": { "map_Kd": "dds/James_Eye_Inner_Green.dds" },
13 | "eyeball": { "map_Kd": "dds/James_Eye_Green.dds" },
14 | "pants": { "map_Kd": "dds/MJeans1TEX_Lores.dds", "Ks": [30,30,30], "Ns": 20 },
15 | "tshirt3": { "map_Kd": "dds/MTshirt3TEX_Lores.dds", "Ks": [30,30,30], "Ns": 20 },
16 | "skinbody": { "map_Kd": "dds/James_Body_Lores.dds", "Ks": [25,25,25], "Ns": 70 },
17 | "fingernails": { "map_Kd": "dds/Nail_Hand_01_Lores.dds" },
18 | "soleshoe": { "map_Kd": "dds/MCasShoe1TEX_Lores.dds" },
19 | "sole": { "map_Kd": "dds/MCasShoe1TEX_Lores.dds" },
20 | "laces": { "map_Kd": "dds/MCasShoe1TEX_Lores.dds" },
21 | "bow": { "map_Kd": "dds/MCasShoe1TEX_Lores.dds" }
22 | },
23 | "decodeParams": {
24 | "decodeOffsets": [-2533,-149,-6225,0,0,-511,-511,-511],
25 | "decodeScales": [0.000043,0.000043,0.000043,0.000978,0.000978,0.001957,0.001957,0.001957]
26 | },
27 | "urls": {
28 | "ben.utf8": [
29 | { "material": "bottomeyelashes",
30 | "attribRange": [0, 130],
31 | "codeRange": [1040, 388, 192]
32 | },
33 | { "material": "bow",
34 | "attribRange": [1428, 1848],
35 | "codeRange": [16212, 6457, 3224]
36 | },
37 | { "material": "eyeball",
38 | "attribRange": [22669, 3834],
39 | "codeRange": [53341, 14697, 7284]
40 | },
41 | { "material": "eyetrans",
42 | "attribRange": [68038, 5248],
43 | "codeRange": [110022, 20180, 9964]
44 | },
45 | { "material": "fingernails",
46 | "attribRange": [130202, 1023],
47 | "codeRange": [138386, 2669, 1228]
48 | },
49 | { "material": "gums",
50 | "attribRange": [141055, 1446],
51 | "codeRange": [152623, 5270, 2624]
52 | },
53 | { "material": "head",
54 | "attribRange": [157893, 2219],
55 | "codeRange": [175645, 8353, 4168]
56 | },
57 | { "material": "iris",
58 | "attribRange": [183998, 902],
59 | "codeRange": [191214, 3332, 1664]
60 | },
61 | { "material": "laces",
62 | "attribRange": [194546, 1016],
63 | "codeRange": [202674, 3590, 1792]
64 | },
65 | { "material": "pants",
66 | "attribRange": [206264, 8200],
67 | "codeRange": [271864, 30625, 15293]
68 | },
69 | { "material": "pupil",
70 | "attribRange": [302489, 148],
71 | "codeRange": [303673, 581, 288]
72 | },
73 | { "material": "skinbody",
74 | "attribRange": [304254, 4990],
75 | "codeRange": [344174, 15770, 7830]
76 | },
77 | { "material": "sole",
78 | "attribRange": [359944, 2588],
79 | "codeRange": [380648, 9345, 4668]
80 | },
81 | { "material": "soleshoe",
82 | "attribRange": [389993, 3164],
83 | "codeRange": [415305, 10721, 5352]
84 | },
85 | { "material": "teethbottom",
86 | "attribRange": [426026, 1235],
87 | "codeRange": [435906, 3513, 1656]
88 | },
89 | { "material": "teethtop",
90 | "attribRange": [439419, 1666],
91 | "codeRange": [452747, 3937, 1816]
92 | },
93 | { "material": "tongue",
94 | "attribRange": [456684, 845],
95 | "codeRange": [463444, 3162, 1578]
96 | },
97 | { "material": "topeyelashes",
98 | "attribRange": [466606, 130],
99 | "codeRange": [467646, 388, 192]
100 | },
101 | { "material": "tshirt3",
102 | "attribRange": [468034, 4283],
103 | "codeRange": [502298, 14470, 7216]
104 | }
105 | ]
106 | }
107 | }
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/bundle.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "heavy",
3 | "exports": {
4 | "THREE.UTF8Loader": {
5 | "hand": "hand.js",
6 | "ben": "ben_dds.js"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Body_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Body_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_EyeLashBotTran.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_EyeLashBotTran.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_EyeLashTopTran.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_EyeLashTopTran.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Eye_Green.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Eye_Green.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Eye_Inner_Green.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Eye_Inner_Green.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Face_Color_Hair_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Face_Color_Hair_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Mouth_Gum_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Mouth_Gum_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/James_Tongue_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/James_Tongue_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/MCasShoe1TEX_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/MCasShoe1TEX_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/MJeans1TEX_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/MJeans1TEX_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/MTshirt3TEX_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/MTshirt3TEX_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/dds/Nail_Hand_01_Lores.dds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/dds/Nail_Hand_01_Lores.dds
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/hand.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/heavy.jbbsrc/hand.jpg
--------------------------------------------------------------------------------
/test/media/heavy.jbbsrc/hand.js:
--------------------------------------------------------------------------------
1 | {
2 | "materials": {
3 | "preview": { "Kd": [184, 136, 234] },
4 | "nails": { "Kd": [251, 238, 209], "map_Kd": "hand.jpg", "Ks": [30,30,30], "Ns": 100 },
5 | "skin": { "Kd": [207, 181, 161], "map_Kd": "hand.jpg", "Ks": [30,30,30], "Ns": 30 }
6 | },
7 | "decodeParams": {
8 | "decodeOffsets": [-7473,-239,-8362,0,0,-511,-511,-511],
9 | "decodeScales": [0.000050,0.000050,0.000050,0.000978,0.000978,0.001957,0.001957,0.001957]
10 | },
11 | "urls": {
12 | "hand.utf8": [
13 | { "material": "nails",
14 | "attribRange": [0, 261],
15 | "codeRange": [2088, 817, 404]
16 | },
17 | { "material": "preview",
18 | "attribRange": [2905, 688],
19 | "codeRange": [8409, 2570, 1280]
20 | },
21 | { "material": "skin",
22 | "attribRange": [10979, 8899],
23 | "codeRange": [82171, 31026, 15451]
24 | }
25 | ]
26 | }
27 | }
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/bundle.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "md2",
3 | "exports": {
4 | "THREE.MD2CharacterLoader": {
5 | "ratamahatta": {
6 | "baseUrl": "${BUNDLE}/ratamahatta/",
7 | "body": "ratamahatta.md2",
8 | "skins": [ "ratamahatta.png", "ctf_b.png", "ctf_r.png", "dead.png", "gearwhore.png" ],
9 | "weapons": [ [ "weapon.md2", "weapon.png" ]
10 | ]
11 | }
12 | },
13 | "THREE.TextureLoader": {
14 | "images/ground": "grasslight-big.jpg"
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/grasslight-big.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/grasslight-big.jpg
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/ratamahatta.md2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/ratamahatta.md2
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/ctf_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/ctf_b.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/ctf_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/ctf_r.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/dead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/dead.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/gearwhore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/gearwhore.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/ratamahatta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/ratamahatta.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/skins/weapon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/skins/weapon.png
--------------------------------------------------------------------------------
/test/media/md2.jbbsrc/ratamahatta/weapon.md2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/md2.jbbsrc/ratamahatta/weapon.md2
--------------------------------------------------------------------------------
/test/media/obj.jbbsrc/bundle.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "obj",
3 | "exports": {
4 | "THREE.BinaryLoader": {
5 | "obj/walthead": "walt/WaltHead_bin.js"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/test/media/obj.jbbsrc/walt/WaltHead_bin.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wavesoft/jbb/46c40e0bca02d74201fb99925843cde49e9fe68a/test/media/obj.jbbsrc/walt/WaltHead_bin.bin
--------------------------------------------------------------------------------
/test/media/obj.jbbsrc/walt/WaltHead_bin.js:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "metadata" :
4 | {
5 | "formatVersion" : 3.1,
6 | "sourceFile" : "WaltHead.obj",
7 | "generatedBy" : "OBJConverter",
8 | "vertices" : 8146,
9 | "faces" : 16160,
10 | "normals" : 8146,
11 | "uvs" : 0,
12 | "materials" : 1
13 | },
14 |
15 | "materials": [ {
16 | "DbgColor" : 15658734,
17 | "DbgIndex" : 0,
18 | "DbgName" : "lambert2SG.001",
19 | "colorAmbient" : [0.0, 0.0, 0.0],
20 | "colorDiffuse" : [0.64, 0.64, 0.64],
21 | "colorSpecular" : [0.25, 0.25, 0.25],
22 | "illumination" : 2,
23 | "opticalDensity" : 1.0,
24 | "specularCoef" : 92.156863,
25 | "opacity" : 1.0
26 | }],
27 |
28 | "buffers": "WaltHead_bin.bin"
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/test/media/vrml.jbbsrc/bundle.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vrml",
3 | "exports": {
4 | "THREE.VRMLLoader": {
5 | "house": "house.wrl"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/test/simple-profile/objects.js:
--------------------------------------------------------------------------------
1 | /**
2 | * THREE Bundles - Binary Encoder/Decoder Test Suite
3 | * Copyright (C) 2015 Ioannis Charalampidis
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License along
16 | * with this program; if not, write to the Free Software Foundation, Inc.,
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | *
19 | * @author Ioannis Charalampidis / https://github.com/wavesoft
20 | */
21 |
22 | // A coule of local objects, part of Object Table
23 | var ObjectA = function() {
24 | this.objApropA = 125;
25 | this.objApropB = 65532;
26 | this.objApropC = "A string";
27 | };
28 | var ObjectB = function( propA, propB ) {
29 | this.objBpropA = propA;
30 | this.objBpropB = propB;
31 | this.objBpropC = new Uint16Array([ 1, 4, 120, 4123 ]);
32 | };
33 | var ObjectC = function( propA, propB ) {
34 | this.objCpropA = propA;
35 | this.objCpropB = propB;
36 | this.objCpropC = { 'some': { 'sub': 'object' } };
37 | this.objCpropD = "I am ignored :(";
38 | };
39 | var ObjectD = function() {
40 | this.objDpropA = 0;
41 | this.objDpropB = 1;
42 | this.objDpropC = "Not part of ObjectTable";
43 | };
44 |
45 | // Some more objects for the second object table
46 | var ObjectE = function() {
47 | this.objEpropA = 125;
48 | this.objEpropB = 65532;
49 | this.objEpropC = "A string";
50 | };
51 | var ObjectF = function( propA, propB ) {
52 | this.objFpropA = propA;
53 | this.objFpropB = propB;
54 | this.objFpropC = new Uint16Array([ 1, 4, 120, 4123 ]);
55 | };
56 | var ObjectG = function( propA, propB ) {
57 | this.objGpropA = propA;
58 | this.objGpropB = propB;
59 | this.objGpropC = { 'some': { 'sub': 'object' } };
60 | this.objGpropD = "I am ignored :(";
61 | };
62 |
63 |
64 | // Export objects
65 | var exports = module.exports = {
66 | 'ObjectA': ObjectA,
67 | 'ObjectB': ObjectB,
68 | 'ObjectC': ObjectC,
69 | 'ObjectD': ObjectD,
70 | 'ObjectE': ObjectE,
71 | 'ObjectF': ObjectF,
72 | 'ObjectG': ObjectG,
73 | };
74 | module.exports.static = function(scope) {
75 | Object.keys(exports).forEach(function(key,index) {
76 | scope[key] = exports[key];
77 | });
78 | };
79 |
--------------------------------------------------------------------------------
/test/simple-profile/second-decode.js:
--------------------------------------------------------------------------------
1 | var OT = require('./objects');
2 |
3 | /**
4 | * Factory & Initializer of OT.ObjectE
5 | */
6 | var factory_OT_ObjectE = {
7 | props: 3,
8 | create: function() {
9 | return new OT.ObjectE();
10 | },
11 | init: function(inst, props, pagesize, offset) {
12 | inst.objEpropA = props[offset+pagesize*0];
13 | inst.objEpropB = props[offset+pagesize*1];
14 | inst.objEpropC = props[offset+pagesize*2];
15 | }
16 | }
17 |
18 | /**
19 | * Factory & Initializer of OT.ObjectF
20 | */
21 | var factory_OT_ObjectF = {
22 | props: 3,
23 | create: function() {
24 | return new OT.ObjectF();
25 | },
26 | init: function(inst, props, pagesize, offset) {
27 | inst.objFpropA = props[offset+pagesize*0];
28 | inst.objFpropB = props[offset+pagesize*1];
29 | inst.objFpropC = props[offset+pagesize*2];
30 | }
31 | }
32 |
33 | /**
34 | * Factory & Initializer of OT.ObjectG
35 | */
36 | var factory_OT_ObjectG = {
37 | props: 3,
38 | create: function() {
39 | return Object.create(OT.ObjectG.prototype);
40 | },
41 | init: function(inst, props, pagesize, offset) {
42 | OT.ObjectG.call(inst,
43 | props[offset+pagesize*0],
44 | props[offset+pagesize*1]);
45 | inst.objGpropC = props[offset+pagesize*2];
46 | }
47 | }
48 |
49 | module.exports = {
50 | id: 15024,
51 | size: 3,
52 | frequent: 2,
53 | decode: function( id ) {
54 | if (id < 32) {
55 | if (id < 1) {
56 | if (id === 0)
57 | return factory_OT_ObjectE;
58 | } else {
59 | if (id === 1)
60 | return factory_OT_ObjectF;
61 | }
62 | } else {
63 | if (id === 32)
64 | return factory_OT_ObjectG;
65 | }
66 | }
67 | };
68 |
--------------------------------------------------------------------------------
/test/simple-profile/second-encode.js:
--------------------------------------------------------------------------------
1 | var OT = require('./objects');
2 |
3 | /**
4 | * Property getter OT.ObjectE
5 | */
6 | function getter_OT_ObjectE(inst) {
7 | return [
8 | inst.objEpropA,
9 | inst.objEpropB,
10 | inst.objEpropC];
11 | }
12 |
13 | /**
14 | * Property getter OT.ObjectF
15 | */
16 | function getter_OT_ObjectF(inst) {
17 | return [
18 | inst.objFpropA,
19 | inst.objFpropB,
20 | inst.objFpropC];
21 | }
22 |
23 | /**
24 | * Property getter OT.ObjectG
25 | */
26 | function getter_OT_ObjectG(inst) {
27 | return [
28 | inst.objGpropA,
29 | inst.objGpropB,
30 | inst.objGpropC];
31 | }
32 |
33 |
34 | module.exports = {
35 | id: 15024,
36 | size: 3,
37 | frequent: 2,
38 | encode: function( inst ) {
39 | if (inst instanceof OT.ObjectE) {
40 | return [0, getter_OT_ObjectE];
41 | } else if (inst instanceof OT.ObjectF) {
42 | return [1, getter_OT_ObjectF];
43 | } else if (inst instanceof OT.ObjectG) {
44 | return [32, getter_OT_ObjectG];
45 | }
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/test/simple-profile/second.yaml:
--------------------------------------------------------------------------------
1 |
2 | # Meta
3 |
4 | @uuid: 0x3AB
5 | @require:
6 | OT: ./objects
7 |
8 | # Simple objects
9 |
10 | OT.ObjectE:
11 | frequent: 1
12 | properties:
13 | - objEpropA
14 | - objEpropB
15 | - objEpropC
16 |
17 | OT.ObjectF:
18 | frequent: 1
19 | properties:
20 | - objFpropA
21 | - objFpropB
22 | - objFpropC
23 |
24 | OT.ObjectG:
25 | init: [ objGpropA, objGpropB ]
26 | properties:
27 | - objGpropA
28 | - objGpropB
29 | - objGpropC
30 |
--------------------------------------------------------------------------------
/test/simple-profile/specs-decode.js:
--------------------------------------------------------------------------------
1 | var OT = require('./objects');
2 |
3 | /**
4 | * Factory & Initializer of OT.ObjectA
5 | */
6 | var factory_OT_ObjectA = {
7 | props: 3,
8 | create: function() {
9 | return new OT.ObjectA();
10 | },
11 | init: function(inst, props, pagesize, offset) {
12 | inst.objApropA = props[offset+pagesize*0];
13 | inst.objApropB = props[offset+pagesize*1];
14 | inst.objApropC = props[offset+pagesize*2];
15 | }
16 | }
17 |
18 | /**
19 | * Factory & Initializer of OT.ObjectB
20 | */
21 | var factory_OT_ObjectB = {
22 | props: 3,
23 | create: function() {
24 | return new OT.ObjectB();
25 | },
26 | init: function(inst, props, pagesize, offset) {
27 | inst.objBpropA = props[offset+pagesize*0];
28 | inst.objBpropB = props[offset+pagesize*1];
29 | inst.objBpropC = props[offset+pagesize*2];
30 | }
31 | }
32 |
33 | /**
34 | * Factory & Initializer of OT.ObjectC
35 | */
36 | var factory_OT_ObjectC = {
37 | props: 3,
38 | create: function() {
39 | return Object.create(OT.ObjectC.prototype);
40 | },
41 | init: function(inst, props, pagesize, offset) {
42 | OT.ObjectC.call(inst,
43 | props[offset+pagesize*0],
44 | props[offset+pagesize*1]);
45 | inst.objCpropC = props[offset+pagesize*2];
46 | }
47 | }
48 |
49 | module.exports = {
50 | id: 7760,
51 | size: 3,
52 | frequent: 1,
53 | decode: function( id ) {
54 | if (id < 32) {
55 | if (id === 0)
56 | return factory_OT_ObjectA;
57 | } else {
58 | if (id < 33) {
59 | if (id === 32)
60 | return factory_OT_ObjectB;
61 | } else {
62 | if (id === 33)
63 | return factory_OT_ObjectC;
64 | }
65 | }
66 | }
67 | };
68 |
--------------------------------------------------------------------------------
/test/simple-profile/specs-encode.js:
--------------------------------------------------------------------------------
1 | var OT = require('./objects');
2 |
3 | /**
4 | * Property getter OT.ObjectA
5 | */
6 | function getter_OT_ObjectA(inst) {
7 | return [
8 | inst.objApropA,
9 | inst.objApropB,
10 | inst.objApropC];
11 | }
12 |
13 | /**
14 | * Property getter OT.ObjectB
15 | */
16 | function getter_OT_ObjectB(inst) {
17 | return [
18 | inst.objBpropA,
19 | inst.objBpropB,
20 | inst.objBpropC];
21 | }
22 |
23 | /**
24 | * Property getter OT.ObjectC
25 | */
26 | function getter_OT_ObjectC(inst) {
27 | return [
28 | inst.objCpropA,
29 | inst.objCpropB,
30 | inst.objCpropC];
31 | }
32 |
33 |
34 | module.exports = {
35 | id: 7760,
36 | size: 3,
37 | frequent: 1,
38 | encode: function( inst ) {
39 | if (inst instanceof OT.ObjectA) {
40 | return [0, getter_OT_ObjectA];
41 | } else if (inst instanceof OT.ObjectB) {
42 | return [32, getter_OT_ObjectB];
43 | } else if (inst instanceof OT.ObjectC) {
44 | return [33, getter_OT_ObjectC];
45 | }
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/test/simple-profile/specs.yaml:
--------------------------------------------------------------------------------
1 |
2 | # Meta
3 |
4 | @uuid: 0x1E5
5 | @require:
6 | OT: ./objects
7 |
8 | # Simple objects
9 |
10 | OT.ObjectA:
11 | frequent: true
12 | properties:
13 | - objApropA
14 | - objApropB
15 | - objApropC
16 |
17 | OT.ObjectB:
18 | properties:
19 | - objBpropA
20 | - objBpropB
21 | - objBpropC
22 |
23 | OT.ObjectC:
24 | init: [ objCpropA, objCpropB ]
25 | properties:
26 | - objCpropA
27 | - objCpropB
28 | - objCpropC
29 |
--------------------------------------------------------------------------------
/test/test-three.js:
--------------------------------------------------------------------------------
1 | /**
2 | * THREE Bundles - Binary Encoder/Decoder Test Suite
3 | * Copyright (C) 2015 Ioannis Charalampidis
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License along
16 | * with this program; if not, write to the Free Software Foundation, Inc.,
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | *
19 | * @author Ioannis Charalampidis / https://github.com/wavesoft
20 | */
21 |
22 | global.PROD = true;
23 |
24 | var assert = require('assert');
25 | var path = require('path');
26 | var temp = require('temp');
27 | var fs = require('fs');
28 | var mute = require('mute');
29 | var common = require('./utils/common');
30 | var compare = require('./utils/compare');
31 | var JBBSourceLoader = require('../loader');
32 | var JBBBinaryLoader = require('../decoder');
33 | var JBBProfileThreeLoader = require('jbb-profile-three/profile-loader');
34 | var THREEEncodeProfile = require('jbb-profile-three/profile-encode');
35 | var THREEDecodeProfile = require('jbb-profile-three/profile-decode');
36 | var BinaryCompiler = require('../compiler');
37 | require('./utils/common').static(global);
38 | require('./utils/tests').static(global);
39 |
40 | ////////////////////////////////////////////////////////////////
41 | // Initialization
42 | ////////////////////////////////////////////////////////////////
43 |
44 | // Path to media folder
45 | var mediaDir = path.join(__dirname, 'media');
46 |
47 | // Prepare a fake browser
48 | var MockBrowser = require('mock-browser').mocks.MockBrowser;
49 | var mock = new MockBrowser();
50 |
51 | // Fake 'self', 'document' and 'window'
52 | global.document = mock.getDocument(),
53 | global.self = MockBrowser.createWindow(),
54 | global.window = global.self;
55 |
56 | // Fake 'XMLHttpRequest' (shall not be used)
57 | global.XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
58 |
59 | // Fake Blob
60 | global.Blob = function(url) { };
61 | global.URL = { createObjectURL: function(blob) { return ""; } };
62 |
63 | // Initialize environment for node.js
64 | JBBProfileThreeLoader.initialize();
65 |
66 | ////////////////////////////////////////////////////////////////
67 | // Helper Functinos
68 | ////////////////////////////////////////////////////////////////
69 |
70 | /**
71 | * Closure for repeating the test with different bundles
72 | */
73 | function describe_clojure( bundleName, testFn ) {
74 | return function() {
75 | var srcDB, binDB, tmpFile, sourceLoadingTime, binaryLoadingTime;
76 |
77 | it('should properly load the source bundle', function( done ) {
78 |
79 | /* Load the source bundle */
80 | var unmute = mute();
81 | var sourceLoader = new JBBSourceLoader( mediaDir );
82 | sourceLoadingTime = Date.now();
83 | sourceLoader.addProfileLoader( JBBProfileThreeLoader )
84 | sourceLoader.add( bundleName );
85 | sourceLoader.load(function( err ) {
86 | unmute();
87 | assert.ok( err == null, err );
88 | sourceLoadingTime = Date.now() - sourceLoadingTime;
89 |
90 | /* Keep the database for the next test */
91 | srcDB = sourceLoader.database;
92 | done();
93 |
94 | });
95 |
96 | });
97 | it('should properly compile the bundle', function( done ) {
98 |
99 | /* This can take long time. Give it 2 minutes. */
100 | this.timeout(120000);
101 |
102 | /* Create a temporary file to compile */
103 | var unmute = mute();
104 | tmpFile = path.join(__dirname, bundleName+'.tmp');// temp.path({suffix: '.test'});
105 | BinaryCompiler.compileFile( path.join(mediaDir, bundleName+'.jbbsrc'), tmpFile, {
106 | 'path' : mediaDir,
107 | 'log' : 0x8000,
108 | 'profileEncoder': THREEEncodeProfile,
109 | 'profileLoader' : JBBProfileThreeLoader,
110 | 'sparse' : false
111 | }, function( err ) {
112 | unmute();
113 |
114 | tmpFile += ".jbb";
115 | assert.ok( fs.existsSync( tmpFile ), 'bundle file was not created' );
116 | assert.ok( err == null, err );
117 |
118 | /* Loaded */
119 | done();
120 |
121 | }
122 | );
123 |
124 | });
125 | it('should properly load the binary bundle on time', function( done ) {
126 |
127 | /* Load the source bundle */
128 | var unmute = mute();
129 | var binaryLoader = new JBBBinaryLoader( path.dirname(tmpFile) );
130 | binaryLoadingTime = Date.now();
131 | binaryLoader.addProfile( THREEDecodeProfile );
132 | binaryLoader.addByBuffer( common.readChunk(tmpFile) );
133 | binaryLoader.load(function( err ) {
134 | unmute();
135 | assert.ok( err == null, err );
136 | binaryLoadingTime = Date.now() - binaryLoadingTime;
137 |
138 | /* Delete bundle */
139 | fs.unlink( tmpFile );
140 |
141 | /* Keep the database for the next test */
142 | binDB = binaryLoader.database;
143 | done();
144 |
145 | });
146 |
147 | });
148 | it('should be encoded correctly', function(done) {
149 |
150 | /* This is not optimized, can take up to 10 seconds. */
151 | this.timeout(10000);
152 |
153 | assert.deepEqual( Object.keys(srcDB).sort(), Object.keys(binDB).sort(), 'database keys must be the same' );
154 |
155 | testFn( srcDB, binDB );
156 | done();
157 |
158 | });
159 | it('should be loaded faster than the source bundle', function(done) {
160 | // Give a tollerance of 5 ms
161 | if (binaryLoadingTime > sourceLoadingTime + 5) {
162 | var percent = 100 * (binaryLoadingTime - sourceLoadingTime) / sourceLoadingTime;
163 | assert.ok( binaryLoadingTime < sourceLoadingTime, 'binary bundle loaded slower (by ' + percent.toFixed(2) + ' %)' );
164 | }
165 | done();
166 | });
167 |
168 | };
169 | }
170 |
171 | ////////////////////////////////////////////////////////////////
172 | // Test Entry Point
173 | ////////////////////////////////////////////////////////////////
174 |
175 | // Profiled encoding/decoding
176 | describe('[THREE.js Profile Tests]', function() {
177 |
178 | var commonIgnoredKeys = [
179 | // Functions
180 | 'onChangeCallback',
181 | 'constructor',
182 | 'set',
183 | // OK To change
184 | 'uuid',
185 | 'parent',
186 | // Pointless to compare
187 | 'solid',
188 | 'image',
189 | 'version',
190 | ];
191 |
192 | describe('animated.jbbsrc', describe_clojure( 'animated', function( original, encoded ) {
193 |
194 | // Configuration for explicit deep equal
195 | var config = {
196 | ignoreKeys: commonIgnoredKeys,
197 | ignoreClasses: [ ],
198 | numericTollerance: 0.0001
199 | };
200 |
201 | // Explicit deep equal comparison
202 | compare.explicitDeepEqual( original['animated/flamingo'],
203 | encoded['animated/flamingo'],
204 | 'in animated/flamingo', config );
205 | compare.explicitDeepEqual( original['animated/horse'],
206 | encoded['animated/horse'],
207 | 'in animated/horse', config );
208 | compare.explicitDeepEqual( original['animated/monster'],
209 | encoded['animated/monster'],
210 | 'in animated/monster', config );
211 |
212 | }));
213 |
214 | describe('vrml.jbbsrc', describe_clojure( 'vrml', function( original, encoded ) {
215 |
216 | // Configuration for explicit deep equal
217 | var config = {
218 | ignoreKeys: commonIgnoredKeys,
219 | ignoreClasses: [ ],
220 | numericTollerance: 0.001
221 | };
222 |
223 | // Explicit deep equal comparison
224 | compare.explicitDeepEqual( original['vrml/house'],
225 | encoded['vrml/house'],
226 | 'in vrml/house', config );
227 |
228 | }));
229 |
230 | describe('md2.jbbsrc', describe_clojure( 'md2', function( original, encoded ) {
231 |
232 | // Configuration for explicit deep equal
233 | var config = {
234 | ignoreKeys: commonIgnoredKeys,
235 | ignoreClasses: [ ],
236 | numericTollerance: 0.001
237 | };
238 |
239 | // Explicit deep equal comparison
240 | compare.explicitDeepEqual( original['md2/ratamahatta'],
241 | encoded['md2/ratamahatta'],
242 | 'in md2/ratamahatta', config );
243 |
244 | }));
245 |
246 | describe('heavy.jbbsrc', describe_clojure( 'heavy', function( original, encoded ) {
247 |
248 | // Configuration for explicit deep equal
249 | var config = {
250 | ignoreKeys: commonIgnoredKeys,
251 | ignoreClasses: [ ],
252 | numericTollerance: 0.001
253 | };
254 |
255 | // Explicit deep equal comparison
256 | compare.explicitDeepEqual( original['heavy/hand'],
257 | encoded['heavy/hand'],
258 | 'in heavy/hand', config );
259 |
260 | // Explicit deep equal comparison
261 | compare.explicitDeepEqual( original['heavy/ben'],
262 | encoded['heavy/ben'],
263 | 'in heavy/ben', config );
264 |
265 | }));
266 |
267 | describe('obj.jbbsrc', describe_clojure( 'obj', function( original, encoded ) {
268 |
269 | // Configuration for explicit deep equal
270 | var config = {
271 | ignoreKeys: commonIgnoredKeys,
272 | ignoreClasses: [ ],
273 | numericTollerance: 0.001
274 | };
275 |
276 | // Explicit deep equal comparison
277 | compare.explicitDeepEqual( original['obj/walthead'],
278 | encoded['obj/walthead'],
279 | 'in obj/walthead', config );
280 |
281 | }));
282 |
283 | });
284 |
--------------------------------------------------------------------------------
/test/utils/common.js:
--------------------------------------------------------------------------------
1 | /**
2 | * THREE Bundles - Binary Encoder/Decoder Test Suite
3 | * Copyright (C) 2015 Ioannis Charalampidis
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License along
16 | * with this program; if not, write to the Free Software Foundation, Inc.,
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | *
19 | * @author Ioannis Charalampidis / https://github.com/wavesoft
20 | */
21 |
22 | var BinaryEncoder = require("../../encoder.js");
23 | var BinaryLoader = require("../../decoder.js");
24 | var temp = require("temp").track();
25 | var fs = require('fs');
26 |
27 | /**
28 | * Read filename to buffer
29 | */
30 | function readChunk( filename ) {
31 | // Read into buffer
32 | var file = fs.readFileSync(filename),
33 | u8 = new Uint8Array(file);
34 | // Return buffer
35 | return u8.buffer;
36 | }
37 |
38 | /**
39 | * Create a binary encoder pointing to a random file
40 | */
41 | function open_encoder( profile, sparse ) {
42 | // Create a temporary file
43 | var tempName = temp.path({suffix: '.tmp'});
44 |
45 | // Create an encoder
46 | var encoder = new BinaryEncoder(tempName, {
47 | 'name' : 'test',
48 | 'log' : 0,
49 | 'sparse' : sparse || false
50 | });
51 |
52 | // Add one or more profiles
53 | if (profile.length) {
54 | for (var i=0; i
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License along
16 | * with this program; if not, write to the Free Software Foundation, Inc.,
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | *
19 | * @author Ioannis Charalampidis / https://github.com/wavesoft
20 | */
21 |
22 | var assert = require('assert');
23 | var mute = require('mute');
24 |
25 | /**
26 | * assert.equal with deep comparion only on some objects
27 | */
28 | function explicitDeepEqual( expected, actual, message, config, path ) {
29 | var path = path || "object",
30 | config = config || {}, a, b, unmute;
31 |
32 | if ((actual === undefined) || (expected === undefined)) {
33 | if ( ((actual === undefined) && (expected !== undefined)) ||
34 | ((actual !== undefined) && (expected === undefined))) {
35 | console.log("- Actual=", actual);
36 | assert.equal(
37 | (actual === undefined) ? '[undefined]' : (typeof actual),
38 | (expected === undefined) ? '[undefined]' : (typeof expected),
39 | path + ' mismatch ' + message );
40 | }
41 | return;
42 | }
43 |
44 | if (typeof actual === "object") {
45 | assert.equal( "object", typeof expected, path + ': ' + message );
46 | assert.equal( (actual === null), (expected === null), path + ': ' + message );
47 |
48 | for (var k in actual) {
49 |
50 | // Get values
51 | unmute = mute();
52 | try {
53 | a = actual[k];
54 | b = expected[k];
55 | } finally {
56 | unmute();
57 | }
58 |
59 | // Skip ignored keys and classes
60 | if (typeof a === 'function') continue;
61 | if (config.ignoreKeys.indexOf(k) >= 0) continue;
62 | for (var i=0; i config.numericTollerance) {
70 | assert.equal( actual, expected, path + ': ' + message );
71 | }
72 | } else {
73 | assert.equal( actual, expected, path + ' mismatch ' + message );
74 | }
75 | }
76 |
77 | // Export functions
78 | var exports = module.exports = {
79 | 'explicitDeepEqual': explicitDeepEqual,
80 | };
81 | module.exports.static = function(scope) {
82 | Object.keys(exports).forEach(function(key,index) {
83 | scope[key] = exports[key];
84 | });
85 | };
86 |
87 |
--------------------------------------------------------------------------------
/test/utils/tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * THREE Bundles - Binary Encoder/Decoder Test Suite
3 | * Copyright (C) 2015 Ioannis Charalampidis
4 | *
5 | * This program is free software; you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation; either version 2 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License along
16 | * with this program; if not, write to the Free Software Foundation, Inc.,
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | *
19 | * @author Ioannis Charalampidis / https://github.com/wavesoft
20 | */
21 |
22 | var util = require('util');
23 | var assert = require('assert');
24 | var seed = require('seed-random');
25 | var compare = require('./compare');
26 |
27 | require('./common').static(global);
28 | require('../simple-profile/objects').static(global);
29 |
30 | var EncodeProfile = require('../simple-profile/specs-encode');
31 | var DecodeProfile = require('../simple-profile/specs-decode');
32 | var EncodeProfile2 = require('../simple-profile/second-encode');
33 | var DecodeProfile2 = require('../simple-profile/second-decode');
34 |
35 | var random = seed('jbbtests');
36 |
37 | ////////////////////////////////////////////////////////////////
38 | // Generator helpers
39 | ////////////////////////////////////////////////////////////////
40 |
41 | /**
42 | * Sequential array generator
43 | */
44 | function gen_array_seq( typeName, length, min, step ) {
45 | var arr = new global[typeName](length);
46 | for (var i=0, v=min; i> smallest ("+min+","+max+")=",smallest);
62 | for (var i=0; i