From a24d536de0b0031e16895a8b87aad47a45c53022 Mon Sep 17 00:00:00 2001 From: Keith Date: Tue, 15 Oct 2013 15:47:45 -0400 Subject: [PATCH 1/3] Beta Zip Loading Manifest can now load zip files. AssetPackLoader saves each file in the zip as a blob and loads normally. - only tested so far with png, jpeg, mp3, ogg, fnt, and xml so far - only works if blob is supported --- src/flambe/asset/AssetEntry.hx | 3 + src/flambe/asset/Manifest.hx | 3 +- src/flambe/platform/BasicAssetPackLoader.hx | 2 + .../platform/html/HtmlAssetPackLoader.hx | 70 ++++++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/flambe/asset/AssetEntry.hx b/src/flambe/asset/AssetEntry.hx index e43d1151..14f65312 100644 --- a/src/flambe/asset/AssetEntry.hx +++ b/src/flambe/asset/AssetEntry.hx @@ -20,6 +20,9 @@ enum AssetFormat // Raw text/data Data; + + // Archived file format + ZIP; } /** diff --git a/src/flambe/asset/Manifest.hx b/src/flambe/asset/Manifest.hx index b46aa1b9..3b423985 100644 --- a/src/flambe/asset/Manifest.hx +++ b/src/flambe/asset/Manifest.hx @@ -196,7 +196,7 @@ class Manifest return basePath; } - private static function inferFormat (url :String) :AssetFormat + public static function inferFormat (url :String) :AssetFormat { var extension = url.getUrlExtension(); if (extension != null) { @@ -216,6 +216,7 @@ class Manifest case "ogg": return OGG; case "opus": return OPUS; case "wav": return WAV; + case "zip": return ZIP; } } else { Log.warn("No file extension for asset, it will be loaded as data", ["url", url]); diff --git a/src/flambe/platform/BasicAssetPackLoader.hx b/src/flambe/platform/BasicAssetPackLoader.hx index d2ddacee..a193ecf1 100644 --- a/src/flambe/platform/BasicAssetPackLoader.hx +++ b/src/flambe/platform/BasicAssetPackLoader.hx @@ -174,6 +174,8 @@ class BasicAssetPackLoader map = _pack.sounds; case Data: map = _pack.files; + case ZIP: + map = _pack.files; } #if debug // Allow some methods to get stripped in release builds, which don't allow reloading diff --git a/src/flambe/platform/html/HtmlAssetPackLoader.hx b/src/flambe/platform/html/HtmlAssetPackLoader.hx index 70d14cc5..808e2b40 100644 --- a/src/flambe/platform/html/HtmlAssetPackLoader.hx +++ b/src/flambe/platform/html/HtmlAssetPackLoader.hx @@ -8,6 +8,8 @@ import js.Browser; import js.html.*; import haxe.Http; +import haxe.io.BytesInput; +import haxe.io.Bytes; import flambe.asset.AssetEntry; import flambe.asset.Manifest; @@ -16,6 +18,9 @@ import flambe.util.Promise; import flambe.util.Signal0; import flambe.util.Signal1; +using StringTools; +using flambe.util.Strings; + class HtmlAssetPackLoader extends BasicAssetPackLoader { public function new (platform :HtmlPlatform, manifest :Manifest) @@ -138,6 +143,61 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader downloadText(url, entry, function (text) { handleLoad(entry, new BasicFile(text)); }); + + case ZIP: + if (supportsBlob()) { + downloadArrayBuffer(url, entry, function (buffer) { + var bytes = Bytes.ofData(cast new js.html.Uint8Array(buffer)); + var zip = new haxe.zip.Reader(new BytesInput(bytes)); + var entries:List = zip.read(); + + for (entry in entries) { + var extension = entry.fileName.getUrlExtension(); + if(entry.fileName.charAt(0)=="." || entry.fileName.indexOf("/.")>=0) { + extension=""; + } + if(extension=="" || extension==null) { + Log.warn("No extension or weird format for zipped entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + _assetsRemaining += 1; + promise.total += entry.dataSize; + + var type = ""; + var format = Manifest.inferFormat(entry.fileName); + var name = entry.fileName.removeFileExtension(); + switch(format) { + case PNG: type = "image/png"; + case JPG: type = "image/jpeg"; + case JXR: type = "image/vnd.ms-photo"; + case GIF: type = "image/gif"; + case WEBP: type = "image/webp"; + case M4A: type = "audio/mp4"; + case MP3: type = "audio/mpeg"; + case OGG, OPUS: type = "audio/ogg"; + case WAV: type = "audio/wave"; + case Data: name = entry.fileName; + case ZIP: type = "application/zip"; + case DDS, PVR, PKM: type = "application/octet-stream"; + } + + var buff = new js.html.Uint8Array(entry.data.getData()); + var blob = new Blob([buff], {type:type}); + if(format == Data) { + blob = new Blob([haxe.zip.Reader.unzip(entry)], {type:type}); + } + var generatedUrl = _URL.createObjectURL(blob); + var entryFlambe = manifest.add(name, entry.fileName, entry.dataSize, Manifest.inferFormat(entry.fileName)); + loadEntry(generatedUrl, entryFlambe); + } + + handleLoad(entry, {}); + }); + } + else { + Log.warn("Blob not supported, ignoring this asset", ["url", url]); + } } } @@ -147,7 +207,8 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader _supportedFormats = new Promise(); detectImageFormats(function (imageFormats) { _supportedFormats.result = _platform.getRenderer().getCompressedTextureFormats() - .concat(imageFormats).concat(detectAudioFormats()).concat([Data]); + .concat(imageFormats).concat(detectAudioFormats()).concat(detectArchiveFormats()) + .concat([Data]); }); } _supportedFormats.get(fn); @@ -313,6 +374,13 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader return result; } + private static function detectArchiveFormats () :Array + { + var result = [ZIP]; + + return result; + } + private static function supportsBlob () :Bool { if (_detectBlobSupport) { From f8e8cc9fb4af76d779de90ba8263224893699f73 Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 17 Oct 2013 17:09:33 -0400 Subject: [PATCH 2/3] Flash zip loading Added flash support. FlashAssetPackLoader loads the zip file using a URLLoader. Each file in the zip is loaded in the same way as a regular file except it uses bytes instead of a URLRequest - tested with png, jpg, mp3, xml, and fnt --- .../platform/flash/FlashAssetPackLoader.hx | 77 ++++++++++++++++++- .../platform/html/HtmlAssetPackLoader.hx | 2 +- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/flambe/platform/flash/FlashAssetPackLoader.hx b/src/flambe/platform/flash/FlashAssetPackLoader.hx index 419cb3c6..ef0ea5fb 100644 --- a/src/flambe/platform/flash/FlashAssetPackLoader.hx +++ b/src/flambe/platform/flash/FlashAssetPackLoader.hx @@ -23,6 +23,12 @@ import flambe.asset.AssetEntry; import flambe.asset.Manifest; import flambe.util.Assert; +import haxe.io.BytesInput; +import haxe.io.Bytes; + +using flambe.util.Strings; +using StringTools; + class FlashAssetPackLoader extends BasicAssetPackLoader { public function new (platform :FlashPlatform, manifest :Manifest) @@ -66,6 +72,75 @@ class FlashAssetPackLoader extends BasicAssetPackLoader var urlLoader = new URLLoader(req); dispatcher = urlLoader; create = function () return new BasicFile(urlLoader.data); + + case ZIP: + var urlLoader = new URLLoader(req); + urlLoader.dataFormat = flash.net.URLLoaderDataFormat.BINARY; + dispatcher = urlLoader; + var events = new EventGroup(); + events.addDisposingListener(dispatcher, Event.COMPLETE, function (_) { + var bytes = Bytes.ofData(urlLoader.data); + var zip = new haxe.zip.Reader(new BytesInput(bytes)); + var entries:List = zip.read(); + + for (entry in entries) { + var extension = entry.fileName.getUrlExtension(); + if(entry.fileName.charAt(0)=="." || entry.fileName.indexOf("/.")>=0) { + extension=""; + } + if(extension=="" || extension==null) { + Log.warn("No extension or weird format for zipped entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + _assetsRemaining += 1; + promise.total += entry.dataSize; + + var format = Manifest.inferFormat(entry.fileName); + var name = entry.fileName.removeFileExtension(); + if(format == Data) { + name = entry.fileName; + } + var entryFlambe = manifest.add(name, entry.fileName, entry.dataSize, format); + var asset; + var canAdd = false; + switch(format) { + case JXR, PNG, JPG, GIF: + var loader = new Loader(); + loader.loadBytes(entry.data.getData()); + var dispatcher:IEventDispatcher = loader.contentLoaderInfo; + var events = new EventGroup(); + events.addDisposingListener(dispatcher, Event.COMPLETE, function (_) { + create = function () { + var bitmap :Bitmap = cast loader.content; + var texture = _platform.getRenderer().createTexture(bitmap.bitmapData); + bitmap.bitmapData.dispose(); + return texture; + }; + asset = create(); + handleLoad(entryFlambe, asset); + }); + case MP3: + var sound = new Sound(); + sound.loadCompressedDataFromByteArray(entry.data.getData(), entry.dataSize); + create = function () return new FlashSound(sound); + canAdd = true; + case Data: + create = function () return new BasicFile(entry.data.toString()); + canAdd = true; + default: + Log.warn("Format not supported for zipped entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + if (canAdd) { + asset = create(); + handleLoad(entryFlambe, asset); + } + } + handleLoad(entry, {}); + }); + return; default: // Should never happen @@ -102,6 +177,6 @@ class FlashAssetPackLoader extends BasicAssetPackLoader override private function getAssetFormats (fn :Array -> Void) { - fn([JXR, PNG, JPG, GIF, MP3, Data]); + fn([JXR, PNG, JPG, GIF, MP3, Data, ZIP]); } } diff --git a/src/flambe/platform/html/HtmlAssetPackLoader.hx b/src/flambe/platform/html/HtmlAssetPackLoader.hx index 808e2b40..d2309f43 100644 --- a/src/flambe/platform/html/HtmlAssetPackLoader.hx +++ b/src/flambe/platform/html/HtmlAssetPackLoader.hx @@ -188,7 +188,7 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader blob = new Blob([haxe.zip.Reader.unzip(entry)], {type:type}); } var generatedUrl = _URL.createObjectURL(blob); - var entryFlambe = manifest.add(name, entry.fileName, entry.dataSize, Manifest.inferFormat(entry.fileName)); + var entryFlambe = manifest.add(name, entry.fileName, entry.dataSize, format); loadEntry(generatedUrl, entryFlambe); } From 6665ebd91ff907836b2a5ff9431d49bbea8fe36c Mon Sep 17 00:00:00 2001 From: Keith Date: Thu, 24 Oct 2013 15:48:59 -0400 Subject: [PATCH 3/3] Tar loading Added tar loading to flash and html5. Works similar to zip loading except it uses format.tar.Reader - note: I'm not sure why loading a tar entry in HtmlAssetPackLoader doesn't work as an inline function --- src/flambe/asset/AssetEntry.hx | 2 +- src/flambe/asset/Manifest.hx | 1 + src/flambe/platform/BasicAssetPackLoader.hx | 4 +- .../platform/flash/FlashAssetPackLoader.hx | 77 ++++++++++++++++++- .../platform/html/HtmlAssetPackLoader.hx | 69 +++++++++++++++-- 5 files changed, 141 insertions(+), 12 deletions(-) diff --git a/src/flambe/asset/AssetEntry.hx b/src/flambe/asset/AssetEntry.hx index 14f65312..f074edbe 100644 --- a/src/flambe/asset/AssetEntry.hx +++ b/src/flambe/asset/AssetEntry.hx @@ -22,7 +22,7 @@ enum AssetFormat Data; // Archived file format - ZIP; + ZIP; TAR; } /** diff --git a/src/flambe/asset/Manifest.hx b/src/flambe/asset/Manifest.hx index 3b423985..91c1c539 100644 --- a/src/flambe/asset/Manifest.hx +++ b/src/flambe/asset/Manifest.hx @@ -217,6 +217,7 @@ class Manifest case "opus": return OPUS; case "wav": return WAV; case "zip": return ZIP; + case "tar": return TAR; } } else { Log.warn("No file extension for asset, it will be loaded as data", ["url", url]); diff --git a/src/flambe/platform/BasicAssetPackLoader.hx b/src/flambe/platform/BasicAssetPackLoader.hx index a193ecf1..c60efe02 100644 --- a/src/flambe/platform/BasicAssetPackLoader.hx +++ b/src/flambe/platform/BasicAssetPackLoader.hx @@ -172,9 +172,7 @@ class BasicAssetPackLoader map = _pack.textures; case MP3, M4A, OPUS, OGG, WAV: map = _pack.sounds; - case Data: - map = _pack.files; - case ZIP: + case Data, ZIP, TAR: map = _pack.files; } diff --git a/src/flambe/platform/flash/FlashAssetPackLoader.hx b/src/flambe/platform/flash/FlashAssetPackLoader.hx index ef0ea5fb..09a87721 100644 --- a/src/flambe/platform/flash/FlashAssetPackLoader.hx +++ b/src/flambe/platform/flash/FlashAssetPackLoader.hx @@ -23,6 +23,8 @@ import flambe.asset.AssetEntry; import flambe.asset.Manifest; import flambe.util.Assert; +import format.tar.Data; + import haxe.io.BytesInput; import haxe.io.Bytes; @@ -138,8 +140,79 @@ class FlashAssetPackLoader extends BasicAssetPackLoader handleLoad(entryFlambe, asset); } } - handleLoad(entry, {}); }); + handleLoad(entry, {}); + return; + + case TAR: + var urlLoader = new URLLoader(req); + urlLoader.dataFormat = flash.net.URLLoaderDataFormat.BINARY; + dispatcher = urlLoader; + var events = new EventGroup(); + events.addDisposingListener(dispatcher, Event.COMPLETE, function (_) { + var bytes = Bytes.ofData(urlLoader.data); + var tar = new format.tar.Reader(new BytesInput(bytes)); + var entries:List = tar.read(); + + for (entry in entries) { + var extension = entry.fileName.getUrlExtension(); + if(entry.fileName.charAt(0)=="." || entry.fileName.indexOf("/.")>=0) { + extension=""; + } + if(extension=="" || extension==null) { + Log.warn("No extension or weird format for tar entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + _assetsRemaining += 1; + promise.total += entry.fileSize; + + var format = Manifest.inferFormat(entry.fileName); + var name = entry.fileName.removeFileExtension(); + if(format == Data) { + name = entry.fileName; + } + var entryFlambe = manifest.add(name, entry.fileName, entry.fileSize, format); + var asset; + var canAdd = false; + switch(format) { + case JXR, PNG, JPG, GIF: + var loader = new Loader(); + loader.loadBytes(entry.data.getData()); + var dispatcher:IEventDispatcher = loader.contentLoaderInfo; + var events = new EventGroup(); + events.addDisposingListener(dispatcher, Event.COMPLETE, function (_) { + create = function () { + var bitmap :Bitmap = cast loader.content; + var texture = _platform.getRenderer().createTexture(bitmap.bitmapData); + bitmap.bitmapData.dispose(); + return texture; + }; + asset = create(); + handleLoad(entryFlambe, asset); + }); + case MP3: + var sound = new Sound(); + sound.loadCompressedDataFromByteArray(entry.data.getData(), entry.fileSize); + create = function () return new FlashSound(sound); + canAdd = true; + case Data: + create = function () return new BasicFile(entry.data.toString()); + canAdd = true; + default: + _assetsRemaining -= 1; + promise.total -= entry.fileSize; + Log.warn("Format not supported for tar entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + if (canAdd) { + asset = create(); + handleLoad(entryFlambe, asset); + } + } + }); + handleLoad(entry, {}); return; default: @@ -177,6 +250,6 @@ class FlashAssetPackLoader extends BasicAssetPackLoader override private function getAssetFormats (fn :Array -> Void) { - fn([JXR, PNG, JPG, GIF, MP3, Data, ZIP]); + fn([JXR, PNG, JPG, GIF, MP3, Data, ZIP, TAR]); } } diff --git a/src/flambe/platform/html/HtmlAssetPackLoader.hx b/src/flambe/platform/html/HtmlAssetPackLoader.hx index d2309f43..2a81f42f 100644 --- a/src/flambe/platform/html/HtmlAssetPackLoader.hx +++ b/src/flambe/platform/html/HtmlAssetPackLoader.hx @@ -18,6 +18,8 @@ import flambe.util.Promise; import flambe.util.Signal0; import flambe.util.Signal1; +import format.tar.Data; + using StringTools; using flambe.util.Strings; @@ -180,6 +182,7 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader case Data: name = entry.fileName; case ZIP: type = "application/zip"; case DDS, PVR, PKM: type = "application/octet-stream"; + case TAR: type = "application/x-tar"; } var buff = new js.html.Uint8Array(entry.data.getData()); @@ -191,16 +194,70 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader var entryFlambe = manifest.add(name, entry.fileName, entry.dataSize, format); loadEntry(generatedUrl, entryFlambe); } - - handleLoad(entry, {}); }); - } - else { + } else { Log.warn("Blob not supported, ignoring this asset", ["url", url]); } + handleLoad(entry, {}); + case TAR: + if (supportsBlob()) { + downloadArrayBuffer(url, entry, function (buffer) { + var bytes = Bytes.ofData(cast new js.html.Uint8Array(buffer)); + var tar = new format.tar.Reader(new BytesInput(bytes)); + var entries:List = tar.read(); + + for (entry in entries) { + var extension = entry.fileName.getUrlExtension(); + if(entry.fileName.charAt(0)=="." || entry.fileName.indexOf("/.")>=0) { + extension=""; + } + if(extension=="" || extension==null) { + Log.warn("No extension or weird format for tar entry, ignoring this asset", ["url", entry.fileName]); + continue; + } + + _assetsRemaining += 1; + promise.total += entry.fileSize; + + loadTarEntry(entry); + }; + }); + } else { + Log.warn("Blob not supported, ignoring this asset", ["url", url]); + } + handleLoad(entry, {}); } } - + + private function loadTarEntry (entry:format.tar.Entry) { + var type = ""; + var format = Manifest.inferFormat(entry.fileName); + var name = entry.fileName.removeFileExtension(); + switch(format) { + case PNG: type = "image/png"; + case JPG: type = "image/jpeg"; + case JXR: type = "image/vnd.ms-photo"; + case GIF: type = "image/gif"; + case WEBP: type = "image/webp"; + case M4A: type = "audio/mp4"; + case MP3: type = "audio/mpeg"; + case OGG, OPUS: type = "audio/ogg"; + case WAV: type = "audio/wave"; + case Data: name = entry.fileName; + case ZIP: type = "application/zip"; + case DDS, PVR, PKM: type = "application/octet-stream"; + case TAR: type = "application/x-tar"; + } + var buff = new js.html.Uint8Array(entry.data.getData()); + var blob = new Blob([buff], {type:type}); + if(format == Data) { + blob = new Blob([entry.data], {type:type}); + } + var generatedUrl = _URL.createObjectURL(blob); + var entryFlambe = manifest.add(name, entry.fileName, entry.fileSize, format); + loadEntry(generatedUrl, entryFlambe); + } + override private function getAssetFormats (fn :Array -> Void) { if (_supportedFormats == null) { @@ -376,7 +433,7 @@ class HtmlAssetPackLoader extends BasicAssetPackLoader private static function detectArchiveFormats () :Array { - var result = [ZIP]; + var result = [ZIP, TAR]; return result; }