1/** 2 * Copyright (C) 2014-2017 Triumph LLC 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17"use strict"; 18/** 19 * Low-level resource loader. 20 * 21 * NOTE: setup Nginx /etc/nginx/mime.types: 22 * audio/ogg ogg; 23 * to prevent 206 partial content response 24 * 25 * @name assets 26 * @namespace 27 * @exports exports as assets 28 */ 29b4w.module["__assets"] = function(exports, require) { 30 31var m_cfg = require("__config"); 32var m_compat = require("__compat"); 33var m_pako = require("__pako_inflate"); 34var m_print = require("__print"); 35var m_sfg = require("__sfx"); 36var m_util = require("__util"); 37var m_version = require("__version"); 38 39var cfg_def = m_cfg.defaults; 40var cfg_ldr = m_cfg.assets; 41 42// asset types 43exports.AT_ARRAYBUFFER = 10; 44exports.AT_ARRAYBUFFER_ZIP = 20; 45exports.AT_JSON = 30; 46exports.AT_JSON_ZIP = 40; 47exports.AT_TEXT = 50; 48exports.AT_AUDIOBUFFER = 60; 49exports.AT_IMAGE_ELEMENT = 70; 50exports.AT_AUDIO_ELEMENT = 80; 51exports.AT_VIDEO_ELEMENT = 90; 52exports.AT_SEQ_VIDEO_ELEMENT = 100; 53 54// asset states: enqueued -> requested -> received 55var ASTATE_ENQUEUED = 10; 56var ASTATE_REQUESTED = 20; 57var ASTATE_RECEIVED = 30; 58var ASTATE_HALTED = 40; 59 60var _assets_queue = []; 61var _assets_pack_index = 0; 62 63// deprecated 64var _loaded_assets = {}; 65 66var _arraybuffer_cache = {}; 67var _img_cache = {}; 68var _sound_cache = {}; 69var _arraybuffer_sound_cache = {}; 70 71function get_built_in_data() { 72 if (m_cfg.is_built_in_data()) 73 return require(m_cfg.paths.built_in_data_module)["data"]; 74 else 75 return null; 76} 77 78function FakeHttpRequest() { 79 var req = { 80 _source_url: null, 81 _parse_response: function(source) { 82 switch(req.responseType) { 83 case "json": 84 case "text": 85 return source; 86 case "arraybuffer": 87 var bin_str = atob(source); 88 var len = bin_str.length; 89 90 var arr_buffer = new Int8Array(len); 91 for (var i = 0; i < len; i++) 92 arr_buffer[i] = bin_str.charCodeAt(i); 93 return arr_buffer.buffer; 94 default: 95 return source; 96 } 97 }, 98 99 status: 0, 100 readyState: 0, 101 response: "", 102 responseType: "", 103 onreadystatechange: null, 104 105 overrideMimeType: function() {}, 106 addEventListener: function() {}, 107 open: function(method, url, async) { 108 req._source_url = url; 109 req.readyState = 1; 110 }, 111 send: function() { 112 req.status = 404; 113 req.readyState = 4; 114 var bd = get_built_in_data(); 115 if (bd && req._source_url in bd) { 116 req.status = 200; 117 if (bd[req._source_url]) 118 req.response = req._parse_response(bd[req._source_url]); 119 } 120 var get_type = {}; 121 if (get_type.toString.call(req.onreadystatechange) 122 === '[object Function]') 123 req.onreadystatechange(); 124 } 125 } 126 return req; 127} 128 129/** 130 * Split path to head and extension: "123.txt" -> ["123", "txt"] 131 */ 132exports.split_extension = function(path) { 133 var dot_split = path.split("."); 134 135 var head_ext = Array(2); 136 137 head_ext[0] = dot_split.slice(0, -1).join("."); 138 head_ext[1] = String(dot_split.slice(-1)); 139 140 return head_ext; 141} 142 143/** 144 * Get text by sync request. 145 * @deprecated Any usage is strongly discouraged 146 */ 147exports.get_text_sync = function(asset_uri) { 148 // check in cache 149 if (_loaded_assets[asset_uri]) 150 return _loaded_assets[asset_uri]; 151 152 if (cfg_ldr.prevent_caching) 153 var filepath = asset_uri + m_version.timestamp(); 154 else 155 var filepath = asset_uri; 156 157 var req = new XMLHttpRequest(); 158 req.overrideMimeType("text/plain"); // to prevent "not well formed" error 159 req.open("GET", filepath, false); 160 req.send(null); 161 162 if (req.status == 200 || req.status == 0) { 163 var resp_text = req.responseText; 164 if (resp_text.length) { 165 // save in cache 166 _loaded_assets[asset_uri] = resp_text; 167 return resp_text; 168 } else 169 m_util.panic("Error XHR: responce is empty, GET " + asset_uri); 170 } else { 171 m_util.panic("Error XHR: " + req.status + ", GET " + asset_uri); 172 } 173} 174 175exports.cleanup = function() { 176 for (var i = 0; i < _assets_queue.length; i++)
177 _assets_queue[i].state = ASTATE_HALTED; 178 _assets_queue = []; 179 _assets_pack_index = 0; 180 181 // deprecated 182 _loaded_assets = {}; 183} 184 185exports.enqueue = function(assets_pack, asset_cb, pack_cb, progress_cb, json_reviver) { 186 for (var i = 0; i < assets_pack.length; i++) { 187 var elem = assets_pack[i]; 188 189 var asset = { 190 id: elem.id, 191 type: elem.type, 192 url: elem.url, 193 is_fetch: elem.is_fetch, 194 request_method: elem.request_method ? elem.request_method : "GET", 195 overwrite_header: elem.overwrite_header ? elem.overwrite_header : null, 196 post_data: elem.post_data ? elem.post_data : null, 197 param: elem.param ? elem.param : null, 198 199 state: ASTATE_ENQUEUED, 200 201 asset_cb: asset_cb || (function() {}), 202 pack_cb: pack_cb || (function() {}), 203 progress_cb: progress_cb || (function() {}), 204 json_reviver: json_reviver || null, 205 206 pack_index: _assets_pack_index 207 } 208 209 if (cfg_ldr.prevent_caching) { 210 var bd = get_built_in_data(); 211 if (!(bd && asset.url in bd)) 212 asset.url += m_version.timestamp(); 213 } 214 215 _assets_queue.push(asset); 216 } 217 218 request_assets(_assets_queue); 219 _assets_pack_index++; 220} 221 222/** 223 * Executed every frame 224 */ 225exports.update = function() { 226 request_assets(_assets_queue); 227 handle_packs(_assets_queue); 228} 229 230function request_assets(queue) { 231 232 var req_cnt = 0; 233 234 for (var i = 0; i < queue.length; i++) { 235 var asset = queue[i]; 236 237 if (asset.state === ASTATE_REQUESTED) 238 req_cnt++; 239 240 // check requests limit 241 if (req_cnt >= cfg_ldr.max_requests) 242 break; 243 244 // pass recently enqueued 245 if (asset.state !== ASTATE_ENQUEUED) 246 continue; 247 248 asset.state = ASTATE_REQUESTED; 249 req_cnt++; 250 251 switch (asset.type) { 252 case exports.AT_JSON_ZIP: 253 case exports.AT_ARRAYBUFFER: 254 case exports.AT_ARRAYBUFFER_ZIP: 255 request_arraybuffer(asset, "arraybuffer"); 256 break; 257 case exports.AT_JSON: 258 request_arraybuffer(asset, "json"); 259 break; 260 case exports.AT_TEXT: 261 request_arraybuffer(asset, "text"); 262 break; 263 case exports.AT_AUDIOBUFFER: 264 request_audiobuffer(asset); 265 break; 266 case exports.AT_IMAGE_ELEMENT: 267 request_image(asset); 268 break; 269 case exports.AT_AUDIO_ELEMENT: 270 request_audio(asset); 271 break; 272 case exports.AT_VIDEO_ELEMENT: 273 request_video(asset); 274 break; 275 case exports.AT_SEQ_VIDEO_ELEMENT: 276 request_seq_video(asset); 277 break; 278 default: 279 m_util.panic("Wrong asset type: " + asset.type); 280 break; 281 } 282 } 283} 284 285function request_arraybuffer(asset, response_type) { 286 var filepath = asset.url.split("?v=")[0]; 287 if (filepath in _arraybuffer_cache) { 288 if (response_type == "json") 289 asset.asset_cb(m_util.clone_object_r(_arraybuffer_cache[filepath]), asset.id, asset.type, 290 asset.url, asset.param); 291 else 292 asset.asset_cb(_arraybuffer_cache[filepath], asset.id, asset.type, 293 asset.url, asset.param); 294 return; 295 } 296 var bd = get_built_in_data(); 297 if (bd && asset.url in bd) 298 var req = new FakeHttpRequest(); 299 else 300 var req = new XMLHttpRequest(); 301 302 var content_type = null; 303 if (asset.request_method == "GET") { 304 req.open("GET", asset.url, true); 305 } else if (asset.request_method == "POST") { 306 req.open("POST", asset.url, true); 307 switch (asset.type) { 308 case exports.AT_TEXT: 309 content_type = 'text/plain'; 310 break; 311 case exports.AT_JSON: 312 content_type = 'application/json'; 313 break; 314 } 315 } 316 317 if (asset.overwrite_header) { 318 for (var key in asset.overwrite_header) { 319 if (key == "Content-Type") 320 content_type = asset.overwrite_header[key]; 321 else 322 req.setRequestHeader(key, asset.overwrite_header[key]); 323 } 324 } 325 326 if (content_type) 327 req.setRequestHeader("Content-Type", content_type); 328 329 if (response_type == "text") { 330 // to prevent "not well formed" error (GLSL) 331 req.overrideMimeType("text/plain"); 332 req.responseType = "text"; 333 } else if (response_type == "json") { 334 // NOTE: workaround, json response type not implemented in some browsers
335 //m_print.log("Apply json load workaround"); 336 req.overrideMimeType("application/json"); 337 req.responseType = "text"; 338 } else 339 req.responseType = response_type; 340 341 req.onreadystatechange = function() { 342 if (asset.state != ASTATE_HALTED) 343 if (req.readyState == 4) { 344 if (req.status == 200 || req.status == 0) { 345 var response = req.response; 346 var empty_response = !response 347 || (response_type == "arraybuffer" && response["byteLength"] == 0) 348 if (!empty_response) { 349 350 switch (asset.type) { 351 case exports.AT_JSON_ZIP: 352 try { 353 response = m_pako.inflate(response, { to: "string" }); 354 } catch(e) { 355 m_print.error(e + " (parsing gzipped file " + asset.url + ")"); 356 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 357 return; 358 } 359 case exports.AT_JSON: 360 try { 361 response = JSON.parse(response, asset.json_reviver); 362 } catch(e) { 363 m_print.error(e + " (parsing JSON " + asset.url + ")"); 364 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 365 return; 366 } 367 break; 368 case exports.AT_ARRAYBUFFER_ZIP: 369 try { 370 response = m_pako.inflate(response).buffer; 371 } catch(e) { 372 m_print.error(e + " (parsing gzipped file " + asset.url + ")"); 373 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 374 return; 375 } 376 break; 377 } 378 379 if (asset.is_fetch) 380 if (asset.type == exports.AT_JSON || asset.type == exports.AT_JSON_ZIP) 381 _arraybuffer_cache[filepath] = m_util.clone_object_r(response); 382 else 383 _arraybuffer_cache[filepath] = response; 384 385 asset.asset_cb(response, asset.id, asset.type, asset.url, asset.param); 386 } else { 387 m_print.error("empty responce when trying to get " + asset.url); 388 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 389 } 390 } else { 391 m_print.error(req.status + " when trying to get " + asset.url); 392 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 393 } 394 asset.state = ASTATE_RECEIVED; 395 } 396 }; 397 398 req.addEventListener("progress", function(e) { 399 // compute progress information if total size is known 400 if (e.lengthComputable) 401 asset.progress_cb(e.loaded / e.total); 402 }, false); 403 404 req.send(asset.post_data); 405} 406 407function request_audiobuffer(asset) { 408 var filepath = asset.url.split("?v=")[0]; 409 if (filepath in _arraybuffer_sound_cache) { 410 asset.asset_cb(_arraybuffer_sound_cache[filepath], asset.id, asset.type, 411 asset.url, asset.param); 412 asset.state = ASTATE_RECEIVED; 413 return; 414 } 415 if (asset.request_method != "GET") { 416 m_util.panic("Unsupported request type for audio buffer"); 417 } 418 var bd = get_built_in_data(); 419 if (bd && asset.url in bd) 420 var req = new FakeHttpRequest(); 421 else 422 var req = new XMLHttpRequest(); 423 424 req.open("GET", asset.url, true); 425 426 req.responseType = "arraybuffer"; 427 428 req.onreadystatechange = function() {
429 if (asset.state != ASTATE_HALTED) 430 if (req.readyState == 4) { 431 if (req.status == 200 || req.status == 0) { 432 var response = req.response; 433 if (response) { 434 var decode_cb = function(audio_buffer) { 435 asset.asset_cb(audio_buffer, asset.id, asset.type, asset.url, asset.param); 436 asset.state = ASTATE_RECEIVED; 437 if (asset.is_fetch) { 438 var filepath = asset.url.split("?v=")[0]; 439 _arraybuffer_sound_cache[filepath] = audio_buffer; 440 } 441 } 442 var fail_cb = function() { 443 m_print.error("failed to decode " + asset.url); 444 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 445 asset.state = ASTATE_RECEIVED; 446 } 447 448 m_sfg.decode_audio_data(response, decode_cb, fail_cb); 449 450 } else { 451 m_print.error("empty responce when trying to get " + asset.url); 452 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 453 asset.state = ASTATE_RECEIVED; 454 } 455 } else { 456 m_print.error(req.status + " when trying to get " + asset.url); 457 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 458 asset.state = ASTATE_RECEIVED; 459 } 460 } 461 }; 462 463 req.send(); 464} 465 466function request_image(asset) { 467 var filepath = asset.url.split("?v=")[0]; 468 if (filepath in _img_cache) { 469 asset.asset_cb(_img_cache[filepath], asset.id, asset.type, asset.url, asset.param); 470 asset.state = ASTATE_RECEIVED; 471 return; 472 } 473 if (asset.request_method != "GET") { 474 m_util.panic("Unsupported request type for image element"); 475 } 476 var image = document.createElement("img"); 477 if (cfg_def.allow_cors) 478 image.crossOrigin = "Anonymous"; 479 image.onload = function() { 480 if (asset.state != ASTATE_HALTED) { 481 asset.asset_cb(image, asset.id, asset.type, asset.url, asset.param); 482 asset.state = ASTATE_RECEIVED; 483 if (asset.is_fetch) { 484 var filepath = asset.url.split("?v=")[0]; 485 _img_cache[filepath] = image; 486 } 487 } 488 }; 489 image.addEventListener("error", function() { 490 if (asset.state != ASTATE_HALTED) { 491 m_print.error("could not load image: " + asset.url); 492 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 493 asset.state = ASTATE_RECEIVED; 494 } 495 }, false); 496 497 var bd = get_built_in_data(); 498 if (bd && asset.url in bd) { 499 if (bd[asset.url]) { 500 var img_mime_type = get_image_mime_type(asset.url); 501 image.src = "data:" + img_mime_type + ";base64," + bd[asset.url]; 502 } else { 503 if (m_compat.is_ie11()) { 504 var e = document.createEvent("CustomEvent"); 505 e.initCustomEvent("error", false, false, null); 506 } else 507 var e = new CustomEvent("error"); 508 image.dispatchEvent(e); 509 } 510 } else 511 image.src = asset.url; 512} 513 514function request_audio(asset) { 515 var filepath = asset.url.split("?v=")[0]; 516 if (filepath in _sound_cache) { 517 asset.asset_cb(_sound_cache[filepath], asset.id, asset.type, 518 asset.url, asset.param); 519 asset.state = ASTATE_RECEIVED; 520 return; 521 } 522 if (asset.request_method != "GET") { 523 m_util.panic("Unsupported request type for audio element"); 524 } 525 var audio = document.createElement("audio"); 526 if (cfg_def.allow_cors) 527 audio.crossOrigin = "Anonymous"; 528 529 audio.addEventListener("loadeddata", function() { 530 if (asset.state != ASTATE_HALTED) { 531 asset.asset_cb(audio, asset.id, asset.type, asset.url, asset.param); 532 asset.state = ASTATE_RECEIVED; 533 if (asset.is_fetch) { 534 var filepath = asset.url.split("?v=")[0];
535 _sound_cache[filepath] = audio; 536 } 537 } 538 }, false); 539 540 audio.addEventListener("error", function() { 541 if (asset.state != ASTATE_HALTED) { 542 m_print.error("could not load sound: " + asset.url); 543 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 544 asset.state = ASTATE_RECEIVED; 545 } 546 }, false); 547 548 audio.addEventListener("stalled", function() { 549 if (asset.state != ASTATE_HALTED) { 550 m_print.error("could not load sound: " + asset.url); 551 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 552 asset.state = ASTATE_RECEIVED; 553 } 554 }, false); 555 556 var bd = get_built_in_data(); 557 if (bd && asset.url in bd) { 558 if (bd[asset.url]) { 559 var snd_mime_type = get_sound_mime_type(asset.url); 560 audio.src = "data:" + snd_mime_type + ";base64," + bd[asset.url]; 561 if (asset.state != ASTATE_HALTED) { 562 asset.asset_cb(audio, asset.id, asset.type, asset.url, asset.param); 563 asset.state = ASTATE_RECEIVED; 564 } 565 566 } else { 567 if (m_compat.is_ie11()) { 568 var e = document.createEvent("CustomEvent"); 569 e.initCustomEvent("error", false, false, null); 570 } else 571 var e = new CustomEvent("error"); 572 audio.dispatchEvent(e); 573 } 574 } else { 575 audio.src = asset.url; 576 if (cfg_def.is_mobile_device) 577 audio.load(); 578 } 579 580 if (cfg_def.mobile_firefox_media_hack) { 581 audio.autoplay = true; 582 audio.pause(); 583 } 584 585 // HACK: workaround for some garbage collector bug 586 setTimeout(function() {audio.some_prop_to_prevent_gc = 1}, 5000); 587} 588 589function request_video(asset) { 590 var filepath = asset.url.split("?v=")[0]; 591 if (filepath in _img_cache) { 592 asset.asset_cb(_img_cache[filepath], asset.id, asset.type, asset.url, asset.param); 593 asset.state = ASTATE_RECEIVED; 594 return; 595 } 596 if (asset.request_method != "GET") { 597 m_util.panic("Unsupported request type for video element"); 598 } 599 var video = document.createElement("video"); 600 video.muted = true; 601 // HACK: allow crossOrigin for mobile devices (Android Chrome bug) 602 if (cfg_def.allow_cors) 603 video.crossOrigin = "Anonymous"; 604 video.addEventListener("loadeddata", function() { 605 video.removeEventListener("error", video_error_event, false); 606 if (asset.state != ASTATE_HALTED) { 607 asset.asset_cb(video, asset.id, asset.type, asset.url, asset.param); 608 asset.state = ASTATE_RECEIVED; 609 if (asset.is_fetch) { 610 var filepath = asset.url.split("?v=")[0]; 611 _img_cache[filepath] = video; 612 } 613 } 614 }, false); 615 616 function video_error_event(e) { 617 if (asset.state != ASTATE_HALTED) { 618 m_print.error("could not load video: " + asset.url, asset.param); 619 asset.asset_cb(null, asset.id, asset.type, asset.url); 620 asset.state = ASTATE_RECEIVED; 621 } 622 } 623 video.addEventListener("error", video_error_event, false); 624 625 var bd = get_built_in_data(); 626 if (bd && asset.url in bd) { 627 if (bd[asset.url]) { 628 var vid_mime_type = get_video_mime_type(asset.url); 629 video.src = "data:" + vid_mime_type + ";base64," + bd[asset.url]; 630 if (asset.state != ASTATE_HALTED) 631 video.addEventListener("loadeddata", function() { 632 asset.asset_cb(video, asset.id, asset.type, asset.url, asset.param); 633 asset.state = ASTATE_RECEIVED; 634 }, false); 635 } else { 636 if (m_compat.is_ie11()) { 637 var e = document.createEvent("CustomEvent"); 638 e.initCustomEvent("error", false, false, null); 639 } else 640 var e = new CustomEvent("error"); 641 video.dispatchEvent(e); 642 } 643 } else { 644 video.src = asset.url; 645 if (cfg_def.is_mobile_device) 646 video.load(); 647 } 648 649 if (cfg_def.mobile_firefox_media_hack) { 650 video.autoplay = true; 651 video.pause(); 652 } 653 654 // HACK: workaround for some garbage collector bug 655 setTimeout(function() {video.some_prop_to_prevent_gc = 1}, 10000); 656} 657 658function request_seq_video(asset) { 659 var filepath = asset.url.split("?v=")[0]; 660 if (filepath in _img_cache) { 661 asset.asset_cb(_img_cache[filepath], asset.id, asset.type, asset.url, asset.param); 662 asset.state = ASTATE_RECEIVED; 663 return; 664 } 665 if (asset.request_method != "GET") { 666 m_util.panic("Unsupported request type for seq video element"); 667 } 668 var bd = get_built_in_data(); 669 if (bd && asset.url in bd) 670 var req = new FakeHttpRequest(); 671 else 672 var req = new XMLHttpRequest(); 673 674 req.open("GET", asset.url, true); 675 req.responseType = "arraybuffer"; 676 677 function load_cb(images) { 678 asset.asset_cb(images, asset.id, asset.type, asset.url, asset.param); 679 asset.state = ASTATE_RECEIVED; 680 if (asset.is_fetch) { 681 var filepath = asset.url.split("?v=")[0]; 682 _img_cache[filepath] = images; 683 } 684 } 685 686 req.onreadystatechange = function() {
687 if (asset.state != ASTATE_HALTED) 688 if (req.readyState == 4) { 689 if (req.status == 200 || req.status == 0) { 690 var response = req.response; 691 if (response) 692 parse_seq_video_file(response, load_cb); 693 else { 694 m_print.error("empty responce when trying to get " + asset.url); 695 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 696 asset.state = ASTATE_RECEIVED; 697 } 698 } else { 699 m_print.error(req.status + " when trying to get " + asset.url); 700 asset.asset_cb(null, asset.id, asset.type, asset.url, asset.param); 701 asset.state = ASTATE_RECEIVED; 702 } 703 } 704 }; 705 req.addEventListener("progress", function(e) { 706 // compute progress information if total size is known 707 if (e.lengthComputable) 708 asset.progress_cb(e.loaded / e.total); 709 }, false); 710 711 req.send(); 712} 713 714function parse_seq_video_file(response, callback) { 715 var buffer = new Int32Array(response); 716 var seq_image_data = new Int8Array(response); 717 var number = buffer[3]; 718 var data = { 719 images: [], 720 blobs: [], 721 fps: buffer[4] 722 }; 723 var offset = 20; 724 for (var j = 0; j < number; j++) { 725 var size = buffer[offset/4]; 726 var frame = seq_image_data.subarray(offset + 4, offset + 4 + size); 727 var blob = new Blob([frame], {type: "image/jpg"}); 728 var image = document.createElement("img"); 729 image.src = window.URL.createObjectURL(blob); 730 data.images.push(image); 731 // NOTE: IE HTML7007 message hack 732 data.blobs.push(blob); 733 offset +=size + 8 - size % 4; 734 } 735 // NOTE: wait for loading last image 736 image.onload = function() { 737 for (var i = 0; i < data.images.length; i++) 738 window.URL.revokeObjectURL(data.images[i].src); 739 delete data.blobs; 740 callback(data); 741 } 742} 743 744function get_image_mime_type(file_path) { 745 var ext = m_util.get_file_extension(file_path); 746 var mime_type = "image"; 747 switch(ext.toLowerCase()) { 748 case "jpeg": 749 case "jpg": 750 mime_type += "/jpeg"; 751 break; 752 case "png": 753 mime_type += "/png"; 754 break; 755 } 756 757 return mime_type; 758} 759 760function get_sound_mime_type(file_path) { 761 var ext = m_util.get_file_extension(file_path); 762 var mime_type = "audio"; 763 switch(ext.toLowerCase()) { 764 case "ogv": 765 case "ogg": 766 mime_type += "/ogg"; 767 break; 768 case "mp3": 769 mime_type += "/mpeg"; 770 break; 771 case "m4v": 772 case "mp4": 773 mime_type += "/mp4"; 774 break; 775 case "webm": 776 mime_type += "/webm"; 777 break; 778 } 779 780 return mime_type; 781} 782 783function get_video_mime_type(file_path) { 784 var ext = m_util.get_file_extension(file_path); 785 var mime_type = "video"; 786 switch(ext.toLowerCase()) { 787 case "ogv": 788 mime_type += "/ogg"; 789 break; 790 case "webm": 791 mime_type += "/webm"; 792 break; 793 case "m4v": 794 mime_type += "/mp4"; 795 break; 796 } 797 798 return mime_type; 799} 800 801exports.check_image_extension = function(ext) { 802 if (ext == "png" 803 || ext == "jpg" 804 || ext == "jpeg" 805 || ext == "gif" 806 || ext == "bmp" 807 || ext == "dds" 808 || ext == "pvr") 809 return true; 810 811 return false; 812} 813 814/** 815 * Find loaded packs, exec callback and remove from queue 816 */ 817function handle_packs(queue) { 818 819 var pack_first_index = 0; 820 var pack_cb_exec = true; 821 822 for (var i = 0; i < queue.length; i++) { 823 var asset = queue[i]; 824 var asset_pack_first = queue[pack_first_index]; 825 826 if (asset.pack_index === asset_pack_first.pack_index) { 827 if (asset.state !== ASTATE_RECEIVED) 828 pack_cb_exec = false; 829 } else { 830 if (pack_cb_exec) { 831 queue[i-1].pack_cb(); 832 var spliced_count = i-pack_first_index; 833 queue.splice(pack_first_index, spliced_count); 834 i-=spliced_count; 835 } 836 837 pack_first_index = i; 838 pack_cb_exec = (queue[i].state === ASTATE_RECEIVED) ? true : false;
839 } 840 841 if ((i === (queue.length-1)) && pack_cb_exec) { 842 var last_asset = queue[i]; 843 queue.splice(pack_first_index); 844 // Should be executed after splice. Possible enqueue in pack_cb 845 last_asset.pack_cb(); 846 } 847 } 848} 849 850function debug_queue(queue, opt_log_prefix) { 851 var state_str = "["; 852 853 for (var i = 0; i < queue.length; i++) 854 state_str += String(queue[i].state / 10); 855 856 state_str += "]"; 857 858 if (opt_log_prefix || opt_log_prefix === 0) 859 m_print.log(opt_log_prefix, state_str); 860 else 861 m_print.log(state_str); 862} 863 864exports.clear_cache = function() { 865 _arraybuffer_cache = {}; 866 _img_cache = {}; 867 _sound_cache = {}; 868 _arraybuffer_sound_cache = {}; 869} 870 871}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.