PageRenderTime 469ms CodeModel.GetById 129ms app.highlight 175ms RepoModel.GetById 157ms app.codeStats 0ms

/src/away3d/loaders/misc/SingleFileLoader.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 522 lines | 247 code | 85 blank | 190 comment | 24 complexity | bb830a14ccc0e5da6279219002d506a5 MD5 | raw file
  1package away3d.loaders.misc
  2{
  3	import away3d.arcane;
  4	import away3d.events.AssetEvent;
  5	import away3d.events.LoaderEvent;
  6	import away3d.events.ParserEvent;
  7	import away3d.loaders.parsers.ImageParser;
  8	import away3d.loaders.parsers.ParserBase;
  9	import away3d.loaders.parsers.ParserDataFormat;
 10	
 11	import flash.events.Event;
 12	import flash.events.EventDispatcher;
 13	import flash.events.IOErrorEvent;
 14	import flash.net.URLLoader;
 15	import flash.net.URLLoaderDataFormat;
 16	import flash.net.URLRequest;
 17	
 18	use namespace arcane;
 19	
 20	/**
 21	 * Dispatched when any asset finishes parsing. Also see specific events for each
 22	 * individual asset type (meshes, materials et c.)
 23	 *
 24	 * @eventType away3d.events.AssetEvent
 25	 */
 26	[Event(name="assetComplete", type="away3d.events.AssetEvent")]
 27			
 28	
 29	/**
 30	 * Dispatched when a single dependency (which may be the main file of a resource)
 31	 * finishes loading.
 32	 *
 33	 * @eventType away3d.events.LoaderEvent
 34	 */
 35	[Event(name="dependencyComplete", type="away3d.events.LoaderEvent")]
 36	
 37	
 38	/**
 39	 * Dispatched when an error occurs during loading. I
 40	 *
 41	 * @eventType away3d.events.LoaderEvent
 42	 */
 43	[Event(name="loadError", type="away3d.events.LoaderEvent")]
 44	
 45	
 46	/**
 47	 * Dispatched when an error occurs during parsing.
 48	 *
 49	 * @eventType away3d.events.ParserEvent
 50	 */
 51	[Event(name="parseError", type="away3d.events.ParserEvent")]
 52	
 53	
 54	/**
 55	 * Dispatched when a skybox asset has been costructed from a ressource.
 56	 * 
 57	 * @eventType away3d.events.AssetEvent
 58	 */
 59	[Event(name="skyboxComplete", type="away3d.events.AssetEvent")]
 60	
 61	/**
 62	 * Dispatched when a camera3d asset has been costructed from a ressource.
 63	 * 
 64	 * @eventType away3d.events.AssetEvent
 65	 */
 66	[Event(name="cameraComplete", type="away3d.events.AssetEvent")]
 67	
 68	/**
 69	 * Dispatched when a mesh asset has been costructed from a ressource.
 70	 * 
 71	 * @eventType away3d.events.AssetEvent
 72	 */
 73	[Event(name="meshComplete", type="away3d.events.AssetEvent")]
 74	
 75	/**
 76	 * Dispatched when a geometry asset has been constructed from a resource.
 77	 *
 78	 * @eventType away3d.events.AssetEvent
 79	 */
 80	[Event(name="geometryComplete", type="away3d.events.AssetEvent")]
 81	
 82	/**
 83	 * Dispatched when a skeleton asset has been constructed from a resource.
 84	 *
 85	 * @eventType away3d.events.AssetEvent
 86	 */
 87	[Event(name="skeletonComplete", type="away3d.events.AssetEvent")]
 88	
 89	/**
 90	 * Dispatched when a skeleton pose asset has been constructed from a resource.
 91	 *
 92	 * @eventType away3d.events.AssetEvent
 93	 */
 94	[Event(name="skeletonPoseComplete", type="away3d.events.AssetEvent")]
 95	
 96	/**
 97	 * Dispatched when a container asset has been constructed from a resource.
 98	 *
 99	 * @eventType away3d.events.AssetEvent
100	 */
101	[Event(name="containerComplete", type="away3d.events.AssetEvent")]
102	
103	/**
104	 * Dispatched when a texture asset has been constructed from a resource.
105	 *
106	 * @eventType away3d.events.AssetEvent
107	 */
108	[Event(name="textureComplete", type="away3d.events.AssetEvent")]
109	
110	/**
111	 * Dispatched when a texture projector asset has been constructed from a resource.
112	 *
113	 * @eventType away3d.events.AssetEvent
114	 */
115	[Event(name="textureProjectorComplete", type="away3d.events.AssetEvent")]
116	
117	
118	/**
119	 * Dispatched when a material asset has been constructed from a resource.
120	 *
121	 * @eventType away3d.events.AssetEvent
122	 */
123	[Event(name="materialComplete", type="away3d.events.AssetEvent")]
124	
125	
126	/**
127	 * Dispatched when a animator asset has been constructed from a resource.
128	 *
129	 * @eventType away3d.events.AssetEvent
130	 */
131	[Event(name="animatorComplete", type="away3d.events.AssetEvent")]
132	
133	
134	/**
135	 * Dispatched when an animation set has been constructed from a group of animation state resources.
136	 *
137	 * @eventType away3d.events.AssetEvent
138	 */
139	[Event(name="animationSetComplete", type="away3d.events.AssetEvent")]
140	
141	
142	/**
143	 * Dispatched when an animation state has been constructed from a group of animation node resources.
144	 *
145	 * @eventType away3d.events.AssetEvent
146	 */
147	[Event(name="animationStateComplete", type="away3d.events.AssetEvent")]
148	
149	
150	/**
151	 * Dispatched when an animation node has been constructed from a resource.
152	 *
153	 * @eventType away3d.events.AssetEvent
154	 */
155	[Event(name="animationNodeComplete", type="away3d.events.AssetEvent")]
156	
157	
158	/**
159	 * Dispatched when an animation state transition has been constructed from a group of animation node resources.
160	 *
161	 * @eventType away3d.events.AssetEvent
162	 */
163	[Event(name="stateTransitionComplete", type="away3d.events.AssetEvent")]
164	
165	
166	/**
167	 * Dispatched when an light asset has been constructed from a resources.
168	 *
169	 * @eventType away3d.events.AssetEvent
170	 */
171	[Event(name="lightComplete", type="away3d.events.AssetEvent")]
172	
173	
174	/**
175	 * Dispatched when an light picker asset has been constructed from a resources.
176	 *
177	 * @eventType away3d.events.AssetEvent
178	 */
179	[Event(name="lightPickerComplete", type="away3d.events.AssetEvent")]
180	
181	
182	/**
183	 * Dispatched when an effect method asset has been constructed from a resources.
184	 *
185	 * @eventType away3d.events.AssetEvent
186	 */
187	[Event(name="effectMethodComplete", type="away3d.events.AssetEvent")]
188	
189	
190	/**
191	 * Dispatched when an shadow map method asset has been constructed from a resources.
192	 *
193	 * @eventType away3d.events.AssetEvent
194	 */
195	[Event(name="shadowMapMethodComplete", type="away3d.events.AssetEvent")]
196	
197	/**
198	 * The SingleFileLoader is used to load a single file, as part of a resource.
199	 *
200	 * While SingleFileLoader can be used directly, e.g. to create a third-party asset
201	 * management system, it's recommended to use any of the classes Loader3D, AssetLoader
202	 * and AssetLibrary instead in most cases.
203	 *
204	 * @see away3d.loading.Loader3D
205	 * @see away3d.loading.AssetLoader
206	 * @see away3d.loading.AssetLibrary
207	 */
208	public class SingleFileLoader extends EventDispatcher
209	{
210		private var _parser:ParserBase;
211		private var _req:URLRequest;
212		private var _fileExtension:String;
213		private var _fileName:String;
214		private var _loadAsRawData:Boolean;
215		private var _materialMode:uint;
216		private var _data:*;
217		
218		// Image parser only parser that is added by default, to save file size.
219		private static var _parsers:Vector.<Class> = Vector.<Class>([ ImageParser ]);
220		
221		/**
222		 * Creates a new SingleFileLoader object.
223		 */
224		public function SingleFileLoader(materialMode:uint = 0)
225		{
226			
227			_materialMode = materialMode;
228		}
229		
230		public function get url():String
231		{
232			return _req? _req.url : '';
233		}
234		
235		public function get data():*
236		{
237			return _data;
238		}
239		
240		public function get loadAsRawData():Boolean
241		{
242			return _loadAsRawData;
243		}
244		
245		public static function enableParser(parser:Class):void
246		{
247			if (_parsers.indexOf(parser) < 0)
248				_parsers.push(parser);
249		}
250		
251		public static function enableParsers(parsers:Vector.<Class>):void
252		{
253			var pc:Class;
254			for each (pc in parsers)
255				enableParser(pc);
256		}
257		
258		/**
259		 * Load a resource from a file.
260		 *
261		 * @param urlRequest The URLRequest object containing the URL of the object to be loaded.
262		 * @param parser An optional parser object that will translate the loaded data into a usable resource. If not provided, AssetLoader will attempt to auto-detect the file type.
263		 */
264		public function load(urlRequest:URLRequest, parser:ParserBase = null, loadAsRawData:Boolean = false):void
265		{
266			var urlLoader:URLLoader;
267			var dataFormat:String;
268			
269			_loadAsRawData = loadAsRawData;
270			_req = urlRequest;
271			decomposeFilename(_req.url);
272			
273			if (_loadAsRawData) {
274				// Always use binary for raw data loading
275				dataFormat = URLLoaderDataFormat.BINARY;
276			} else {
277				if (parser)
278					_parser = parser;
279				
280				if (!_parser)
281					_parser = getParserFromSuffix();
282				
283				if (_parser) {
284					switch (_parser.dataFormat) {
285						case ParserDataFormat.BINARY:
286							dataFormat = URLLoaderDataFormat.BINARY;
287							break;
288						case ParserDataFormat.PLAIN_TEXT:
289							dataFormat = URLLoaderDataFormat.TEXT;
290							break;
291					}
292					
293				} else {
294					// Always use BINARY for unknown file formats. The thorough
295					// file type check will determine format after load, and if
296					// binary, a text load will have broken the file data.
297					dataFormat = URLLoaderDataFormat.BINARY;
298				}
299			}
300			
301			urlLoader = new URLLoader();
302			urlLoader.dataFormat = dataFormat;
303			urlLoader.addEventListener(Event.COMPLETE, handleUrlLoaderComplete);
304			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleUrlLoaderError);
305			urlLoader.load(urlRequest);
306		}
307		
308		/**
309		 * Loads a resource from already loaded data.
310		 * @param data The data to be parsed. Depending on the parser type, this can be a ByteArray, String or XML.
311		 * @param uri The identifier (url or id) of the object to be loaded, mainly used for resource management.
312		 * @param parser An optional parser object that will translate the data into a usable resource. If not provided, AssetLoader will attempt to auto-detect the file type.
313		 */
314		public function parseData(data:*, parser:ParserBase = null, req:URLRequest = null):void
315		{
316			if (data is Class)
317				data = new data();
318			
319			if (parser)
320				_parser = parser;
321			
322			_req = req;
323			
324			parse(data);
325		}
326		
327		/**
328		 * A reference to the parser that will translate the loaded data into a usable resource.
329		 */
330		public function get parser():ParserBase
331		{
332			return _parser;
333		}
334		
335		/**
336		 * A list of dependencies that need to be loaded and resolved for the loaded object.
337		 */
338		public function get dependencies():Vector.<ResourceDependency>
339		{
340			return _parser? _parser.dependencies : new Vector.<ResourceDependency>;
341		}
342		
343		/**
344		 * Splits a url string into base and extension.
345		 * @param url The url to be decomposed.
346		 */
347		private function decomposeFilename(url:String):void
348		{
349			
350			// Get rid of query string if any and extract suffix
351			var base:String = (url.indexOf('?') > 0)? url.split('?')[0] : url;
352			var i:int = base.lastIndexOf('.');
353			_fileExtension = base.substr(i + 1).toLowerCase();
354			_fileName = base.substr(0, i);
355		}
356		
357		/**
358		 * Guesses the parser to be used based on the file extension.
359		 * @return An instance of the guessed parser.
360		 */
361		private function getParserFromSuffix():ParserBase
362		{
363			var len:uint = _parsers.length;
364			
365			// go in reverse order to allow application override of default parser added in Away3D proper
366			for (var i:int = len - 1; i >= 0; i--) {
367				if (_parsers[i].supportsType(_fileExtension))
368					return new _parsers[i]();
369			}
370			
371			return null;
372		}
373		
374		/**
375		 * Guesses the parser to be used based on the file contents.
376		 * @param data The data to be parsed.
377		 * @param uri The url or id of the object to be parsed.
378		 * @return An instance of the guessed parser.
379		 */
380		private function getParserFromData(data:*):ParserBase
381		{
382			var len:uint = _parsers.length;
383			
384			// go in reverse order to allow application override of default parser added in Away3D proper
385			for (var i:int = len - 1; i >= 0; i--) {
386				if (_parsers[i].supportsData(data))
387					return new _parsers[i]();
388			}
389			
390			return null;
391		}
392		
393		/**
394		 * Cleanups
395		 */
396		private function removeListeners(urlLoader:URLLoader):void
397		{
398			urlLoader.removeEventListener(Event.COMPLETE, handleUrlLoaderComplete);
399			urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, handleUrlLoaderError);
400		}
401		
402		/**
403		 * Called when loading of a file has failed
404		 */
405		private function handleUrlLoaderError(event:IOErrorEvent):void
406		{
407			var urlLoader:URLLoader = URLLoader(event.currentTarget);
408			removeListeners(urlLoader);
409			
410			if (hasEventListener(LoaderEvent.LOAD_ERROR))
411				dispatchEvent(new LoaderEvent(LoaderEvent.LOAD_ERROR, _req.url, true, event.text));
412		}
413		
414		/**
415		 * Called when loading of a file is complete
416		 */
417		private function handleUrlLoaderComplete(event:Event):void
418		{
419			var urlLoader:URLLoader = URLLoader(event.currentTarget);
420			removeListeners(urlLoader);
421			
422			_data = urlLoader.data;
423			
424			if (_loadAsRawData) {
425				// No need to parse this data, which should be returned as is
426				dispatchEvent(new LoaderEvent(LoaderEvent.DEPENDENCY_COMPLETE));
427			} else
428				parse(_data);
429		}
430		
431		/**
432		 * Initiates parsing of the loaded data.
433		 * @param data The data to be parsed.
434		 */
435		private function parse(data:*):void
436		{
437			// If no parser has been defined, try to find one by letting
438			// all plugged in parsers inspect the actual data.
439			if (!_parser)
440				_parser = getParserFromData(data);
441			
442			if (_parser) {
443				_parser.addEventListener(ParserEvent.READY_FOR_DEPENDENCIES, onReadyForDependencies);
444				_parser.addEventListener(ParserEvent.PARSE_ERROR, onParseError);
445				_parser.addEventListener(ParserEvent.PARSE_COMPLETE, onParseComplete);
446				_parser.addEventListener(AssetEvent.TEXTURE_SIZE_ERROR, onTextureSizeError);
447				_parser.addEventListener(AssetEvent.ASSET_COMPLETE, onAssetComplete);
448				_parser.addEventListener(AssetEvent.ANIMATION_SET_COMPLETE, onAssetComplete);
449				_parser.addEventListener(AssetEvent.ANIMATION_STATE_COMPLETE, onAssetComplete);
450				_parser.addEventListener(AssetEvent.ANIMATION_NODE_COMPLETE, onAssetComplete);
451				_parser.addEventListener(AssetEvent.STATE_TRANSITION_COMPLETE, onAssetComplete);
452				_parser.addEventListener(AssetEvent.TEXTURE_COMPLETE, onAssetComplete);
453				_parser.addEventListener(AssetEvent.CONTAINER_COMPLETE, onAssetComplete);
454				_parser.addEventListener(AssetEvent.GEOMETRY_COMPLETE, onAssetComplete);
455				_parser.addEventListener(AssetEvent.MATERIAL_COMPLETE, onAssetComplete);
456				_parser.addEventListener(AssetEvent.MESH_COMPLETE, onAssetComplete);
457				_parser.addEventListener(AssetEvent.ENTITY_COMPLETE, onAssetComplete);
458				_parser.addEventListener(AssetEvent.SKELETON_COMPLETE, onAssetComplete);
459				_parser.addEventListener(AssetEvent.SKELETON_POSE_COMPLETE, onAssetComplete);
460				
461				if (_req && _req.url)
462					_parser._fileName = _req.url;
463				_parser.materialMode = _materialMode;
464				_parser.parseAsync(data);
465			} else {
466				var msg:String = "No parser defined. To enable all parsers for auto-detection, use Parsers.enableAllBundled()";
467				if (hasEventListener(LoaderEvent.LOAD_ERROR))
468					this.dispatchEvent(new LoaderEvent(LoaderEvent.LOAD_ERROR, "", true, msg));
469				else
470					throw new Error(msg);
471			}
472		}
473		
474		private function onParseError(event:ParserEvent):void
475		{
476			if (hasEventListener(ParserEvent.PARSE_ERROR))
477				dispatchEvent(event.clone());
478		}
479		
480		private function onReadyForDependencies(event:ParserEvent):void
481		{
482			dispatchEvent(event.clone());
483		}
484		
485		private function onAssetComplete(event:AssetEvent):void
486		{
487			this.dispatchEvent(event.clone());
488		}
489		
490		private function onTextureSizeError(event:AssetEvent):void
491		{
492			this.dispatchEvent(event.clone());
493		}
494		
495		/**
496		 * Called when parsing is complete.
497		 */
498		private function onParseComplete(event:ParserEvent):void
499		{
500			this.dispatchEvent(new LoaderEvent(LoaderEvent.DEPENDENCY_COMPLETE, this.url)); //dispatch in front of removing listeners to allow any remaining asset events to propagate
501			
502			_parser.removeEventListener(ParserEvent.READY_FOR_DEPENDENCIES, onReadyForDependencies);
503			_parser.removeEventListener(ParserEvent.PARSE_COMPLETE, onParseComplete);
504			_parser.removeEventListener(ParserEvent.PARSE_ERROR, onParseError);
505			_parser.removeEventListener(AssetEvent.TEXTURE_SIZE_ERROR, onTextureSizeError);
506			_parser.removeEventListener(AssetEvent.ASSET_COMPLETE, onAssetComplete);
507			_parser.removeEventListener(AssetEvent.ANIMATION_SET_COMPLETE, onAssetComplete);
508			_parser.removeEventListener(AssetEvent.ANIMATION_STATE_COMPLETE, onAssetComplete);
509			_parser.removeEventListener(AssetEvent.ANIMATION_NODE_COMPLETE, onAssetComplete);
510			_parser.removeEventListener(AssetEvent.STATE_TRANSITION_COMPLETE, onAssetComplete);
511			_parser.removeEventListener(AssetEvent.TEXTURE_COMPLETE, onAssetComplete);
512			_parser.removeEventListener(AssetEvent.CONTAINER_COMPLETE, onAssetComplete);
513			_parser.removeEventListener(AssetEvent.GEOMETRY_COMPLETE, onAssetComplete);
514			_parser.removeEventListener(AssetEvent.MATERIAL_COMPLETE, onAssetComplete);
515			_parser.removeEventListener(AssetEvent.MESH_COMPLETE, onAssetComplete);
516			_parser.removeEventListener(AssetEvent.ENTITY_COMPLETE, onAssetComplete);
517			_parser.removeEventListener(AssetEvent.SKELETON_COMPLETE, onAssetComplete);
518			_parser.removeEventListener(AssetEvent.SKELETON_POSE_COMPLETE, onAssetComplete);
519		}
520	}
521}
522