├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── regltf.dev.js ├── regltf.dev.js.map ├── regltf.js ├── regltf.js.map ├── regltf.min.js └── regltf.min.js.map ├── examples ├── index.html ├── main.js ├── package.json └── renderer.js ├── index.js ├── lib ├── build-cmd-data.js ├── builtin-programs.js ├── builtin-techniques.js ├── loader.js ├── pools.js └── resl.js ├── package.json ├── script └── rollup.config.js └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "rules": { 4 | "comma-dangle": 0, 5 | "no-console": 0, 6 | "no-constant-condition": 0, 7 | "semi": 1 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": 6, 11 | "sourceType": "module", 12 | "ecmaFeatures": { 13 | "jsx": true 14 | } 15 | }, 16 | "env": { 17 | "browser": true, 18 | "node": true, 19 | "es6": true, 20 | "mocha": true 21 | }, 22 | "plugins": [ 23 | ], 24 | "globals": { 25 | "deprecate": false, 26 | "helper": false, 27 | "tap": false, 28 | "unused": false 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # mac-osx files 2 | .DS_store 3 | profile 4 | 5 | # visual-studio files 6 | *.ncb *.sln 7 | *.suo 8 | *.vcproj.*.user 9 | *.pdb 10 | *.idb 11 | *.csproj 12 | *.csproj.user 13 | 14 | # visual-studio code 15 | .vscode/ 16 | 17 | # exvim files 18 | *.err 19 | *.exvim 20 | .exvim.*/ 21 | 22 | # webstorm 23 | .idea 24 | 25 | # log files 26 | *.log 27 | 28 | # project files 29 | node_modules/ 30 | bower_components/ 31 | examples/assets_01/ 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017 Johnny Wu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## regltf 2 | 3 | gltf with regl. 4 | 5 | ## Install 6 | 7 | ```bash 8 | npm install regltf 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```javascript 14 | regltf.load(regl, './your/gltf/file.gltf', (err, result) => { 15 | console.log(result); 16 | }); 17 | ``` 18 | 19 | ## License 20 | 21 | MIT © 2017 Johnny Wu -------------------------------------------------------------------------------- /dist/regltf.dev.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * regltf v1.0.0 4 | * (c) 2017 @Johnny Wu 5 | * Released under the MIT License. 6 | */ 7 | 8 | (function (exports,memop,sceneGraph,vmath) { 9 | 'use strict'; 10 | 11 | let f32a_m4_pool = new memop.FramePool(function() { 12 | return new Float32Array(16); 13 | }, 256); 14 | 15 | /** 16 | * (c) 2016 Mikola Lysenko. MIT License 17 | * https://github.com/regl-project/resl 18 | */ 19 | 20 | /* global XMLHttpRequest */ 21 | const configParameters = [ 22 | 'manifest', 23 | 'onDone', 24 | 'onProgress', 25 | 'onError' 26 | ]; 27 | 28 | const manifestParameters = [ 29 | 'type', 30 | 'src', 31 | 'stream', 32 | 'credentials', 33 | 'parser' 34 | ]; 35 | 36 | const parserParameters = [ 37 | 'onData', 38 | 'onDone' 39 | ]; 40 | 41 | const STATE_ERROR = -1; 42 | const STATE_DATA = 0; 43 | const STATE_COMPLETE = 1; 44 | 45 | function raise(message) { 46 | throw new Error('resl: ' + message); 47 | } 48 | 49 | function checkType(object, parameters, name) { 50 | Object.keys(object).forEach(function (param) { 51 | if (parameters.indexOf(param) < 0) { 52 | raise('invalid parameter "' + param + '" in ' + name); 53 | } 54 | }); 55 | } 56 | 57 | function Loader(name, cancel) { 58 | this.state = STATE_DATA; 59 | this.ready = false; 60 | this.progress = 0; 61 | this.name = name; 62 | this.cancel = cancel; 63 | } 64 | 65 | function resl(config) { 66 | if (typeof config !== 'object' || !config) { 67 | raise('invalid or missing configuration'); 68 | } 69 | 70 | checkType(config, configParameters, 'config'); 71 | 72 | let manifest = config.manifest; 73 | if (typeof manifest !== 'object' || !manifest) { 74 | raise('missing manifest'); 75 | } 76 | 77 | function getFunction(name) { 78 | if (name in config) { 79 | let func = config[name]; 80 | if (typeof func !== 'function') { 81 | raise('invalid callback "' + name + '"'); 82 | } 83 | return func; 84 | } 85 | return null; 86 | } 87 | 88 | let onDone = getFunction('onDone'); 89 | if (!onDone) { 90 | raise('missing onDone() callback'); 91 | } 92 | 93 | let onProgress = getFunction('onProgress'); 94 | let onError = getFunction('onError'); 95 | 96 | let assets = {}; 97 | 98 | let state = STATE_DATA; 99 | 100 | function loadXHR(request) { 101 | let name = request.name; 102 | let stream = request.stream; 103 | let binary = request.type === 'binary'; 104 | let parser = request.parser; 105 | 106 | let xhr = new XMLHttpRequest(); 107 | let asset = null; 108 | 109 | let loader = new Loader(name, cancel); 110 | 111 | if (stream) { 112 | xhr.onreadystatechange = onReadyStateChange; 113 | } else { 114 | xhr.onreadystatechange = function () { 115 | if (xhr.readyState === 4) { 116 | onReadyStateChange(); 117 | } 118 | }; 119 | } 120 | 121 | if (binary) { 122 | xhr.responseType = 'arraybuffer'; 123 | } 124 | 125 | function onReadyStateChange() { 126 | if (xhr.readyState < 2 || 127 | loader.state === STATE_COMPLETE || 128 | loader.state === STATE_ERROR) { 129 | return; 130 | } 131 | if (xhr.status !== 200) { 132 | return abort('error loading resource "' + request.name + '"'); 133 | } 134 | if (xhr.readyState > 2 && loader.state === STATE_DATA) { 135 | let response; 136 | if (request.type === 'binary') { 137 | response = xhr.response; 138 | } else { 139 | response = xhr.responseText; 140 | } 141 | if (parser.data) { 142 | try { 143 | asset = parser.data(response); 144 | } catch (e) { 145 | return abort(e); 146 | } 147 | } else { 148 | asset = response; 149 | } 150 | } 151 | if (xhr.readyState > 3 && loader.state === STATE_DATA) { 152 | if (parser.done) { 153 | try { 154 | asset = parser.done(); 155 | } catch (e) { 156 | return abort(e); 157 | } 158 | } 159 | loader.state = STATE_COMPLETE; 160 | } 161 | assets[name] = asset; 162 | loader.progress = 0.75 * loader.progress + 0.25; 163 | loader.ready = 164 | (request.stream && !!asset) || 165 | loader.state === STATE_COMPLETE; 166 | notifyProgress(); 167 | } 168 | 169 | function cancel() { 170 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 171 | return; 172 | } 173 | xhr.onreadystatechange = null; 174 | xhr.abort(); 175 | loader.state = STATE_ERROR; 176 | } 177 | 178 | // set up request 179 | if (request.credentials) { 180 | xhr.withCredentials = true; 181 | } 182 | xhr.open('GET', request.src, true); 183 | xhr.send(); 184 | 185 | return loader; 186 | } 187 | 188 | function loadElement(request, element) { 189 | let name = request.name; 190 | let parser = request.parser; 191 | 192 | let loader = new Loader(name, cancel); 193 | let asset = element; 194 | 195 | function handleProgress() { 196 | if (loader.state === STATE_DATA) { 197 | if (parser.data) { 198 | try { 199 | asset = parser.data(element); 200 | } catch (e) { 201 | return abort(e); 202 | } 203 | } else { 204 | asset = element; 205 | } 206 | } 207 | } 208 | 209 | function onProgress(e) { 210 | handleProgress(); 211 | assets[name] = asset; 212 | if (e.lengthComputable) { 213 | loader.progress = Math.max(loader.progress, e.loaded / e.total); 214 | } else { 215 | loader.progress = 0.75 * loader.progress + 0.25; 216 | } 217 | notifyProgress(name); 218 | } 219 | 220 | function onComplete() { 221 | handleProgress(); 222 | if (loader.state === STATE_DATA) { 223 | if (parser.done) { 224 | try { 225 | asset = parser.done(); 226 | } catch (e) { 227 | return abort(e); 228 | } 229 | } 230 | loader.state = STATE_COMPLETE; 231 | } 232 | loader.progress = 1; 233 | loader.ready = true; 234 | assets[name] = asset; 235 | removeListeners(); 236 | notifyProgress('finish ' + name); 237 | } 238 | 239 | function onError() { 240 | abort('error loading asset "' + name + '"'); 241 | } 242 | 243 | if (request.stream) { 244 | element.addEventListener('progress', onProgress); 245 | } 246 | if (request.type === 'image') { 247 | element.addEventListener('load', onComplete); 248 | } else { 249 | let canPlay = false; 250 | let loadedMetaData = false; 251 | element.addEventListener('loadedmetadata', function () { 252 | loadedMetaData = true; 253 | if (canPlay) { 254 | onComplete(); 255 | } 256 | }); 257 | element.addEventListener('canplay', function () { 258 | canPlay = true; 259 | if (loadedMetaData) { 260 | onComplete(); 261 | } 262 | }); 263 | } 264 | element.addEventListener('error', onError); 265 | 266 | function removeListeners() { 267 | if (request.stream) { 268 | element.removeEventListener('progress', onProgress); 269 | } 270 | if (request.type === 'image') { 271 | element.addEventListener('load', onComplete); 272 | } else { 273 | element.addEventListener('canplay', onComplete); 274 | } 275 | element.removeEventListener('error', onError); 276 | } 277 | 278 | function cancel() { 279 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 280 | return; 281 | } 282 | 283 | loader.state = STATE_ERROR; 284 | removeListeners(); 285 | element.src = ''; 286 | } 287 | 288 | // set up request 289 | if (request.credentials) { 290 | element.crossOrigin = 'use-credentials'; 291 | } else { 292 | element.crossOrigin = 'anonymous'; 293 | } 294 | element.src = request.src; 295 | 296 | return loader; 297 | } 298 | 299 | let loaders = { 300 | text: loadXHR, 301 | binary: function (request) { 302 | // TODO use fetch API for streaming if supported 303 | return loadXHR(request); 304 | }, 305 | image: function (request) { 306 | return loadElement(request, document.createElement('img')); 307 | }, 308 | video: function (request) { 309 | return loadElement(request, document.createElement('video')); 310 | }, 311 | audio: function (request) { 312 | return loadElement(request, document.createElement('audio')); 313 | } 314 | }; 315 | 316 | // First we parse all objects in order to verify that all type information 317 | // is correct 318 | let pending = Object.keys(manifest).map(function (name) { 319 | let request = manifest[name]; 320 | if (typeof request === 'string') { 321 | request = { 322 | src: request 323 | }; 324 | } else if (typeof request !== 'object' || !request) { 325 | raise('invalid asset definition "' + name + '"'); 326 | } 327 | 328 | checkType(request, manifestParameters, 'asset "' + name + '"'); 329 | 330 | function getParameter(prop, accepted, init) { 331 | let value = init; 332 | if (prop in request) { 333 | value = request[prop]; 334 | } 335 | if (accepted.indexOf(value) < 0) { 336 | raise('invalid ' + prop + ' "' + value + '" for asset "' + name + '", possible values: ' + accepted); 337 | } 338 | return value; 339 | } 340 | 341 | function getString(prop, required, init) { 342 | let value = init; 343 | if (prop in request) { 344 | value = request[prop]; 345 | } else if (required) { 346 | raise('missing ' + prop + ' for asset "' + name + '"'); 347 | } 348 | if (typeof value !== 'string') { 349 | raise('invalid ' + prop + ' for asset "' + name + '", must be a string'); 350 | } 351 | return value; 352 | } 353 | 354 | function getParseFunc(name, dflt) { 355 | if (name in request.parser) { 356 | let result = request.parser[name]; 357 | if (typeof result !== 'function') { 358 | raise('invalid parser callback ' + name + ' for asset "' + name + '"'); 359 | } 360 | return result; 361 | } else { 362 | return dflt; 363 | } 364 | } 365 | 366 | let parser = {}; 367 | if ('parser' in request) { 368 | if (typeof request.parser === 'function') { 369 | parser = { 370 | data: request.parser 371 | }; 372 | } else if (typeof request.parser === 'object' && request.parser) { 373 | checkType(request.parser, parserParameters, 'parser for asset "' + name + '"'); 374 | if (!('onData' in request.parser)) { 375 | raise('missing onData callback for parser in asset "' + name + '"'); 376 | } 377 | parser = { 378 | data: getParseFunc('onData'), 379 | done: getParseFunc('onDone') 380 | }; 381 | } else { 382 | raise('invalid parser for asset "' + name + '"'); 383 | } 384 | } 385 | 386 | return { 387 | name: name, 388 | type: getParameter('type', Object.keys(loaders), 'text'), 389 | stream: !!request.stream, 390 | credentials: !!request.credentials, 391 | src: getString('src', true, ''), 392 | parser: parser 393 | }; 394 | }).map(function (request) { 395 | return (loaders[request.type])(request); 396 | }); 397 | 398 | function abort(message) { 399 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 400 | return; 401 | } 402 | state = STATE_ERROR; 403 | pending.forEach(function (loader) { 404 | loader.cancel(); 405 | }); 406 | if (onError) { 407 | if (typeof message === 'string') { 408 | onError(new Error('resl: ' + message)); 409 | } else { 410 | onError(message); 411 | } 412 | } else { 413 | console.error('resl error:', message); 414 | } 415 | } 416 | 417 | function notifyProgress(message) { 418 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 419 | return; 420 | } 421 | 422 | let progress = 0; 423 | let numReady = 0; 424 | pending.forEach(function (loader) { 425 | if (loader.ready) { 426 | numReady += 1; 427 | } 428 | progress += loader.progress; 429 | }); 430 | 431 | if (numReady === pending.length) { 432 | state = STATE_COMPLETE; 433 | onDone(assets); 434 | } else { 435 | if (onProgress) { 436 | onProgress(progress / pending.length, message); 437 | } 438 | } 439 | } 440 | 441 | if (pending.length === 0) { 442 | setTimeout(function () { 443 | notifyProgress('done'); 444 | }, 1); 445 | } 446 | } 447 | 448 | var builtinPrograms = { 449 | // ======================== 450 | // diffuse 451 | // ======================== 452 | 453 | diffuse: { 454 | attributes: [ 455 | 'a_position', 456 | 'a_normal', 457 | 'a_uv0' 458 | ], 459 | vertexShader: ` 460 | precision mediump float; 461 | uniform mat4 model, view, projection; 462 | 463 | attribute vec3 a_position; 464 | attribute vec3 a_normal; 465 | attribute vec2 a_uv0; 466 | 467 | varying vec2 v_uv0; 468 | 469 | void main() { 470 | v_uv0 = a_uv0; 471 | gl_Position = projection * view * model * vec4(a_position, 1); 472 | } 473 | `, 474 | fragmentShader: ` 475 | #extension GL_OES_standard_derivatives : enable 476 | 477 | precision mediump float; 478 | uniform sampler2D u_mainTexture; 479 | uniform vec2 u_mainTextureTiling; 480 | uniform vec2 u_mainTextureOffset; 481 | 482 | varying vec2 v_uv0; 483 | 484 | void main () { 485 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 486 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 487 | 488 | vec2 uv0 = v_uv0 * u_mainTextureTiling + u_mainTextureOffset; 489 | 490 | gl_FragColor = texture2D( u_mainTexture, uv0 ); 491 | 492 | if (!gl_FrontFacing) { 493 | gl_FragColor *= 0.05; 494 | } 495 | } 496 | `, 497 | }, 498 | 499 | // ======================== 500 | // diffuse_skinning 501 | // ======================== 502 | 503 | diffuse_skinning: { 504 | attributes: [ 505 | 'a_position', 506 | 'a_normal', 507 | 'a_uv0', 508 | 'a_joint', 509 | 'a_weight' 510 | ], 511 | vertexShader: ` 512 | precision mediump float; 513 | uniform mat4 model, view, projection; 514 | 515 | attribute vec3 a_position; 516 | attribute vec3 a_normal; 517 | attribute vec2 a_uv0; 518 | attribute vec4 a_weight; 519 | attribute vec4 a_joint; 520 | 521 | uniform sampler2D u_bonesTexture; 522 | uniform float u_bonesTextureSize; 523 | 524 | varying vec2 v_uv0; 525 | 526 | mat4 getBoneMatrix(const in float i) { 527 | float size = u_bonesTextureSize; 528 | float j = i * 4.0; 529 | float x = mod(j, size); 530 | float y = floor(j / size); 531 | 532 | float dx = 1.0 / size; 533 | float dy = 1.0 / size; 534 | 535 | y = dy * (y + 0.5); 536 | 537 | vec4 v1 = texture2D(u_bonesTexture, vec2(dx * (x + 0.5), y)); 538 | vec4 v2 = texture2D(u_bonesTexture, vec2(dx * (x + 1.5), y)); 539 | vec4 v3 = texture2D(u_bonesTexture, vec2(dx * (x + 2.5), y)); 540 | vec4 v4 = texture2D(u_bonesTexture, vec2(dx * (x + 3.5), y)); 541 | 542 | mat4 bone = mat4(v1, v2, v3, v4); 543 | 544 | return bone; 545 | } 546 | 547 | void main() { 548 | v_uv0 = a_uv0; 549 | mat4 matSkin = 550 | getBoneMatrix(a_joint.x) * a_weight.x + 551 | getBoneMatrix(a_joint.y) * a_weight.y + 552 | getBoneMatrix(a_joint.z) * a_weight.z + 553 | getBoneMatrix(a_joint.w) * a_weight.w ; 554 | 555 | gl_Position = projection * view * model * matSkin * vec4(a_position, 1); 556 | } 557 | `, 558 | fragmentShader: ` 559 | #extension GL_OES_standard_derivatives : enable 560 | 561 | precision mediump float; 562 | uniform sampler2D u_mainTexture; 563 | 564 | varying vec2 v_uv0; 565 | 566 | void main () { 567 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 568 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 569 | 570 | gl_FragColor = texture2D( u_mainTexture, v_uv0 ); 571 | 572 | if (!gl_FrontFacing) { 573 | gl_FragColor *= 0.05; 574 | } 575 | } 576 | `, 577 | } 578 | }; 579 | 580 | const GL$1 = WebGLRenderingContext.prototype; 581 | 582 | var builtinTechniques = { 583 | diffuse: { 584 | name: 'diffuse', 585 | program: 'diffuse', 586 | parameters: { 587 | position: { 588 | type: GL$1.FLOAT_VEC3, 589 | semantic: 'POSITION' 590 | }, 591 | normal: { 592 | type: GL$1.FLOAT_VEC3, 593 | semantic: 'NORMAL' 594 | }, 595 | uv0: { 596 | type: GL$1.FLOAT_VEC2, 597 | semantic: 'TEXCOORD_0' 598 | }, 599 | model: { 600 | type: GL$1.FLOAT_MAT4, 601 | semantic: 'MODEL' 602 | }, 603 | view: { 604 | type: GL$1.FLOAT_MAT4, 605 | semantic: 'VIEW' 606 | }, 607 | projection: { 608 | type: GL$1.FLOAT_MAT4, 609 | semantic: 'PROJECTION' 610 | }, 611 | mainTexture: { 612 | type: GL$1.SAMPLER_2D, 613 | }, 614 | mainTextureTiling: { 615 | type: GL$1.FLOAT_VEC2, 616 | }, 617 | mainTextureOffset: { 618 | type: GL$1.FLOAT_VEC2, 619 | }, 620 | }, 621 | 622 | attributes: { 623 | a_position: 'position', 624 | a_normal: 'normal', 625 | a_uv0: 'uv0', 626 | }, 627 | 628 | uniforms: { 629 | model: 'model', 630 | // view: 'view', 631 | // projection: 'projection', 632 | u_mainTexture: 'mainTexture', 633 | u_mainTextureTiling: 'mainTextureTiling', 634 | u_mainTextureOffset: 'mainTextureOffset', 635 | }, 636 | }, 637 | 638 | diffuse_skinning: { 639 | name: 'diffuse_skinning', 640 | program: 'diffuse_skinning', 641 | parameters: { 642 | position: { 643 | type: GL$1.FLOAT_VEC3, 644 | semantic: 'POSITION' 645 | }, 646 | normal: { 647 | type: GL$1.FLOAT_VEC3, 648 | semantic: 'NORMAL' 649 | }, 650 | uv0: { 651 | type: GL$1.FLOAT_VEC2, 652 | semantic: 'TEXCOORD_0' 653 | }, 654 | joint: { 655 | type: GL$1.FLOAT_VEC4, 656 | semantic: 'JOINT' 657 | }, 658 | weight: { 659 | type: GL$1.FLOAT_VEC4, 660 | semantic: 'WEIGHT' 661 | }, 662 | model: { 663 | type: GL$1.FLOAT_MAT4, 664 | semantic: 'MODEL' 665 | }, 666 | view: { 667 | type: GL$1.FLOAT_MAT4, 668 | semantic: 'VIEW' 669 | }, 670 | projection: { 671 | type: GL$1.FLOAT_MAT4, 672 | semantic: 'PROJECTION' 673 | }, 674 | mainTexture: { 675 | type: GL$1.SAMPLER_2D, 676 | }, 677 | bonesTexture: { 678 | type: GL$1.SAMPLER_2D, 679 | }, 680 | bonesTextureSize: { 681 | type: GL$1.FLOAT, 682 | }, 683 | }, 684 | 685 | attributes: { 686 | a_position: 'position', 687 | a_normal: 'normal', 688 | a_uv0: 'uv0', 689 | a_joint: 'joint', 690 | a_weight: 'weight', 691 | }, 692 | 693 | uniforms: { 694 | model: 'model', 695 | // view: 'view', 696 | // projection: 'projection', 697 | u_bonesTexture: 'bonesTexture', 698 | u_bonesTextureSize: 'bonesTextureSize', 699 | u_mainTexture: 'mainTexture', 700 | }, 701 | }, 702 | }; 703 | 704 | const GL = WebGLRenderingContext.prototype; 705 | 706 | let _programs = {}; 707 | for (let name in builtinPrograms) { 708 | _programs[name] = builtinPrograms[name]; 709 | } 710 | 711 | let _techniques = {}; 712 | for (let name in builtinTechniques) { 713 | _techniques[name] = builtinTechniques[name]; 714 | } 715 | 716 | function _gl2reglWrapMode(wrap) { 717 | if (wrap === GL.REPEAT) { 718 | return 'repeat'; 719 | } else if (wrap === GL.CLAMP_TO_EDGE) { 720 | return 'clamp'; 721 | } else if (wrap === GL.MIRRORED_REPEAT) { 722 | return 'mirror'; 723 | } 724 | 725 | return 'repeat'; 726 | } 727 | 728 | function _gl2reglFilter(filter) { 729 | if (filter === GL.NEAREST) { 730 | return 'nearest'; 731 | } else if (filter === GL.LINEAR) { 732 | return 'linear'; 733 | } else if (filter === GL.LINEAR_MIPMAP_LINEAR) { 734 | return 'linear mipmap linear'; 735 | } else if (filter === GL.NEAREST_MIPMAP_LINEAR) { 736 | return 'nearest mipmap linear'; 737 | } else if (filter === GL.LINEAR_MIPMAP_NEAREST) { 738 | return 'linear mipmap nearest'; 739 | } else if (filter === GL.NEAREST_MIPMAP_NEAREST) { 740 | return 'nearest mipmap nearest'; 741 | } 742 | 743 | return 'nearest mipmap linear'; 744 | } 745 | 746 | function _walk(scene, fn) { 747 | scene.nodes.forEach(node => { 748 | fn(node); 749 | 750 | sceneGraph.utils.walk(node, child => { 751 | return fn(child); 752 | }); 753 | }); 754 | } 755 | 756 | function _replace(scene, oldNode, newNode) { 757 | if (oldNode._parent) { 758 | return sceneGraph.utils.replace(oldNode, newNode); 759 | } 760 | 761 | for (let i = 0; i < scene.nodes.length; ++i) { 762 | if (scene.nodes[i] === oldNode) { 763 | scene.nodes[i] = newNode; 764 | return; 765 | } 766 | } 767 | } 768 | 769 | function _serializeCommands(regl, json, commands) { 770 | for ( let techID in _techniques ) { 771 | let gltfTechnique = _techniques[techID]; 772 | let gltfProgram = _programs[gltfTechnique.program]; 773 | 774 | // draw options 775 | let opts = { 776 | // frontFace: 'ccw', 777 | cull: { 778 | enable: true, 779 | face: 'back' 780 | }, 781 | 782 | vert: gltfProgram.vertexShader, 783 | frag: gltfProgram.fragmentShader, 784 | 785 | primitive: regl.prop('primitive'), 786 | offset: regl.prop('offset'), 787 | count: regl.prop('count'), 788 | 789 | elements: regl.prop('elements'), 790 | attributes: {}, 791 | uniforms: {}, 792 | }; 793 | for (let attrName in gltfTechnique.attributes) { 794 | opts.attributes[attrName] = regl.prop(`attributes.${attrName}`); 795 | } 796 | for (let uniformName in gltfTechnique.uniforms) { 797 | opts.uniforms[uniformName] = regl.prop(`uniforms.${uniformName}`); 798 | } 799 | // TODO: states 800 | // TODO: functions 801 | 802 | // finalize 803 | commands[techID] = regl(opts); 804 | } 805 | } 806 | 807 | function _serializeNodes(json, parent, childrenIDs, out) { 808 | childrenIDs.forEach(nodeID => { 809 | let gltfNode = json.nodes[nodeID]; 810 | let node = new sceneGraph.Node(gltfNode.name); 811 | let data; 812 | 813 | node._id = nodeID; 814 | node._parent = parent; 815 | 816 | data = gltfNode.translation; 817 | node.lpos = data ? 818 | vmath.vec3.new(data[0], data[1], data[2]) : 819 | vmath.vec3.new(0, 0, 0) 820 | ; 821 | 822 | data = gltfNode.rotation; 823 | node.lrot = data ? 824 | vmath.quat.new(data[0], data[1], data[2], data[3]) : 825 | vmath.quat.new(0, 0, 0, 1) 826 | ; 827 | 828 | data = gltfNode.scale; 829 | node.lscale = data ? 830 | vmath.vec3.new(data[0], data[1], data[2]) : 831 | vmath.vec3.new(1, 1, 1) 832 | ; 833 | 834 | node._meshes = gltfNode.meshes; 835 | node._skeletons = gltfNode.skeletons; 836 | node._skin = gltfNode.skin; 837 | node._extras = gltfNode.extras; 838 | 839 | if (gltfNode.children) { 840 | _serializeNodes(json, node, gltfNode.children, node.children); 841 | } 842 | 843 | out.push(node); 844 | }); 845 | 846 | return out; 847 | } 848 | 849 | function _serializeJoint(json, parent, id, joints) { 850 | let node = joints[id]; 851 | if (node) { 852 | if (parent) { 853 | node._parent = parent; 854 | parent.children.push(node); 855 | } 856 | 857 | return; 858 | } 859 | 860 | let gltfNode = json.nodes[id]; 861 | node = new sceneGraph.Node(gltfNode.name); 862 | 863 | node._id = id; 864 | node._parent = parent; 865 | 866 | let data; 867 | data = gltfNode.translation; 868 | node.lpos = data ? 869 | vmath.vec3.new(data[0], data[1], data[2]) : 870 | vmath.vec3.new(0, 0, 0) 871 | ; 872 | 873 | data = gltfNode.rotation; 874 | node.lrot = data ? 875 | vmath.quat.new(data[0], data[1], data[2], data[3]) : 876 | vmath.quat.new(0, 0, 0, 1) 877 | ; 878 | 879 | data = gltfNode.scale; 880 | node.lscale = data ? 881 | vmath.vec3.new(data[0], data[1], data[2]) : 882 | vmath.vec3.new(1, 1, 1) 883 | ; 884 | 885 | joints[id] = node; 886 | 887 | if (parent) { 888 | parent.children.push(node); 889 | } 890 | 891 | if (gltfNode.children) { 892 | gltfNode.children.forEach(childNodeID => { 893 | _serializeJoint(json, node, childNodeID, joints); 894 | }); 895 | } 896 | } 897 | 898 | function _serializeTextures(regl, json, textures, callback) { 899 | let manifest = {}; 900 | let samplers = {}; 901 | 902 | for ( let name in json.textures ) { 903 | let gltfTexture = json.textures[name]; 904 | let gltfImage = json.images[gltfTexture.source]; 905 | 906 | textures[name] = regl.texture(); 907 | samplers[name] = json.samplers[gltfTexture.sampler]; 908 | manifest[name] = { 909 | type: 'image', 910 | src: `${json.baseURL}/${gltfImage.uri}` 911 | }; 912 | } 913 | 914 | resl({ 915 | manifest, 916 | onError(err) { 917 | console.error(err); 918 | }, 919 | onDone(assets) { 920 | for (let name in assets) { 921 | let gltfSampler = samplers[name]; 922 | 923 | textures[name]({ 924 | data: assets[name], 925 | wrapS: _gl2reglWrapMode(gltfSampler.wrapS || GL.REPEAT), 926 | wrapT: _gl2reglWrapMode(gltfSampler.wrapT || GL.REPEAT), 927 | mag: _gl2reglFilter(gltfSampler.magFilter || GL.LINEAR), 928 | min: _gl2reglFilter(gltfSampler.minFilter || GL.NEAREST_MIPMAP_LINEAR), 929 | mipmap: 'nice', 930 | flipY: true 931 | }); 932 | } 933 | 934 | if (callback) { 935 | callback(null, textures); 936 | } 937 | }, 938 | }); 939 | } 940 | 941 | function _serializeBuffers(regl, json, buffers, callback) { 942 | let manifest = {}; 943 | let buffer2viewIDs = {}; 944 | 945 | for ( let id in json.buffers ) { 946 | let gltfBuffer = json.buffers[id]; 947 | manifest[id] = { 948 | type: 'binary', 949 | src: `${json.baseURL}/${gltfBuffer.uri}` 950 | }; 951 | buffer2viewIDs[id] = []; 952 | } 953 | 954 | for ( let id in json.bufferViews ) { 955 | let gltfBufferView = json.bufferViews[id]; 956 | if ( gltfBufferView.target === regl._gl.ARRAY_BUFFER ) { 957 | buffers[id] = regl.buffer(gltfBufferView.byteLength); 958 | } else if ( gltfBufferView.target === regl._gl.ELEMENT_ARRAY_BUFFER ) { 959 | buffers[id] = regl.elements(gltfBufferView.byteLength); 960 | } else { 961 | buffers[id] = new ArrayBuffer(); 962 | } 963 | 964 | buffer2viewIDs[gltfBufferView.buffer].push(id); 965 | } 966 | 967 | resl({ 968 | manifest, 969 | onError(err) { 970 | console.error(err); 971 | }, 972 | onDone(assets) { 973 | for ( let id in assets ) { 974 | let viewIDs = buffer2viewIDs[id]; 975 | viewIDs.forEach(viewID => { 976 | let gltfBufferView = json.bufferViews[viewID]; 977 | if ( gltfBufferView.target ) { 978 | let reglBuf = buffers[viewID]; 979 | reglBuf({ 980 | type: 'uint16', // HACK 981 | data: new Uint8Array(assets[id], gltfBufferView.byteOffset, gltfBufferView.byteLength) 982 | }); 983 | } else { 984 | // ArrayBuffer.slice 985 | buffers[viewID] = assets[id].slice( 986 | gltfBufferView.byteOffset, 987 | gltfBufferView.byteOffset + gltfBufferView.byteLength 988 | ); 989 | } 990 | }); 991 | } 992 | 993 | if (callback) { 994 | callback(null, buffers); 995 | } 996 | } 997 | }); 998 | } 999 | 1000 | function _serializePrefabs(regl, json, scene, prefabs, callback) { 1001 | if (!json.extras || !json.extras.prefabs) { 1002 | if (callback) { 1003 | callback(null, prefabs); 1004 | } 1005 | 1006 | return; 1007 | } 1008 | 1009 | let count = 0; 1010 | let manifest = {}; 1011 | for (let id in json.extras.prefabs) { 1012 | let asset = json.extras.prefabs[id]; 1013 | manifest[id] = { 1014 | type: 'text', 1015 | src: `${json.baseURL}/${asset.uri}`, 1016 | parser: JSON.parse 1017 | }; 1018 | ++count; 1019 | } 1020 | 1021 | resl({ 1022 | manifest, 1023 | onError(err) { 1024 | console.error(err); 1025 | }, 1026 | onDone(assets) { 1027 | for ( let id in assets ) { 1028 | let url = manifest[id].src; 1029 | let prefabJson = assets[id]; 1030 | 1031 | let idx = url.lastIndexOf('/'); 1032 | if (idx !== -1) { 1033 | prefabJson.baseURL = url.substring(0, idx); 1034 | } else { 1035 | prefabJson.baseURL = url; 1036 | } 1037 | 1038 | _serializeGLTF(regl, prefabJson, scene, (err, result) => { 1039 | prefabs[id] = result; 1040 | 1041 | --count; 1042 | if (count === 0 && callback) { 1043 | callback(null, prefabs); 1044 | } 1045 | }); 1046 | } 1047 | } 1048 | }); 1049 | } 1050 | 1051 | function _serializeGLTF(regl, json, scene, callback) { 1052 | let gltfScene = json.scenes[json.scene]; 1053 | let result = { 1054 | name: gltfScene.name, 1055 | json: json, 1056 | nodes: [], 1057 | joints: {}, 1058 | }; 1059 | 1060 | // update programs & techinques 1061 | for (let name in json.programs) { 1062 | _programs[name] = json.programs[name]; 1063 | } 1064 | for ( let name in json.techniques ) { 1065 | _techniques[name] = json.techniques[name]; 1066 | } 1067 | 1068 | // serialize gltf globally 1069 | scene.programs = _programs; 1070 | scene.techniques = _techniques; 1071 | for ( let id in json.meshes ) { 1072 | scene.meshes[id] = json.meshes[id]; 1073 | } 1074 | for ( let id in json.materials ) { 1075 | scene.materials[id] = json.materials[id]; 1076 | } 1077 | for ( let id in json.accessors ) { 1078 | scene.accessors[id] = json.accessors[id]; 1079 | } 1080 | 1081 | // serialize commands 1082 | _serializeCommands(regl, json, scene.commands); 1083 | 1084 | // serialize nodes 1085 | _serializeNodes(json, null, gltfScene.nodes, result.nodes); 1086 | 1087 | // serialize joints 1088 | for (let id in json.nodes) { 1089 | let node = json.nodes[id]; 1090 | if (node.jointName) { 1091 | _serializeJoint(json, null, id, result.joints); 1092 | } 1093 | } 1094 | 1095 | // serialize textures 1096 | _serializeTextures(regl, json, scene.textures); 1097 | 1098 | // serialize buffers 1099 | _serializeBuffers(regl, json, scene.buffers); 1100 | 1101 | // serialize extras.prefabs 1102 | _serializePrefabs(regl, json, scene, scene.prefabs, (err, prefabs) => { 1103 | _walk(result, child => { 1104 | console.log(child.name); 1105 | if (child._extras && child._extras.prefab) { 1106 | let prefabID = child._extras.prefab; 1107 | let prefab = prefabs[prefabID]; 1108 | let root = prefab.nodes[0]; 1109 | let prefabNode = root.deepClone((newNode, oldNode) => { 1110 | newNode._meshes = oldNode._meshes; 1111 | newNode._skeletons = oldNode._skeletons; 1112 | newNode._skin = oldNode._skin; 1113 | newNode._extras = oldNode._extras; 1114 | }); 1115 | vmath.vec3.copy(prefabNode.lpos, child.lpos); 1116 | vmath.vec3.copy(prefabNode.lscale, child.lscale); 1117 | vmath.quat.copy(prefabNode.lrot, child.lrot); 1118 | 1119 | _replace(result, child, prefabNode); 1120 | 1121 | scene._dirty = true; 1122 | 1123 | return false; // stop walking on child 1124 | } 1125 | 1126 | return true; 1127 | }); 1128 | }); 1129 | 1130 | // done 1131 | callback(null, result); 1132 | } 1133 | 1134 | function load (regl, url, callback) { 1135 | resl({ 1136 | manifest: { 1137 | json: { 1138 | type: 'text', 1139 | src: url, 1140 | parser: JSON.parse 1141 | } 1142 | }, 1143 | 1144 | onDone(assets) { 1145 | let idx = url.lastIndexOf('/'); 1146 | if (idx !== -1) { 1147 | assets.json.baseURL = url.substring(0,idx); 1148 | } else { 1149 | assets.json.baseURL = url; 1150 | } 1151 | 1152 | let scene = { 1153 | _dirty: false, 1154 | 1155 | // 1156 | name: '', 1157 | json: '', 1158 | nodes: [], 1159 | joints: {}, 1160 | 1161 | // gltf (global) 1162 | techniques: {}, 1163 | programs: {}, 1164 | meshes: {}, 1165 | materials: {}, 1166 | accessors: {}, 1167 | 1168 | // resources 1169 | textures: {}, // texture id to regl texture 1170 | buffers: {}, // buffer-view id to regl buffer 1171 | prefabs: {}, // serialized prefabs 1172 | commands: {}, // technique id to regl command 1173 | }; 1174 | _serializeGLTF(regl, assets.json, scene, (err,result) => { 1175 | scene.name = result.name; 1176 | scene.json = result.json; 1177 | scene.nodes = result.nodes; 1178 | scene.joints = result.joints; 1179 | 1180 | if (callback) { 1181 | callback(null, scene); 1182 | } 1183 | }); 1184 | }, 1185 | 1186 | onError(err) { 1187 | console.error(err); 1188 | callback(err); 1189 | } 1190 | }); 1191 | } 1192 | 1193 | const GL$2 = WebGLRenderingContext.prototype; 1194 | let m4_a = vmath.mat4.create(); 1195 | 1196 | function _type2buffersize(type) { 1197 | if (type === 'SCALAR') { 1198 | return 1; 1199 | } else if (type === 'VEC2') { 1200 | return 2; 1201 | } else if (type === 'VEC3') { 1202 | return 3; 1203 | } else if (type === 'VEC4') { 1204 | return 4; 1205 | } else if (type === 'MAT2') { 1206 | return 4; 1207 | } else if (type === 'MAT3') { 1208 | return 9; 1209 | } else if (type === 'MAT4') { 1210 | return 16; 1211 | } 1212 | 1213 | return 1; 1214 | } 1215 | 1216 | function _mode2primitive(mode) { 1217 | if (mode === GL$2.POINTS) { 1218 | return 'points'; 1219 | } else if (mode === GL$2.LINES) { 1220 | return 'lines'; 1221 | } else if (mode === GL$2.LINE_LOOP) { 1222 | return 'line loop'; 1223 | } else if (mode === GL$2.LINE_STRIP) { 1224 | return 'line strip'; 1225 | } else if (mode === GL$2.TRIANGLES) { 1226 | return 'triangles'; 1227 | } else if (mode === GL$2.TRIANGLE_STRIP) { 1228 | return 'triangle strip'; 1229 | } else if (mode === GL$2.TRIANGLE_FAN) { 1230 | return 'triangle fan'; 1231 | } 1232 | 1233 | return 'triangles'; 1234 | } 1235 | 1236 | function buildCommandData(scene, node, gltfPrimitive) { 1237 | // get material & technique 1238 | let gltfMaterial = scene.materials[gltfPrimitive.material]; 1239 | // let techID = useSkin ? gltfMaterial.technique + '_skinning' : gltfMaterial.technique; 1240 | let techID = gltfMaterial.technique; 1241 | let tech = scene.techniques[techID]; 1242 | let program = scene.programs[tech.program]; 1243 | 1244 | let data = { 1245 | techID: techID, 1246 | primitive: _mode2primitive(gltfPrimitive.mode), 1247 | attributes: {}, 1248 | uniforms: {}, 1249 | }; 1250 | 1251 | // get attribute accessor 1252 | program.attributes.forEach(attrName => { 1253 | let paramName = tech.attributes[attrName]; 1254 | let param = tech.parameters[paramName]; 1255 | let accessorID = gltfPrimitive.attributes[param.semantic]; 1256 | if (!accessorID) { 1257 | console.warn(`can not find attribute by semantic ${param.semantic}`); 1258 | return; 1259 | } 1260 | 1261 | let accessor = scene.accessors[accessorID]; 1262 | data.attributes[attrName] = { 1263 | buffer: scene.buffers[accessor.bufferView], 1264 | offset: accessor.byteOffset, 1265 | stride: accessor.byteStride, 1266 | // type: _type2buffertype(accessor.componentType), 1267 | type: accessor.componentType, 1268 | size: _type2buffersize(accessor.type), 1269 | }; 1270 | }); 1271 | 1272 | // get uniforms 1273 | for (let name in tech.uniforms) { 1274 | let paramName = tech.uniforms[name]; 1275 | let param = tech.parameters[paramName]; 1276 | 1277 | let value = gltfMaterial.values[paramName]; 1278 | if (value !== undefined) { 1279 | if (param.type === GL$2.SAMPLER_2D) { 1280 | data.uniforms[name] = scene.textures[value]; 1281 | } else { 1282 | data.uniforms[name] = value; 1283 | } 1284 | continue; 1285 | } 1286 | 1287 | // use default value 1288 | if (param.value !== undefined) { 1289 | if (param.type === GL$2.SAMPLER_2D) { 1290 | data.uniforms[name] = scene.textures[param.value]; 1291 | } else { 1292 | data.uniforms[name] = value; 1293 | } 1294 | } 1295 | } 1296 | 1297 | // get indices accessor 1298 | if (gltfPrimitive.indices) { 1299 | let accessor = scene.accessors[gltfPrimitive.indices]; 1300 | data.elements = scene.buffers[accessor.bufferView]; 1301 | data.offset = accessor.byteOffset; 1302 | data.count = accessor.count; 1303 | } 1304 | 1305 | // TODO: states 1306 | 1307 | // node uniforms 1308 | node.getWorldMatrix(m4_a); 1309 | data.uniforms.model = vmath.mat4.array(f32a_m4_pool.alloc(), m4_a); 1310 | 1311 | // if (bonesTexture) { 1312 | // info.uniforms.u_bonesTexture = bonesTexture; 1313 | // info.uniforms.u_bonesTextureSize = bonesTexture.width; 1314 | // } 1315 | 1316 | return data; 1317 | } 1318 | 1319 | function reset() { 1320 | f32a_m4_pool.reset(); 1321 | } 1322 | 1323 | exports.reset = reset; 1324 | exports.load = load; 1325 | exports.buildCommandData = buildCommandData; 1326 | 1327 | }((this.regltf = this.regltf || {}),window.memop,window.sgraph,window.vmath)); 1328 | //# sourceMappingURL=regltf.dev.js.map 1329 | -------------------------------------------------------------------------------- /dist/regltf.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * regltf v1.0.0 4 | * (c) 2017 @Johnny Wu 5 | * Released under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | Object.defineProperty(exports, '__esModule', { value: true }); 11 | 12 | var memop = require('memop'); 13 | var sceneGraph = require('scene-graph'); 14 | var vmath = require('vmath'); 15 | 16 | let f32a_m4_pool = new memop.FramePool(function() { 17 | return new Float32Array(16); 18 | }, 256); 19 | 20 | /** 21 | * (c) 2016 Mikola Lysenko. MIT License 22 | * https://github.com/regl-project/resl 23 | */ 24 | 25 | /* global XMLHttpRequest */ 26 | const configParameters = [ 27 | 'manifest', 28 | 'onDone', 29 | 'onProgress', 30 | 'onError' 31 | ]; 32 | 33 | const manifestParameters = [ 34 | 'type', 35 | 'src', 36 | 'stream', 37 | 'credentials', 38 | 'parser' 39 | ]; 40 | 41 | const parserParameters = [ 42 | 'onData', 43 | 'onDone' 44 | ]; 45 | 46 | const STATE_ERROR = -1; 47 | const STATE_DATA = 0; 48 | const STATE_COMPLETE = 1; 49 | 50 | function raise(message) { 51 | throw new Error('resl: ' + message); 52 | } 53 | 54 | function checkType(object, parameters, name) { 55 | Object.keys(object).forEach(function (param) { 56 | if (parameters.indexOf(param) < 0) { 57 | raise('invalid parameter "' + param + '" in ' + name); 58 | } 59 | }); 60 | } 61 | 62 | function Loader(name, cancel) { 63 | this.state = STATE_DATA; 64 | this.ready = false; 65 | this.progress = 0; 66 | this.name = name; 67 | this.cancel = cancel; 68 | } 69 | 70 | function resl(config) { 71 | if (typeof config !== 'object' || !config) { 72 | raise('invalid or missing configuration'); 73 | } 74 | 75 | checkType(config, configParameters, 'config'); 76 | 77 | let manifest = config.manifest; 78 | if (typeof manifest !== 'object' || !manifest) { 79 | raise('missing manifest'); 80 | } 81 | 82 | function getFunction(name) { 83 | if (name in config) { 84 | let func = config[name]; 85 | if (typeof func !== 'function') { 86 | raise('invalid callback "' + name + '"'); 87 | } 88 | return func; 89 | } 90 | return null; 91 | } 92 | 93 | let onDone = getFunction('onDone'); 94 | if (!onDone) { 95 | raise('missing onDone() callback'); 96 | } 97 | 98 | let onProgress = getFunction('onProgress'); 99 | let onError = getFunction('onError'); 100 | 101 | let assets = {}; 102 | 103 | let state = STATE_DATA; 104 | 105 | function loadXHR(request) { 106 | let name = request.name; 107 | let stream = request.stream; 108 | let binary = request.type === 'binary'; 109 | let parser = request.parser; 110 | 111 | let xhr = new XMLHttpRequest(); 112 | let asset = null; 113 | 114 | let loader = new Loader(name, cancel); 115 | 116 | if (stream) { 117 | xhr.onreadystatechange = onReadyStateChange; 118 | } else { 119 | xhr.onreadystatechange = function () { 120 | if (xhr.readyState === 4) { 121 | onReadyStateChange(); 122 | } 123 | }; 124 | } 125 | 126 | if (binary) { 127 | xhr.responseType = 'arraybuffer'; 128 | } 129 | 130 | function onReadyStateChange() { 131 | if (xhr.readyState < 2 || 132 | loader.state === STATE_COMPLETE || 133 | loader.state === STATE_ERROR) { 134 | return; 135 | } 136 | if (xhr.status !== 200) { 137 | return abort('error loading resource "' + request.name + '"'); 138 | } 139 | if (xhr.readyState > 2 && loader.state === STATE_DATA) { 140 | let response; 141 | if (request.type === 'binary') { 142 | response = xhr.response; 143 | } else { 144 | response = xhr.responseText; 145 | } 146 | if (parser.data) { 147 | try { 148 | asset = parser.data(response); 149 | } catch (e) { 150 | return abort(e); 151 | } 152 | } else { 153 | asset = response; 154 | } 155 | } 156 | if (xhr.readyState > 3 && loader.state === STATE_DATA) { 157 | if (parser.done) { 158 | try { 159 | asset = parser.done(); 160 | } catch (e) { 161 | return abort(e); 162 | } 163 | } 164 | loader.state = STATE_COMPLETE; 165 | } 166 | assets[name] = asset; 167 | loader.progress = 0.75 * loader.progress + 0.25; 168 | loader.ready = 169 | (request.stream && !!asset) || 170 | loader.state === STATE_COMPLETE; 171 | notifyProgress(); 172 | } 173 | 174 | function cancel() { 175 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 176 | return; 177 | } 178 | xhr.onreadystatechange = null; 179 | xhr.abort(); 180 | loader.state = STATE_ERROR; 181 | } 182 | 183 | // set up request 184 | if (request.credentials) { 185 | xhr.withCredentials = true; 186 | } 187 | xhr.open('GET', request.src, true); 188 | xhr.send(); 189 | 190 | return loader; 191 | } 192 | 193 | function loadElement(request, element) { 194 | let name = request.name; 195 | let parser = request.parser; 196 | 197 | let loader = new Loader(name, cancel); 198 | let asset = element; 199 | 200 | function handleProgress() { 201 | if (loader.state === STATE_DATA) { 202 | if (parser.data) { 203 | try { 204 | asset = parser.data(element); 205 | } catch (e) { 206 | return abort(e); 207 | } 208 | } else { 209 | asset = element; 210 | } 211 | } 212 | } 213 | 214 | function onProgress(e) { 215 | handleProgress(); 216 | assets[name] = asset; 217 | if (e.lengthComputable) { 218 | loader.progress = Math.max(loader.progress, e.loaded / e.total); 219 | } else { 220 | loader.progress = 0.75 * loader.progress + 0.25; 221 | } 222 | notifyProgress(name); 223 | } 224 | 225 | function onComplete() { 226 | handleProgress(); 227 | if (loader.state === STATE_DATA) { 228 | if (parser.done) { 229 | try { 230 | asset = parser.done(); 231 | } catch (e) { 232 | return abort(e); 233 | } 234 | } 235 | loader.state = STATE_COMPLETE; 236 | } 237 | loader.progress = 1; 238 | loader.ready = true; 239 | assets[name] = asset; 240 | removeListeners(); 241 | notifyProgress('finish ' + name); 242 | } 243 | 244 | function onError() { 245 | abort('error loading asset "' + name + '"'); 246 | } 247 | 248 | if (request.stream) { 249 | element.addEventListener('progress', onProgress); 250 | } 251 | if (request.type === 'image') { 252 | element.addEventListener('load', onComplete); 253 | } else { 254 | let canPlay = false; 255 | let loadedMetaData = false; 256 | element.addEventListener('loadedmetadata', function () { 257 | loadedMetaData = true; 258 | if (canPlay) { 259 | onComplete(); 260 | } 261 | }); 262 | element.addEventListener('canplay', function () { 263 | canPlay = true; 264 | if (loadedMetaData) { 265 | onComplete(); 266 | } 267 | }); 268 | } 269 | element.addEventListener('error', onError); 270 | 271 | function removeListeners() { 272 | if (request.stream) { 273 | element.removeEventListener('progress', onProgress); 274 | } 275 | if (request.type === 'image') { 276 | element.addEventListener('load', onComplete); 277 | } else { 278 | element.addEventListener('canplay', onComplete); 279 | } 280 | element.removeEventListener('error', onError); 281 | } 282 | 283 | function cancel() { 284 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 285 | return; 286 | } 287 | 288 | loader.state = STATE_ERROR; 289 | removeListeners(); 290 | element.src = ''; 291 | } 292 | 293 | // set up request 294 | if (request.credentials) { 295 | element.crossOrigin = 'use-credentials'; 296 | } else { 297 | element.crossOrigin = 'anonymous'; 298 | } 299 | element.src = request.src; 300 | 301 | return loader; 302 | } 303 | 304 | let loaders = { 305 | text: loadXHR, 306 | binary: function (request) { 307 | // TODO use fetch API for streaming if supported 308 | return loadXHR(request); 309 | }, 310 | image: function (request) { 311 | return loadElement(request, document.createElement('img')); 312 | }, 313 | video: function (request) { 314 | return loadElement(request, document.createElement('video')); 315 | }, 316 | audio: function (request) { 317 | return loadElement(request, document.createElement('audio')); 318 | } 319 | }; 320 | 321 | // First we parse all objects in order to verify that all type information 322 | // is correct 323 | let pending = Object.keys(manifest).map(function (name) { 324 | let request = manifest[name]; 325 | if (typeof request === 'string') { 326 | request = { 327 | src: request 328 | }; 329 | } else if (typeof request !== 'object' || !request) { 330 | raise('invalid asset definition "' + name + '"'); 331 | } 332 | 333 | checkType(request, manifestParameters, 'asset "' + name + '"'); 334 | 335 | function getParameter(prop, accepted, init) { 336 | let value = init; 337 | if (prop in request) { 338 | value = request[prop]; 339 | } 340 | if (accepted.indexOf(value) < 0) { 341 | raise('invalid ' + prop + ' "' + value + '" for asset "' + name + '", possible values: ' + accepted); 342 | } 343 | return value; 344 | } 345 | 346 | function getString(prop, required, init) { 347 | let value = init; 348 | if (prop in request) { 349 | value = request[prop]; 350 | } else if (required) { 351 | raise('missing ' + prop + ' for asset "' + name + '"'); 352 | } 353 | if (typeof value !== 'string') { 354 | raise('invalid ' + prop + ' for asset "' + name + '", must be a string'); 355 | } 356 | return value; 357 | } 358 | 359 | function getParseFunc(name, dflt) { 360 | if (name in request.parser) { 361 | let result = request.parser[name]; 362 | if (typeof result !== 'function') { 363 | raise('invalid parser callback ' + name + ' for asset "' + name + '"'); 364 | } 365 | return result; 366 | } else { 367 | return dflt; 368 | } 369 | } 370 | 371 | let parser = {}; 372 | if ('parser' in request) { 373 | if (typeof request.parser === 'function') { 374 | parser = { 375 | data: request.parser 376 | }; 377 | } else if (typeof request.parser === 'object' && request.parser) { 378 | checkType(request.parser, parserParameters, 'parser for asset "' + name + '"'); 379 | if (!('onData' in request.parser)) { 380 | raise('missing onData callback for parser in asset "' + name + '"'); 381 | } 382 | parser = { 383 | data: getParseFunc('onData'), 384 | done: getParseFunc('onDone') 385 | }; 386 | } else { 387 | raise('invalid parser for asset "' + name + '"'); 388 | } 389 | } 390 | 391 | return { 392 | name: name, 393 | type: getParameter('type', Object.keys(loaders), 'text'), 394 | stream: !!request.stream, 395 | credentials: !!request.credentials, 396 | src: getString('src', true, ''), 397 | parser: parser 398 | }; 399 | }).map(function (request) { 400 | return (loaders[request.type])(request); 401 | }); 402 | 403 | function abort(message) { 404 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 405 | return; 406 | } 407 | state = STATE_ERROR; 408 | pending.forEach(function (loader) { 409 | loader.cancel(); 410 | }); 411 | if (onError) { 412 | if (typeof message === 'string') { 413 | onError(new Error('resl: ' + message)); 414 | } else { 415 | onError(message); 416 | } 417 | } else { 418 | console.error('resl error:', message); 419 | } 420 | } 421 | 422 | function notifyProgress(message) { 423 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 424 | return; 425 | } 426 | 427 | let progress = 0; 428 | let numReady = 0; 429 | pending.forEach(function (loader) { 430 | if (loader.ready) { 431 | numReady += 1; 432 | } 433 | progress += loader.progress; 434 | }); 435 | 436 | if (numReady === pending.length) { 437 | state = STATE_COMPLETE; 438 | onDone(assets); 439 | } else { 440 | if (onProgress) { 441 | onProgress(progress / pending.length, message); 442 | } 443 | } 444 | } 445 | 446 | if (pending.length === 0) { 447 | setTimeout(function () { 448 | notifyProgress('done'); 449 | }, 1); 450 | } 451 | } 452 | 453 | var builtinPrograms = { 454 | // ======================== 455 | // diffuse 456 | // ======================== 457 | 458 | diffuse: { 459 | attributes: [ 460 | 'a_position', 461 | 'a_normal', 462 | 'a_uv0' 463 | ], 464 | vertexShader: ` 465 | precision mediump float; 466 | uniform mat4 model, view, projection; 467 | 468 | attribute vec3 a_position; 469 | attribute vec3 a_normal; 470 | attribute vec2 a_uv0; 471 | 472 | varying vec2 v_uv0; 473 | 474 | void main() { 475 | v_uv0 = a_uv0; 476 | gl_Position = projection * view * model * vec4(a_position, 1); 477 | } 478 | `, 479 | fragmentShader: ` 480 | #extension GL_OES_standard_derivatives : enable 481 | 482 | precision mediump float; 483 | uniform sampler2D u_mainTexture; 484 | uniform vec2 u_mainTextureTiling; 485 | uniform vec2 u_mainTextureOffset; 486 | 487 | varying vec2 v_uv0; 488 | 489 | void main () { 490 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 491 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 492 | 493 | vec2 uv0 = v_uv0 * u_mainTextureTiling + u_mainTextureOffset; 494 | 495 | gl_FragColor = texture2D( u_mainTexture, uv0 ); 496 | 497 | if (!gl_FrontFacing) { 498 | gl_FragColor *= 0.05; 499 | } 500 | } 501 | `, 502 | }, 503 | 504 | // ======================== 505 | // diffuse_skinning 506 | // ======================== 507 | 508 | diffuse_skinning: { 509 | attributes: [ 510 | 'a_position', 511 | 'a_normal', 512 | 'a_uv0', 513 | 'a_joint', 514 | 'a_weight' 515 | ], 516 | vertexShader: ` 517 | precision mediump float; 518 | uniform mat4 model, view, projection; 519 | 520 | attribute vec3 a_position; 521 | attribute vec3 a_normal; 522 | attribute vec2 a_uv0; 523 | attribute vec4 a_weight; 524 | attribute vec4 a_joint; 525 | 526 | uniform sampler2D u_bonesTexture; 527 | uniform float u_bonesTextureSize; 528 | 529 | varying vec2 v_uv0; 530 | 531 | mat4 getBoneMatrix(const in float i) { 532 | float size = u_bonesTextureSize; 533 | float j = i * 4.0; 534 | float x = mod(j, size); 535 | float y = floor(j / size); 536 | 537 | float dx = 1.0 / size; 538 | float dy = 1.0 / size; 539 | 540 | y = dy * (y + 0.5); 541 | 542 | vec4 v1 = texture2D(u_bonesTexture, vec2(dx * (x + 0.5), y)); 543 | vec4 v2 = texture2D(u_bonesTexture, vec2(dx * (x + 1.5), y)); 544 | vec4 v3 = texture2D(u_bonesTexture, vec2(dx * (x + 2.5), y)); 545 | vec4 v4 = texture2D(u_bonesTexture, vec2(dx * (x + 3.5), y)); 546 | 547 | mat4 bone = mat4(v1, v2, v3, v4); 548 | 549 | return bone; 550 | } 551 | 552 | void main() { 553 | v_uv0 = a_uv0; 554 | mat4 matSkin = 555 | getBoneMatrix(a_joint.x) * a_weight.x + 556 | getBoneMatrix(a_joint.y) * a_weight.y + 557 | getBoneMatrix(a_joint.z) * a_weight.z + 558 | getBoneMatrix(a_joint.w) * a_weight.w ; 559 | 560 | gl_Position = projection * view * model * matSkin * vec4(a_position, 1); 561 | } 562 | `, 563 | fragmentShader: ` 564 | #extension GL_OES_standard_derivatives : enable 565 | 566 | precision mediump float; 567 | uniform sampler2D u_mainTexture; 568 | 569 | varying vec2 v_uv0; 570 | 571 | void main () { 572 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 573 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 574 | 575 | gl_FragColor = texture2D( u_mainTexture, v_uv0 ); 576 | 577 | if (!gl_FrontFacing) { 578 | gl_FragColor *= 0.05; 579 | } 580 | } 581 | `, 582 | } 583 | }; 584 | 585 | const GL$1 = WebGLRenderingContext.prototype; 586 | 587 | var builtinTechniques = { 588 | diffuse: { 589 | name: 'diffuse', 590 | program: 'diffuse', 591 | parameters: { 592 | position: { 593 | type: GL$1.FLOAT_VEC3, 594 | semantic: 'POSITION' 595 | }, 596 | normal: { 597 | type: GL$1.FLOAT_VEC3, 598 | semantic: 'NORMAL' 599 | }, 600 | uv0: { 601 | type: GL$1.FLOAT_VEC2, 602 | semantic: 'TEXCOORD_0' 603 | }, 604 | model: { 605 | type: GL$1.FLOAT_MAT4, 606 | semantic: 'MODEL' 607 | }, 608 | view: { 609 | type: GL$1.FLOAT_MAT4, 610 | semantic: 'VIEW' 611 | }, 612 | projection: { 613 | type: GL$1.FLOAT_MAT4, 614 | semantic: 'PROJECTION' 615 | }, 616 | mainTexture: { 617 | type: GL$1.SAMPLER_2D, 618 | }, 619 | mainTextureTiling: { 620 | type: GL$1.FLOAT_VEC2, 621 | }, 622 | mainTextureOffset: { 623 | type: GL$1.FLOAT_VEC2, 624 | }, 625 | }, 626 | 627 | attributes: { 628 | a_position: 'position', 629 | a_normal: 'normal', 630 | a_uv0: 'uv0', 631 | }, 632 | 633 | uniforms: { 634 | model: 'model', 635 | // view: 'view', 636 | // projection: 'projection', 637 | u_mainTexture: 'mainTexture', 638 | u_mainTextureTiling: 'mainTextureTiling', 639 | u_mainTextureOffset: 'mainTextureOffset', 640 | }, 641 | }, 642 | 643 | diffuse_skinning: { 644 | name: 'diffuse_skinning', 645 | program: 'diffuse_skinning', 646 | parameters: { 647 | position: { 648 | type: GL$1.FLOAT_VEC3, 649 | semantic: 'POSITION' 650 | }, 651 | normal: { 652 | type: GL$1.FLOAT_VEC3, 653 | semantic: 'NORMAL' 654 | }, 655 | uv0: { 656 | type: GL$1.FLOAT_VEC2, 657 | semantic: 'TEXCOORD_0' 658 | }, 659 | joint: { 660 | type: GL$1.FLOAT_VEC4, 661 | semantic: 'JOINT' 662 | }, 663 | weight: { 664 | type: GL$1.FLOAT_VEC4, 665 | semantic: 'WEIGHT' 666 | }, 667 | model: { 668 | type: GL$1.FLOAT_MAT4, 669 | semantic: 'MODEL' 670 | }, 671 | view: { 672 | type: GL$1.FLOAT_MAT4, 673 | semantic: 'VIEW' 674 | }, 675 | projection: { 676 | type: GL$1.FLOAT_MAT4, 677 | semantic: 'PROJECTION' 678 | }, 679 | mainTexture: { 680 | type: GL$1.SAMPLER_2D, 681 | }, 682 | bonesTexture: { 683 | type: GL$1.SAMPLER_2D, 684 | }, 685 | bonesTextureSize: { 686 | type: GL$1.FLOAT, 687 | }, 688 | }, 689 | 690 | attributes: { 691 | a_position: 'position', 692 | a_normal: 'normal', 693 | a_uv0: 'uv0', 694 | a_joint: 'joint', 695 | a_weight: 'weight', 696 | }, 697 | 698 | uniforms: { 699 | model: 'model', 700 | // view: 'view', 701 | // projection: 'projection', 702 | u_bonesTexture: 'bonesTexture', 703 | u_bonesTextureSize: 'bonesTextureSize', 704 | u_mainTexture: 'mainTexture', 705 | }, 706 | }, 707 | }; 708 | 709 | const GL = WebGLRenderingContext.prototype; 710 | 711 | let _programs = {}; 712 | for (let name in builtinPrograms) { 713 | _programs[name] = builtinPrograms[name]; 714 | } 715 | 716 | let _techniques = {}; 717 | for (let name in builtinTechniques) { 718 | _techniques[name] = builtinTechniques[name]; 719 | } 720 | 721 | function _gl2reglWrapMode(wrap) { 722 | if (wrap === GL.REPEAT) { 723 | return 'repeat'; 724 | } else if (wrap === GL.CLAMP_TO_EDGE) { 725 | return 'clamp'; 726 | } else if (wrap === GL.MIRRORED_REPEAT) { 727 | return 'mirror'; 728 | } 729 | 730 | return 'repeat'; 731 | } 732 | 733 | function _gl2reglFilter(filter) { 734 | if (filter === GL.NEAREST) { 735 | return 'nearest'; 736 | } else if (filter === GL.LINEAR) { 737 | return 'linear'; 738 | } else if (filter === GL.LINEAR_MIPMAP_LINEAR) { 739 | return 'linear mipmap linear'; 740 | } else if (filter === GL.NEAREST_MIPMAP_LINEAR) { 741 | return 'nearest mipmap linear'; 742 | } else if (filter === GL.LINEAR_MIPMAP_NEAREST) { 743 | return 'linear mipmap nearest'; 744 | } else if (filter === GL.NEAREST_MIPMAP_NEAREST) { 745 | return 'nearest mipmap nearest'; 746 | } 747 | 748 | return 'nearest mipmap linear'; 749 | } 750 | 751 | function _walk(scene, fn) { 752 | scene.nodes.forEach(node => { 753 | fn(node); 754 | 755 | sceneGraph.utils.walk(node, child => { 756 | return fn(child); 757 | }); 758 | }); 759 | } 760 | 761 | function _replace(scene, oldNode, newNode) { 762 | if (oldNode._parent) { 763 | return sceneGraph.utils.replace(oldNode, newNode); 764 | } 765 | 766 | for (let i = 0; i < scene.nodes.length; ++i) { 767 | if (scene.nodes[i] === oldNode) { 768 | scene.nodes[i] = newNode; 769 | return; 770 | } 771 | } 772 | } 773 | 774 | function _serializeCommands(regl, json, commands) { 775 | for ( let techID in _techniques ) { 776 | let gltfTechnique = _techniques[techID]; 777 | let gltfProgram = _programs[gltfTechnique.program]; 778 | 779 | // draw options 780 | let opts = { 781 | // frontFace: 'ccw', 782 | cull: { 783 | enable: true, 784 | face: 'back' 785 | }, 786 | 787 | vert: gltfProgram.vertexShader, 788 | frag: gltfProgram.fragmentShader, 789 | 790 | primitive: regl.prop('primitive'), 791 | offset: regl.prop('offset'), 792 | count: regl.prop('count'), 793 | 794 | elements: regl.prop('elements'), 795 | attributes: {}, 796 | uniforms: {}, 797 | }; 798 | for (let attrName in gltfTechnique.attributes) { 799 | opts.attributes[attrName] = regl.prop(`attributes.${attrName}`); 800 | } 801 | for (let uniformName in gltfTechnique.uniforms) { 802 | opts.uniforms[uniformName] = regl.prop(`uniforms.${uniformName}`); 803 | } 804 | // TODO: states 805 | // TODO: functions 806 | 807 | // finalize 808 | commands[techID] = regl(opts); 809 | } 810 | } 811 | 812 | function _serializeNodes(json, parent, childrenIDs, out) { 813 | childrenIDs.forEach(nodeID => { 814 | let gltfNode = json.nodes[nodeID]; 815 | let node = new sceneGraph.Node(gltfNode.name); 816 | let data; 817 | 818 | node._id = nodeID; 819 | node._parent = parent; 820 | 821 | data = gltfNode.translation; 822 | node.lpos = data ? 823 | vmath.vec3.new(data[0], data[1], data[2]) : 824 | vmath.vec3.new(0, 0, 0) 825 | ; 826 | 827 | data = gltfNode.rotation; 828 | node.lrot = data ? 829 | vmath.quat.new(data[0], data[1], data[2], data[3]) : 830 | vmath.quat.new(0, 0, 0, 1) 831 | ; 832 | 833 | data = gltfNode.scale; 834 | node.lscale = data ? 835 | vmath.vec3.new(data[0], data[1], data[2]) : 836 | vmath.vec3.new(1, 1, 1) 837 | ; 838 | 839 | node._meshes = gltfNode.meshes; 840 | node._skeletons = gltfNode.skeletons; 841 | node._skin = gltfNode.skin; 842 | node._extras = gltfNode.extras; 843 | 844 | if (gltfNode.children) { 845 | _serializeNodes(json, node, gltfNode.children, node.children); 846 | } 847 | 848 | out.push(node); 849 | }); 850 | 851 | return out; 852 | } 853 | 854 | function _serializeJoint(json, parent, id, joints) { 855 | let node = joints[id]; 856 | if (node) { 857 | if (parent) { 858 | node._parent = parent; 859 | parent.children.push(node); 860 | } 861 | 862 | return; 863 | } 864 | 865 | let gltfNode = json.nodes[id]; 866 | node = new sceneGraph.Node(gltfNode.name); 867 | 868 | node._id = id; 869 | node._parent = parent; 870 | 871 | let data; 872 | data = gltfNode.translation; 873 | node.lpos = data ? 874 | vmath.vec3.new(data[0], data[1], data[2]) : 875 | vmath.vec3.new(0, 0, 0) 876 | ; 877 | 878 | data = gltfNode.rotation; 879 | node.lrot = data ? 880 | vmath.quat.new(data[0], data[1], data[2], data[3]) : 881 | vmath.quat.new(0, 0, 0, 1) 882 | ; 883 | 884 | data = gltfNode.scale; 885 | node.lscale = data ? 886 | vmath.vec3.new(data[0], data[1], data[2]) : 887 | vmath.vec3.new(1, 1, 1) 888 | ; 889 | 890 | joints[id] = node; 891 | 892 | if (parent) { 893 | parent.children.push(node); 894 | } 895 | 896 | if (gltfNode.children) { 897 | gltfNode.children.forEach(childNodeID => { 898 | _serializeJoint(json, node, childNodeID, joints); 899 | }); 900 | } 901 | } 902 | 903 | function _serializeTextures(regl, json, textures, callback) { 904 | let manifest = {}; 905 | let samplers = {}; 906 | 907 | for ( let name in json.textures ) { 908 | let gltfTexture = json.textures[name]; 909 | let gltfImage = json.images[gltfTexture.source]; 910 | 911 | textures[name] = regl.texture(); 912 | samplers[name] = json.samplers[gltfTexture.sampler]; 913 | manifest[name] = { 914 | type: 'image', 915 | src: `${json.baseURL}/${gltfImage.uri}` 916 | }; 917 | } 918 | 919 | resl({ 920 | manifest, 921 | onError(err) { 922 | console.error(err); 923 | }, 924 | onDone(assets) { 925 | for (let name in assets) { 926 | let gltfSampler = samplers[name]; 927 | 928 | textures[name]({ 929 | data: assets[name], 930 | wrapS: _gl2reglWrapMode(gltfSampler.wrapS || GL.REPEAT), 931 | wrapT: _gl2reglWrapMode(gltfSampler.wrapT || GL.REPEAT), 932 | mag: _gl2reglFilter(gltfSampler.magFilter || GL.LINEAR), 933 | min: _gl2reglFilter(gltfSampler.minFilter || GL.NEAREST_MIPMAP_LINEAR), 934 | mipmap: 'nice', 935 | flipY: true 936 | }); 937 | } 938 | 939 | if (callback) { 940 | callback(null, textures); 941 | } 942 | }, 943 | }); 944 | } 945 | 946 | function _serializeBuffers(regl, json, buffers, callback) { 947 | let manifest = {}; 948 | let buffer2viewIDs = {}; 949 | 950 | for ( let id in json.buffers ) { 951 | let gltfBuffer = json.buffers[id]; 952 | manifest[id] = { 953 | type: 'binary', 954 | src: `${json.baseURL}/${gltfBuffer.uri}` 955 | }; 956 | buffer2viewIDs[id] = []; 957 | } 958 | 959 | for ( let id in json.bufferViews ) { 960 | let gltfBufferView = json.bufferViews[id]; 961 | if ( gltfBufferView.target === regl._gl.ARRAY_BUFFER ) { 962 | buffers[id] = regl.buffer(gltfBufferView.byteLength); 963 | } else if ( gltfBufferView.target === regl._gl.ELEMENT_ARRAY_BUFFER ) { 964 | buffers[id] = regl.elements(gltfBufferView.byteLength); 965 | } else { 966 | buffers[id] = new ArrayBuffer(); 967 | } 968 | 969 | buffer2viewIDs[gltfBufferView.buffer].push(id); 970 | } 971 | 972 | resl({ 973 | manifest, 974 | onError(err) { 975 | console.error(err); 976 | }, 977 | onDone(assets) { 978 | for ( let id in assets ) { 979 | let viewIDs = buffer2viewIDs[id]; 980 | viewIDs.forEach(viewID => { 981 | let gltfBufferView = json.bufferViews[viewID]; 982 | if ( gltfBufferView.target ) { 983 | let reglBuf = buffers[viewID]; 984 | reglBuf({ 985 | type: 'uint16', // HACK 986 | data: new Uint8Array(assets[id], gltfBufferView.byteOffset, gltfBufferView.byteLength) 987 | }); 988 | } else { 989 | // ArrayBuffer.slice 990 | buffers[viewID] = assets[id].slice( 991 | gltfBufferView.byteOffset, 992 | gltfBufferView.byteOffset + gltfBufferView.byteLength 993 | ); 994 | } 995 | }); 996 | } 997 | 998 | if (callback) { 999 | callback(null, buffers); 1000 | } 1001 | } 1002 | }); 1003 | } 1004 | 1005 | function _serializePrefabs(regl, json, scene, prefabs, callback) { 1006 | if (!json.extras || !json.extras.prefabs) { 1007 | if (callback) { 1008 | callback(null, prefabs); 1009 | } 1010 | 1011 | return; 1012 | } 1013 | 1014 | let count = 0; 1015 | let manifest = {}; 1016 | for (let id in json.extras.prefabs) { 1017 | let asset = json.extras.prefabs[id]; 1018 | manifest[id] = { 1019 | type: 'text', 1020 | src: `${json.baseURL}/${asset.uri}`, 1021 | parser: JSON.parse 1022 | }; 1023 | ++count; 1024 | } 1025 | 1026 | resl({ 1027 | manifest, 1028 | onError(err) { 1029 | console.error(err); 1030 | }, 1031 | onDone(assets) { 1032 | for ( let id in assets ) { 1033 | let url = manifest[id].src; 1034 | let prefabJson = assets[id]; 1035 | 1036 | let idx = url.lastIndexOf('/'); 1037 | if (idx !== -1) { 1038 | prefabJson.baseURL = url.substring(0, idx); 1039 | } else { 1040 | prefabJson.baseURL = url; 1041 | } 1042 | 1043 | _serializeGLTF(regl, prefabJson, scene, (err, result) => { 1044 | prefabs[id] = result; 1045 | 1046 | --count; 1047 | if (count === 0 && callback) { 1048 | callback(null, prefabs); 1049 | } 1050 | }); 1051 | } 1052 | } 1053 | }); 1054 | } 1055 | 1056 | function _serializeGLTF(regl, json, scene, callback) { 1057 | let gltfScene = json.scenes[json.scene]; 1058 | let result = { 1059 | name: gltfScene.name, 1060 | json: json, 1061 | nodes: [], 1062 | joints: {}, 1063 | }; 1064 | 1065 | // update programs & techinques 1066 | for (let name in json.programs) { 1067 | _programs[name] = json.programs[name]; 1068 | } 1069 | for ( let name in json.techniques ) { 1070 | _techniques[name] = json.techniques[name]; 1071 | } 1072 | 1073 | // serialize gltf globally 1074 | scene.programs = _programs; 1075 | scene.techniques = _techniques; 1076 | for ( let id in json.meshes ) { 1077 | scene.meshes[id] = json.meshes[id]; 1078 | } 1079 | for ( let id in json.materials ) { 1080 | scene.materials[id] = json.materials[id]; 1081 | } 1082 | for ( let id in json.accessors ) { 1083 | scene.accessors[id] = json.accessors[id]; 1084 | } 1085 | 1086 | // serialize commands 1087 | _serializeCommands(regl, json, scene.commands); 1088 | 1089 | // serialize nodes 1090 | _serializeNodes(json, null, gltfScene.nodes, result.nodes); 1091 | 1092 | // serialize joints 1093 | for (let id in json.nodes) { 1094 | let node = json.nodes[id]; 1095 | if (node.jointName) { 1096 | _serializeJoint(json, null, id, result.joints); 1097 | } 1098 | } 1099 | 1100 | // serialize textures 1101 | _serializeTextures(regl, json, scene.textures); 1102 | 1103 | // serialize buffers 1104 | _serializeBuffers(regl, json, scene.buffers); 1105 | 1106 | // serialize extras.prefabs 1107 | _serializePrefabs(regl, json, scene, scene.prefabs, (err, prefabs) => { 1108 | _walk(result, child => { 1109 | console.log(child.name); 1110 | if (child._extras && child._extras.prefab) { 1111 | let prefabID = child._extras.prefab; 1112 | let prefab = prefabs[prefabID]; 1113 | let root = prefab.nodes[0]; 1114 | let prefabNode = root.deepClone((newNode, oldNode) => { 1115 | newNode._meshes = oldNode._meshes; 1116 | newNode._skeletons = oldNode._skeletons; 1117 | newNode._skin = oldNode._skin; 1118 | newNode._extras = oldNode._extras; 1119 | }); 1120 | vmath.vec3.copy(prefabNode.lpos, child.lpos); 1121 | vmath.vec3.copy(prefabNode.lscale, child.lscale); 1122 | vmath.quat.copy(prefabNode.lrot, child.lrot); 1123 | 1124 | _replace(result, child, prefabNode); 1125 | 1126 | scene._dirty = true; 1127 | 1128 | return false; // stop walking on child 1129 | } 1130 | 1131 | return true; 1132 | }); 1133 | }); 1134 | 1135 | // done 1136 | callback(null, result); 1137 | } 1138 | 1139 | function load (regl, url, callback) { 1140 | resl({ 1141 | manifest: { 1142 | json: { 1143 | type: 'text', 1144 | src: url, 1145 | parser: JSON.parse 1146 | } 1147 | }, 1148 | 1149 | onDone(assets) { 1150 | let idx = url.lastIndexOf('/'); 1151 | if (idx !== -1) { 1152 | assets.json.baseURL = url.substring(0,idx); 1153 | } else { 1154 | assets.json.baseURL = url; 1155 | } 1156 | 1157 | let scene = { 1158 | _dirty: false, 1159 | 1160 | // 1161 | name: '', 1162 | json: '', 1163 | nodes: [], 1164 | joints: {}, 1165 | 1166 | // gltf (global) 1167 | techniques: {}, 1168 | programs: {}, 1169 | meshes: {}, 1170 | materials: {}, 1171 | accessors: {}, 1172 | 1173 | // resources 1174 | textures: {}, // texture id to regl texture 1175 | buffers: {}, // buffer-view id to regl buffer 1176 | prefabs: {}, // serialized prefabs 1177 | commands: {}, // technique id to regl command 1178 | }; 1179 | _serializeGLTF(regl, assets.json, scene, (err,result) => { 1180 | scene.name = result.name; 1181 | scene.json = result.json; 1182 | scene.nodes = result.nodes; 1183 | scene.joints = result.joints; 1184 | 1185 | if (callback) { 1186 | callback(null, scene); 1187 | } 1188 | }); 1189 | }, 1190 | 1191 | onError(err) { 1192 | console.error(err); 1193 | callback(err); 1194 | } 1195 | }); 1196 | } 1197 | 1198 | const GL$2 = WebGLRenderingContext.prototype; 1199 | let m4_a = vmath.mat4.create(); 1200 | 1201 | function _type2buffersize(type) { 1202 | if (type === 'SCALAR') { 1203 | return 1; 1204 | } else if (type === 'VEC2') { 1205 | return 2; 1206 | } else if (type === 'VEC3') { 1207 | return 3; 1208 | } else if (type === 'VEC4') { 1209 | return 4; 1210 | } else if (type === 'MAT2') { 1211 | return 4; 1212 | } else if (type === 'MAT3') { 1213 | return 9; 1214 | } else if (type === 'MAT4') { 1215 | return 16; 1216 | } 1217 | 1218 | return 1; 1219 | } 1220 | 1221 | function _mode2primitive(mode) { 1222 | if (mode === GL$2.POINTS) { 1223 | return 'points'; 1224 | } else if (mode === GL$2.LINES) { 1225 | return 'lines'; 1226 | } else if (mode === GL$2.LINE_LOOP) { 1227 | return 'line loop'; 1228 | } else if (mode === GL$2.LINE_STRIP) { 1229 | return 'line strip'; 1230 | } else if (mode === GL$2.TRIANGLES) { 1231 | return 'triangles'; 1232 | } else if (mode === GL$2.TRIANGLE_STRIP) { 1233 | return 'triangle strip'; 1234 | } else if (mode === GL$2.TRIANGLE_FAN) { 1235 | return 'triangle fan'; 1236 | } 1237 | 1238 | return 'triangles'; 1239 | } 1240 | 1241 | function buildCommandData(scene, node, gltfPrimitive) { 1242 | // get material & technique 1243 | let gltfMaterial = scene.materials[gltfPrimitive.material]; 1244 | // let techID = useSkin ? gltfMaterial.technique + '_skinning' : gltfMaterial.technique; 1245 | let techID = gltfMaterial.technique; 1246 | let tech = scene.techniques[techID]; 1247 | let program = scene.programs[tech.program]; 1248 | 1249 | let data = { 1250 | techID: techID, 1251 | primitive: _mode2primitive(gltfPrimitive.mode), 1252 | attributes: {}, 1253 | uniforms: {}, 1254 | }; 1255 | 1256 | // get attribute accessor 1257 | program.attributes.forEach(attrName => { 1258 | let paramName = tech.attributes[attrName]; 1259 | let param = tech.parameters[paramName]; 1260 | let accessorID = gltfPrimitive.attributes[param.semantic]; 1261 | if (!accessorID) { 1262 | console.warn(`can not find attribute by semantic ${param.semantic}`); 1263 | return; 1264 | } 1265 | 1266 | let accessor = scene.accessors[accessorID]; 1267 | data.attributes[attrName] = { 1268 | buffer: scene.buffers[accessor.bufferView], 1269 | offset: accessor.byteOffset, 1270 | stride: accessor.byteStride, 1271 | // type: _type2buffertype(accessor.componentType), 1272 | type: accessor.componentType, 1273 | size: _type2buffersize(accessor.type), 1274 | }; 1275 | }); 1276 | 1277 | // get uniforms 1278 | for (let name in tech.uniforms) { 1279 | let paramName = tech.uniforms[name]; 1280 | let param = tech.parameters[paramName]; 1281 | 1282 | let value = gltfMaterial.values[paramName]; 1283 | if (value !== undefined) { 1284 | if (param.type === GL$2.SAMPLER_2D) { 1285 | data.uniforms[name] = scene.textures[value]; 1286 | } else { 1287 | data.uniforms[name] = value; 1288 | } 1289 | continue; 1290 | } 1291 | 1292 | // use default value 1293 | if (param.value !== undefined) { 1294 | if (param.type === GL$2.SAMPLER_2D) { 1295 | data.uniforms[name] = scene.textures[param.value]; 1296 | } else { 1297 | data.uniforms[name] = value; 1298 | } 1299 | } 1300 | } 1301 | 1302 | // get indices accessor 1303 | if (gltfPrimitive.indices) { 1304 | let accessor = scene.accessors[gltfPrimitive.indices]; 1305 | data.elements = scene.buffers[accessor.bufferView]; 1306 | data.offset = accessor.byteOffset; 1307 | data.count = accessor.count; 1308 | } 1309 | 1310 | // TODO: states 1311 | 1312 | // node uniforms 1313 | node.getWorldMatrix(m4_a); 1314 | data.uniforms.model = vmath.mat4.array(f32a_m4_pool.alloc(), m4_a); 1315 | 1316 | // if (bonesTexture) { 1317 | // info.uniforms.u_bonesTexture = bonesTexture; 1318 | // info.uniforms.u_bonesTextureSize = bonesTexture.width; 1319 | // } 1320 | 1321 | return data; 1322 | } 1323 | 1324 | function reset() { 1325 | f32a_m4_pool.reset(); 1326 | } 1327 | 1328 | exports.reset = reset; 1329 | exports.load = load; 1330 | exports.buildCommandData = buildCommandData; 1331 | //# sourceMappingURL=regltf.js.map 1332 | -------------------------------------------------------------------------------- /dist/regltf.min.js: -------------------------------------------------------------------------------- 1 | (function(e,t,n,r){"use strict";let s=new t.FramePool(function(){return new Float32Array(16)},256);const i=["manifest","onDone","onProgress","onError"];const a=["type","src","stream","credentials","parser"];const o=["onData","onDone"];const f=-1;const u=0;const c=1;function l(e){throw new Error("resl: "+e)}function p(e,t,n){Object.keys(e).forEach(function(e){if(t.indexOf(e)<0){l('invalid parameter "'+e+'" in '+n)}})}function m(e,t){this.state=u;this.ready=false;this.progress=0;this.name=e;this.cancel=t}function d(e){if(typeof e!=="object"||!e){l("invalid or missing configuration")}p(e,i,"config");let t=e.manifest;if(typeof t!=="object"||!t){l("missing manifest")}function n(t){if(t in e){let n=e[t];if(typeof n!=="function"){l('invalid callback "'+t+'"')}return n}return null}let r=n("onDone");if(!r){l("missing onDone() callback")}let s=n("onProgress");let d=n("onError");let y={};let _=u;function E(e){let t=e.name;let n=e.stream;let r=e.type==="binary";let s=e.parser;let i=new XMLHttpRequest;let a=null;let o=new m(t,p);if(n){i.onreadystatechange=l}else{i.onreadystatechange=function(){if(i.readyState===4){l()}}}if(r){i.responseType="arraybuffer"}function l(){if(i.readyState<2||o.state===c||o.state===f){return}if(i.status!==200){return h('error loading resource "'+e.name+'"')}if(i.readyState>2&&o.state===u){let t;if(e.type==="binary"){t=i.response}else{t=i.responseText}if(s.data){try{a=s.data(t)}catch(e){return h(e)}}else{a=t}}if(i.readyState>3&&o.state===u){if(s.done){try{a=s.done()}catch(e){return h(e)}}o.state=c}y[t]=a;o.progress=.75*o.progress+.25;o.ready=e.stream&&!!a||o.state===c;A()}function p(){if(o.state===c||o.state===f){return}i.onreadystatechange=null;i.abort();o.state=f}if(e.credentials){i.withCredentials=true}i.open("GET",e.src,true);i.send();return o}function g(e,t){let n=e.name;let r=e.parser;let s=new m(n,_);let i=t;function a(){if(s.state===u){if(r.data){try{i=r.data(t)}catch(e){return h(e)}}else{i=t}}}function o(e){a();y[n]=i;if(e.lengthComputable){s.progress=Math.max(s.progress,e.loaded/e.total)}else{s.progress=.75*s.progress+.25}A(n)}function l(){a();if(s.state===u){if(r.done){try{i=r.done()}catch(e){return h(e)}}s.state=c}s.progress=1;s.ready=true;y[n]=i;d();A("finish "+n)}function p(){h('error loading asset "'+n+'"')}if(e.stream){t.addEventListener("progress",o)}if(e.type==="image"){t.addEventListener("load",l)}else{let e=false;let n=false;t.addEventListener("loadedmetadata",function(){n=true;if(e){l()}});t.addEventListener("canplay",function(){e=true;if(n){l()}})}t.addEventListener("error",p);function d(){if(e.stream){t.removeEventListener("progress",o)}if(e.type==="image"){t.addEventListener("load",l)}else{t.addEventListener("canplay",l)}t.removeEventListener("error",p)}function _(){if(s.state===c||s.state===f){return}s.state=f;d();t.src=""}if(e.credentials){t.crossOrigin="use-credentials"}else{t.crossOrigin="anonymous"}t.src=e.src;return s}let b={text:E,binary:function(e){return E(e)},image:function(e){return g(e,document.createElement("img"))},video:function(e){return g(e,document.createElement("video"))},audio:function(e){return g(e,document.createElement("audio"))}};let T=Object.keys(t).map(function(e){let n=t[e];if(typeof n==="string"){n={src:n}}else if(typeof n!=="object"||!n){l('invalid asset definition "'+e+'"')}p(n,a,'asset "'+e+'"');function r(t,r,s){let i=s;if(t in n){i=n[t]}if(r.indexOf(i)<0){l("invalid "+t+' "'+i+'" for asset "'+e+'", possible values: '+r)}return i}function s(t,r,s){let i=s;if(t in n){i=n[t]}else if(r){l("missing "+t+' for asset "'+e+'"')}if(typeof i!=="string"){l("invalid "+t+' for asset "'+e+'", must be a string')}return i}function i(e,t){if(e in n.parser){let t=n.parser[e];if(typeof t!=="function"){l("invalid parser callback "+e+' for asset "'+e+'"')}return t}else{return t}}let f={};if("parser"in n){if(typeof n.parser==="function"){f={data:n.parser}}else if(typeof n.parser==="object"&&n.parser){p(n.parser,o,'parser for asset "'+e+'"');if(!("onData"in n.parser)){l('missing onData callback for parser in asset "'+e+'"')}f={data:i("onData"),done:i("onDone")}}else{l('invalid parser for asset "'+e+'"')}}return{name:e,type:r("type",Object.keys(b),"text"),stream:!!n.stream,credentials:!!n.credentials,src:s("src",true,""),parser:f}}).map(function(e){return b[e.type](e)});function h(e){if(_===f||_===c){return}_=f;T.forEach(function(e){e.cancel()});if(d){if(typeof e==="string"){d(new Error("resl: "+e))}else{d(e)}}else{console.error("resl error:",e)}}function A(e){if(_===f||_===c){return}let t=0;let n=0;T.forEach(function(e){if(e.ready){n+=1}t+=e.progress});if(n===T.length){_=c;r(y)}else{if(s){s(t/T.length,e)}}}if(T.length===0){setTimeout(function(){A("done")},1)}}var y={diffuse:{attributes:["a_position","a_normal","a_uv0"],vertexShader:`\n precision mediump float;\n uniform mat4 model, view, projection;\n\n attribute vec3 a_position;\n attribute vec3 a_normal;\n attribute vec2 a_uv0;\n\n varying vec2 v_uv0;\n\n void main() {\n v_uv0 = a_uv0;\n gl_Position = projection * view * model * vec4(a_position, 1);\n }\n `,fragmentShader:`\n #extension GL_OES_standard_derivatives : enable\n\n precision mediump float;\n uniform sampler2D u_mainTexture;\n uniform vec2 u_mainTextureTiling;\n uniform vec2 u_mainTextureOffset;\n\n varying vec2 v_uv0;\n\n void main () {\n // gl_FragColor = vec4( 1, 1, 1, 1 );\n // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 );\n\n vec2 uv0 = v_uv0 * u_mainTextureTiling + u_mainTextureOffset;\n\n gl_FragColor = texture2D( u_mainTexture, uv0 );\n\n if (!gl_FrontFacing) {\n gl_FragColor *= 0.05;\n }\n }\n `},diffuse_skinning:{attributes:["a_position","a_normal","a_uv0","a_joint","a_weight"],vertexShader:`\n precision mediump float;\n uniform mat4 model, view, projection;\n\n attribute vec3 a_position;\n attribute vec3 a_normal;\n attribute vec2 a_uv0;\n attribute vec4 a_weight;\n attribute vec4 a_joint;\n\n uniform sampler2D u_bonesTexture;\n uniform float u_bonesTextureSize;\n\n varying vec2 v_uv0;\n\n mat4 getBoneMatrix(const in float i) {\n float size = u_bonesTextureSize;\n float j = i * 4.0;\n float x = mod(j, size);\n float y = floor(j / size);\n\n float dx = 1.0 / size;\n float dy = 1.0 / size;\n\n y = dy * (y + 0.5);\n\n vec4 v1 = texture2D(u_bonesTexture, vec2(dx * (x + 0.5), y));\n vec4 v2 = texture2D(u_bonesTexture, vec2(dx * (x + 1.5), y));\n vec4 v3 = texture2D(u_bonesTexture, vec2(dx * (x + 2.5), y));\n vec4 v4 = texture2D(u_bonesTexture, vec2(dx * (x + 3.5), y));\n\n mat4 bone = mat4(v1, v2, v3, v4);\n\n return bone;\n }\n\n void main() {\n v_uv0 = a_uv0;\n mat4 matSkin =\n getBoneMatrix(a_joint.x) * a_weight.x +\n getBoneMatrix(a_joint.y) * a_weight.y +\n getBoneMatrix(a_joint.z) * a_weight.z +\n getBoneMatrix(a_joint.w) * a_weight.w ;\n\n gl_Position = projection * view * model * matSkin * vec4(a_position, 1);\n }\n `,fragmentShader:`\n #extension GL_OES_standard_derivatives : enable\n\n precision mediump float;\n uniform sampler2D u_mainTexture;\n\n varying vec2 v_uv0;\n\n void main () {\n // gl_FragColor = vec4( 1, 1, 1, 1 );\n // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 );\n\n gl_FragColor = texture2D( u_mainTexture, v_uv0 );\n\n if (!gl_FrontFacing) {\n gl_FragColor *= 0.05;\n }\n }\n `}};const _=WebGLRenderingContext.prototype;var E={diffuse:{name:"diffuse",program:"diffuse",parameters:{position:{type:_.FLOAT_VEC3,semantic:"POSITION"},normal:{type:_.FLOAT_VEC3,semantic:"NORMAL"},uv0:{type:_.FLOAT_VEC2,semantic:"TEXCOORD_0"},model:{type:_.FLOAT_MAT4,semantic:"MODEL"},view:{type:_.FLOAT_MAT4,semantic:"VIEW"},projection:{type:_.FLOAT_MAT4,semantic:"PROJECTION"},mainTexture:{type:_.SAMPLER_2D},mainTextureTiling:{type:_.FLOAT_VEC2},mainTextureOffset:{type:_.FLOAT_VEC2}},attributes:{a_position:"position",a_normal:"normal",a_uv0:"uv0"},uniforms:{model:"model",u_mainTexture:"mainTexture",u_mainTextureTiling:"mainTextureTiling",u_mainTextureOffset:"mainTextureOffset"}},diffuse_skinning:{name:"diffuse_skinning",program:"diffuse_skinning",parameters:{position:{type:_.FLOAT_VEC3,semantic:"POSITION"},normal:{type:_.FLOAT_VEC3,semantic:"NORMAL"},uv0:{type:_.FLOAT_VEC2,semantic:"TEXCOORD_0"},joint:{type:_.FLOAT_VEC4,semantic:"JOINT"},weight:{type:_.FLOAT_VEC4,semantic:"WEIGHT"},model:{type:_.FLOAT_MAT4,semantic:"MODEL"},view:{type:_.FLOAT_MAT4,semantic:"VIEW"},projection:{type:_.FLOAT_MAT4,semantic:"PROJECTION"},mainTexture:{type:_.SAMPLER_2D},bonesTexture:{type:_.SAMPLER_2D},bonesTextureSize:{type:_.FLOAT}},attributes:{a_position:"position",a_normal:"normal",a_uv0:"uv0",a_joint:"joint",a_weight:"weight"},uniforms:{model:"model",u_bonesTexture:"bonesTexture",u_bonesTextureSize:"bonesTextureSize",u_mainTexture:"mainTexture"}}};const g=WebGLRenderingContext.prototype;let b={};for(let e in y){b[e]=y[e]}let T={};for(let e in E){T[e]=E[e]}function h(e){if(e===g.REPEAT){return"repeat"}else if(e===g.CLAMP_TO_EDGE){return"clamp"}else if(e===g.MIRRORED_REPEAT){return"mirror"}return"repeat"}function A(e){if(e===g.NEAREST){return"nearest"}else if(e===g.LINEAR){return"linear"}else if(e===g.LINEAR_MIPMAP_LINEAR){return"linear mipmap linear"}else if(e===g.NEAREST_MIPMAP_LINEAR){return"nearest mipmap linear"}else if(e===g.LINEAR_MIPMAP_NEAREST){return"linear mipmap nearest"}else if(e===g.NEAREST_MIPMAP_NEAREST){return"nearest mipmap nearest"}return"nearest mipmap linear"}function L(e,t){e.nodes.forEach(e=>{t(e);n.utils.walk(e,e=>{return t(e)})})}function O(e,t,r){if(t._parent){return n.utils.replace(t,r)}for(let n=0;n{let a=e.nodes[s];let o=new n.Node(a.name);let f;o._id=s;o._parent=t;f=a.translation;o.lpos=f?r.vec3.new(f[0],f[1],f[2]):r.vec3.new(0,0,0);f=a.rotation;o.lrot=f?r.quat.new(f[0],f[1],f[2],f[3]):r.quat.new(0,0,0,1);f=a.scale;o.lscale=f?r.vec3.new(f[0],f[1],f[2]):r.vec3.new(1,1,1);o._meshes=a.meshes;o._skeletons=a.skeletons;o._skin=a.skin;o._extras=a.extras;if(a.children){R(e,o,a.children,o.children)}i.push(o)});return i}function x(e,t,s,i){let a=i[s];if(a){if(t){a._parent=t;t.children.push(a)}return}let o=e.nodes[s];a=new n.Node(o.name);a._id=s;a._parent=t;let f;f=o.translation;a.lpos=f?r.vec3.new(f[0],f[1],f[2]):r.vec3.new(0,0,0);f=o.rotation;a.lrot=f?r.quat.new(f[0],f[1],f[2],f[3]):r.quat.new(0,0,0,1);f=o.scale;a.lscale=f?r.vec3.new(f[0],f[1],f[2]):r.vec3.new(1,1,1);i[s]=a;if(t){t.children.push(a)}if(o.children){o.children.forEach(t=>{x(e,a,t,i)})}}function w(e,t,n,r){let s={};let i={};for(let r in t.textures){let a=t.textures[r];let o=t.images[a.source];n[r]=e.texture();i[r]=t.samplers[a.sampler];s[r]={type:"image",src:`${t.baseURL}/${o.uri}`}}d({manifest:s,onError(e){console.error(e)},onDone(e){for(let t in e){let r=i[t];n[t]({data:e[t],wrapS:h(r.wrapS||g.REPEAT),wrapT:h(r.wrapT||g.REPEAT),mag:A(r.magFilter||g.LINEAR),min:A(r.minFilter||g.NEAREST_MIPMAP_LINEAR),mipmap:"nice",flipY:true})}if(r){r(null,n)}}})}function S(e,t,n,r){let s={};let i={};for(let e in t.buffers){let n=t.buffers[e];s[e]={type:"binary",src:`${t.baseURL}/${n.uri}`};i[e]=[]}for(let r in t.bufferViews){let s=t.bufferViews[r];if(s.target===e._gl.ARRAY_BUFFER){n[r]=e.buffer(s.byteLength)}else if(s.target===e._gl.ELEMENT_ARRAY_BUFFER){n[r]=e.elements(s.byteLength)}else{n[r]=new ArrayBuffer}i[s.buffer].push(r)}d({manifest:s,onError(e){console.error(e)},onDone(e){for(let r in e){let s=i[r];s.forEach(s=>{let i=t.bufferViews[s];if(i.target){let t=n[s];t({type:"uint16",data:new Uint8Array(e[r],i.byteOffset,i.byteLength)})}else{n[s]=e[r].slice(i.byteOffset,i.byteOffset+i.byteLength)}})}if(r){r(null,n)}}})}function I(e,t,n,r,s){if(!t.extras||!t.extras.prefabs){if(s){s(null,r)}return}let i=0;let a={};for(let e in t.extras.prefabs){let n=t.extras.prefabs[e];a[e]={type:"text",src:`${t.baseURL}/${n.uri}`,parser:JSON.parse};++i}d({manifest:a,onError(e){console.error(e)},onDone(t){for(let o in t){let f=a[o].src;let u=t[o];let c=f.lastIndexOf("/");if(c!==-1){u.baseURL=f.substring(0,c)}else{u.baseURL=f}M(e,u,n,(e,t)=>{r[o]=t;--i;if(i===0&&s){s(null,r)}})}}})}function M(e,t,n,s){let i=t.scenes[t.scene];let a={name:i.name,json:t,nodes:[],joints:{}};for(let e in t.programs){b[e]=t.programs[e]}for(let e in t.techniques){T[e]=t.techniques[e]}n.programs=b;n.techniques=T;for(let e in t.meshes){n.meshes[e]=t.meshes[e]}for(let e in t.materials){n.materials[e]=t.materials[e]}for(let e in t.accessors){n.accessors[e]=t.accessors[e]}v(e,t,n.commands);R(t,null,i.nodes,a.nodes);for(let e in t.nodes){let n=t.nodes[e];if(n.jointName){x(t,null,e,a.joints)}}w(e,t,n.textures);S(e,t,n.buffers);I(e,t,n,n.prefabs,(e,t)=>{L(a,e=>{console.log(e.name);if(e._extras&&e._extras.prefab){let s=e._extras.prefab;let i=t[s];let o=i.nodes[0];let f=o.deepClone((e,t)=>{e._meshes=t._meshes;e._skeletons=t._skeletons;e._skin=t._skin;e._extras=t._extras});r.vec3.copy(f.lpos,e.lpos);r.vec3.copy(f.lscale,e.lscale);r.quat.copy(f.lrot,e.lrot);O(a,e,f);n._dirty=true;return false}return true})});s(null,a)}function N(e,t,n){d({manifest:{json:{type:"text",src:t,parser:JSON.parse}},onDone(r){let s=t.lastIndexOf("/");if(s!==-1){r.json.baseURL=t.substring(0,s)}else{r.json.baseURL=t}let i={_dirty:false,name:"",json:"",nodes:[],joints:{},techniques:{},programs:{},meshes:{},materials:{},accessors:{},textures:{},buffers:{},prefabs:{},commands:{}};M(e,r.json,i,(e,t)=>{i.name=t.name;i.json=t.json;i.nodes=t.nodes;i.joints=t.joints;if(n){n(null,i)}})},onError(e){console.error(e);n(e)}})}const P=WebGLRenderingContext.prototype;let j=r.mat4.create();function C(e){if(e==="SCALAR"){return 1}else if(e==="VEC2"){return 2}else if(e==="VEC3"){return 3}else if(e==="VEC4"){return 4}else if(e==="MAT2"){return 4}else if(e==="MAT3"){return 9}else if(e==="MAT4"){return 16}return 1}function F(e){if(e===P.POINTS){return"points"}else if(e===P.LINES){return"lines"}else if(e===P.LINE_LOOP){return"line loop"}else if(e===P.LINE_STRIP){return"line strip"}else if(e===P.TRIANGLES){return"triangles"}else if(e===P.TRIANGLE_STRIP){return"triangle strip"}else if(e===P.TRIANGLE_FAN){return"triangle fan"}return"triangles"}function D(e,t,n){let i=e.materials[n.material];let a=i.technique;let o=e.techniques[a];let f=e.programs[o.program];let u={techID:a,primitive:F(n.mode),attributes:{},uniforms:{}};f.attributes.forEach(t=>{let r=o.attributes[t];let s=o.parameters[r];let i=n.attributes[s.semantic];if(!i){console.warn(`can not find attribute by semantic ${s.semantic}`);return}let a=e.accessors[i];u.attributes[t]={buffer:e.buffers[a.bufferView],offset:a.byteOffset,stride:a.byteStride,type:a.componentType,size:C(a.type)}});for(let t in o.uniforms){let n=o.uniforms[t];let r=o.parameters[n];let s=i.values[n];if(s!==undefined){if(r.type===P.SAMPLER_2D){u.uniforms[t]=e.textures[s]}else{u.uniforms[t]=s}continue}if(r.value!==undefined){if(r.type===P.SAMPLER_2D){u.uniforms[t]=e.textures[r.value]}else{u.uniforms[t]=s}}}if(n.indices){let t=e.accessors[n.indices];u.elements=e.buffers[t.bufferView];u.offset=t.byteOffset;u.count=t.count}t.getWorldMatrix(j);u.uniforms.model=r.mat4.array(s.alloc(),j);return u}function k(){s.reset()}e.reset=k;e.load=N;e.buildCommandData=D})(this.regltf=this.regltf||{},window.memop,window.sgraph,window.vmath); 2 | //# sourceMappingURL=regltf.min.js.map -------------------------------------------------------------------------------- /dist/regltf.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["./dist/regltf.dev.js"],"names":["exports","memop","sceneGraph","vmath","f32a_m4_pool","FramePool","Float32Array","configParameters","manifestParameters","parserParameters","STATE_ERROR","STATE_DATA","STATE_COMPLETE","raise","message","Error","checkType","object","parameters","name","Object","keys","forEach","param","indexOf","Loader","cancel","this","state","ready","progress","resl","config","manifest","getFunction","func","onDone","onProgress","onError","assets","loadXHR","request","stream","binary","type","parser","xhr","XMLHttpRequest","asset","loader","onreadystatechange","onReadyStateChange","readyState","responseType","status","abort","response","responseText","data","e","done","notifyProgress","credentials","withCredentials","open","src","send","loadElement","element","handleProgress","lengthComputable","Math","max","loaded","total","onComplete","removeListeners","addEventListener","canPlay","loadedMetaData","removeEventListener","crossOrigin","loaders","text","image","document","createElement","video","audio","pending","map","getParameter","prop","accepted","init","value","getString","required","getParseFunc","dflt","result","console","error","numReady","length","setTimeout","builtinPrograms","diffuse","attributes","vertexShader","fragmentShader","diffuse_skinning","GL$1","WebGLRenderingContext","prototype","builtinTechniques","program","position","FLOAT_VEC3","semantic","normal","uv0","FLOAT_VEC2","model","FLOAT_MAT4","view","projection","mainTexture","SAMPLER_2D","mainTextureTiling","mainTextureOffset","a_position","a_normal","a_uv0","uniforms","u_mainTexture","u_mainTextureTiling","u_mainTextureOffset","joint","FLOAT_VEC4","weight","bonesTexture","bonesTextureSize","FLOAT","a_joint","a_weight","u_bonesTexture","u_bonesTextureSize","GL","_programs","_techniques","_gl2reglWrapMode","wrap","REPEAT","CLAMP_TO_EDGE","MIRRORED_REPEAT","_gl2reglFilter","filter","NEAREST","LINEAR","LINEAR_MIPMAP_LINEAR","NEAREST_MIPMAP_LINEAR","LINEAR_MIPMAP_NEAREST","NEAREST_MIPMAP_NEAREST","_walk","scene","fn","nodes","node","utils","walk","child","_replace","oldNode","newNode","_parent","replace","i","_serializeCommands","regl","json","commands","techID","gltfTechnique","gltfProgram","opts","cull","enable","face","vert","frag","primitive","offset","count","elements","attrName","uniformName","_serializeNodes","parent","childrenIDs","out","nodeID","gltfNode","Node","_id","translation","lpos","vec3","new","rotation","lrot","quat","scale","lscale","_meshes","meshes","_skeletons","skeletons","_skin","skin","_extras","extras","children","push","_serializeJoint","id","joints","childNodeID","_serializeTextures","textures","callback","samplers","gltfTexture","gltfImage","images","source","texture","sampler","baseURL","uri","[object Object]","err","gltfSampler","wrapS","wrapT","mag","magFilter","min","minFilter","mipmap","flipY","_serializeBuffers","buffers","buffer2viewIDs","gltfBuffer","bufferViews","gltfBufferView","target","_gl","ARRAY_BUFFER","buffer","byteLength","ELEMENT_ARRAY_BUFFER","ArrayBuffer","viewIDs","viewID","reglBuf","Uint8Array","byteOffset","slice","_serializePrefabs","prefabs","JSON","parse","url","prefabJson","idx","lastIndexOf","substring","_serializeGLTF","gltfScene","scenes","programs","techniques","materials","accessors","jointName","log","prefab","prefabID","root","prefabNode","deepClone","copy","_dirty","load","GL$2","m4_a","mat4","create","_type2buffersize","_mode2primitive","mode","POINTS","LINES","LINE_LOOP","LINE_STRIP","TRIANGLES","TRIANGLE_STRIP","TRIANGLE_FAN","buildCommandData","gltfPrimitive","gltfMaterial","material","technique","tech","paramName","accessorID","warn","accessor","bufferView","stride","byteStride","componentType","size","values","undefined","indices","getWorldMatrix","array","alloc","reset","regltf","window","sgraph"],"mappings":"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"} -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Example: Simple 6 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const {app, BrowserWindow} = require('electron'); 4 | let win; 5 | 6 | app.on('ready', function () { 7 | win = new BrowserWindow({ 8 | center: true, 9 | width: 800, 10 | height: 600, 11 | webPreferences: { 12 | blinkFeatures: 'PreciseMemoryInfo' 13 | } 14 | }); 15 | win.loadURL(`file://${__dirname}/index.html`); 16 | }); 17 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "main.js" 5 | } -------------------------------------------------------------------------------- /examples/renderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // var SPECTOR = require('spectorjs'); 4 | // var spector = new SPECTOR.Spector(); 5 | // spector.displayUI(); 6 | 7 | let lstats = new window.LStats(document.body); 8 | 9 | const ddraw = window.ddraw; 10 | const {utils} = window.sgraph; 11 | const regltf = window.regltf; 12 | 13 | // init global 14 | let canvasEL = document.getElementById('canvas'); 15 | let shell = new ddraw.Shell(canvasEL); 16 | let renderer = shell._renderer; 17 | let regl = renderer._regl; 18 | 19 | let nodes = []; 20 | let scene = null; 21 | 22 | function _buildNodes(scene) { 23 | let nodes = []; 24 | 25 | scene.nodes.forEach(node => { 26 | let flats = utils.flat(node); 27 | nodes = nodes.concat(flats); 28 | }); 29 | 30 | return nodes; 31 | } 32 | 33 | 34 | let gltfPath = '/Users/johnny/jwu/gltf-exporter/Assets/gltf-exports/scene.gltf'; 35 | // let gltfPath = './assets_02/scene.gltf'; 36 | regltf.load(regl, gltfPath, (err, result) => { 37 | console.log(result); 38 | scene = result; 39 | 40 | // init scene 41 | nodes = _buildNodes(scene); 42 | }); 43 | 44 | // frame 45 | shell.frame(() => { 46 | regltf.reset(); 47 | lstats.tick(); 48 | 49 | if (scene) { 50 | if (scene._dirty) { 51 | nodes = _buildNodes(scene); 52 | scene._dirty = false; 53 | } 54 | 55 | nodes.forEach(node => { 56 | 57 | renderer.drawNode(node); 58 | 59 | if (!node._meshes) { 60 | return; 61 | } 62 | 63 | node._meshes.forEach(id => { 64 | let gltfMesh = scene.meshes[id]; 65 | if (!gltfMesh) { 66 | // console.warn('mesh data not ready'); 67 | return; 68 | } 69 | 70 | gltfMesh.primitives.forEach(gltfPrimitive => { 71 | let data = regltf.buildCommandData(scene, node, gltfPrimitive); 72 | let cmd = scene.commands[data.techID]; 73 | 74 | if (!cmd) { 75 | console.warn(`Can not find draw command for ${data.techID}`); 76 | return; 77 | } 78 | 79 | renderer.addCommand(cmd, data); 80 | }); 81 | }); 82 | }); 83 | } 84 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { f32a_m4_pool } from './lib/pools'; 2 | export { default as load } from './lib/loader'; 3 | export { default as buildCommandData } from './lib/build-cmd-data'; 4 | 5 | export function reset() { 6 | f32a_m4_pool.reset(); 7 | } -------------------------------------------------------------------------------- /lib/build-cmd-data.js: -------------------------------------------------------------------------------- 1 | import {mat4} from 'vmath'; 2 | import { f32a_m4_pool } from './pools'; 3 | 4 | const GL = WebGLRenderingContext.prototype; 5 | let m4_a = mat4.create(); 6 | 7 | function _type2buffersize(type) { 8 | if (type === 'SCALAR') { 9 | return 1; 10 | } else if (type === 'VEC2') { 11 | return 2; 12 | } else if (type === 'VEC3') { 13 | return 3; 14 | } else if (type === 'VEC4') { 15 | return 4; 16 | } else if (type === 'MAT2') { 17 | return 4; 18 | } else if (type === 'MAT3') { 19 | return 9; 20 | } else if (type === 'MAT4') { 21 | return 16; 22 | } 23 | 24 | return 1; 25 | } 26 | 27 | function _mode2primitive(mode) { 28 | if (mode === GL.POINTS) { 29 | return 'points'; 30 | } else if (mode === GL.LINES) { 31 | return 'lines'; 32 | } else if (mode === GL.LINE_LOOP) { 33 | return 'line loop'; 34 | } else if (mode === GL.LINE_STRIP) { 35 | return 'line strip'; 36 | } else if (mode === GL.TRIANGLES) { 37 | return 'triangles'; 38 | } else if (mode === GL.TRIANGLE_STRIP) { 39 | return 'triangle strip'; 40 | } else if (mode === GL.TRIANGLE_FAN) { 41 | return 'triangle fan'; 42 | } 43 | 44 | return 'triangles'; 45 | } 46 | 47 | export default function buildCommandData(scene, node, gltfPrimitive) { 48 | // get material & technique 49 | let gltfMaterial = scene.materials[gltfPrimitive.material]; 50 | // let techID = useSkin ? gltfMaterial.technique + '_skinning' : gltfMaterial.technique; 51 | let techID = gltfMaterial.technique; 52 | let tech = scene.techniques[techID]; 53 | let program = scene.programs[tech.program]; 54 | 55 | let data = { 56 | techID: techID, 57 | primitive: _mode2primitive(gltfPrimitive.mode), 58 | attributes: {}, 59 | uniforms: {}, 60 | }; 61 | 62 | // get attribute accessor 63 | program.attributes.forEach(attrName => { 64 | let paramName = tech.attributes[attrName]; 65 | let param = tech.parameters[paramName]; 66 | let accessorID = gltfPrimitive.attributes[param.semantic]; 67 | if (!accessorID) { 68 | console.warn(`can not find attribute by semantic ${param.semantic}`); 69 | return; 70 | } 71 | 72 | let accessor = scene.accessors[accessorID]; 73 | data.attributes[attrName] = { 74 | buffer: scene.buffers[accessor.bufferView], 75 | offset: accessor.byteOffset, 76 | stride: accessor.byteStride, 77 | // type: _type2buffertype(accessor.componentType), 78 | type: accessor.componentType, 79 | size: _type2buffersize(accessor.type), 80 | }; 81 | }); 82 | 83 | // get uniforms 84 | for (let name in tech.uniforms) { 85 | let paramName = tech.uniforms[name]; 86 | let param = tech.parameters[paramName]; 87 | 88 | let value = gltfMaterial.values[paramName]; 89 | if (value !== undefined) { 90 | if (param.type === GL.SAMPLER_2D) { 91 | data.uniforms[name] = scene.textures[value]; 92 | } else { 93 | data.uniforms[name] = value; 94 | } 95 | continue; 96 | } 97 | 98 | // use default value 99 | if (param.value !== undefined) { 100 | if (param.type === GL.SAMPLER_2D) { 101 | data.uniforms[name] = scene.textures[param.value]; 102 | } else { 103 | data.uniforms[name] = value; 104 | } 105 | } 106 | } 107 | 108 | // get indices accessor 109 | if (gltfPrimitive.indices) { 110 | let accessor = scene.accessors[gltfPrimitive.indices]; 111 | data.elements = scene.buffers[accessor.bufferView]; 112 | data.offset = accessor.byteOffset; 113 | data.count = accessor.count; 114 | } 115 | 116 | // TODO: states 117 | 118 | // node uniforms 119 | node.getWorldMatrix(m4_a); 120 | data.uniforms.model = mat4.array(f32a_m4_pool.add(), m4_a); 121 | 122 | // if (bonesTexture) { 123 | // info.uniforms.u_bonesTexture = bonesTexture; 124 | // info.uniforms.u_bonesTextureSize = bonesTexture.width; 125 | // } 126 | 127 | return data; 128 | } -------------------------------------------------------------------------------- /lib/builtin-programs.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // ======================== 3 | // diffuse 4 | // ======================== 5 | 6 | diffuse: { 7 | attributes: [ 8 | 'a_position', 9 | 'a_normal', 10 | 'a_uv0' 11 | ], 12 | vertexShader: ` 13 | precision mediump float; 14 | uniform mat4 model, view, projection; 15 | 16 | attribute vec3 a_position; 17 | attribute vec3 a_normal; 18 | attribute vec2 a_uv0; 19 | 20 | varying vec2 v_uv0; 21 | 22 | void main() { 23 | v_uv0 = a_uv0; 24 | gl_Position = projection * view * model * vec4(a_position, 1); 25 | } 26 | `, 27 | fragmentShader: ` 28 | #extension GL_OES_standard_derivatives : enable 29 | 30 | precision mediump float; 31 | uniform sampler2D u_mainTexture; 32 | uniform vec2 u_mainTextureTiling; 33 | uniform vec2 u_mainTextureOffset; 34 | 35 | varying vec2 v_uv0; 36 | 37 | void main () { 38 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 39 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 40 | 41 | vec2 uv0 = v_uv0 * u_mainTextureTiling + u_mainTextureOffset; 42 | 43 | gl_FragColor = texture2D( u_mainTexture, uv0 ); 44 | 45 | if (!gl_FrontFacing) { 46 | gl_FragColor *= 0.05; 47 | } 48 | } 49 | `, 50 | }, 51 | 52 | // ======================== 53 | // diffuse_skinning 54 | // ======================== 55 | 56 | diffuse_skinning: { 57 | attributes: [ 58 | 'a_position', 59 | 'a_normal', 60 | 'a_uv0', 61 | 'a_joint', 62 | 'a_weight' 63 | ], 64 | vertexShader: ` 65 | precision mediump float; 66 | uniform mat4 model, view, projection; 67 | 68 | attribute vec3 a_position; 69 | attribute vec3 a_normal; 70 | attribute vec2 a_uv0; 71 | attribute vec4 a_weight; 72 | attribute vec4 a_joint; 73 | 74 | uniform sampler2D u_bonesTexture; 75 | uniform float u_bonesTextureSize; 76 | 77 | varying vec2 v_uv0; 78 | 79 | mat4 getBoneMatrix(const in float i) { 80 | float size = u_bonesTextureSize; 81 | float j = i * 4.0; 82 | float x = mod(j, size); 83 | float y = floor(j / size); 84 | 85 | float dx = 1.0 / size; 86 | float dy = 1.0 / size; 87 | 88 | y = dy * (y + 0.5); 89 | 90 | vec4 v1 = texture2D(u_bonesTexture, vec2(dx * (x + 0.5), y)); 91 | vec4 v2 = texture2D(u_bonesTexture, vec2(dx * (x + 1.5), y)); 92 | vec4 v3 = texture2D(u_bonesTexture, vec2(dx * (x + 2.5), y)); 93 | vec4 v4 = texture2D(u_bonesTexture, vec2(dx * (x + 3.5), y)); 94 | 95 | mat4 bone = mat4(v1, v2, v3, v4); 96 | 97 | return bone; 98 | } 99 | 100 | void main() { 101 | v_uv0 = a_uv0; 102 | mat4 matSkin = 103 | getBoneMatrix(a_joint.x) * a_weight.x + 104 | getBoneMatrix(a_joint.y) * a_weight.y + 105 | getBoneMatrix(a_joint.z) * a_weight.z + 106 | getBoneMatrix(a_joint.w) * a_weight.w ; 107 | 108 | gl_Position = projection * view * model * matSkin * vec4(a_position, 1); 109 | } 110 | `, 111 | fragmentShader: ` 112 | #extension GL_OES_standard_derivatives : enable 113 | 114 | precision mediump float; 115 | uniform sampler2D u_mainTexture; 116 | 117 | varying vec2 v_uv0; 118 | 119 | void main () { 120 | // gl_FragColor = vec4( 1, 1, 1, 1 ); 121 | // gl_FragColor = vec4( v_uv0.x, v_uv0.y, 0, 1 ); 122 | 123 | gl_FragColor = texture2D( u_mainTexture, v_uv0 ); 124 | 125 | if (!gl_FrontFacing) { 126 | gl_FragColor *= 0.05; 127 | } 128 | } 129 | `, 130 | } 131 | }; -------------------------------------------------------------------------------- /lib/builtin-techniques.js: -------------------------------------------------------------------------------- 1 | const GL = WebGLRenderingContext.prototype; 2 | 3 | export default { 4 | diffuse: { 5 | name: 'diffuse', 6 | program: 'diffuse', 7 | parameters: { 8 | position: { 9 | type: GL.FLOAT_VEC3, 10 | semantic: 'POSITION' 11 | }, 12 | normal: { 13 | type: GL.FLOAT_VEC3, 14 | semantic: 'NORMAL' 15 | }, 16 | uv0: { 17 | type: GL.FLOAT_VEC2, 18 | semantic: 'TEXCOORD_0' 19 | }, 20 | model: { 21 | type: GL.FLOAT_MAT4, 22 | semantic: 'MODEL' 23 | }, 24 | view: { 25 | type: GL.FLOAT_MAT4, 26 | semantic: 'VIEW' 27 | }, 28 | projection: { 29 | type: GL.FLOAT_MAT4, 30 | semantic: 'PROJECTION' 31 | }, 32 | mainTexture: { 33 | type: GL.SAMPLER_2D, 34 | }, 35 | mainTextureTiling: { 36 | type: GL.FLOAT_VEC2, 37 | }, 38 | mainTextureOffset: { 39 | type: GL.FLOAT_VEC2, 40 | }, 41 | }, 42 | 43 | attributes: { 44 | a_position: 'position', 45 | a_normal: 'normal', 46 | a_uv0: 'uv0', 47 | }, 48 | 49 | uniforms: { 50 | model: 'model', 51 | // view: 'view', 52 | // projection: 'projection', 53 | u_mainTexture: 'mainTexture', 54 | u_mainTextureTiling: 'mainTextureTiling', 55 | u_mainTextureOffset: 'mainTextureOffset', 56 | }, 57 | }, 58 | 59 | diffuse_skinning: { 60 | name: 'diffuse_skinning', 61 | program: 'diffuse_skinning', 62 | parameters: { 63 | position: { 64 | type: GL.FLOAT_VEC3, 65 | semantic: 'POSITION' 66 | }, 67 | normal: { 68 | type: GL.FLOAT_VEC3, 69 | semantic: 'NORMAL' 70 | }, 71 | uv0: { 72 | type: GL.FLOAT_VEC2, 73 | semantic: 'TEXCOORD_0' 74 | }, 75 | joint: { 76 | type: GL.FLOAT_VEC4, 77 | semantic: 'JOINT' 78 | }, 79 | weight: { 80 | type: GL.FLOAT_VEC4, 81 | semantic: 'WEIGHT' 82 | }, 83 | model: { 84 | type: GL.FLOAT_MAT4, 85 | semantic: 'MODEL' 86 | }, 87 | view: { 88 | type: GL.FLOAT_MAT4, 89 | semantic: 'VIEW' 90 | }, 91 | projection: { 92 | type: GL.FLOAT_MAT4, 93 | semantic: 'PROJECTION' 94 | }, 95 | mainTexture: { 96 | type: GL.SAMPLER_2D, 97 | }, 98 | bonesTexture: { 99 | type: GL.SAMPLER_2D, 100 | }, 101 | bonesTextureSize: { 102 | type: GL.FLOAT, 103 | }, 104 | }, 105 | 106 | attributes: { 107 | a_position: 'position', 108 | a_normal: 'normal', 109 | a_uv0: 'uv0', 110 | a_joint: 'joint', 111 | a_weight: 'weight', 112 | }, 113 | 114 | uniforms: { 115 | model: 'model', 116 | // view: 'view', 117 | // projection: 'projection', 118 | u_bonesTexture: 'bonesTexture', 119 | u_bonesTextureSize: 'bonesTextureSize', 120 | u_mainTexture: 'mainTexture', 121 | }, 122 | }, 123 | }; -------------------------------------------------------------------------------- /lib/loader.js: -------------------------------------------------------------------------------- 1 | import {Node, utils} from 'scene-graph'; 2 | import {vec3, quat} from 'vmath'; 3 | 4 | import resl from './resl'; 5 | import builtinPrograms from './builtin-programs'; 6 | import builtinTechniques from './builtin-techniques'; 7 | 8 | const GL = WebGLRenderingContext.prototype; 9 | 10 | let _programs = {}; 11 | for (let name in builtinPrograms) { 12 | _programs[name] = builtinPrograms[name]; 13 | } 14 | 15 | let _techniques = {}; 16 | for (let name in builtinTechniques) { 17 | _techniques[name] = builtinTechniques[name]; 18 | } 19 | 20 | function _gl2reglWrapMode(wrap) { 21 | if (wrap === GL.REPEAT) { 22 | return 'repeat'; 23 | } else if (wrap === GL.CLAMP_TO_EDGE) { 24 | return 'clamp'; 25 | } else if (wrap === GL.MIRRORED_REPEAT) { 26 | return 'mirror'; 27 | } 28 | 29 | return 'repeat'; 30 | } 31 | 32 | function _gl2reglFilter(filter) { 33 | if (filter === GL.NEAREST) { 34 | return 'nearest'; 35 | } else if (filter === GL.LINEAR) { 36 | return 'linear'; 37 | } else if (filter === GL.LINEAR_MIPMAP_LINEAR) { 38 | return 'linear mipmap linear'; 39 | } else if (filter === GL.NEAREST_MIPMAP_LINEAR) { 40 | return 'nearest mipmap linear'; 41 | } else if (filter === GL.LINEAR_MIPMAP_NEAREST) { 42 | return 'linear mipmap nearest'; 43 | } else if (filter === GL.NEAREST_MIPMAP_NEAREST) { 44 | return 'nearest mipmap nearest'; 45 | } 46 | 47 | return 'nearest mipmap linear'; 48 | } 49 | 50 | function _walk(scene, fn) { 51 | scene.nodes.forEach(node => { 52 | fn(node); 53 | 54 | utils.walk(node, child => { 55 | return fn(child); 56 | }); 57 | }); 58 | } 59 | 60 | function _replace(scene, oldNode, newNode) { 61 | if (oldNode._parent) { 62 | return utils.replace(oldNode, newNode); 63 | } 64 | 65 | for (let i = 0; i < scene.nodes.length; ++i) { 66 | if (scene.nodes[i] === oldNode) { 67 | scene.nodes[i] = newNode; 68 | return; 69 | } 70 | } 71 | } 72 | 73 | function _serializeCommands(regl, json, commands) { 74 | for ( let techID in _techniques ) { 75 | let gltfTechnique = _techniques[techID]; 76 | let gltfProgram = _programs[gltfTechnique.program]; 77 | 78 | // draw options 79 | let opts = { 80 | // frontFace: 'ccw', 81 | cull: { 82 | enable: true, 83 | face: 'back' 84 | }, 85 | 86 | vert: gltfProgram.vertexShader, 87 | frag: gltfProgram.fragmentShader, 88 | 89 | primitive: regl.prop('primitive'), 90 | offset: regl.prop('offset'), 91 | count: regl.prop('count'), 92 | 93 | elements: regl.prop('elements'), 94 | attributes: {}, 95 | uniforms: {}, 96 | }; 97 | for (let attrName in gltfTechnique.attributes) { 98 | opts.attributes[attrName] = regl.prop(`attributes.${attrName}`); 99 | } 100 | for (let uniformName in gltfTechnique.uniforms) { 101 | opts.uniforms[uniformName] = regl.prop(`uniforms.${uniformName}`); 102 | } 103 | // TODO: states 104 | // TODO: functions 105 | 106 | // finalize 107 | commands[techID] = regl(opts); 108 | } 109 | } 110 | 111 | function _serializeNodes(json, parent, childrenIDs, out) { 112 | childrenIDs.forEach(nodeID => { 113 | let gltfNode = json.nodes[nodeID]; 114 | let node = new Node(gltfNode.name); 115 | let data; 116 | 117 | node._id = nodeID; 118 | node._parent = parent; 119 | 120 | data = gltfNode.translation; 121 | node.lpos = data ? 122 | vec3.new(data[0], data[1], data[2]) : 123 | vec3.new(0, 0, 0) 124 | ; 125 | 126 | data = gltfNode.rotation; 127 | node.lrot = data ? 128 | quat.new(data[0], data[1], data[2], data[3]) : 129 | quat.new(0, 0, 0, 1) 130 | ; 131 | 132 | data = gltfNode.scale; 133 | node.lscale = data ? 134 | vec3.new(data[0], data[1], data[2]) : 135 | vec3.new(1, 1, 1) 136 | ; 137 | 138 | node._meshes = gltfNode.meshes; 139 | node._skeletons = gltfNode.skeletons; 140 | node._skin = gltfNode.skin; 141 | node._extras = gltfNode.extras; 142 | 143 | if (gltfNode.children) { 144 | _serializeNodes(json, node, gltfNode.children, node.children); 145 | } 146 | 147 | out.push(node); 148 | }); 149 | 150 | return out; 151 | } 152 | 153 | function _serializeJoint(json, parent, id, joints) { 154 | let node = joints[id]; 155 | if (node) { 156 | if (parent) { 157 | node._parent = parent; 158 | parent.children.push(node); 159 | } 160 | 161 | return; 162 | } 163 | 164 | let gltfNode = json.nodes[id]; 165 | node = new Node(gltfNode.name); 166 | 167 | node._id = id; 168 | node._parent = parent; 169 | 170 | let data; 171 | data = gltfNode.translation; 172 | node.lpos = data ? 173 | vec3.new(data[0], data[1], data[2]) : 174 | vec3.new(0, 0, 0) 175 | ; 176 | 177 | data = gltfNode.rotation; 178 | node.lrot = data ? 179 | quat.new(data[0], data[1], data[2], data[3]) : 180 | quat.new(0, 0, 0, 1) 181 | ; 182 | 183 | data = gltfNode.scale; 184 | node.lscale = data ? 185 | vec3.new(data[0], data[1], data[2]) : 186 | vec3.new(1, 1, 1) 187 | ; 188 | 189 | joints[id] = node; 190 | 191 | if (parent) { 192 | parent.children.push(node); 193 | } 194 | 195 | if (gltfNode.children) { 196 | gltfNode.children.forEach(childNodeID => { 197 | _serializeJoint(json, node, childNodeID, joints); 198 | }); 199 | } 200 | } 201 | 202 | function _serializeTextures(regl, json, textures, callback) { 203 | let manifest = {}; 204 | let samplers = {}; 205 | 206 | for ( let name in json.textures ) { 207 | let gltfTexture = json.textures[name]; 208 | let gltfImage = json.images[gltfTexture.source]; 209 | 210 | textures[name] = regl.texture(); 211 | samplers[name] = json.samplers[gltfTexture.sampler]; 212 | manifest[name] = { 213 | type: 'image', 214 | src: `${json.baseURL}/${gltfImage.uri}` 215 | }; 216 | } 217 | 218 | resl({ 219 | manifest, 220 | onError(err) { 221 | console.error(err); 222 | }, 223 | onDone(assets) { 224 | for (let name in assets) { 225 | let gltfSampler = samplers[name]; 226 | 227 | textures[name]({ 228 | data: assets[name], 229 | wrapS: _gl2reglWrapMode(gltfSampler.wrapS || GL.REPEAT), 230 | wrapT: _gl2reglWrapMode(gltfSampler.wrapT || GL.REPEAT), 231 | mag: _gl2reglFilter(gltfSampler.magFilter || GL.LINEAR), 232 | min: _gl2reglFilter(gltfSampler.minFilter || GL.NEAREST_MIPMAP_LINEAR), 233 | mipmap: 'nice', 234 | flipY: true 235 | }); 236 | } 237 | 238 | if (callback) { 239 | callback(null, textures); 240 | } 241 | }, 242 | }); 243 | } 244 | 245 | function _serializeBuffers(regl, json, buffers, callback) { 246 | let manifest = {}; 247 | let buffer2viewIDs = {}; 248 | 249 | for ( let id in json.buffers ) { 250 | let gltfBuffer = json.buffers[id]; 251 | manifest[id] = { 252 | type: 'binary', 253 | src: `${json.baseURL}/${gltfBuffer.uri}` 254 | }; 255 | buffer2viewIDs[id] = []; 256 | } 257 | 258 | for ( let id in json.bufferViews ) { 259 | let gltfBufferView = json.bufferViews[id]; 260 | if ( gltfBufferView.target === regl._gl.ARRAY_BUFFER ) { 261 | buffers[id] = regl.buffer(gltfBufferView.byteLength); 262 | } else if ( gltfBufferView.target === regl._gl.ELEMENT_ARRAY_BUFFER ) { 263 | buffers[id] = regl.elements(gltfBufferView.byteLength); 264 | } else { 265 | buffers[id] = new ArrayBuffer(); 266 | } 267 | 268 | buffer2viewIDs[gltfBufferView.buffer].push(id); 269 | } 270 | 271 | resl({ 272 | manifest, 273 | onError(err) { 274 | console.error(err); 275 | }, 276 | onDone(assets) { 277 | for ( let id in assets ) { 278 | let viewIDs = buffer2viewIDs[id]; 279 | viewIDs.forEach(viewID => { 280 | let gltfBufferView = json.bufferViews[viewID]; 281 | if ( gltfBufferView.target ) { 282 | let reglBuf = buffers[viewID]; 283 | reglBuf({ 284 | type: 'uint16', // HACK 285 | data: new Uint8Array(assets[id], gltfBufferView.byteOffset, gltfBufferView.byteLength) 286 | }); 287 | } else { 288 | // ArrayBuffer.slice 289 | buffers[viewID] = assets[id].slice( 290 | gltfBufferView.byteOffset, 291 | gltfBufferView.byteOffset + gltfBufferView.byteLength 292 | ); 293 | } 294 | }); 295 | } 296 | 297 | if (callback) { 298 | callback(null, buffers); 299 | } 300 | } 301 | }); 302 | } 303 | 304 | function _serializePrefabs(regl, json, scene, prefabs, callback) { 305 | if (!json.extras || !json.extras.prefabs) { 306 | if (callback) { 307 | callback(null, prefabs); 308 | } 309 | 310 | return; 311 | } 312 | 313 | let count = 0; 314 | let manifest = {}; 315 | for (let id in json.extras.prefabs) { 316 | let asset = json.extras.prefabs[id]; 317 | manifest[id] = { 318 | type: 'text', 319 | src: `${json.baseURL}/${asset.uri}`, 320 | parser: JSON.parse 321 | }; 322 | ++count; 323 | } 324 | 325 | resl({ 326 | manifest, 327 | onError(err) { 328 | console.error(err); 329 | }, 330 | onDone(assets) { 331 | for ( let id in assets ) { 332 | let url = manifest[id].src; 333 | let prefabJson = assets[id]; 334 | 335 | let idx = url.lastIndexOf('/'); 336 | if (idx !== -1) { 337 | prefabJson.baseURL = url.substring(0, idx); 338 | } else { 339 | prefabJson.baseURL = url; 340 | } 341 | 342 | _serializeGLTF(regl, prefabJson, scene, (err, result) => { 343 | prefabs[id] = result; 344 | 345 | --count; 346 | if (count === 0 && callback) { 347 | callback(null, prefabs); 348 | } 349 | }); 350 | } 351 | } 352 | }); 353 | } 354 | 355 | function _serializeGLTF(regl, json, scene, callback) { 356 | let gltfScene = json.scenes[json.scene]; 357 | let result = { 358 | name: gltfScene.name, 359 | json: json, 360 | nodes: [], 361 | joints: {}, 362 | }; 363 | 364 | // update programs & techinques 365 | for (let name in json.programs) { 366 | _programs[name] = json.programs[name]; 367 | } 368 | for ( let name in json.techniques ) { 369 | _techniques[name] = json.techniques[name]; 370 | } 371 | 372 | // serialize gltf globally 373 | scene.programs = _programs; 374 | scene.techniques = _techniques; 375 | for ( let id in json.meshes ) { 376 | scene.meshes[id] = json.meshes[id]; 377 | } 378 | for ( let id in json.materials ) { 379 | scene.materials[id] = json.materials[id]; 380 | } 381 | for ( let id in json.accessors ) { 382 | scene.accessors[id] = json.accessors[id]; 383 | } 384 | 385 | // serialize commands 386 | _serializeCommands(regl, json, scene.commands); 387 | 388 | // serialize nodes 389 | _serializeNodes(json, null, gltfScene.nodes, result.nodes); 390 | 391 | // serialize joints 392 | for (let id in json.nodes) { 393 | let node = json.nodes[id]; 394 | if (node.jointName) { 395 | _serializeJoint(json, null, id, result.joints); 396 | } 397 | } 398 | 399 | // serialize textures 400 | _serializeTextures(regl, json, scene.textures); 401 | 402 | // serialize buffers 403 | _serializeBuffers(regl, json, scene.buffers); 404 | 405 | // serialize extras.prefabs 406 | _serializePrefabs(regl, json, scene, scene.prefabs, (err, prefabs) => { 407 | _walk(result, child => { 408 | console.log(child.name); 409 | if (child._extras && child._extras.prefab) { 410 | let prefabID = child._extras.prefab; 411 | let prefab = prefabs[prefabID]; 412 | let root = prefab.nodes[0]; 413 | let prefabNode = root.deepClone((newNode, oldNode) => { 414 | newNode._meshes = oldNode._meshes; 415 | newNode._skeletons = oldNode._skeletons; 416 | newNode._skin = oldNode._skin; 417 | newNode._extras = oldNode._extras; 418 | }); 419 | vec3.copy(prefabNode.lpos, child.lpos); 420 | vec3.copy(prefabNode.lscale, child.lscale); 421 | quat.copy(prefabNode.lrot, child.lrot); 422 | 423 | _replace(result, child, prefabNode); 424 | 425 | scene._dirty = true; 426 | 427 | return false; // stop walking on child 428 | } 429 | 430 | return true; 431 | }); 432 | }); 433 | 434 | // done 435 | callback(null, result); 436 | } 437 | 438 | export default function load (regl, url, callback) { 439 | resl({ 440 | manifest: { 441 | json: { 442 | type: 'text', 443 | src: url, 444 | parser: JSON.parse 445 | } 446 | }, 447 | 448 | onDone(assets) { 449 | let idx = url.lastIndexOf('/'); 450 | if (idx !== -1) { 451 | assets.json.baseURL = url.substring(0,idx); 452 | } else { 453 | assets.json.baseURL = url; 454 | } 455 | 456 | let scene = { 457 | _dirty: false, 458 | 459 | // 460 | name: '', 461 | json: '', 462 | nodes: [], 463 | joints: {}, 464 | 465 | // gltf (global) 466 | techniques: {}, 467 | programs: {}, 468 | meshes: {}, 469 | materials: {}, 470 | accessors: {}, 471 | 472 | // resources 473 | textures: {}, // texture id to regl texture 474 | buffers: {}, // buffer-view id to regl buffer 475 | prefabs: {}, // serialized prefabs 476 | commands: {}, // technique id to regl command 477 | }; 478 | _serializeGLTF(regl, assets.json, scene, (err,result) => { 479 | scene.name = result.name; 480 | scene.json = result.json; 481 | scene.nodes = result.nodes; 482 | scene.joints = result.joints; 483 | 484 | if (callback) { 485 | callback(null, scene); 486 | } 487 | }); 488 | }, 489 | 490 | onError(err) { 491 | console.error(err); 492 | callback(err); 493 | } 494 | }); 495 | } -------------------------------------------------------------------------------- /lib/pools.js: -------------------------------------------------------------------------------- 1 | import { RecyclePool } from 'memop'; 2 | 3 | export let f32a_m4_pool = new RecyclePool(function() { 4 | return new Float32Array(16); 5 | }, 256); -------------------------------------------------------------------------------- /lib/resl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * (c) 2016 Mikola Lysenko. MIT License 3 | * https://github.com/regl-project/resl 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /* global XMLHttpRequest */ 9 | const configParameters = [ 10 | 'manifest', 11 | 'onDone', 12 | 'onProgress', 13 | 'onError' 14 | ]; 15 | 16 | const manifestParameters = [ 17 | 'type', 18 | 'src', 19 | 'stream', 20 | 'credentials', 21 | 'parser' 22 | ]; 23 | 24 | const parserParameters = [ 25 | 'onData', 26 | 'onDone' 27 | ]; 28 | 29 | const STATE_ERROR = -1; 30 | const STATE_DATA = 0; 31 | const STATE_COMPLETE = 1; 32 | 33 | function raise(message) { 34 | throw new Error('resl: ' + message); 35 | } 36 | 37 | function checkType(object, parameters, name) { 38 | Object.keys(object).forEach(function (param) { 39 | if (parameters.indexOf(param) < 0) { 40 | raise('invalid parameter "' + param + '" in ' + name); 41 | } 42 | }); 43 | } 44 | 45 | function Loader(name, cancel) { 46 | this.state = STATE_DATA; 47 | this.ready = false; 48 | this.progress = 0; 49 | this.name = name; 50 | this.cancel = cancel; 51 | } 52 | 53 | export default function resl(config) { 54 | if (typeof config !== 'object' || !config) { 55 | raise('invalid or missing configuration'); 56 | } 57 | 58 | checkType(config, configParameters, 'config'); 59 | 60 | let manifest = config.manifest; 61 | if (typeof manifest !== 'object' || !manifest) { 62 | raise('missing manifest'); 63 | } 64 | 65 | function getFunction(name) { 66 | if (name in config) { 67 | let func = config[name]; 68 | if (typeof func !== 'function') { 69 | raise('invalid callback "' + name + '"'); 70 | } 71 | return func; 72 | } 73 | return null; 74 | } 75 | 76 | let onDone = getFunction('onDone'); 77 | if (!onDone) { 78 | raise('missing onDone() callback'); 79 | } 80 | 81 | let onProgress = getFunction('onProgress'); 82 | let onError = getFunction('onError'); 83 | 84 | let assets = {}; 85 | 86 | let state = STATE_DATA; 87 | 88 | function loadXHR(request) { 89 | let name = request.name; 90 | let stream = request.stream; 91 | let binary = request.type === 'binary'; 92 | let parser = request.parser; 93 | 94 | let xhr = new XMLHttpRequest(); 95 | let asset = null; 96 | 97 | let loader = new Loader(name, cancel); 98 | 99 | if (stream) { 100 | xhr.onreadystatechange = onReadyStateChange; 101 | } else { 102 | xhr.onreadystatechange = function () { 103 | if (xhr.readyState === 4) { 104 | onReadyStateChange(); 105 | } 106 | }; 107 | } 108 | 109 | if (binary) { 110 | xhr.responseType = 'arraybuffer'; 111 | } 112 | 113 | function onReadyStateChange() { 114 | if (xhr.readyState < 2 || 115 | loader.state === STATE_COMPLETE || 116 | loader.state === STATE_ERROR) { 117 | return; 118 | } 119 | if (xhr.status !== 200) { 120 | return abort('error loading resource "' + request.name + '"'); 121 | } 122 | if (xhr.readyState > 2 && loader.state === STATE_DATA) { 123 | let response; 124 | if (request.type === 'binary') { 125 | response = xhr.response; 126 | } else { 127 | response = xhr.responseText; 128 | } 129 | if (parser.data) { 130 | try { 131 | asset = parser.data(response); 132 | } catch (e) { 133 | return abort(e); 134 | } 135 | } else { 136 | asset = response; 137 | } 138 | } 139 | if (xhr.readyState > 3 && loader.state === STATE_DATA) { 140 | if (parser.done) { 141 | try { 142 | asset = parser.done(); 143 | } catch (e) { 144 | return abort(e); 145 | } 146 | } 147 | loader.state = STATE_COMPLETE; 148 | } 149 | assets[name] = asset; 150 | loader.progress = 0.75 * loader.progress + 0.25; 151 | loader.ready = 152 | (request.stream && !!asset) || 153 | loader.state === STATE_COMPLETE; 154 | notifyProgress(); 155 | } 156 | 157 | function cancel() { 158 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 159 | return; 160 | } 161 | xhr.onreadystatechange = null; 162 | xhr.abort(); 163 | loader.state = STATE_ERROR; 164 | } 165 | 166 | // set up request 167 | if (request.credentials) { 168 | xhr.withCredentials = true; 169 | } 170 | xhr.open('GET', request.src, true); 171 | xhr.send(); 172 | 173 | return loader; 174 | } 175 | 176 | function loadElement(request, element) { 177 | let name = request.name; 178 | let parser = request.parser; 179 | 180 | let loader = new Loader(name, cancel); 181 | let asset = element; 182 | 183 | function handleProgress() { 184 | if (loader.state === STATE_DATA) { 185 | if (parser.data) { 186 | try { 187 | asset = parser.data(element); 188 | } catch (e) { 189 | return abort(e); 190 | } 191 | } else { 192 | asset = element; 193 | } 194 | } 195 | } 196 | 197 | function onProgress(e) { 198 | handleProgress(); 199 | assets[name] = asset; 200 | if (e.lengthComputable) { 201 | loader.progress = Math.max(loader.progress, e.loaded / e.total); 202 | } else { 203 | loader.progress = 0.75 * loader.progress + 0.25; 204 | } 205 | notifyProgress(name); 206 | } 207 | 208 | function onComplete() { 209 | handleProgress(); 210 | if (loader.state === STATE_DATA) { 211 | if (parser.done) { 212 | try { 213 | asset = parser.done(); 214 | } catch (e) { 215 | return abort(e); 216 | } 217 | } 218 | loader.state = STATE_COMPLETE; 219 | } 220 | loader.progress = 1; 221 | loader.ready = true; 222 | assets[name] = asset; 223 | removeListeners(); 224 | notifyProgress('finish ' + name); 225 | } 226 | 227 | function onError() { 228 | abort('error loading asset "' + name + '"'); 229 | } 230 | 231 | if (request.stream) { 232 | element.addEventListener('progress', onProgress); 233 | } 234 | if (request.type === 'image') { 235 | element.addEventListener('load', onComplete); 236 | } else { 237 | let canPlay = false; 238 | let loadedMetaData = false; 239 | element.addEventListener('loadedmetadata', function () { 240 | loadedMetaData = true; 241 | if (canPlay) { 242 | onComplete(); 243 | } 244 | }); 245 | element.addEventListener('canplay', function () { 246 | canPlay = true; 247 | if (loadedMetaData) { 248 | onComplete(); 249 | } 250 | }); 251 | } 252 | element.addEventListener('error', onError); 253 | 254 | function removeListeners() { 255 | if (request.stream) { 256 | element.removeEventListener('progress', onProgress); 257 | } 258 | if (request.type === 'image') { 259 | element.addEventListener('load', onComplete); 260 | } else { 261 | element.addEventListener('canplay', onComplete); 262 | } 263 | element.removeEventListener('error', onError); 264 | } 265 | 266 | function cancel() { 267 | if (loader.state === STATE_COMPLETE || loader.state === STATE_ERROR) { 268 | return; 269 | } 270 | 271 | loader.state = STATE_ERROR; 272 | removeListeners(); 273 | element.src = ''; 274 | } 275 | 276 | // set up request 277 | if (request.credentials) { 278 | element.crossOrigin = 'use-credentials'; 279 | } else { 280 | element.crossOrigin = 'anonymous'; 281 | } 282 | element.src = request.src; 283 | 284 | return loader; 285 | } 286 | 287 | let loaders = { 288 | text: loadXHR, 289 | binary: function (request) { 290 | // TODO use fetch API for streaming if supported 291 | return loadXHR(request); 292 | }, 293 | image: function (request) { 294 | return loadElement(request, document.createElement('img')); 295 | }, 296 | video: function (request) { 297 | return loadElement(request, document.createElement('video')); 298 | }, 299 | audio: function (request) { 300 | return loadElement(request, document.createElement('audio')); 301 | } 302 | }; 303 | 304 | // First we parse all objects in order to verify that all type information 305 | // is correct 306 | let pending = Object.keys(manifest).map(function (name) { 307 | let request = manifest[name]; 308 | if (typeof request === 'string') { 309 | request = { 310 | src: request 311 | }; 312 | } else if (typeof request !== 'object' || !request) { 313 | raise('invalid asset definition "' + name + '"'); 314 | } 315 | 316 | checkType(request, manifestParameters, 'asset "' + name + '"'); 317 | 318 | function getParameter(prop, accepted, init) { 319 | let value = init; 320 | if (prop in request) { 321 | value = request[prop]; 322 | } 323 | if (accepted.indexOf(value) < 0) { 324 | raise('invalid ' + prop + ' "' + value + '" for asset "' + name + '", possible values: ' + accepted); 325 | } 326 | return value; 327 | } 328 | 329 | function getString(prop, required, init) { 330 | let value = init; 331 | if (prop in request) { 332 | value = request[prop]; 333 | } else if (required) { 334 | raise('missing ' + prop + ' for asset "' + name + '"'); 335 | } 336 | if (typeof value !== 'string') { 337 | raise('invalid ' + prop + ' for asset "' + name + '", must be a string'); 338 | } 339 | return value; 340 | } 341 | 342 | function getParseFunc(name, dflt) { 343 | if (name in request.parser) { 344 | let result = request.parser[name]; 345 | if (typeof result !== 'function') { 346 | raise('invalid parser callback ' + name + ' for asset "' + name + '"'); 347 | } 348 | return result; 349 | } else { 350 | return dflt; 351 | } 352 | } 353 | 354 | let parser = {}; 355 | if ('parser' in request) { 356 | if (typeof request.parser === 'function') { 357 | parser = { 358 | data: request.parser 359 | }; 360 | } else if (typeof request.parser === 'object' && request.parser) { 361 | checkType(request.parser, parserParameters, 'parser for asset "' + name + '"'); 362 | if (!('onData' in request.parser)) { 363 | raise('missing onData callback for parser in asset "' + name + '"'); 364 | } 365 | parser = { 366 | data: getParseFunc('onData'), 367 | done: getParseFunc('onDone') 368 | }; 369 | } else { 370 | raise('invalid parser for asset "' + name + '"'); 371 | } 372 | } 373 | 374 | return { 375 | name: name, 376 | type: getParameter('type', Object.keys(loaders), 'text'), 377 | stream: !!request.stream, 378 | credentials: !!request.credentials, 379 | src: getString('src', true, ''), 380 | parser: parser 381 | }; 382 | }).map(function (request) { 383 | return (loaders[request.type])(request); 384 | }); 385 | 386 | function abort(message) { 387 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 388 | return; 389 | } 390 | state = STATE_ERROR; 391 | pending.forEach(function (loader) { 392 | loader.cancel(); 393 | }); 394 | if (onError) { 395 | if (typeof message === 'string') { 396 | onError(new Error('resl: ' + message)); 397 | } else { 398 | onError(message); 399 | } 400 | } else { 401 | console.error('resl error:', message); 402 | } 403 | } 404 | 405 | function notifyProgress(message) { 406 | if (state === STATE_ERROR || state === STATE_COMPLETE) { 407 | return; 408 | } 409 | 410 | let progress = 0; 411 | let numReady = 0; 412 | pending.forEach(function (loader) { 413 | if (loader.ready) { 414 | numReady += 1; 415 | } 416 | progress += loader.progress; 417 | }); 418 | 419 | if (numReady === pending.length) { 420 | state = STATE_COMPLETE; 421 | onDone(assets); 422 | } else { 423 | if (onProgress) { 424 | onProgress(progress / pending.length, message); 425 | } 426 | } 427 | } 428 | 429 | if (pending.length === 0) { 430 | setTimeout(function () { 431 | notifyProgress('done'); 432 | }, 1); 433 | } 434 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regltf", 3 | "version": "1.0.0", 4 | "description": "Visualizing and monitor your performance.", 5 | "main": "dist/regltf", 6 | "scripts": { 7 | "build:dev": "rollup -c ./script/rollup.config.js", 8 | "build:min": "uglifyjs ./dist/regltf.dev.js --mangle --source-map url=regltf.min.js.map -o ./dist/regltf.min.js", 9 | "release": "npm run build:dev && npm run build:min", 10 | "start": "electron", 11 | "server": "preview -p 8002 -e examples", 12 | "dev": "rollup -w -c ./script/rollup.config.js", 13 | "test": "npm run build:dev && tap test/*.spec.js" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/gamedev-js/regltf.git" 18 | }, 19 | "keywords": [ 20 | "gltf" 21 | ], 22 | "author": "jwu", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/gamedev-js/regltf/issues" 26 | }, 27 | "homepage": "https://github.com/gamedev-js/regltf/issues", 28 | "dependencies": { 29 | "memop": "^1.1.0", 30 | "scene-graph": "^1.0.3", 31 | "vmath": "^1.2.0" 32 | }, 33 | "devDependencies": { 34 | "debug-draw": "^1.0.0", 35 | "electron": "^1.7.3", 36 | "fs-jetpack": "^0.13.0", 37 | "lstats.js": "^1.2.2", 38 | "preview-server": "^1.0.7", 39 | "regl": "^1.3.0", 40 | "rollup": "^0.54.1", 41 | "rollup-plugin-buble": "^0.18.0", 42 | "spectorjs": "^0.0.10", 43 | "uglify-es": "^3.0.15", 44 | "vconsole": "^2.5.2" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /script/rollup.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const buble = require('rollup-plugin-buble'); 4 | const fsJetpack = require('fs-jetpack'); 5 | const pjson = require('../package.json'); 6 | 7 | let banner = ` 8 | /* 9 | * ${pjson.name} v${pjson.version} 10 | * (c) ${new Date().getFullYear()} @gamedev-js 11 | * Released under the MIT License. 12 | */ 13 | `; 14 | 15 | let dest = './dist'; 16 | let file = 'regltf'; 17 | let name = 'regltf'; 18 | let sourcemap = true; 19 | let globals = { 20 | 'memop': 'window.memop', 21 | 'vmath': 'window.vmath', 22 | 'scene-graph': 'window.sgraph', 23 | 'WebGLRenderingContext': 'window.WebGLRenderingContext', 24 | }; 25 | 26 | // clear directory 27 | fsJetpack.dir(dest, { empty: true }); 28 | 29 | module.exports = { 30 | input: './index.js', 31 | external: [ 32 | 'memop', 33 | 'vmath', 34 | 'scene-graph', 35 | 'WebGLRenderingContext', 36 | ], 37 | plugins: [ 38 | buble(), 39 | ], 40 | output: [ 41 | { 42 | file: `${dest}/${file}.dev.js`, 43 | format: 'iife', 44 | name, 45 | banner, 46 | globals, 47 | sourcemap 48 | }, 49 | { 50 | file: `${dest}/${file}.js`, 51 | format: 'cjs', 52 | name, 53 | banner, 54 | globals, 55 | sourcemap 56 | }, 57 | ], 58 | }; -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | acorn-jsx@^3.0.1: 6 | version "3.0.1" 7 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 8 | dependencies: 9 | acorn "^3.0.4" 10 | 11 | acorn5-object-spread@^4.0.0: 12 | version "4.0.0" 13 | resolved "https://registry.yarnpkg.com/acorn5-object-spread/-/acorn5-object-spread-4.0.0.tgz#d5758081eed97121ab0be47e31caaef2aa399697" 14 | dependencies: 15 | acorn "^5.1.2" 16 | 17 | acorn@^3.0.4: 18 | version "3.3.0" 19 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 20 | 21 | acorn@^5.1.2: 22 | version "5.3.0" 23 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" 24 | 25 | ansi-styles@^3.1.0: 26 | version "3.2.0" 27 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" 28 | dependencies: 29 | color-convert "^1.9.0" 30 | 31 | arr-diff@^2.0.0: 32 | version "2.0.0" 33 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 34 | dependencies: 35 | arr-flatten "^1.0.1" 36 | 37 | arr-flatten@^1.0.1: 38 | version "1.1.0" 39 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 40 | 41 | array-unique@^0.2.1: 42 | version "0.2.1" 43 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 44 | 45 | async@0.9.0: 46 | version "0.9.0" 47 | resolved "https://registry.yarnpkg.com/async/-/async-0.9.0.tgz#ac3613b1da9bed1b47510bb4651b8931e47146c7" 48 | 49 | balanced-match@^0.4.1: 50 | version "0.4.2" 51 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 52 | 53 | brace-expansion@^1.0.0: 54 | version "1.1.6" 55 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 56 | dependencies: 57 | balanced-match "^0.4.1" 58 | concat-map "0.0.1" 59 | 60 | braces@^1.8.2: 61 | version "1.8.5" 62 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 63 | dependencies: 64 | expand-range "^1.8.1" 65 | preserve "^0.2.0" 66 | repeat-element "^1.1.2" 67 | 68 | buble@^0.18.0: 69 | version "0.18.0" 70 | resolved "https://registry.yarnpkg.com/buble/-/buble-0.18.0.tgz#63b338b8248c474b46fd3e3546560ae08d8abe91" 71 | dependencies: 72 | acorn "^5.1.2" 73 | acorn-jsx "^3.0.1" 74 | acorn5-object-spread "^4.0.0" 75 | chalk "^2.1.0" 76 | magic-string "^0.22.4" 77 | minimist "^1.2.0" 78 | os-homedir "^1.0.1" 79 | vlq "^0.2.2" 80 | 81 | chalk@^2.1.0: 82 | version "2.3.0" 83 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" 84 | dependencies: 85 | ansi-styles "^3.1.0" 86 | escape-string-regexp "^1.0.5" 87 | supports-color "^4.0.0" 88 | 89 | color-convert@^1.9.0: 90 | version "1.9.1" 91 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" 92 | dependencies: 93 | color-name "^1.1.1" 94 | 95 | color-name@^1.1.1: 96 | version "1.1.3" 97 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 98 | 99 | colors@1.0.3: 100 | version "1.0.3" 101 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" 102 | 103 | commander@~2.9.0: 104 | version "2.9.0" 105 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 106 | dependencies: 107 | graceful-readlink ">= 1.0.0" 108 | 109 | concat-map@0.0.1: 110 | version "0.0.1" 111 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 112 | 113 | corser@~2.0.0: 114 | version "2.0.1" 115 | resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" 116 | 117 | debug-draw@^1.0.0: 118 | version "1.0.0" 119 | resolved "https://registry.yarnpkg.com/debug-draw/-/debug-draw-1.0.0.tgz#7d2048ff9352caffc1d83daddabab73be6c8d6dd" 120 | dependencies: 121 | input.js "^1.1.2" 122 | regl "^1.3.0" 123 | scene-graph "^1.0.2" 124 | vmath "^1.1.1" 125 | 126 | ecstatic@^1.4.0: 127 | version "1.4.1" 128 | resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-1.4.1.tgz#32cb7b6fa2e290d58668674d115e8f0c3d567d6a" 129 | dependencies: 130 | he "^0.5.0" 131 | mime "^1.2.11" 132 | minimist "^1.1.0" 133 | url-join "^1.0.0" 134 | 135 | escape-string-regexp@^1.0.5: 136 | version "1.0.5" 137 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 138 | 139 | estree-walker@^0.3.0: 140 | version "0.3.1" 141 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" 142 | 143 | eventemitter3@1.x.x: 144 | version "1.2.0" 145 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" 146 | 147 | expand-brackets@^0.1.4: 148 | version "0.1.5" 149 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 150 | dependencies: 151 | is-posix-bracket "^0.1.0" 152 | 153 | expand-range@^1.8.1: 154 | version "1.8.2" 155 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 156 | dependencies: 157 | fill-range "^2.1.0" 158 | 159 | extglob@^0.3.1: 160 | version "0.3.2" 161 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 162 | dependencies: 163 | is-extglob "^1.0.0" 164 | 165 | filename-regex@^2.0.0: 166 | version "2.0.1" 167 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 168 | 169 | fill-range@^2.1.0: 170 | version "2.2.3" 171 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 172 | dependencies: 173 | is-number "^2.1.0" 174 | isobject "^2.0.0" 175 | randomatic "^1.1.3" 176 | repeat-element "^1.1.2" 177 | repeat-string "^1.5.2" 178 | 179 | for-in@^1.0.1: 180 | version "1.0.2" 181 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 182 | 183 | for-own@^0.1.4: 184 | version "0.1.5" 185 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 186 | dependencies: 187 | for-in "^1.0.1" 188 | 189 | fs-jetpack@^0.13.0: 190 | version "0.13.2" 191 | resolved "https://registry.yarnpkg.com/fs-jetpack/-/fs-jetpack-0.13.2.tgz#6de7cfe3968f13f539455e8c82fab7650ca959bc" 192 | dependencies: 193 | minimatch "^3.0.2" 194 | 195 | glob-base@^0.3.0: 196 | version "0.3.0" 197 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 198 | dependencies: 199 | glob-parent "^2.0.0" 200 | is-glob "^2.0.0" 201 | 202 | glob-parent@^2.0.0: 203 | version "2.0.0" 204 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 205 | dependencies: 206 | is-glob "^2.0.0" 207 | 208 | "graceful-readlink@>= 1.0.0": 209 | version "1.0.1" 210 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 211 | 212 | has-flag@^2.0.0: 213 | version "2.0.0" 214 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 215 | 216 | he@^0.5.0: 217 | version "0.5.0" 218 | resolved "https://registry.yarnpkg.com/he/-/he-0.5.0.tgz#2c05ffaef90b68e860f3fd2b54ef580989277ee2" 219 | 220 | http-proxy@^1.8.1: 221 | version "1.16.2" 222 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" 223 | dependencies: 224 | eventemitter3 "1.x.x" 225 | requires-port "1.x.x" 226 | 227 | http-server@^0.9.0: 228 | version "0.9.0" 229 | resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.9.0.tgz#8f1b06bdc733618d4dc42831c7ba1aff4e06001a" 230 | dependencies: 231 | colors "1.0.3" 232 | corser "~2.0.0" 233 | ecstatic "^1.4.0" 234 | http-proxy "^1.8.1" 235 | opener "~1.4.0" 236 | optimist "0.6.x" 237 | portfinder "0.4.x" 238 | union "~0.4.3" 239 | 240 | input.js@^1.1.2: 241 | version "1.1.2" 242 | resolved "https://registry.yarnpkg.com/input.js/-/input.js-1.1.2.tgz#cbe39e92b6151bcab2a4884b8f4096342589ca6e" 243 | 244 | ip@^1.1.5: 245 | version "1.1.5" 246 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" 247 | 248 | is-buffer@^1.1.5: 249 | version "1.1.6" 250 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 251 | 252 | is-dotfile@^1.0.0: 253 | version "1.0.3" 254 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 255 | 256 | is-equal-shallow@^0.1.3: 257 | version "0.1.3" 258 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 259 | dependencies: 260 | is-primitive "^2.0.0" 261 | 262 | is-extendable@^0.1.1: 263 | version "0.1.1" 264 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 265 | 266 | is-extglob@^1.0.0: 267 | version "1.0.0" 268 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 269 | 270 | is-glob@^2.0.0, is-glob@^2.0.1: 271 | version "2.0.1" 272 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 273 | dependencies: 274 | is-extglob "^1.0.0" 275 | 276 | is-number@^2.1.0: 277 | version "2.1.0" 278 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 279 | dependencies: 280 | kind-of "^3.0.2" 281 | 282 | is-number@^3.0.0: 283 | version "3.0.0" 284 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 285 | dependencies: 286 | kind-of "^3.0.2" 287 | 288 | is-posix-bracket@^0.1.0: 289 | version "0.1.1" 290 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 291 | 292 | is-primitive@^2.0.0: 293 | version "2.0.0" 294 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 295 | 296 | isarray@1.0.0: 297 | version "1.0.0" 298 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 299 | 300 | isobject@^2.0.0: 301 | version "2.1.0" 302 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 303 | dependencies: 304 | isarray "1.0.0" 305 | 306 | kind-of@^3.0.2: 307 | version "3.2.2" 308 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 309 | dependencies: 310 | is-buffer "^1.1.5" 311 | 312 | kind-of@^4.0.0: 313 | version "4.0.0" 314 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 315 | dependencies: 316 | is-buffer "^1.1.5" 317 | 318 | lstats.js@^1.2.2: 319 | version "1.2.2" 320 | resolved "https://registry.yarnpkg.com/lstats.js/-/lstats.js-1.2.2.tgz#ddc3219b88b0f92514ed4ea2379a8eb19653a039" 321 | 322 | magic-string@^0.22.4: 323 | version "0.22.4" 324 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.4.tgz#31039b4e40366395618c1d6cf8193c53917475ff" 325 | dependencies: 326 | vlq "^0.2.1" 327 | 328 | memop@^1.1.0: 329 | version "1.1.0" 330 | resolved "https://registry.yarnpkg.com/memop/-/memop-1.1.0.tgz#ab61680eb74a869deeaf65ce8719717f5254629f" 331 | 332 | micromatch@^2.3.11: 333 | version "2.3.11" 334 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 335 | dependencies: 336 | arr-diff "^2.0.0" 337 | array-unique "^0.2.1" 338 | braces "^1.8.2" 339 | expand-brackets "^0.1.4" 340 | extglob "^0.3.1" 341 | filename-regex "^2.0.0" 342 | is-extglob "^1.0.0" 343 | is-glob "^2.0.1" 344 | kind-of "^3.0.2" 345 | normalize-path "^2.0.1" 346 | object.omit "^2.0.0" 347 | parse-glob "^3.0.4" 348 | regex-cache "^0.4.2" 349 | 350 | mime@^1.2.11: 351 | version "1.3.4" 352 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 353 | 354 | minimatch@^3.0.2: 355 | version "3.0.3" 356 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 357 | dependencies: 358 | brace-expansion "^1.0.0" 359 | 360 | minimist@0.0.8, minimist@~0.0.1: 361 | version "0.0.8" 362 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 363 | 364 | minimist@^1.1.0, minimist@^1.2.0: 365 | version "1.2.0" 366 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 367 | 368 | mkdirp@0.5.x: 369 | version "0.5.0" 370 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" 371 | dependencies: 372 | minimist "0.0.8" 373 | 374 | normalize-path@^2.0.1: 375 | version "2.1.1" 376 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 377 | dependencies: 378 | remove-trailing-separator "^1.0.1" 379 | 380 | object.omit@^2.0.0: 381 | version "2.0.1" 382 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 383 | dependencies: 384 | for-own "^0.1.4" 385 | is-extendable "^0.1.1" 386 | 387 | opener@~1.4.0: 388 | version "1.4.3" 389 | resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" 390 | 391 | optimist@0.6.x: 392 | version "0.6.1" 393 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 394 | dependencies: 395 | minimist "~0.0.1" 396 | wordwrap "~0.0.2" 397 | 398 | os-homedir@^1.0.1: 399 | version "1.0.2" 400 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 401 | 402 | parse-glob@^3.0.4: 403 | version "3.0.4" 404 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 405 | dependencies: 406 | glob-base "^0.3.0" 407 | is-dotfile "^1.0.0" 408 | is-extglob "^1.0.0" 409 | is-glob "^2.0.0" 410 | 411 | portfinder@0.4.x: 412 | version "0.4.0" 413 | resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-0.4.0.tgz#a3ffadffafe4fb98e0601a85eda27c27ce84ca1e" 414 | dependencies: 415 | async "0.9.0" 416 | mkdirp "0.5.x" 417 | 418 | preserve@^0.2.0: 419 | version "0.2.0" 420 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 421 | 422 | preview-server@^1.0.7: 423 | version "1.0.7" 424 | resolved "https://registry.yarnpkg.com/preview-server/-/preview-server-1.0.7.tgz#a3843383ba5464e5fd08e87ee3cd6b20d7e73cff" 425 | dependencies: 426 | http-server "^0.9.0" 427 | ip "^1.1.5" 428 | qrcode-terminal "^0.11.0" 429 | 430 | qrcode-terminal@^0.11.0: 431 | version "0.11.0" 432 | resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz#ffc6c28a2fc0bfb47052b47e23f4f446a5fbdb9e" 433 | 434 | qs@~2.3.3: 435 | version "2.3.3" 436 | resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" 437 | 438 | randomatic@^1.1.3: 439 | version "1.1.7" 440 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" 441 | dependencies: 442 | is-number "^3.0.0" 443 | kind-of "^4.0.0" 444 | 445 | regex-cache@^0.4.2: 446 | version "0.4.4" 447 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" 448 | dependencies: 449 | is-equal-shallow "^0.1.3" 450 | 451 | regl@^1.3.0: 452 | version "1.3.0" 453 | resolved "https://registry.yarnpkg.com/regl/-/regl-1.3.0.tgz#ccde82eff8a8a068a559581ceacbef1afea78ebd" 454 | 455 | remove-trailing-separator@^1.0.1: 456 | version "1.1.0" 457 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 458 | 459 | repeat-element@^1.1.2: 460 | version "1.1.2" 461 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 462 | 463 | repeat-string@^1.5.2: 464 | version "1.6.1" 465 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 466 | 467 | requires-port@1.x.x: 468 | version "1.0.0" 469 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 470 | 471 | rollup-plugin-buble@^0.18.0: 472 | version "0.18.0" 473 | resolved "https://registry.yarnpkg.com/rollup-plugin-buble/-/rollup-plugin-buble-0.18.0.tgz#6e20d1b2840c59eb496b9f954f75243e51786ac1" 474 | dependencies: 475 | buble "^0.18.0" 476 | rollup-pluginutils "^2.0.1" 477 | 478 | rollup-pluginutils@^2.0.1: 479 | version "2.0.1" 480 | resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz#7ec95b3573f6543a46a6461bd9a7c544525d0fc0" 481 | dependencies: 482 | estree-walker "^0.3.0" 483 | micromatch "^2.3.11" 484 | 485 | rollup@^0.54.1: 486 | version "0.54.1" 487 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.54.1.tgz#415a5d999421502646cf54b873fc4ce1a7393970" 488 | 489 | scene-graph@^1.0.2, scene-graph@^1.0.3: 490 | version "1.0.3" 491 | resolved "https://registry.yarnpkg.com/scene-graph/-/scene-graph-1.0.3.tgz#de0cd34e3e8a08c905907ee4471e64acaf60d7d2" 492 | dependencies: 493 | vmath "^1.1.0" 494 | 495 | source-map@~0.5.1: 496 | version "0.5.6" 497 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 498 | 499 | spectorjs@^0.0.10: 500 | version "0.0.10" 501 | resolved "https://registry.yarnpkg.com/spectorjs/-/spectorjs-0.0.10.tgz#b2b445fbdebdf10107ec49a4124dccc80687607c" 502 | 503 | supports-color@^4.0.0: 504 | version "4.5.0" 505 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" 506 | dependencies: 507 | has-flag "^2.0.0" 508 | 509 | uglify-es@^3.0.15: 510 | version "3.0.15" 511 | resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.0.15.tgz#4a23d0e9cb5f25f7bb3f1f0bbe0bb364e600d047" 512 | dependencies: 513 | commander "~2.9.0" 514 | source-map "~0.5.1" 515 | 516 | union@~0.4.3: 517 | version "0.4.6" 518 | resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" 519 | dependencies: 520 | qs "~2.3.3" 521 | 522 | url-join@^1.0.0: 523 | version "1.1.0" 524 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" 525 | 526 | vconsole@^2.5.2: 527 | version "2.5.2" 528 | resolved "https://registry.yarnpkg.com/vconsole/-/vconsole-2.5.2.tgz#07092d9a459552d89604553cef512308553848df" 529 | 530 | vlq@^0.2.1, vlq@^0.2.2: 531 | version "0.2.3" 532 | resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" 533 | 534 | vmath@^1.1.0, vmath@^1.1.1, vmath@^1.2.0: 535 | version "1.2.0" 536 | resolved "https://registry.yarnpkg.com/vmath/-/vmath-1.2.0.tgz#71991031f8e9458189709a64d95b18bb07f5b662" 537 | 538 | wordwrap@~0.0.2: 539 | version "0.0.2" 540 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" 541 | --------------------------------------------------------------------------------