root/as3/Metasequoia/src/org/libspark/pv3d/Metasequoia_1_5.as

リビジョン 100, 13.1 kB (コミッタ: rch850, コミット時期: 4 年 前)

・Papervision3D 1.7に対応させました
 ・1.5用のクラスは別名で保持しておきます
・コンストラクタで読み込まず、別途loadメソッドを用意しました
・モデル内のパーツ別に読み込むようにしました

Line 
1 package org.libspark.pv3d {
2         import flash.events.*;
3         import flash.net.URLLoader;
4         import flash.net.URLLoaderDataFormat;
5         import flash.net.URLRequest;
6         import flash.utils.ByteArray;
7         import flash.utils.Dictionary;
8         import org.papervision3d.core.geom.Face3D;
9         import org.papervision3d.core.geom.Mesh3D;
10         import org.papervision3d.core.geom.Vertex3D;
11         import org.papervision3d.core.Matrix3D;
12         import org.papervision3d.core.NumberUV;
13         import org.papervision3d.core.proto.GeometryObject3D;
14         import org.papervision3d.core.proto.MaterialObject3D;
15         import org.papervision3d.events.FileLoadEvent;
16         import org.papervision3d.materials.BitmapFileMaterial;
17         import org.papervision3d.materials.ColorMaterial;
18         import org.papervision3d.materials.MaterialsList;
19         import org.papervision3d.objects.DisplayObject3D;
20        
21         /**
22         * メタセコイアのファイル(.mqo)を読み込むためのクラス。
23         */
24         public class Metasequoia_1_5 extends Mesh3D {
25                 private var mLoader:URLLoader;
26                 private var mFilename:String;
27                 private var mMaterialsToLoad:int =0;
28                 private var mMaterialNames:Array;
29                 private var mScale:Number = 1;
30                 private var mCharset:String = "shift_jis";
31                
32                 /**
33                 * @param file 読み込むファイルの URL。絶対パスで指定してください。
34                 * @param scale 読み込むときの拡大率。1 が原寸大です。
35                 * @param charset ファイルの文字コード。よほどのことが無い限り shift_jis だと思います。
36                 */
37                 function Metasequoia_1_5(file:String, scale:Number = 1, charset:String = "shift_jis") {
38                         this.materials = new MaterialsList();
39                         this.mCharset = charset;
40                         super(null, new Array(), new Array(), null);
41                        
42                         mFilename = file;
43                         mScale = scale;
44                         loadMetasequoia();
45                 }
46                
47                 private function loadMetasequoia():void {
48                         mLoader = new URLLoader();
49                         mLoader.dataFormat = URLLoaderDataFormat.BINARY;
50                         mLoader.addEventListener(Event.COMPLETE, completeHandler);
51                         mLoader.addEventListener(IOErrorEvent.IO_ERROR, defaultHandler);
52                         mLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, defaultHandler);
53                         mLoader.addEventListener(ProgressEvent.PROGRESS, defaultHandler);
54                         mLoader.load(new URLRequest(mFilename));
55                 }
56                
57                 private function completeHandler(evt:Event):void {
58                         var byteArray:ByteArray = ByteArray(mLoader.data);
59                         buildMetasequoia(byteArray.readMultiByte(byteArray.length, mCharset));
60                         dispatchEvent(evt.clone());
61                 }
62                
63                 private function defaultHandler(evt:Event):void {
64                         dispatchEvent(evt.clone());
65                 }
66                
67                 private function buildMetasequoia(plainText:String):void {
68                         var lines:Array = plainText.split("\r\n");
69                         trace("num lines = " + lines.length);
70                         var l:int = 0;
71                        
72                         // Material チャンクを読み込む
73                         l = parseMaterialChunk(lines, 0);
74                        
75                         // Object チャンクを読み込めなくなるまで読み込む
76                         while (l != -1) {
77                                 l = parseObjectChunk(lines, l);
78                         }
79                        
80                         geometry.ready = true;
81                 }
82                
83                 /**
84                 * Material チャンクの開始行を返します。
85                 * 見つからなかった場合には -1 を返します。
86                 */
87                 private function getMaterialChunkLine(lines:Array, startLine:int = 0):int {
88                         for (var i:uint = startLine; i < lines.length; ++i) {
89                                 if (lines[i].indexOf("Material") == 0) {
90                                         return int(i);
91                                 }
92                         }
93                         return -1;
94                 }
95                
96                 /**
97                 * Material チャンクを読み込み、その最後の行番号を返します。
98                 * エラーが起こった場合は -1 を返します。
99                 */
100                 private function parseMaterialChunk(lines:Array, startLine:int):int {
101                         var l:int = getMaterialChunkLine(lines, startLine);
102                         if (l == -1) {
103                                 return -1;
104                         }
105                        
106                         // 解析中の行の文字列
107                         var line:String = lines[l];
108                        
109                         // マテリアル数を取得
110                         var num:Number = parseInt(line.substr(9));
111                         if (isNaN(num)) {
112                                 return -1;
113                         }
114                         ++l;
115                         mMaterialNames = new Array();
116                        
117                         // } で閉じているところの行番号
118                         var endLine:int = l + int(num);
119                        
120                         // mqo ファイルのあるディレクトリのパス
121                         var path:String = mFilename.slice(0, mFilename.lastIndexOf("/") + 1);
122                        
123                         for (; l < endLine; ++l) {
124                                 var material:MaterialObject3D;
125                                 line = lines[l];
126                                
127                                 // マテリアルの名前を取得
128                                 var nameBeginIndex:int = line.indexOf("\"");
129                                 var nameEndIndex:int = line.indexOf("\"", nameBeginIndex + 1);
130                                 var name:String = line.substring(nameBeginIndex + 1, nameEndIndex);
131                                 mMaterialNames.push(name);
132                                
133                                 // テクスチャファイル名
134                                 var tex:String = getParam(line, "tex");
135                                
136                                 if (tex) {
137                                         // テクスチャファイル名を取り囲む " " を取り除く
138                                         tex = tex.substr(1, tex.length - 2);
139                                         mMaterialsToLoad++;
140                                         // テクスチャの URL を絶対にして読み込む
141                                         material = new BitmapFileMaterial(path + tex);
142                                         material.addEventListener(FileLoadEvent.LOAD_COMPLETE, materialLoadCompleteHandler);
143                                         material.addEventListener(FileLoadEvent.LOAD_ERROR, materialLoadErrorHandler);
144                                         // あまり重さが変わらないのでせっかくだからスムージング
145                                         material.smooth = true;
146                                 } else {
147                                         // 形式 - col(1.000 1.000 0.000 1.000)
148                                         var colorstr:String = getParam(line, "col");
149                                         if (colorstr != null) {
150                                                 var color:Array = colorstr.match(/\d+\.\d+/g);
151                                                 var r:int = parseFloat(color[0]) * 255;
152                                                 var g:int = parseFloat(color[1]) * 255;
153                                                 var b:int = parseFloat(color[2]) * 255;
154                                                 var a:Number = parseFloat(color[3]) * 100;
155                                                 trace("rgb = " + r + "," + g + "," + b);
156                                                 material = new ColorMaterial((r << 16) | (g << 8) | b);
157                                         } else {
158                                                 material = MaterialObject3D.DEFAULT;
159                                         }
160                                 }
161                                
162                                 material.doubleSided = true;
163                                 material.name = name;
164                                
165                                 materials.addMaterial(material, name);
166                         }
167                        
168                         return endLine;
169                 }
170                
171                 private function materialLoadCompleteHandler(evt:FileLoadEvent):void {
172                         mMaterialsToLoad--;
173                         if(mMaterialsToLoad == 0){
174                                 //COLLADA のソースにあった謎の一行。不具合の元になるのでコメントアウト
175                                 //materials = new MaterialsList();
176                                 dispatchEvent(new FileLoadEvent(FileLoadEvent.COLLADA_MATERIALS_DONE));
177                         }
178                 }
179                
180                 private function materialLoadErrorHandler(evt:FileLoadEvent):void {
181                         mMaterialsToLoad--;
182                         if(mMaterialsToLoad == 0){
183                                 dispatchEvent(new FileLoadEvent(FileLoadEvent.COLLADA_MATERIALS_DONE));
184                         }
185                 }
186                
187                 /**
188                 * Object チャンクの開始行を返します。
189                 * 見つからなかった場合には -1 を返します。
190                 */
191                 private function getObjectChunkLine(lines:Array, startLine:int = 0):int {
192                         for (var i:uint = startLine; i < lines.length; ++i) {
193                                 if (lines[i].indexOf("Object") == 0) {
194                                         return int(i);
195                                 }
196                         }
197                         return -1;
198                 }
199                
200                 /**
201                 * Object チャンクを読み込み、その最後の行番号を返します。
202                 * エラーが起こった場合は -1 を返します。
203                 */
204                 private function parseObjectChunk(lines:Array, startLine:int):int {
205                         var vertices:Array = geometry.vertices;
206                         var faces:Array = geometry.faces;
207                        
208                         var l:int = getObjectChunkLine(lines, startLine);
209                         if (l == -1) {
210                                 return -1;
211                         }
212                        
213                         // 解析中の行の文字列
214                         var line:String = lines[l];
215                        
216                         // オブジェクト名を取得
217                         var objectName:String = line.substring(8, line.indexOf("\"", 8));
218                         ++l;
219                        
220                         // vertex チャンクを検索
221                         var vline:int = getChunkLine(lines, "vertex", l);
222                         if (vline == -1) {
223                                 return -1;
224                         }
225                        
226                         // プロパティを読み込む
227                         var properties:Dictionary = new Dictionary();
228                         for (; l < vline; ++l) {
229                                 line = lines[l];
230                                 var props:Array = RegExp(/^\s*([\w]+)\s+(.*)$/).exec(line);
231                                 properties[props[1]] = props[2];
232                         }
233                        
234                         line = lines[l];
235                         l = vline + 1;
236                        
237                         // 頂点数を取得
238                         var numVertices:int = parseInt(line.substring(line.indexOf("vertex") + 7));
239                         var vertexEndLine:int = l + numVertices;
240                         var firstVertexIndex:int = vertices.length;
241                        
242                         // vertex チャンクを読み込む
243                         for (; l < vertexEndLine; ++l) {
244                                 line = lines[l];
245                                 var coords:Array = line.match(/(-?\d+\.\d+)/g);
246                                 var x:Number = parseFloat(coords[0]) * mScale;
247                                 var y:Number = parseFloat(coords[1]) * mScale;
248                                 var z:Number = parseFloat(coords[2]) * mScale;
249                                 vertices.push(new Vertex3D(x, y, z));
250                         }
251                        
252                         // face チャンクを検索
253                         l = getChunkLine(lines,  "face", l);
254                         if (l == -1) {
255                                 return -1;
256                         }
257                         line = lines[l++];
258                        
259                         // 面数を取得
260                         var numFaces:int = parseInt(line.substring(line.indexOf("face") + 5));
261                         var faceEndLine:int = l + numFaces;
262                        
263                         // face チャンクを読み込む
264                         for (; l < faceEndLine; ++l) {
265                                 if (properties["visible"] == "15") {
266                                         parseFace(faces, lines[l], vertices, firstVertexIndex, properties);
267                                 }
268                         }
269                        
270                         return l;
271                 }
272                
273                 private function parseFace(faces:Array, line:String, vertices:Array, vertexOffset:int,
274                                 properties:Dictionary):void {
275                         var vstr:String = getParam(line, "V");
276                         var mstr:String = getParam(line, "M");
277                         var uvstr:String = getParam(line, "UV");
278                        
279                         var v:Array = (vstr != null) ? vstr.match(/\d+/g) : [];
280                         var uv:Array = (uvstr != null) ? uvstr.match(/-?\d+\.\d+/g) : [];
281                         var a:Vertex3D;
282                         var b:Vertex3D;
283                         var c:Vertex3D;
284                         var d:Vertex3D;
285                         var materialName:String;
286                         var uvA:NumberUV;
287                         var uvB:NumberUV;
288                         var uvC:NumberUV;
289                         var uvD:NumberUV;
290                         var face:Face3D;
291                        
292                         if (v.length == 3) {
293                                 a = vertices[parseInt(v[0]) + vertexOffset];
294                                 b = vertices[parseInt(v[1]) + vertexOffset];
295                                 c = vertices[parseInt(v[2]) + vertexOffset];
296                                
297                                 if (mstr != null) {
298                                         materialName = mMaterialNames[parseInt(mstr)];
299                                 }
300                                
301                                 if (uv.length != 0) {
302                                         uvA = new NumberUV(parseFloat(uv[0]), 1 - parseFloat(uv[1]));
303                                         uvB = new NumberUV(parseFloat(uv[2]), 1 - parseFloat(uv[3]));
304                                         uvC = new NumberUV(parseFloat(uv[4]), 1 - parseFloat(uv[5]));
305                                         face = new Face3D([a, b, c], materialName, [uvA, uvB, uvC]);
306                                 } else {
307                                         face = new Face3D([a, b, c], materialName,
308                                                 [new NumberUV(0, 0), new NumberUV(1, 0), new NumberUV(0, 1)]);
309                                 }
310                                
311                                 faces.push(face);
312                                
313                                 if (properties["mirror"] == "1") {
314                                         var mirrorAxis:int = parseInt(properties["mirror_axis"]);
315                                         a = mirrorVertex(a, mirrorAxis);
316                                         b = mirrorVertex(b, mirrorAxis);
317                                         c = mirrorVertex(c, mirrorAxis);
318                                         vertices.push(a);
319                                         vertices.push(b);
320                                         vertices.push(c);
321                                         face = new Face3D([a, b, c], face.materialName, face.uv);
322                                         faces.push(face);
323                                 }
324                         } else if (v.length == 4) {
325                                 a = vertices[parseInt(v[0]) + vertexOffset];
326                                 b = vertices[parseInt(v[1]) + vertexOffset];
327                                 c = vertices[parseInt(v[2]) + vertexOffset];
328                                 d = vertices[parseInt(v[3]) + vertexOffset];
329                                
330                                 if (mstr != null) {
331                                         materialName = mMaterialNames[parseInt(mstr)];
332                                 }
333                                
334                                 if (uv.length != 0) {
335                                         uvA = new NumberUV(parseFloat(uv[0]), 1 - parseFloat(uv[1]));
336                                         uvB = new NumberUV(parseFloat(uv[2]), 1 - parseFloat(uv[3]));
337                                         uvC = new NumberUV(parseFloat(uv[4]), 1 - parseFloat(uv[5]));
338                                         uvD = new NumberUV(parseFloat(uv[6]), 1 - parseFloat(uv[7]));
339                                 } else {
340                                         uvA = new NumberUV(0, 0);
341                                         uvB = new NumberUV(1, 0);
342                                         uvC = new NumberUV(0, 1);
343                                         uvD = new NumberUV(1, 1);
344                                 }
345                                 face = new Face3D([a, b, c], materialName, [uvA, uvB, uvC]);
346                                 faces.push(face);
347                                 face = new Face3D([c, d, a], materialName, [uvC, uvD, uvA]);
348                                 faces.push(face);
349                                
350                                 if (properties["mirror"] == "1") {
351                                         mirrorAxis = parseInt(properties["mirror_axis"]);
352                                         a = mirrorVertex(a, mirrorAxis);
353                                         b = mirrorVertex(b, mirrorAxis);
354                                         c = mirrorVertex(c, mirrorAxis);
355                                         d = mirrorVertex(d, mirrorAxis);
356                                         vertices.push(a);
357                                         vertices.push(b);
358                                         vertices.push(c);
359                                         vertices.push(d);
360                                         face = new Face3D([a, b, c], materialName, [uvA, uvB, uvC]);
361                                         faces.push(face);
362                                         face = new Face3D([c, d, a], materialName, [uvC, uvD, uvA]);
363                                         faces.push(face);
364                                 }
365                         }
366                 }
367                
368                 /**
369                 * 頂点を軸に沿って反転させたものを返します。
370                 */
371                 private static function mirrorVertex(v:Vertex3D, axis:int):Vertex3D {
372                         return new Vertex3D(
373                                 ((axis & 1) != 0) ? -v.x : v.x,
374                                 ((axis & 2) != 0) ? -v.y : v.y,
375                                 ((axis & 4) != 0) ? -v.z : v.z);
376                 }
377                
378                 /**
379                 * Object チャンクの開始行を返します。
380                 */
381                 private static function getChunkLine(lines:Array, chunkName:String, startLine:int = 0):int {
382                         for (var i:uint = startLine; i < lines.length; ++i) {
383                                 if (lines[i].indexOf(chunkName) != -1) {
384                                         return int(i);
385                                 }
386                         }
387                         return -1;
388                 }
389                
390                 /**
391                 * line 内で paramName(...) という形式で指定されているパラメータを返します。
392                 */
393                 private static function getParam(line:String, paramName:String):String {
394                         var prefix:String = paramName + "(";
395                         var prefixLen:int = prefix.length;
396                        
397                         var begin:int = line.indexOf(prefix, 0);
398                         if (begin == -1) {
399                                 return null;
400                         }
401                         var end:int = line.indexOf(")", begin + prefixLen);
402                         if (end == -1){
403                                 return null;
404                         }
405                         return line.substring(begin + prefixLen, end);
406                 }
407         }
408 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。