diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-07-18 16:24:37 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-07-18 16:24:37 -0700 |
commit | a97aab0522858f3e24ab96fe93e7be9e2b976878 (patch) | |
tree | f8585d79dc26206ca04786ee7a3538934eb86eac | |
parent | 168e8fd12dca0316f4edd08da5fb0c2608d67368 (diff) |
refactor file preloading to happen in FS.createPreloadedFile, so that not only file_packager preloading gets preloaded Images and Audios
-rw-r--r-- | src/library.js | 69 | ||||
-rw-r--r-- | src/library_browser.js | 68 | ||||
-rw-r--r-- | src/postamble.js | 1 | ||||
-rw-r--r-- | src/preamble.js | 6 | ||||
-rw-r--r-- | tests/emscripten_fs_api_browser.cpp | 17 | ||||
-rwxr-xr-x | tests/runner.py | 1 | ||||
-rw-r--r-- | tools/file_packager.py | 74 |
7 files changed, 134 insertions, 102 deletions
diff --git a/src/library.js b/src/library.js index 01619b2a..2677eb10 100644 --- a/src/library.js +++ b/src/library.js @@ -273,10 +273,71 @@ LibraryManager.library = { }, // Preloads a file asynchronously. You can call this before run, for example in // preRun. run will be delayed until this file arrives and is set up. - createPreloadedFile: function(parent, name, url, canRead, canWrite) { - Browser.asyncLoad(url, function(data) { - FS.createDataFile(parent, name, data, canRead, canWrite); - }); + // If you call it after run(), you may want to pause the main loop until it + // completes, if so, you can use the onload parameter to be notified when + // that happens. + // In addition to normally creating the file, we also asynchronously preload + // the browser-friendly versions of it: For an image, we preload an Image + // element and for an audio, and Audio. These are necessary for SDL_Image + // and _Mixer to find the files in preloadedImages/Audios. + createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror) { + Browser.ensureObjects(); + Browser.asyncLoad(url, function(byteArray) { + FS.createDataFile(parent, name, byteArray, canRead, canWrite); + if (Browser.isImageFile(name)) { + var bb = new Browser.BlobBuilder(); + bb.append(byteArray.buffer); + var b = bb.getBlob(); + var url = Browser.URLObject.createObjectURL(b); + var img = new Image(); + img.onload = function() { + assert(img.complete, 'Image ' + url + ' could not be decoded'); + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + Module["preloadedImages"][name] = canvas; + Browser.URLObject.revokeObjectURL(url); + Module['removeRunDependency'](); + if (onload) onload(); + }; + img.onerror = function(event) { + console.log('Image ' + url + ' could not be decoded'); + if (onerror) onerror(); + }; + img.src = url; + } else if (Browser.isAudioFile(name)) { + if (Browser.hasBlobConstructor) { + var b = new Blob([byteArray.buffer], { type: Browser.getAudioMimetype(name) }); + var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this! + var audio = new Audio(); + audio.removedDependency = false; + audio['oncanplaythrough'] = function() { // XXX string for closure + audio['oncanplaythrough'] = null; + Module["preloadedAudios"][name] = audio; + if (!audio.removedDependency) { + Module['removeRunDependency'](); + audio.removedDependency = true; + } + }; + audio.onerror = function(event) { + if (!audio.removedDependency) { + console.log('Audio ' + url + ' could not be decoded or timed out trying to decode'); + Module['removeRunDependency'](); + audio.removedDependency = true; + } + }; + setTimeout(audio.onerror, 2000); // workaround for chromium bug 124926 (still no audio with this, but at least we don't hang) + audio.src = url; + } else { + Module["preloadedAudios"]['%(filename)s'] = new Audio(); // empty shim + Module['removeRunDependency'](); + } + } else { + if (onload) onload(); + } + }, onerror); }, // Creates a link to a sepcific local path. createLink: function(parent, name, target, canRead, canWrite) { diff --git a/src/library_browser.js b/src/library_browser.js index ce59dbdd..4d7a0aa5 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -27,6 +27,20 @@ mergeInto(LibraryManager.library, { pointerLock: false, moduleContextCreatedCallbacks: [], + ensureObjects: function() { + if (Browser.ensured) return; + Browser.ensured = true; + try { + new Blob(); + Browser.hasBlobConstructor = true; + } catch(e) { + Browser.hasBlobConstructor = false; + console.log("warning: no blob constructor, cannot create blobs with mimetypes"); + } + Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : console.log("warning: cannot build blobs")); + Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : console.log("warning: cannot create object URLs"); + }, + createContext: function(canvas, useWebGL, setInModule) { #if !USE_TYPED_ARRAYS if (useWebGL) { @@ -172,38 +186,52 @@ mergeInto(LibraryManager.library, { xhr.send(null); }, - asyncLoad: function(url, callback) { + asyncLoad: function(url, onload, onerror) { Browser.xhrLoad(url, function(arrayBuffer) { assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); - callback(new Uint8Array(arrayBuffer)); + onload(new Uint8Array(arrayBuffer)); removeRunDependency(); }, function(event) { - throw 'Loading data file "' + url + '" failed.'; + if (onerror) { + onerror(); + } else { + throw 'Loading data file "' + url + '" failed.'; + } }); addRunDependency(); - } + }, + + isImageFile: function(name) { + return name.substr(-4) in { '.jpg': 1, '.png': 1, '.bmp': 1 }; + }, + + isAudioFile: function(name) { + return name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 }; + }, + + getAudioMimetype: function(name) { + var ret = { 'ogg': 'audio/ogg', 'wav': 'audio/wav', 'mp3': 'audio/mpeg' }[name.substr(0, name.length-3)]; + assert(ret); + return ret; + }, + }, emscripten_async_wget: function(url, file, onload, onerror) { - url = Pointer_stringify(url); - - Browser.xhrLoad(url, function(response) { - var absolute = Pointer_stringify(file); - var index = absolute.lastIndexOf('/'); - FS.createDataFile( - absolute.substr(0, index), - absolute.substr(index +1), - new Uint8Array(response), - true, true); - - if (onload) { + var _url = Pointer_stringify(url); + var _file = Pointer_stringify(file); + var index = _file.lastIndexOf('/'); + FS.createPreloadedFile( + _file.substr(0, index), + _file.substr(index +1), + _url, true, true, + function() { FUNCTION_TABLE[onload](file); - } - }, function(event) { - if (onerror) { + }, + function() { FUNCTION_TABLE[onerror](file); } - }); + ); }, emscripten_async_run_script__deps: ['emscripten_run_script'], diff --git a/src/postamble.js b/src/postamble.js index 10ac1888..2944e681 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -45,6 +45,7 @@ function run(args) { function doRun() { var ret = 0; + calledRun = true; if (Module['_main']) { preMain(); ret = Module.callMain(args); diff --git a/src/preamble.js b/src/preamble.js index 5c5e64fc..21b09985 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -793,6 +793,7 @@ var STRING_TABLE = []; // it happens right before run - run will be postponed until // the dependencies are met. var runDependencies = 0; +var calledRun = false; function addRunDependency() { runDependencies++; if (Module['monitorRunDependencies']) { @@ -805,9 +806,12 @@ function removeRunDependency() { if (Module['monitorRunDependencies']) { Module['monitorRunDependencies'](runDependencies); } - if (runDependencies == 0) run(); + if (runDependencies == 0 && !calledRun) run(); } Module['removeRunDependency'] = removeRunDependency; +Module["preloadedImages"] = {}; // maps url to image data +Module["preloadedAudios"] = {}; // maps url to audio data + // === Body === diff --git a/tests/emscripten_fs_api_browser.cpp b/tests/emscripten_fs_api_browser.cpp index 07469f34..bfe33213 100644 --- a/tests/emscripten_fs_api_browser.cpp +++ b/tests/emscripten_fs_api_browser.cpp @@ -1,22 +1,25 @@ #include<stdio.h> #include<emscripten.h> #include<assert.h> -#include <string.h> - +#include<string.h> +#include<SDL/SDL.h> +#include"SDL/SDL_image.h" + extern "C" { int result = 1; int get_count = 0; void wait_wgets() { - if (get_count == 2) { + if (get_count == 3) { + assert(IMG_Load("screen_shot.png")); emscripten_cancel_main_loop(); REPORT_RESULT(); } } void onLoaded(const char* file) { - if (strcmp(file, "/tmp/test.html")) { + if (strcmp(file, "/tmp/test.html") && strcmp(file, "/tmp/screen_shot.png")) { result = 0; } @@ -60,6 +63,12 @@ int main() { onLoaded, onError); + emscripten_async_wget( + "http://localhost:8888/screenshot.png", + "/tmp/screen_shot.png", + onLoaded, + onError); + emscripten_set_main_loop(wait_wgets, 0); return 0; diff --git a/tests/runner.py b/tests/runner.py index 9c714da5..156299db 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7910,6 +7910,7 @@ elif 'browser' in str(sys.argv): self.btest('emscripten_api_browser.cpp', '1') def test_emscripten_fs_api(self): + shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) # preloaded *after* run self.btest('emscripten_fs_api_browser.cpp', '1') def test_gc(self): diff --git a/tools/file_packager.py b/tools/file_packager.py index 8c1e0a43..4d96ef00 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -96,23 +96,6 @@ function assert(check, msg) { } ''' -if has_preloaded: - code += ''' - var BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : console.log("warning: cannot build blobs")); - var URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : console.log("warning: cannot create object URLs"); - var hasBlobConstructor; - try { - new Blob(); - hasBlobConstructor = true; - } catch(e) { - hasBlobConstructor = false; - console.log("warning: no blob constructor, cannot create blobs with mimetypes"); - } -''' - - code += 'Module["preloadedImages"] = {}; // maps url to image data\n' - code += 'Module["preloadedAudios"] = {}; // maps url to audio data\n' - # Expand directories into individual files def add(mode, dirname, names): for name in names: @@ -244,67 +227,12 @@ for file_ in data_files: # Preload varname = 'filePreload%d' % counter counter += 1 - image = filename.endswith(IMAGE_SUFFIXES) - audio = filename.endswith(AUDIO_SUFFIXES) dds = crunch and filename.endswith(CRUNCH_INPUT_SUFFIX) prepare = '' finish = "Module['removeRunDependency']();\n" - if image: - finish = ''' - var bb = new BlobBuilder(); - bb.append(byteArray.buffer); - var b = bb.getBlob(); - var url = URLObject.createObjectURL(b); - var img = new Image(); - img.onload = function() { - assert(img.complete, 'Image %(filename)s could not be decoded'); - var canvas = document.createElement('canvas'); - canvas.width = img.width; - canvas.height = img.height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(img, 0, 0); - Module["preloadedImages"]['%(filename)s'] = canvas; - URLObject.revokeObjectURL(url); - Module['removeRunDependency'](); - }; - img.onerror = function(event) { - console.log('Image %(filename)s could not be decoded'); - }; - img.src = url; -''' % { 'filename': filename } - elif audio: - # Need actual blob constructor here, to set the mimetype or else audios fail to decode - finish = ''' - if (hasBlobConstructor) { - var b = new Blob([byteArray.buffer], { type: '%(mimetype)s' }); - var url = URLObject.createObjectURL(b); // XXX we never revoke this! - var audio = new Audio(); - audio.removedDependency = false; - audio['oncanplaythrough'] = function() { // XXX string for closure - audio['oncanplaythrough'] = null; - Module["preloadedAudios"]['%(filename)s'] = audio; - if (!audio.removedDependency) { - Module['removeRunDependency'](); - audio.removedDependency = true; - } - }; - audio.onerror = function(event) { - if (!audio.removedDependency) { - console.log('Audio %(filename)s could not be decoded or timed out trying to decode'); - Module['removeRunDependency'](); - audio.removedDependency = true; - } - }; - setTimeout(audio.onerror, 2000); // workaround for chromium bug 124926 (still no audio with this, but at least we don't hang) - audio.src = url; - } else { - Module["preloadedAudios"]['%(filename)s'] = new Audio(); // empty shim - Module['removeRunDependency'](); - } -''' % { 'filename': filename, 'mimetype': AUDIO_MIMETYPES[suffix(filename)] } - elif dds: + if dds: # decompress crunch format into dds prepare = ''' var ddsHeader = byteArray.subarray(0, %(dds_header_size)d); |