package; import haxe.Timer; import haxe.Unserializer; import lime.app.Future; import lime.app.Preloader; import lime.app.Promise; import lime.audio.AudioSource; import lime.audio.openal.AL; import lime.audio.AudioBuffer; import lime.graphics.Image; import lime.net.HTTPRequest; import lime.system.CFFI; import lime.text.Font; import lime.utils.Bytes; import lime.utils.UInt8Array; import lime.Assets; #if sys import haxe.io.Path; import sys.FileSystem; #end #if flash import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.ProgressEvent; import flash.media.Sound; import flash.net.URLLoader; import flash.net.URLRequest; #end class DefaultAssetLibrary extends AssetLibrary { public var className (default, null) = new Map (); public var path (default, null) = new Map (); public var type (default, null) = new Map (); private var lastModified:Float; private var timer:Timer; #if windows private var rootPath = FileSystem.absolutePath (Path.directory (#if (haxe_ver >= 3.3) Sys.programPath () #else Sys.executablePath () #end)) + "/"; #else private var rootPath = ""; #end public function new () { super (); #if (openfl && !flash) ::if (assets != null):: ::foreach assets::::if (type == "font")::openfl.text.Font.registerFont (__ASSET__OPENFL__::flatName::);::end:: ::end::::end:: #end #if flash ::if (assets != null)::::foreach assets::::if (embed)::className.set ("::id::", __ASSET__::flatName::);::else::path.set ("::id::", "::resourceName::");::end:: type.set ("::id::", AssetType.$$upper(::type::)); ::end::::end:: #elseif html5 ::if (assets != null)::var id; ::foreach assets::id = "::id::"; ::if (embed)::::if (type == "font")::className.set (id, __ASSET__::flatName::);::else::path.set (id, ::if (resourceName == id)::id::else::"::resourceName::"::end::);::end:: ::else::path.set (id, ::if (resourceName == id)::id::else::"::resourceName::"::end::);::end:: type.set (id, AssetType.$$upper(::type::)); ::end::::end:: var assetsPrefix = null; if (ApplicationMain.config != null && Reflect.hasField (ApplicationMain.config, "assetsPrefix")) { assetsPrefix = ApplicationMain.config.assetsPrefix; } if (assetsPrefix != null) { for (k in path.keys()) { path.set(k, assetsPrefix + path[k]); } } #else #if (windows || mac || linux) var useManifest = false; ::if (assets != null)::::foreach assets::::if (type == "font"):: className.set ("::id::", __ASSET__::flatName::); type.set ("::id::", AssetType.$$upper(::type::)); ::else::::if (embed):: className.set ("::id::", __ASSET__::flatName::); type.set ("::id::", AssetType.$$upper(::type::)); ::else::useManifest = true; ::end::::end::::end::::end:: if (useManifest) { loadManifest (); if (Sys.args ().indexOf ("-livereload") > -1) { var path = FileSystem.fullPath ("manifest"); lastModified = FileSystem.stat (path).mtime.getTime (); timer = new Timer (2000); timer.run = function () { var modified = FileSystem.stat (path).mtime.getTime (); if (modified > lastModified) { lastModified = modified; loadManifest (); onChange.dispatch (); } } } } #else loadManifest (); #end #end } public override function exists (id:String, type:String):Bool { var requestedType = type != null ? cast (type, AssetType) : null; var assetType = this.type.get (id); if (assetType != null) { if (assetType == requestedType || ((requestedType == SOUND || requestedType == MUSIC) && (assetType == MUSIC || assetType == SOUND))) { return true; } #if flash if (requestedType == BINARY && (assetType == BINARY || assetType == TEXT || assetType == IMAGE)) { return true; } else if (requestedType == TEXT && assetType == BINARY) { return true; } else if (requestedType == null || path.exists (id)) { return true; } #else if (requestedType == BINARY || requestedType == null || (assetType == BINARY && requestedType == TEXT)) { return true; } #end } return false; } public override function getAudioBuffer (id:String):AudioBuffer { #if flash var buffer = new AudioBuffer (); buffer.src = cast (Type.createInstance (className.get (id), []), Sound); return buffer; #elseif html5 return null; //return new Sound (new URLRequest (path.get (id))); #else if (className.exists(id)) return AudioBuffer.fromBytes (cast (Type.createInstance (className.get (id), []), Bytes)); else return AudioBuffer.fromFile (rootPath + path.get (id)); #end } public override function getBytes (id:String):Bytes { #if flash switch (type.get (id)) { case TEXT, BINARY: return Bytes.ofData (cast (Type.createInstance (className.get (id), []), flash.utils.ByteArray)); case IMAGE: var bitmapData = cast (Type.createInstance (className.get (id), []), BitmapData); return Bytes.ofData (bitmapData.getPixels (bitmapData.rect)); default: return null; } return cast (Type.createInstance (className.get (id), []), Bytes); #elseif html5 var loader = Preloader.loaders.get (path.get (id)); if (loader == null) { return null; } var bytes = loader.bytes; if (bytes != null) { return bytes; } else { return null; } #else if (className.exists(id)) return cast (Type.createInstance (className.get (id), []), Bytes); else return Bytes.readFile (rootPath + path.get (id)); #end } public override function getFont (id:String):Font { #if flash var src = Type.createInstance (className.get (id), []); var font = new Font (src.fontName); font.src = src; return font; #elseif html5 return cast (Type.createInstance (className.get (id), []), Font); #else if (className.exists (id)) { var fontClass = className.get (id); return cast (Type.createInstance (fontClass, []), Font); } else { return Font.fromFile (rootPath + path.get (id)); } #end } public override function getImage (id:String):Image { #if flash return Image.fromBitmapData (cast (Type.createInstance (className.get (id), []), BitmapData)); #elseif html5 return Image.fromImageElement (Preloader.images.get (path.get (id))); #else if (className.exists (id)) { var fontClass = className.get (id); return cast (Type.createInstance (fontClass, []), Image); } else { return Image.fromFile (rootPath + path.get (id)); } #end } /*public override function getMusic (id:String):Dynamic { #if flash return cast (Type.createInstance (className.get (id), []), Sound); #elseif openfl_html5 //var sound = new Sound (); //sound.__buffer = true; //sound.load (new URLRequest (path.get (id))); //return sound; return null; #elseif html5 return null; //return new Sound (new URLRequest (path.get (id))); #else return null; //if (className.exists(id)) return cast (Type.createInstance (className.get (id), []), Sound); //else return new Sound (new URLRequest (path.get (id)), null, true); #end }*/ public override function getPath (id:String):String { //#if ios //return SystemPath.applicationDirectory + "/assets/" + path.get (id); //#else return path.get (id); //#end } public override function getText (id:String):String { #if html5 var loader = Preloader.loaders.get (path.get (id)); if (loader == null) { return null; } var bytes = loader.bytes; if (bytes != null) { return bytes.getString (0, bytes.length); } else { return null; } #else var bytes = getBytes (id); if (bytes == null) { return null; } else { return bytes.getString (0, bytes.length); } #end } public override function isLocal (id:String, type:String):Bool { var requestedType = type != null ? cast (type, AssetType) : null; #if flash //if (requestedType != AssetType.MUSIC && requestedType != AssetType.SOUND) { return className.exists (id); //} #end return true; } public override function list (type:String):Array { var requestedType = type != null ? cast (type, AssetType) : null; var items = []; for (id in this.type.keys ()) { if (requestedType == null || exists (id, type)) { items.push (id); } } return items; } public override function loadAudioBuffer (id:String):Future { var promise = new Promise (); #if (flash) if (path.exists (id)) { var soundLoader = new Sound (); soundLoader.addEventListener (Event.COMPLETE, function (event) { var audioBuffer:AudioBuffer = new AudioBuffer(); audioBuffer.src = event.currentTarget; promise.complete (audioBuffer); }); soundLoader.addEventListener (ProgressEvent.PROGRESS, function (event) { if (event.bytesTotal == 0) { promise.progress (0); } else { promise.progress (event.bytesLoaded / event.bytesTotal); } }); soundLoader.addEventListener (IOErrorEvent.IO_ERROR, promise.error); soundLoader.load (new URLRequest (path.get (id))); } else { promise.complete (getAudioBuffer (id)); } #else promise.completeWith (new Future (function () return getAudioBuffer (id))); #end return promise.future; } public override function loadBytes (id:String):Future { var promise = new Promise (); #if flash if (path.exists (id)) { var loader = new URLLoader (); loader.dataFormat = flash.net.URLLoaderDataFormat.BINARY; loader.addEventListener (Event.COMPLETE, function (event:Event) { var bytes = Bytes.ofData (event.currentTarget.data); promise.complete (bytes); }); loader.addEventListener (ProgressEvent.PROGRESS, function (event) { if (event.bytesTotal == 0) { promise.progress (0); } else { promise.progress (event.bytesLoaded / event.bytesTotal); } }); loader.addEventListener (IOErrorEvent.IO_ERROR, promise.error); loader.load (new URLRequest (path.get (id))); } else { promise.complete (getBytes (id)); } #elseif html5 if (path.exists (id)) { var request = new HTTPRequest (); promise.completeWith (request.load (path.get (id) + "?" + Assets.cache.version)); } else { promise.complete (getBytes (id)); } #else promise.completeWith (new Future (function () return getBytes (id))); #end return promise.future; } public override function loadImage (id:String):Future { var promise = new Promise (); #if flash if (path.exists (id)) { var loader = new Loader (); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, function (event:Event) { var bitmapData = cast (event.currentTarget.content, Bitmap).bitmapData; promise.complete (Image.fromBitmapData (bitmapData)); }); loader.contentLoaderInfo.addEventListener (ProgressEvent.PROGRESS, function (event) { if (event.bytesTotal == 0) { promise.progress (0); } else { promise.progress (event.bytesLoaded / event.bytesTotal); } }); loader.contentLoaderInfo.addEventListener (IOErrorEvent.IO_ERROR, promise.error); loader.load (new URLRequest (path.get (id))); } else { promise.complete (getImage (id)); } #elseif html5 if (path.exists (id)) { var image = new js.html.Image (); image.onload = function (_):Void { promise.complete (Image.fromImageElement (image)); } image.onerror = promise.error; image.src = path.get (id) + "?" + Assets.cache.version; } else { promise.complete (getImage (id)); } #else promise.completeWith (new Future (function () return getImage (id))); #end return promise.future; } #if (!flash && !html5) private function loadManifest ():Void { try { #if blackberry var bytes = Bytes.readFile ("app/native/manifest"); #elseif tizen var bytes = Bytes.readFile ("../res/manifest"); #elseif emscripten var bytes = Bytes.readFile ("assets/manifest"); #elseif (mac && java) var bytes = Bytes.readFile ("../Resources/manifest"); #elseif (ios || tvos) var bytes = Bytes.readFile ("assets/manifest"); #else var bytes = Bytes.readFile ("manifest"); #end if (bytes != null) { if (bytes.length > 0) { var data = bytes.getString (0, bytes.length); if (data != null && data.length > 0) { var manifest:Array = Unserializer.run (data); for (asset in manifest) { if (!className.exists (asset.id)) { #if (ios || tvos) path.set (asset.id, "assets/" + asset.path); #else path.set (asset.id, asset.path); #end type.set (asset.id, cast (asset.type, AssetType)); } } } } } else { trace ("Warning: Could not load asset manifest (bytes was null)"); } } catch (e:Dynamic) { trace ('Warning: Could not load asset manifest (${e})'); } } #end public override function loadText (id:String):Future { var promise = new Promise (); #if html5 if (path.exists (id)) { var request = new HTTPRequest (); var future = request.load (path.get (id) + "?" + Assets.cache.version); future.onProgress (function (progress) promise.progress (progress)); future.onError (function (msg) promise.error (msg)); future.onComplete (function (bytes) promise.complete (bytes.getString (0, bytes.length))); } else { promise.complete (getText (id)); } #else promise.completeWith (loadBytes (id).then (function (bytes) { return new Future (function () { if (bytes == null) { return null; } else { return bytes.getString (0, bytes.length); } }); })); #end return promise.future; } } #if !display #if flash ::foreach assets::::if (embed)::::if (type == "image")::@:keep @:bind #if display private #end class __ASSET__::flatName:: extends flash.display.BitmapData { public function new () { super (0, 0, true, 0); } }::else::@:keep @:bind #if display private #end class __ASSET__::flatName:: extends ::flashClass:: { }::end::::end:: ::end:: #elseif html5 ::foreach assets::::if (type == "font")::@:keep #if display private #end class __ASSET__::flatName:: extends lime.text.Font { public function new () { super (); name = "::fontName::"; } } ::end:: ::end:: #else ::if (assets != null)::::foreach assets::::if (!embed)::::if (type == "font")::@:keep #if display private #end class __ASSET__::flatName:: extends lime.text.Font { public function new () { __fontPath = #if (ios || tvos) "assets/" + #end "::targetPath::"; name = "::fontName::"; super (); }} ::end::::end::::end::::end:: #if (windows || mac || linux || cpp) ::if (assets != null):: ::foreach assets::::if (embed)::::if (type == "image")::@:image("::sourcePath::") #if display private #end class __ASSET__::flatName:: extends lime.graphics.Image {} ::elseif (type == "sound")::@:file("::sourcePath::") #if display private #end class __ASSET__::flatName:: extends lime.utils.Bytes {} ::elseif (type == "music")::@:file("::sourcePath::") #if display private #end class __ASSET__::flatName:: extends lime.utils.Bytes {} ::elseif (type == "font")::@:font("::sourcePath::") #if display private #end class __ASSET__::flatName:: extends lime.text.Font {} ::else::@:file("::sourcePath::") #if display private #end class __ASSET__::flatName:: extends lime.utils.Bytes {} ::end::::end::::end:: ::end:: #end #end #if (openfl && !flash) ::if (assets != null)::::foreach assets::::if (type == "font")::@:keep #if display private #end class __ASSET__OPENFL__::flatName:: extends openfl.text.Font { public function new () { ::if (embed)::var font = new __ASSET__::flatName:: (); src = font.src; name = font.name;::else::__fontPath = #if (ios || tvos) "assets/" + #end "::targetPath::"; name = "::fontName::";::end:: super (); }} ::end::::end::::end:: #end #end