root/as3/FLARToolKit/trunk/libs/Papervision3D/src/org/papervision3d/objects/parsers/Max3DS.as

リビジョン 3288, 16.2 kB (コミッタ: rokubou, コミット時期: 3 年 前)

Add Papervison3D.

Line 
1 package org.papervision3d.objects.parsers
2 {
3         import flash.events.Event;
4         import flash.events.IOErrorEvent;
5         import flash.net.URLLoader;
6         import flash.net.URLLoaderDataFormat;
7         import flash.net.URLRequest;
8         import flash.utils.ByteArray;
9         import flash.utils.Endian;
10        
11         import org.papervision3d.Papervision3D;
12         import org.papervision3d.core.geom.TriangleMesh3D;
13         import org.papervision3d.core.geom.renderables.Triangle3D;
14         import org.papervision3d.core.geom.renderables.Vertex3D;
15         import org.papervision3d.core.math.NumberUV;
16         import org.papervision3d.core.proto.MaterialObject3D;
17         import org.papervision3d.events.FileLoadEvent;
18         import org.papervision3d.materials.BitmapFileMaterial;
19         import org.papervision3d.materials.ColorMaterial;
20         import org.papervision3d.materials.utils.MaterialsList;
21         import org.papervision3d.objects.DisplayObject3D;
22
23         /**
24          * 3DS File parser.
25          *
26          * @author Tim Knip (based on Away3D's Max3DS class : http://away3d.com)
27          */
28         public class Max3DS extends DisplayObject3D
29         {
30                 /** */
31                 public var filename:String;
32                
33                 /**
34                  * Constuctor
35                  *
36                  * @param       name
37                  */
38                 public function Max3DS(name:String=null)
39                 {
40                         super(name);
41                         _textureExtensionReplacements = new Object();
42                 }
43                
44                 /**
45                  * Load.
46                  *
47                  * @param       asset
48                  * @param       materials
49                  * @param       textureDir
50                  */
51                 public function load(asset:*, materials:MaterialsList=null, textureDir:String="./image/"):void
52                 {
53                         this.materials = materials || new MaterialsList();
54                        
55                         _textureDir = textureDir || _textureDir;
56                        
57                         if(asset is ByteArray)
58                         {
59                                 this.filename = "NoName.3ds";
60                                 parse(ByteArray(asset));
61                         }
62                         else if(asset is String)
63                         {
64                                 this.filename = String(asset);
65                                
66                                 var loader:URLLoader = new URLLoader();
67                                
68                                 loader.dataFormat = URLLoaderDataFormat.BINARY;
69                                 loader.addEventListener(Event.COMPLETE, onFileLoadComplete);
70                                 loader.addEventListener(IOErrorEvent.IO_ERROR, onFileLoadError);
71                                 loader.load(new URLRequest(this.filename));
72                         }
73                         else
74                                 throw new Error("Need String or ByteArray!");
75                 }
76                
77                 /**
78                  * Replaces a texture extension with an alternative extension.
79                  *
80                  * @param       originalExtension       For example "bmp", "gif", etc
81                  * @param       preferredExtension      For example "png"
82                  */
83                 public function replaceTextureExtension(originalExtension:String, preferredExtension:String="png"):void
84                 {
85                         _textureExtensionReplacements[originalExtension] = preferredExtension;
86                 }
87                
88                 /**
89                  * Build a mesh
90                  *
91                  * @param       meshData
92                  */
93                 private function buildMesh(meshData:MeshData):void
94                 {
95                         var i:int;
96                         var mesh:TriangleMesh3D = new TriangleMesh3D(null, meshData.vertices, [], meshData.name);
97                        
98                         for(i = 0; i < meshData.faces.length; i++)
99                         {
100                                 var f:Array = meshData.faces[i];
101                                
102                                 var v0:Vertex3D = mesh.geometry.vertices[f[0]];
103                                 var v1:Vertex3D = mesh.geometry.vertices[f[1]];
104                                 var v2:Vertex3D = mesh.geometry.vertices[f[2]];
105                                
106                                 var hasUV:Boolean = (meshData.uvs.length == meshData.vertices.length);
107                                
108                                 var t0:NumberUV = hasUV ? meshData.uvs[f[0]] : new NumberUV();
109                                 var t1:NumberUV = hasUV ? meshData.uvs[f[1]] : new NumberUV();
110                                 var t2:NumberUV = hasUV ? meshData.uvs[f[2]] : new NumberUV();
111                                
112                                 if(Papervision3D.useRIGHTHANDED)
113                                         mesh.geometry.faces.push(new Triangle3D(mesh, [v2, v1, v0], null, [t2, t1, t0]));
114                                 else
115                                         mesh.geometry.faces.push(new Triangle3D(mesh, [v0, v1, v2], null, [t0, t1, t2]));
116                         }
117                        
118                         for(i = 0; i < meshData.materials.length; i++)
119                         {
120                                 var mat:MaterialData = meshData.materials[i];
121                                 var material:MaterialObject3D = this.materials.getMaterialByName(mat.name) || MaterialObject3D.DEFAULT;
122                                
123                                 for(var j:int = 0; j < mat.faces.length; j++)
124                                 {
125                                         var faceIdx:int = mat.faces[j];
126                                         var tri:Triangle3D = mesh.geometry.faces[faceIdx];
127                                         tri.material = material;
128                                 }
129                         }
130                        
131                         mesh.geometry.ready = true;
132                         mesh.rotationX = Papervision3D.useDEGREES ? -90 : -90 * (Math.PI/180);
133                         //mesh.rotationY = Papervision3D.useDEGREES ? 180 : 180 * (Math.PI/180);
134                        
135                         addChild(mesh);
136                 }
137                
138                 /**
139                  *
140                  * @param       event
141                  */
142                 private function onFileLoadComplete(event:Event=null):void
143                 {
144                         var loader:URLLoader = event.target as URLLoader;
145                
146                         parse(ByteArray(loader.data));
147                 }
148                
149                 /**
150                  *
151                  * @param       event
152                  */
153                 private function onFileLoadError(event:IOErrorEvent):void
154                 {
155                         dispatchEvent(new FileLoadEvent(FileLoadEvent.LOAD_ERROR, this.filename));
156                 }
157                
158                 /**
159                  * Parse.
160                  *
161                  * @param       data
162                  */
163                 private function parse(data:ByteArray):void
164                 {
165                         if(!data)
166                                 throw new Error("Invalid ByteArray!");
167                        
168                         _data = data;
169                         _data.endian = Endian.LITTLE_ENDIAN;
170                         _data.position = 0;
171                        
172                         //first chunk is always the primary, so we simply read it and parse it
173                         var chunk:Chunk3ds = new Chunk3ds();
174                         readChunk(chunk);
175                         parse3DS(chunk);
176                        
177                         dispatchEvent(new FileLoadEvent(FileLoadEvent.LOAD_COMPLETE, this.filename));
178                 }
179                
180                 /**
181                  * Read the base 3DS object.
182                  *
183                  * @param chunk
184                  *
185                  */             
186                 private function parse3DS(chunk:Chunk3ds):void
187                 {
188                         while (chunk.bytesRead < chunk.length)
189                         {
190                                 var subChunk:Chunk3ds = new Chunk3ds();
191                                 readChunk(subChunk);
192                                 switch (subChunk.id)
193                                 {
194                                         case EDIT3DS:
195                                                 parseEdit3DS(subChunk);
196                                                 break;
197                                         case KEYF3DS:
198                                                 skipChunk(subChunk);
199                                                 break;
200                                         default:
201                                                 skipChunk(subChunk);
202                                 }
203                                 chunk.bytesRead += subChunk.length;
204                         }
205                 }
206                
207                 /**
208                  * Read the Edit chunk
209                  *
210                  * @param chunk
211                  */
212                 private function parseEdit3DS(chunk:Chunk3ds):void
213                 {
214                         while (chunk.bytesRead < chunk.length)
215                         {
216                                 var subChunk:Chunk3ds = new Chunk3ds();
217                                 readChunk(subChunk);
218                                 switch (subChunk.id)
219                                 {
220                                         case MATERIAL:
221                                                 parseMaterial(subChunk);
222                                                 //skipChunk(subChunk);
223                                                 break;
224                                         case MESH:
225                                                 var meshData:MeshData = new MeshData();
226                                                 meshData.name = readASCIIZString(_data);
227                                                
228                                                 subChunk.bytesRead += meshData.name.length + 1;
229                                                
230                                                 meshData.vertices = new Array();
231                                                 meshData.faces = new Array();
232                                                 meshData.uvs = new Array();
233                                                 meshData.materials = new Array();
234                                                
235                                                 parseMesh(subChunk, meshData);
236                                                
237                                                 buildMesh(meshData);
238                                                 break;
239                                         default:
240                                                 skipChunk(subChunk);
241                                 }
242                                
243                                 chunk.bytesRead += subChunk.length;
244                         }
245                 }
246                
247                 /**
248                  * Read a material chunk.
249                  *
250                  * @param       chunk
251                  */
252                 private function parseMaterial(chunk:Chunk3ds):String
253                 {
254                         var ret:String = null;
255                         var mat:Object = new Object();
256                         var subChunk:Chunk3ds = new Chunk3ds();
257                         var colorChunk:Chunk3ds = new Chunk3ds();
258                                
259                         mat.textures = new Array();
260                        
261                         while (chunk.bytesRead < chunk.length)
262                         {                               
263                                 readChunk(subChunk);
264                                 var p:uint = 0;
265                                
266                                 switch(subChunk.id)
267                                 {
268                                         case MAT_NAME:
269                                                 mat.name = readASCIIZString(_data);
270                                                 //trace(mat.name);
271                                                 subChunk.bytesRead = subChunk.length;
272                                                 break;
273                                         case MAT_AMBIENT:
274                                                 p = _data.position;
275                                                 readChunk(colorChunk);
276                                                 mat.ambient = readColor(colorChunk);
277                                                 _data.position = p + colorChunk.length;
278                                                 //trace("ambient:"+mat.ambient.toString(16));
279                                                 break;
280                                         case MAT_DIFFUSE:
281                                                 p = _data.position;
282                                                 readChunk(colorChunk);
283                                                 mat.diffuse = readColor(colorChunk);
284                                                 _data.position = p + colorChunk.length;
285                                                 //trace("diffuse:"+mat.diffuse.toString(16));
286                                                 break;
287                                         case MAT_SPECULAR:
288                                                 p = _data.position;
289                                                 readChunk(colorChunk);
290                                                 mat.specular = readColor(colorChunk);
291                                                 _data.position = p + colorChunk.length;
292                                                 //trace("specular:"+mat.specular.toString(16));
293                                                 break;
294                                         case MAT_TEXMAP:
295                                                 mat.textures.push(parseMaterial(subChunk));
296                                                 break;
297                                         case MAT_TEXFLNM:
298                                                 ret = readASCIIZString(_data);
299                                                 subChunk.bytesRead = subChunk.length;
300                                                 break;
301                                         default:
302                                                 skipChunk(subChunk);
303                                 }
304                                 chunk.bytesRead += subChunk.length;
305                         }
306                        
307                         if(mat.name && !this.materials.getMaterialByName(mat.name))
308                         {
309                                 if(mat.textures.length)
310                                 {
311                                         var bitmap:String = mat.textures[0].toLowerCase();
312                                        
313                                         for(var ext:String in _textureExtensionReplacements)
314                                         {
315                                                 if(bitmap.indexOf("."+ext) == -1)
316                                                         continue;
317                                                 var pattern:RegExp = new RegExp("\."+ext, "i");
318                                                 bitmap = bitmap.replace(pattern, "."+_textureExtensionReplacements[ext]);
319                                         }
320                                        
321                                         this.materials.addMaterial(new BitmapFileMaterial(_textureDir+bitmap), mat.name);
322                                 }
323                                 else if(mat.diffuse)
324                                 {
325                                         this.materials.addMaterial(new ColorMaterial(mat.diffuse), mat.name);
326                                 }
327                         }
328                        
329                         return ret;
330                 }
331                
332                 private function parseMesh(chunk:Chunk3ds, meshData:MeshData):void
333                 {
334                         while (chunk.bytesRead < chunk.length)
335                         {
336                                 var subChunk:Chunk3ds = new Chunk3ds();
337                                 readChunk(subChunk);
338                                 switch (subChunk.id)
339                                 {
340                                         case MESH_OBJECT:
341                                                 parseMesh(subChunk, meshData);
342                                                 break;
343                                         case MESH_VERTICES:
344                                                 meshData.vertices = readMeshVertices(subChunk);
345                                                 break;
346                                         case MESH_FACES:
347                                                 meshData.faces = readMeshFaces(subChunk);
348                                                 parseMesh(subChunk, meshData);
349                                                 break;
350                                         case MESH_MATER:
351                                                 readMeshMaterial(subChunk, meshData);
352                                                 break;
353                                         case MESH_TEX_VERT:
354                                                 meshData.uvs = readMeshTexVert(subChunk);
355                                                 break;
356                                         default:
357                                                 skipChunk(subChunk);
358                                 }
359                                 chunk.bytesRead += subChunk.length;
360                         }
361                 }
362                
363                 /**
364                  *
365                  * @param       chunk
366                  */ 
367                 private function readMeshFaces(chunk:Chunk3ds):Array
368                 {
369                         var faces:Array = new Array();
370                         var numFaces:int = _data.readUnsignedShort();
371                         chunk.bytesRead += 2;
372                        
373                         for (var i:int = 0; i < numFaces; i++)
374                         {
375                                 var v2:uint = _data.readUnsignedShort();
376                                 var v1:uint = _data.readUnsignedShort();
377                                 var v0:uint = _data.readUnsignedShort();
378                                 var visible:Boolean = (_data.readUnsignedShort() as Boolean);
379                                 chunk.bytesRead += 8;
380                                
381                                 faces.push([v0, v1, v2]);
382                         }
383                         return faces;
384                 }
385                
386                 /**
387                  * Read the Mesh Material chunk
388                  *
389                  * @param chunk
390                  */
391                 private function readMeshMaterial(chunk:Chunk3ds, meshData:MeshData):void
392                 {
393                         var material:MaterialData = new MaterialData();
394                        
395                         material.name = readASCIIZString(_data);
396                         material.faces = new Array();
397                        
398                         chunk.bytesRead += material.name.length +1;
399                        
400                         var numFaces:int = _data.readUnsignedShort();
401                         chunk.bytesRead += 2;
402                         for (var i:int = 0; i < numFaces; i++)
403                         {
404                                 material.faces.push(_data.readUnsignedShort());
405                                 chunk.bytesRead += 2;
406                         }
407                        
408                         meshData.materials.push(material);
409                 }
410                
411                 /**
412                  *
413                  * @param       chunk
414                  *
415                  * @return
416                  */
417                 private function readMeshTexVert(chunk:Chunk3ds):Array
418                 {
419                         var uvs:Array = new Array();
420                         var numUVs:int = _data.readUnsignedShort();
421                         chunk.bytesRead += 2;
422                        
423                         for (var i:int = 0; i < numUVs; i++)
424                         {
425                                 uvs.push(new NumberUV(_data.readFloat(), _data.readFloat()));
426                                 chunk.bytesRead += 8;
427                         }
428                         return uvs;
429                 }
430                
431                 /**
432                  *
433                  * @param       chunk
434                  */
435                 private function readMeshVertices(chunk:Chunk3ds):Array
436                 {
437                         var vertices:Array = new Array();
438                         var numVerts:int = _data.readUnsignedShort();
439                         chunk.bytesRead += 2;
440                        
441                         for (var i:int = 0; i < numVerts; i++)
442                         {
443                                 vertices.push(new Vertex3D(_data.readFloat(), _data.readFloat(), _data.readFloat()));
444                                 chunk.bytesRead += 12;
445                         }
446                        
447                         return vertices;
448                 }
449                
450                 /**
451                  * Reads a null-terminated ascii string out of a byte array.
452                  *
453                  * @param data The byte array to read from.
454                  *
455                  * @return The string read, without the null-terminating character.
456                  */             
457                 private function readASCIIZString(data:ByteArray):String
458                 {
459                         var readLength:int = 0; // length of string to read
460                         var l:int = data.length - data.position;
461                         var tempByteArray:ByteArray = new ByteArray();
462                        
463                         for (var i:int = 0; i < l; i++)
464                         {
465                                 var c:int = data.readByte();
466                                
467                                 if (c == 0)
468                                 {
469                                         break;
470                                 }
471                                 tempByteArray.writeByte(c);
472                         }
473                        
474                         var asciiz:String = "";
475                         tempByteArray.position = 0;
476                         for (i = 0; i < tempByteArray.length; i++)
477                         {
478                                 asciiz += String.fromCharCode(tempByteArray.readByte());
479                         }
480                         return asciiz;
481                 }
482                
483                 /**
484                  *
485                  */
486                 private function readColor(colorChunk:Chunk3ds):int
487                 {
488                         var color:int = 0;
489                         switch(colorChunk.id)
490                         {
491                                 case COLOR_RGB:
492                                         color = readColorRGB(colorChunk);
493                                         break;
494                                 case COLOR_F:
495                                         color = readColorScale(colorChunk);
496                                         break;
497                                 default:
498                                         throw new Error("Unknown color chunk: " + colorChunk.id);
499                         }
500                         return color;
501                 }
502                
503                 /**
504                  * Read Scaled Color
505                  *
506                  * @param       chunk
507                  */
508                 private function readColorScale(chunk:Chunk3ds):int
509                 {
510                         var color:int = 0;
511
512                         for (var i:int = 0; i < 3; i++)
513                         {
514                                 var c:Number = _data.readFloat();
515                                 var bv:int = 255 * c;
516                                 bv <<= (8 * (2 - i));
517                                 color |= bv;                                                                                                     
518                                 chunk.bytesRead += 4;
519                         }
520                        
521                         return color;
522                 }
523                
524                 /**
525                  * Read RGB
526                  *
527                  * @param       chunk
528                  */
529                 private function readColorRGB(chunk:Chunk3ds):int
530                 {
531                         var color:int = 0;
532                        
533                         for (var i:int = 0; i < 3; i++)
534                         {
535                                 var c:int = _data.readUnsignedByte();
536                                 color += c*Math.pow(0x100, 2-i);
537                                 chunk.bytesRead++;
538                         }
539                        
540                         return color;
541                 }
542                
543                 /**
544                  * Read id and length of 3ds chunk
545                  *
546                  * @param chunk
547                  */             
548                 private function readChunk(chunk:Chunk3ds):void
549                 {
550                         chunk.id = _data.readUnsignedShort();
551                         chunk.length = _data.readUnsignedInt();
552                         chunk.bytesRead = 6;
553                 }
554                
555                 /**
556                  * Skips past a chunk. If we don't understand the meaning of a chunk id,
557                  * we just skip past it.
558                  *
559                  * @param chunk
560                  */             
561                 private function skipChunk(chunk:Chunk3ds):void
562                 {
563                         _data.position += chunk.length - chunk.bytesRead;
564                         chunk.bytesRead = chunk.length;
565                 }
566                
567                 //>----- Color Types --------------------------------------------------------
568                
569                 public const AMBIENT:String = "ambient";
570                 public const DIFFUSE:String = "diffuse";
571                 public const SPECULAR:String = "specular";
572                
573                 //>----- Main Chunks --------------------------------------------------------
574                
575                 public const PRIMARY:int = 0x4D4D;
576                 public const EDIT3DS:int = 0x3D3D;  // Start of our actual objects
577                 public const KEYF3DS:int = 0xB000;  // Start of the keyframe information
578                
579                 //>----- General Chunks -----------------------------------------------------
580                
581                 public const VERSION:int = 0x0002;
582                 public const MESH_VERSION:int = 0x3D3E;
583                 public const KFVERSION:int = 0x0005;
584                 public const COLOR_F:int = 0x0010;
585                 public const COLOR_RGB:int = 0x0011;
586                 public const LIN_COLOR_24:int = 0x0012;
587                 public const LIN_COLOR_F:int = 0x0013;
588                 public const INT_PERCENTAGE:int = 0x0030;
589                 public const FLOAT_PERC:int = 0x0031;
590                 public const MASTER_SCALE:int = 0x0100;
591                 public const IMAGE_FILE:int = 0x1100;
592                 public const AMBIENT_LIGHT:int = 0X2100;
593                
594                 //>----- Object Chunks -----------------------------------------------------
595                
596                 public const MESH:int = 0x4000;
597                 public const MESH_OBJECT:int = 0x4100;
598                 public const MESH_VERTICES:int = 0x4110;
599                 public const VERTEX_FLAGS:int = 0x4111;
600                 public const MESH_FACES:int = 0x4120;
601                 public const MESH_MATER:int = 0x4130;
602                 public const MESH_TEX_VERT:int = 0x4140;
603                 public const MESH_XFMATRIX:int = 0x4160;
604                 public const MESH_COLOR_IND:int = 0x4165;
605                 public const MESH_TEX_INFO:int = 0x4170;
606                 public const HEIRARCHY:int = 0x4F00;
607                
608                 //>----- Material Chunks ---------------------------------------------------
609                
610                 public const MATERIAL:int = 0xAFFF;
611                 public const MAT_NAME:int = 0xA000;
612                 public const MAT_AMBIENT:int = 0xA010;
613                 public const MAT_DIFFUSE:int = 0xA020;
614                 public const MAT_SPECULAR:int = 0xA030;
615                 public const MAT_SHININESS:int = 0xA040;
616                 public const MAT_FALLOFF:int = 0xA052;
617                 public const MAT_EMISSIVE:int = 0xA080;
618                 public const MAT_SHADER:int = 0xA100;
619                 public const MAT_TEXMAP:int = 0xA200;
620                 public const MAT_TEXFLNM:int = 0xA300;
621                 public const OBJ_LIGHT:int = 0x4600;
622                 public const OBJ_CAMERA:int = 0x4700;
623                
624                 //>----- KeyFrames Chunks --------------------------------------------------
625                
626                 public const ANIM_HEADER:int = 0xB00A;
627                 public const ANIM_OBJ:int = 0xB002;
628                 public const ANIM_NAME:int = 0xB010;
629                 public const ANIM_POS:int = 0xB020;
630                 public const ANIM_ROT:int = 0xB021;
631                 public const ANIM_SCALE:int = 0xB022;
632        
633                 private var _data               :ByteArray;
634                
635                 private var _textureDir :String = "./image/";
636                 private var _textureExtensionReplacements:Object;
637         }
638 }
639
640 class Chunk3ds
641 {       
642         public var id:int;
643         public var length:int;
644         public var bytesRead:int;       
645 }
646
647 class MeshData
648 {
649         public var name:String;
650         public var vertices:Array;
651         public var faces:Array;
652         public var uvs:Array;
653         public var materials:Array;
654 }
655
656 class MaterialData
657 {
658         public var name:String;
659         public var faces:Array;
660 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。