PageRenderTime 54ms CodeModel.GetById 15ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/src/away3d/loaders/parsers/Max3DSParser.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 885 lines | 654 code | 145 blank | 86 comment | 91 complexity | e48612e1f5fcfffa1f168190495b02ca MD5 | raw file
  1package away3d.loaders.parsers
  2{
  3	import away3d.*;
  4	import away3d.containers.*;
  5	import away3d.core.base.*;
  6	import away3d.entities.*;
  7	import away3d.library.assets.*;
  8	import away3d.loaders.misc.*;
  9	import away3d.loaders.parsers.utils.*;
 10	import away3d.materials.*;
 11	import away3d.materials.utils.*;
 12	import away3d.textures.*;
 13	import away3d.tools.utils.*;
 14	
 15	import flash.geom.*;
 16	import flash.net.*;
 17	import flash.utils.*;
 18	
 19	use namespace arcane;
 20	
 21	/**
 22	 * Max3DSParser provides a parser for the 3ds data type.
 23	 */
 24	public class Max3DSParser extends ParserBase
 25	{
 26		private var _byteData:ByteArray;
 27		
 28		private var _textures:Object;
 29		private var _materials:Object;
 30		private var _unfinalized_objects:Object;
 31		
 32		private var _cur_obj_end:uint;
 33		private var _cur_obj:ObjectVO;
 34		
 35		private var _cur_mat_end:uint;
 36		private var _cur_mat:MaterialVO;
 37		private var _useSmoothingGroups:Boolean;
 38		
 39		/**
 40		 * Creates a new <code>Max3DSParser</code> object.
 41		 * 
 42		 * @param useSmoothingGroups Determines whether the parser looks for smoothing groups in the 3ds file or assumes uniform smoothing. Defaults to true.
 43		 */
 44		public function Max3DSParser(useSmoothingGroups:Boolean = true)
 45		{
 46			super(ParserDataFormat.BINARY);
 47			
 48			_useSmoothingGroups = useSmoothingGroups;
 49		}
 50		
 51		/**
 52		 * Indicates whether or not a given file extension is supported by the parser.
 53		 * @param extension The file extension of a potential file to be parsed.
 54		 * @return Whether or not the given file type is supported.
 55		 */
 56		public static function supportsType(extension:String):Boolean
 57		{
 58			extension = extension.toLowerCase();
 59			return extension == "3ds";
 60		}
 61		
 62		/**
 63		 * Tests whether a data block can be parsed by the parser.
 64		 * @param data The data block to potentially be parsed.
 65		 * @return Whether or not the given data is supported.
 66		 */
 67		public static function supportsData(data:*):Boolean
 68		{
 69			var ba:ByteArray;
 70			
 71			ba = ParserUtil.toByteArray(data);
 72			if (ba) {
 73				ba.position = 0;
 74				if (ba.readShort() == 0x4d4d)
 75					return true;
 76			}
 77			
 78			return false;
 79		}
 80		
 81		/**
 82		 * @inheritDoc
 83		 */
 84		arcane override function resolveDependency(resourceDependency:ResourceDependency):void
 85		{
 86			if (resourceDependency.assets.length == 1) {
 87				var asset:IAsset;
 88				
 89				asset = resourceDependency.assets[0];
 90				if (asset.assetType == AssetType.TEXTURE) {
 91					var tex:TextureVO;
 92					
 93					tex = _textures[resourceDependency.id];
 94					tex.texture = asset as Texture2DBase;
 95				}
 96			}
 97		}
 98		
 99		/**
100		 * @inheritDoc
101		 */
102		arcane override function resolveDependencyFailure(resourceDependency:ResourceDependency):void
103		{
104			// TODO: Implement
105		}
106		
107		/**
108		 * @inheritDoc
109		 */
110		protected override function startParsing(frameLimit:Number):void
111		{
112			super.startParsing(frameLimit);
113			
114			_byteData = ParserUtil.toByteArray(_data);
115			_byteData.position = 0;
116			_byteData.endian = Endian.LITTLE_ENDIAN;
117			
118			_textures = {};
119			_materials = {};
120			_unfinalized_objects = {};
121		}
122		
123		/**
124		 * @inheritDoc
125		 */
126		protected override function proceedParsing():Boolean
127		{
128			
129			// TODO: With this construct, the loop will run no-op for as long
130			// as there is time once file has finished reading. Consider a nice
131			// way to stop loop when byte array is empty, without putting it in
132			// the while-conditional, which will prevent finalizations from
133			// happening after the last chunk.
134			while (hasTime()) {
135				
136				// If we are currently working on an object, and the most recent chunk was
137				// the last one in that object, finalize the current object.
138				if (_cur_mat && _byteData.position >= _cur_mat_end)
139					finalizeCurrentMaterial();
140				else if (_cur_obj && _byteData.position >= _cur_obj_end) {
141					// Can't finalize at this point, because we have to wait until the full
142					// animation section has been parsed for any potential pivot definitions
143					_unfinalized_objects[_cur_obj.name] = _cur_obj;
144					_cur_obj_end = uint.MAX_VALUE;
145					_cur_obj = null;
146				}
147				
148				if (_byteData.bytesAvailable) {
149					var cid:uint;
150					var len:uint;
151					var end:uint;
152					
153					cid = _byteData.readUnsignedShort();
154					len = _byteData.readUnsignedInt();
155					end = _byteData.position + (len - 6);
156					
157					switch (cid) {
158						case 0x4D4D: // MAIN3DS
159						case 0x3D3D: // EDIT3DS
160						case 0xB000: // KEYF3DS
161							// This types are "container chunks" and contain only
162							// sub-chunks (no data on their own.) This means that
163							// there is nothing more to parse at this point, and 
164							// instead we should progress to the next chunk, which
165							// will be the first sub-chunk of this one.
166							continue;
167							break;
168						
169						case 0xAFFF: // MATERIAL
170							_cur_mat_end = end;
171							_cur_mat = parseMaterial();
172							break;
173						
174						case 0x4000: // EDIT_OBJECT
175							_cur_obj_end = end;
176							_cur_obj = new ObjectVO();
177							_cur_obj.name = readNulTermString();
178							_cur_obj.materials = new Vector.<String>();
179							_cur_obj.materialFaces = {};
180							break;
181						
182						case 0x4100: // OBJ_TRIMESH 
183							_cur_obj.type = AssetType.MESH;
184							break;
185						
186						case 0x4110: // TRI_VERTEXL
187							parseVertexList();
188							break;
189						
190						case 0x4120: // TRI_FACELIST
191							parseFaceList();
192							break;
193						
194						case 0x4140: // TRI_MAPPINGCOORDS
195							parseUVList();
196							break;
197						
198						case 0x4130: // Face materials
199							parseFaceMaterialList();
200							break;
201						
202						case 0x4160: // Transform
203							_cur_obj.transform = readTransform();
204							break;
205						
206						case 0xB002: // Object animation (including pivot)
207							parseObjectAnimation(end);
208							break;
209						
210						case 0x4150: // Smoothing groups
211							parseSmoothingGroups();
212							break;
213						
214						default:
215							// Skip this (unknown) chunk
216							_byteData.position += (len - 6);
217							break;
218					}
219					
220					// Pause parsing if there were any dependencies found during this
221					// iteration (i.e. if there are any dependencies that need to be
222					// retrieved at this time.)
223					if (dependencies.length) {
224						pauseAndRetrieveDependencies();
225						break;
226					}
227				}
228			}
229			
230			// More parsing is required if the entire byte array has not yet
231			// been read, or if there is a currently non-finalized object in
232			// the pipeline.
233			if (_byteData.bytesAvailable || _cur_obj || _cur_mat)
234				return MORE_TO_PARSE;
235			else {
236				var name:String;
237				
238				// Finalize any remaining objects before ending.
239				for (name in _unfinalized_objects) {
240					var obj:ObjectContainer3D;
241					obj = constructObject(_unfinalized_objects[name]);
242					if (obj)
243						finalizeAsset(obj, name);
244				}
245				
246				return PARSING_DONE;
247			}
248		}
249		
250		private function parseMaterial():MaterialVO
251		{
252			var mat:MaterialVO;
253			
254			mat = new MaterialVO();
255			
256			while (_byteData.position < _cur_mat_end) {
257				var cid:uint;
258				var len:uint;
259				var end:uint;
260				
261				cid = _byteData.readUnsignedShort();
262				len = _byteData.readUnsignedInt();
263				end = _byteData.position + (len - 6);
264				
265				switch (cid) {
266					case 0xA000: // Material name
267						mat.name = readNulTermString();
268						break;
269					
270					case 0xA010: // Ambient color
271						mat.ambientColor = readColor();
272						break;
273					
274					case 0xA020: // Diffuse color
275						mat.diffuseColor = readColor();
276						break;
277					
278					case 0xA030: // Specular color
279						mat.specularColor = readColor();
280						break;
281					
282					case 0xA081: // Two-sided, existence indicates "true"
283						mat.twoSided = true;
284						break;
285					
286					case 0xA200: // Main (color) texture 
287						mat.colorMap = parseTexture(end);
288						break;
289					
290					case 0xA204: // Specular map
291						mat.specularMap = parseTexture(end);
292						break;
293					
294					default:
295						_byteData.position = end;
296						break;
297				}
298			}
299			
300			return mat;
301		}
302		
303		private function parseTexture(end:uint):TextureVO
304		{
305			var tex:TextureVO;
306			
307			tex = new TextureVO();
308			
309			while (_byteData.position < end) {
310				var cid:uint;
311				var len:uint;
312				
313				cid = _byteData.readUnsignedShort();
314				len = _byteData.readUnsignedInt();
315				
316				switch (cid) {
317					case 0xA300:
318						tex.url = readNulTermString();
319						break;
320					
321					default:
322						// Skip this unknown texture sub-chunk
323						_byteData.position += (len - 6);
324						break;
325				}
326			}
327			
328			_textures[tex.url] = tex;
329			addDependency(tex.url, new URLRequest(tex.url));
330			
331			return tex;
332		}
333		
334		private function parseVertexList():void
335		{
336			var i:uint;
337			var len:uint;
338			var count:uint;
339			
340			count = _byteData.readUnsignedShort();
341			_cur_obj.verts = new Vector.<Number>(count*3, true);
342			
343			i = 0;
344			len = _cur_obj.verts.length;
345			while (i < len) {
346				var x:Number, y:Number, z:Number;
347				
348				x = _byteData.readFloat();
349				y = _byteData.readFloat();
350				z = _byteData.readFloat();
351				
352				_cur_obj.verts[i++] = x;
353				_cur_obj.verts[i++] = z;
354				_cur_obj.verts[i++] = y;
355			}
356		}
357		
358		private function parseFaceList():void
359		{
360			var i:uint;
361			var len:uint;
362			var count:uint;
363			
364			count = _byteData.readUnsignedShort();
365			_cur_obj.indices = new Vector.<uint>(count*3, true);
366			
367			i = 0;
368			len = _cur_obj.indices.length;
369			while (i < len) {
370				var i0:uint, i1:uint, i2:uint;
371				
372				i0 = _byteData.readUnsignedShort();
373				i1 = _byteData.readUnsignedShort();
374				i2 = _byteData.readUnsignedShort();
375				
376				_cur_obj.indices[i++] = i0;
377				_cur_obj.indices[i++] = i2;
378				_cur_obj.indices[i++] = i1;
379				
380				// Skip "face info", irrelevant in Away3D
381				_byteData.position += 2;
382			}
383			
384			_cur_obj.smoothingGroups = new Vector.<uint>(count, true);
385		}
386		
387		private function parseSmoothingGroups():void
388		{
389			var len:uint = _cur_obj.indices.length/3;
390			var i:uint = 0;
391			while (i < len) {
392				_cur_obj.smoothingGroups[i] = _byteData.readUnsignedInt();
393				i++;
394			}
395		}
396		
397		private function parseUVList():void
398		{
399			var i:uint;
400			var len:uint;
401			var count:uint;
402			
403			count = _byteData.readUnsignedShort();
404			_cur_obj.uvs = new Vector.<Number>(count*2, true);
405			
406			i = 0;
407			len = _cur_obj.uvs.length;
408			while (i < len) {
409				_cur_obj.uvs[i++] = _byteData.readFloat();
410				_cur_obj.uvs[i++] = 1.0 - _byteData.readFloat();
411			}
412		}
413		
414		private function parseFaceMaterialList():void
415		{
416			var mat:String;
417			var count:uint;
418			var i:uint;
419			var faces:Vector.<uint>;
420			
421			mat = readNulTermString();
422			count = _byteData.readUnsignedShort();
423			
424			faces = new Vector.<uint>(count, true);
425			i = 0;
426			while (i < faces.length)
427				faces[i++] = _byteData.readUnsignedShort();
428			
429			_cur_obj.materials.push(mat);
430			_cur_obj.materialFaces[mat] = faces;
431		}
432		
433		private function parseObjectAnimation(end:Number):void
434		{
435			var vo:ObjectVO;
436			var obj:ObjectContainer3D;
437			var pivot:Vector3D;
438			var name:String;
439			var hier:int;
440			
441			// Pivot defaults to origin
442			pivot = new Vector3D;
443			
444			while (_byteData.position < end) {
445				var cid:uint;
446				var len:uint;
447				
448				cid = _byteData.readUnsignedShort();
449				len = _byteData.readUnsignedInt();
450				
451				switch (cid) {
452					case 0xb010: // Name/hierarchy
453						name = readNulTermString();
454						_byteData.position += 4;
455						hier = _byteData.readShort();
456						break;
457					
458					case 0xb013: // Pivot
459						pivot.x = _byteData.readFloat();
460						pivot.z = _byteData.readFloat();
461						pivot.y = _byteData.readFloat();
462						break;
463					
464					default:
465						_byteData.position += (len - 6);
466						break;
467				}
468			}
469			
470			// If name is "$$$DUMMY" this is an empty object (e.g. a container)
471			// and will be ignored in this version of the parser
472			// TODO: Implement containers in 3DS parser.
473			if (name != '$$$DUMMY' && _unfinalized_objects.hasOwnProperty(name)) {
474				vo = _unfinalized_objects[name];
475				obj = constructObject(vo, pivot);
476				
477				if (obj)
478					finalizeAsset(obj, vo.name);
479				
480				delete _unfinalized_objects[name];
481			}
482		}
483		
484		private function constructObject(obj:ObjectVO, pivot:Vector3D = null):ObjectContainer3D
485		{
486			if (obj.type == AssetType.MESH) {
487				var i:uint;
488				var subs:Vector.<ISubGeometry>;
489				var geom:Geometry;
490				var mat:MaterialBase;
491				var mesh:Mesh;
492				var mtx:Matrix3D;
493				var vertices:Vector.<VertexVO>;
494				var faces:Vector.<FaceVO>;
495				
496				if (obj.materials.length > 1)
497					trace('The Away3D 3DS parser does not support multiple materials per mesh at this point.');
498				
499				// Ignore empty objects
500				if (!obj.indices || obj.indices.length == 0)
501					return null;
502				
503				vertices = new Vector.<VertexVO>(obj.verts.length/3, false);
504				faces = new Vector.<FaceVO>(obj.indices.length/3, true);
505				
506				prepareData(vertices, faces, obj);
507				
508				if (_useSmoothingGroups)
509					applySmoothGroups(vertices, faces);
510				
511				obj.verts = new Vector.<Number>(vertices.length*3, true);
512				for (i = 0; i < vertices.length; i++) {
513					obj.verts[i*3] = vertices[i].x;
514					obj.verts[i*3 + 1] = vertices[i].y;
515					obj.verts[i*3 + 2] = vertices[i].z;
516				}
517				obj.indices = new Vector.<uint>(faces.length*3, true);
518				for (i = 0; i < faces.length; i++) {
519					obj.indices[i*3] = faces[i].a;
520					obj.indices[i*3 + 1] = faces[i].b;
521					obj.indices[i*3 + 2] = faces[i].c;
522				}
523				
524				if (obj.uvs) {
525					// If the object had UVs to start with, use UVs generated by
526					// smoothing group splitting algorithm. Otherwise those UVs
527					// will be nonsense and should be skipped.
528					obj.uvs = new Vector.<Number>(vertices.length*2, true);
529					for (i = 0; i < vertices.length; i++) {
530						obj.uvs[i*2] = vertices[i].u;
531						obj.uvs[i*2 + 1] = vertices[i].v;
532					}
533				}
534				
535				geom = new Geometry();
536				
537				// Construct sub-geometries (potentially splitting buffers)
538				// and add them to geometry.
539				subs = GeomUtil.fromVectors(obj.verts, obj.indices, obj.uvs, null, null, null, null);
540				for (i = 0; i < subs.length; i++)
541					geom.subGeometries.push(subs[i]);
542				
543				if (obj.materials.length > 0) {
544					var mname:String;
545					mname = obj.materials[0];
546					mat = _materials[mname].material;
547				}
548				
549				// Apply pivot translation to geometry if a pivot was
550				// found while parsing the keyframe chunk earlier.
551				if (pivot) {
552					if (obj.transform) {
553						// If a transform was found while parsing the
554						// object chunk, use it to find the local pivot vector
555						var dat:Vector.<Number> = obj.transform.concat();
556						dat[12] = 0;
557						dat[13] = 0;
558						dat[14] = 0;
559						mtx = new Matrix3D(dat);
560						pivot = mtx.transformVector(pivot);
561					}
562					
563					pivot.scaleBy(-1);
564					
565					mtx = new Matrix3D();
566					mtx.appendTranslation(pivot.x, pivot.y, pivot.z);
567					geom.applyTransformation(mtx);
568				}
569				
570				// Apply transformation to geometry if a transformation
571				// was found while parsing the object chunk earlier.
572				if (obj.transform) {
573					mtx = new Matrix3D(obj.transform);
574					mtx.invert();
575					geom.applyTransformation(mtx);
576				}
577				
578				// Final transform applied to geometry. Finalize the geometry,
579				// which will no longer be modified after this point.
580				finalizeAsset(geom, obj.name.concat('_geom'));
581				
582				// Build mesh and return it
583				mesh = new Mesh(geom, mat);
584				mesh.transform = new Matrix3D(obj.transform);
585				return mesh;
586			}
587			
588			// If reached, unknown
589			return null;
590		}
591		
592		private function prepareData(vertices:Vector.<VertexVO>, faces:Vector.<FaceVO>, obj:ObjectVO):void
593		{
594			// convert raw ObjectVO's data to structured VertexVO and FaceVO
595			var i:int;
596			var j:int;
597			var k:int;
598			var len:int = obj.verts.length;
599			for (i = 0, j = 0, k = 0; i < len; ) {
600				var v:VertexVO = new VertexVO;
601				v.x = obj.verts[i++];
602				v.y = obj.verts[i++];
603				v.z = obj.verts[i++];
604				if (obj.uvs) {
605					v.u = obj.uvs[j++];
606					v.v = obj.uvs[j++];
607				}
608				vertices[k++] = v;
609			}
610			len = obj.indices.length;
611			for (i = 0, k = 0; i < len; ) {
612				var f:FaceVO = new FaceVO();
613				f.a = obj.indices[i++];
614				f.b = obj.indices[i++];
615				f.c = obj.indices[i++];
616				f.smoothGroup = obj.smoothingGroups[k];
617				faces[k++] = f;
618			}
619		}
620		
621		private function applySmoothGroups(vertices:Vector.<VertexVO>, faces:Vector.<FaceVO>):void
622		{
623			// clone vertices according to following rule:
624			// clone if vertex's in faces from groups 1+2 and 3
625			// don't clone if vertex's in faces from groups 1+2, 3 and 1+3
626			
627			var i:int;
628			var j:int;
629			var k:int;
630			var l:int;
631			var len:int;
632			var numVerts:uint = vertices.length;
633			var numFaces:uint = faces.length;
634			
635			// extract groups data for vertices
636			var vGroups:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(numVerts, true);
637			for (i = 0; i < numVerts; i++)
638				vGroups[i] = new Vector.<uint>;
639			for (i = 0; i < numFaces; i++) {
640				var face:FaceVO = FaceVO(faces[i]);
641				for (j = 0; j < 3; j++) {
642					var groups:Vector.<uint> = vGroups[(j == 0)? face.a : ((j == 1)? face.b : face.c)];
643					var group:uint = face.smoothGroup;
644					for (k = groups.length - 1; k >= 0; k--) {
645						if ((group & groups[k]) > 0) {
646							group |= groups[k];
647							groups.splice(k, 1);
648							k = groups.length - 1;
649						}
650					}
651					groups.push(group);
652				}
653			}
654			// clone vertices
655			var vClones:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(numVerts, true);
656			for (i = 0; i < numVerts; i++) {
657				if ((len = vGroups[i].length) < 1)
658					continue;
659				var clones:Vector.<uint> = new Vector.<uint>(len, true);
660				vClones[i] = clones;
661				clones[0] = i;
662				var v0:VertexVO = vertices[i];
663				for (j = 1; j < len; j++) {
664					var v1:VertexVO = new VertexVO;
665					v1.x = v0.x;
666					v1.y = v0.y;
667					v1.z = v0.z;
668					v1.u = v0.u;
669					v1.v = v0.v;
670					clones[j] = vertices.length;
671					vertices.push(v1);
672				}
673			}
674			numVerts = vertices.length;
675			
676			for (i = 0; i < numFaces; i++) {
677				face = FaceVO(faces[i]);
678				group = face.smoothGroup;
679				for (j = 0; j < 3; j++) {
680					k = (j == 0)? face.a : ((j == 1)? face.b : face.c);
681					groups = vGroups[k];
682					len = groups.length;
683					clones = vClones[k];
684					for (l = 0; l < len; l++) {
685						if (((group == 0) && (groups[l] == 0)) ||
686							((group & groups[l]) > 0)) {
687							var index:uint = clones[l];
688							if (group == 0) {
689								// vertex is unique if no smoothGroup found
690								groups.splice(l, 1);
691								clones.splice(l, 1);
692							}
693							if (j == 0)
694								face.a = index;
695							else if (j == 1)
696								face.b = index;
697							else
698								face.c = index;
699							l = len;
700						}
701					}
702				}
703			}
704		}
705		
706		private function finalizeCurrentMaterial():void
707		{
708			var mat:MaterialBase;
709			if (materialMode < 2) {
710				if (_cur_mat.colorMap)
711					mat = new TextureMaterial(_cur_mat.colorMap.texture || DefaultMaterialManager.getDefaultTexture());
712				else
713					mat = new ColorMaterial(_cur_mat.diffuseColor);
714				SinglePassMaterialBase(mat).ambientColor = _cur_mat.ambientColor;
715				SinglePassMaterialBase(mat).specularColor = _cur_mat.specularColor;
716			} else {
717				if (_cur_mat.colorMap)
718					mat = new TextureMultiPassMaterial(_cur_mat.colorMap.texture || DefaultMaterialManager.getDefaultTexture());
719				else
720					mat = new ColorMultiPassMaterial(_cur_mat.diffuseColor);
721				MultiPassMaterialBase(mat).ambientColor = _cur_mat.ambientColor;
722				MultiPassMaterialBase(mat).specularColor = _cur_mat.specularColor;
723			}
724			
725			mat.bothSides = _cur_mat.twoSided;
726			
727			finalizeAsset(mat, _cur_mat.name);
728			
729			_materials[_cur_mat.name] = _cur_mat;
730			_cur_mat.material = mat;
731			
732			_cur_mat = null;
733		}
734		
735		private function readNulTermString():String
736		{
737			var chr:uint;
738			var str:String = new String();
739			
740			while ((chr = _byteData.readUnsignedByte()) > 0)
741				str += String.fromCharCode(chr);
742			
743			return str;
744		}
745		
746		private function readTransform():Vector.<Number>
747		{
748			var data:Vector.<Number>;
749			
750			data = new Vector.<Number>(16, true);
751			
752			// X axis
753			data[0] = _byteData.readFloat(); // X
754			data[2] = _byteData.readFloat(); // Z
755			data[1] = _byteData.readFloat(); // Y
756			data[3] = 0;
757			
758			// Z axis
759			data[8] = _byteData.readFloat(); // X
760			data[10] = _byteData.readFloat(); // Z
761			data[9] = _byteData.readFloat(); // Y
762			data[11] = 0;
763			
764			// Y Axis
765			data[4] = _byteData.readFloat(); // X 
766			data[6] = _byteData.readFloat(); // Z
767			data[5] = _byteData.readFloat(); // Y
768			data[7] = 0;
769			
770			// Translation
771			data[12] = _byteData.readFloat(); // X
772			data[14] = _byteData.readFloat(); // Z
773			data[13] = _byteData.readFloat(); // Y
774			data[15] = 1;
775			
776			return data;
777		}
778		
779		private function readColor():uint
780		{
781			var cid:uint;
782			var len:uint;
783			var r:uint, g:uint, b:uint;
784			
785			cid = _byteData.readUnsignedShort();
786			len = _byteData.readUnsignedInt();
787			
788			switch (cid) {
789				case 0x0010: // Floats
790					r = _byteData.readFloat()*255;
791					g = _byteData.readFloat()*255;
792					b = _byteData.readFloat()*255;
793					break;
794				case 0x0011: // 24-bit color
795					r = _byteData.readUnsignedByte();
796					g = _byteData.readUnsignedByte();
797					b = _byteData.readUnsignedByte();
798					break;
799				default:
800					_byteData.position += (len - 6);
801					break;
802			}
803			
804			return (r << 16) | (g << 8) | b;
805		}
806	}
807}
808
809import away3d.materials.MaterialBase;
810import away3d.textures.Texture2DBase;
811
812import flash.geom.Vector3D;
813
814internal class TextureVO
815{
816	public var url:String;
817	public var texture:Texture2DBase;
818	
819	public function TextureVO()
820	{
821	}
822}
823
824internal class MaterialVO
825{
826	public var name:String;
827	public var ambientColor:uint;
828	public var diffuseColor:uint;
829	public var specularColor:uint;
830	public var twoSided:Boolean;
831	public var colorMap:TextureVO;
832	public var specularMap:TextureVO;
833	public var material:MaterialBase;
834	
835	public function MaterialVO()
836	{
837	}
838}
839
840internal class ObjectVO
841{
842	public var name:String;
843	public var type:String;
844	public var pivotX:Number;
845	public var pivotY:Number;
846	public var pivotZ:Number;
847	public var transform:Vector.<Number>;
848	public var verts:Vector.<Number>;
849	public var indices:Vector.<uint>;
850	public var uvs:Vector.<Number>;
851	public var materialFaces:Object;
852	public var materials:Vector.<String>;
853	public var smoothingGroups:Vector.<uint>;
854	
855	public function ObjectVO()
856	{
857	}
858}
859
860internal class VertexVO
861{
862	public var x:Number;
863	public var y:Number;
864	public var z:Number;
865	public var u:Number;
866	public var v:Number;
867	public var normal:Vector3D;
868	public var tangent:Vector3D;
869	
870	public function VertexVO()
871	{
872	}
873}
874
875internal class FaceVO
876{
877	public var a:uint;
878	public var b:uint;
879	public var c:uint;
880	public var smoothGroup:uint;
881	
882	public function FaceVO()
883	{
884	}
885}