Metasequoia.as 拡張クラス ( ローカルの zip 書庫内のファイルをロードする )

  概要



Shot_miku

Metasequoia_v クラスについて
Metasequoia クラスは、Papervision3D に Metasequoia のデータをロードするクラスですが、
これに限らず、swf からロードできる WEB 上に置く必要があります。しかし、Flash の 10.0.12 から
ローカルの PC にあるデータ( ファイルシステム ) をロードできるので、zip ファイルに mqo と テクスチャ
を保存して、zip ファイルを読み込む事で本来の Metasequoia クラス の機能を果たせるようにしたものです。
( zip 内にフォルダは作成しないで下さい )

まだ基本機能ができただけなので、後 dae に対応して うまくいったら、
Google SketchUp のエクスポートデータもできるはずなので、
最低そこまではなんとかしたいと思っています

Papervision3D の標準マテリアルは独自形式を作ってロードできるようにして、
最終的には、マテリアル単位の map ファイルを書庫に含めようと思っています。
そうすると、ある意味 3D 紙芝居程度は簡単にできそうな気がします

( もちろん Papervision3D の シューティングゲームはやってみたいです )

zipfile の処理は、Papervision3D に付属していたクラスを使っていますが、
FLARToolKit の Papervision3Dには付属していないので、必要なライブラリを持ち寄る必要があります



  ビルド時の注意



ローカルのファイルをロードする機能を使っていますので以下のようになります

  
mxmlc Main.mxml -target-player=10.0.12
  



  ソースコード


Metasequoia.as を継承して使っていますが、後々のメンテナンス性を考えての事です。
結局 その都合から、Metasequoia.as の private を 全て protected に変更しています。



▼ 実装ページ
WEB カメ くらぶ

サンプルでは、FLARToolKit で使っていますので、インスタンスを FLARToolKit の baseNode に addChild します
それ以外の 通常 Flexでは、rawChildren.addChild です。 ( Canvas 等 )

▼ public class SimpleCube extends PV3DARApp の内部
  
public function loadMqo( data:DisplayObject3D ):void {

	this._baseNode.addChild( data );

}
  

▼ Main.mxml の呼び出し
  
// *************************************************
// メタセコイア拡張のロード完了
// *************************************************
mqo_v = new Metasequoia_v();
mqo_v.addEventListener(Event.COMPLETE, function(e:Event):void {

	sc.loadMqo(mqo_v);
	mqo_v.rotationX = -90;
	mqo_v.scale = 1;
	ns.value = 1;

});
  


  
/**
 * Metasequoia.as
 * 
 * @see http://snippets.libspark.org/
 * @see http://snippets.libspark.org/trac/wiki/rch850/Metasequoia
 * 
 * Copyright (c) 2007-2008 rch850
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.libspark.pv3d {

  // Main.mxml の firebug 関数参照用
  import mx.core.Application;
  import mx.controls.*;

  import flash.display.BitmapData;
  import flash.display.Loader;
  import flash.events.*;
  import flash.net.URLLoader;
  import flash.net.URLLoaderDataFormat;
  import flash.net.URLRequest;
  import flash.net.FileReference;
  import flash.utils.ByteArray;
  import flash.utils.Dictionary;
  import org.libspark.pv3d.decoders.TGADecoder;
  import org.papervision3d.core.geom.TriangleMesh3D;
  import org.papervision3d.core.geom.renderables.Triangle3D;
  import org.papervision3d.core.geom.renderables.Vertex3D;
  import org.papervision3d.core.math.Matrix3D;
  import org.papervision3d.core.math.NumberUV;
  import org.papervision3d.core.proto.DisplayObjectContainer3D;
  import org.papervision3d.core.proto.GeometryObject3D;
  import org.papervision3d.core.proto.MaterialObject3D;
  import org.papervision3d.events.FileLoadEvent;
  import org.papervision3d.events.InteractiveScene3DEvent;
  import org.papervision3d.materials.BitmapFileMaterial;
  import org.papervision3d.materials.BitmapMaterial;
  import org.papervision3d.materials.ColorMaterial;
  import org.papervision3d.materials.utils.MaterialsList;
  import org.papervision3d.objects.DisplayObject3D;
  import nochump.util.zip.*;

  import com.voidelement.images.BMPDecoder;  

  import org.libspark.pv3d.Metasequoia;

  //*******************************************************
  // Metasequoia 継承クラス
  //*******************************************************
  public class Metasequoia_v extends Metasequoia {

    public var fRef:FileReference;
    public var imageExt:String = "png,jpg,jpeg";
    private var texget:BitmapMaterial = null;
    private var loader:Loader;
    private var bmp_loader:Loader;
    private var _ext:String;
    private var data_list:Object = new Object();
    private var zip_num:int;    // zipfile 内の ファイル数
    private var bitmap_num:int;    // zipfile 内の 画像数
    private var zipFile:ZipFile;
    private var mqo_temp:Array;
    private var mqo_target:ByteArray;
    private var bitamp_count:int = 0;
    private var zip:ByteArray;

    // ファイル参照対象ファイルのデフォルト
    private var targetDreft:String = "zipfile";

    // *************************************************
    // コンストラクタ
    // *************************************************
    function Metasequoia_v() {
      super();

      // ファイルリファレンスのイベント登録
      frefinit();
    }

    // *************************************************
    // ファイルリファレンスのイベント登録
    // *************************************************
    private function frefinit():void {

      bmp_loader = new Loader();

      // 画像( テクスチャの取り出し )
      bmp_loader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{

        var i:int;
        var ename:String = ZipEntry(zipFile.entries[bitamp_count]).name;
        // data_list は、Object。ファイル名によるプロパティに
        // Material(テクスチャ) を保存
        data_list[ename] =   new BitmapMaterial( e.target.content.bitmapData );

        bitmap_num--;
        if ( bitmap_num <= 0 ) {
          mx.core.Application.application.firebug("メタセコイアロード開始");
          buildMetasequoia(mqo_target.readMultiByte(mqo_target.length, charset));

          dispatchEvent(new Event(Event.COMPLETE));

        }
        else {
          // 次のテクスチャをロードする
          for( i = bitamp_count+1; i < zip_num; i++ ) {
            if ( chkExt( ZipEntry(zipFile.entries[i]).name, imageExt ) ) {
              // 明示的に ByteArray とする
              zip = zipFile.getInput(ZipEntry(zipFile.entries[i]));
              bmp_loader.loadBytes(zip);
              bitamp_count = i;
              break;
            }
          }
        }
      });

      // ファイルリファレンスの準備
      fRef = new FileReference();
      fRef.addEventListener(Event.OPEN, function(e:Event):void {} );
      fRef.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {} );
      // load 完了
      fRef.addEventListener(Event.COMPLETE, function(e:Event):void {
        mx.core.Application.application.firebug("fref : COMPLETE(load) : "+e.target.name);

        // zipfile の場合、画像ファイルの bitmapData を BitmapMaterial
        // に変換してファイル名で 配列に保存しておく
        if ( chkExt( e.target.name, "zip" ) ) {
          var i:int; // ループ用
          // 明示的に ByteArray とする
          zip = FileReference(e.target).data;
          // ZipFile のインスタンスを作成する
          zipFile = new ZipFile(zip);

          zip_num = zipFile.entries.length;
          bitmap_num = 0;
          // まず画像ファイル数のカウント
          for( i = 0; i < zip_num; i++ ) {
            if ( chkExt( ZipEntry(zipFile.entries[i]).name, imageExt ) ) {
              bitmap_num++;
            }
            // メタセコイアの ByteArray
            if ( chkExt( ZipEntry(zipFile.entries[i]).name, "mqo" ) ) {
              mqo_target = zipFile.getInput(ZipEntry(zipFile.entries[i]));
            }
          }

          // 画像( 最初のテクスチャの取り出し ) : 非同期
          for( i = 0; i < zip_num; i++ ) {
            if ( chkExt( ZipEntry(zipFile.entries[i]).name, imageExt ) ) {
              // 明示的に ByteArray とする
              zip = zipFile.getInput(ZipEntry(zipFile.entries[i]));
              bmp_loader.loadBytes(zip);
              bitamp_count = i;
              break;
            }
          }

        }

      } );
      // キャンセル
      fRef.addEventListener(Event.CANCEL, function(e:Event):void {
        mx.core.Application.application.firebug("fref : cancel : "+e);
      } );
      // 選択直後
      fRef.addEventListener(Event.SELECT, function(e:Event):void {
        mx.core.Application.application.firebug("fref : select : "+e.target.name);
        if ( chkExt( e.target.name, _ext ) ) {
          FileReference(e.target).load();
        }
      } );
      fRef.addEventListener(IOErrorEvent.IO_ERROR, fRefError );
    }
    private function fRefError( e:IOErrorEvent ):void {
      Alert.show(e.text);
    }

    // *************************************************
    // ●公開メソッド : ロード : zipfile のByteArray
    // ※ 未テストです
    // *************************************************
    public function loadZipfle(byteArray:ByteArray, scale:Number = 1):void {
      _scale = scale;
      var i:int; // ループ用
      // ZipFile のインスタンスを作成する
      zipFile = new ZipFile(byteArray);

      zip_num = zipFile.entries.length;
      bitmap_num = 0;
      // まず画像ファイル数のカウント
      for( i = 0; i < zip_num; i++ ) {
        if ( chkExt( ZipEntry(zipFile.entries[i]).name, imageExt ) ) {
          bitmap_num++;
        }
        // メタセコイアの ByteArray
        if ( chkExt( ZipEntry(zipFile.entries[i]).name, "mqo" ) ) {
          mqo_target = zipFile.getInput(ZipEntry(zipFile.entries[i]));
        }
      }

      // 画像( 最初のテクスチャの取り出し ) : 非同期
      for( i = 0; i < zip_num; i++ ) {
        if ( chkExt( ZipEntry(zipFile.entries[i]).name, imageExt ) ) {
          // 明示的に ByteArray とする
          zip = zipFile.getInput(ZipEntry(zipFile.entries[i]));
          bmp_loader.loadBytes(zip);
          bitamp_count = i;
          break;
        }
      }
    }

    // *************************************************
    // ●公開メソッド : 参照 : 引数は拡張子リスト
    // 例 : browse( "zip" ) または 
    //      browse( "jpeg,jpg,png" )
    // *************************************************
    public function browse(ext:String,scale:Number = 1):void {
      _scale = scale;
      _ext = ext;
      fRef.browse();
    }

    // *************************************************
    // 拡張子チェック
    // *************************************************
    private function chkExt( target:String, ext:String ):Boolean {

      var lst:Array = ext.split(",");

      var test:Array = target.split(".");
      if ( test.length == 1 ) {
        return false;
      }
      var str:String = String(test[1]);
      str = str.toLocaleUpperCase();

      var chk:String;
      for( var i:int = 0; i < lst.length; i++ ) {
        chk = (lst[i]).toLocaleUpperCase();
        if ( str == chk ) {
          return true;
        }
      }
      return false;

    }

    
    /**
    * Material チャンクを読み込み、その最後の行番号を返します。
    * エラーが起こった場合は -1 を返します。
    */
    //*******************************************************
    // データ処理の心臓部
    //*******************************************************
    protected override function parseMaterialChunk(lines:Array, startLine:int):int {
      var l:int = getMaterialChunkLine(lines, startLine);

      if (l == -1) {
        return -1;
      }
      

      // 解析中の行の文字列
      var line:String = lines[l];
      
      // マテリアル数を取得
      var num:Number = parseInt(line.substr(9));
      if (isNaN(num)) {
        return -1;
      }

      ++l;
      _materialNames = new Array();
      
      // } で閉じているところの行番号
      var endLine:int = l + int(num);

      // mqo ファイルのあるディレクトリのパス
//      var path:String = _filename.slice(0, _filename.lastIndexOf("/") + 1);

      for (; l < endLine; ++l) {
        var material:MaterialObject3D;
        line = lines[l];
        
        // マテリアルの名前を取得
        var nameBeginIndex:int = line.indexOf("\"");
        var nameEndIndex:int = line.indexOf("\"", nameBeginIndex + 1);
        var name:String = line.substring(nameBeginIndex + 1, nameEndIndex);
        _materialNames.push(name);
        
        // テクスチャファイル名
        var tex:String = getParam(line, "tex");
        
        if (tex) {

          // テクスチャファイル名を取り囲む " " を取り除く
          tex = tex.substr(1, tex.length - 2);

/*
          _materialsToLoad++;
          if (tex.toLowerCase().search(/\.tga$/) != -1) {
            material = loadTGAMaterial(path + tex);
          } else if (tex.toLowerCase().search(/\.bmp$/) != -1) {
            material = loadBMPMaterial(path + tex);
          } else {
            // テクスチャの URL を絶対にして読み込む
            material = new BitmapFileMaterial(path + tex);
            material.addEventListener(FileLoadEvent.LOAD_COMPLETE, materialLoadCompleteHandler);
            material.addEventListener(FileLoadEvent.LOAD_ERROR, materialLoadErrorHandler);
          }
          // あまり重さが変わらないのでせっかくだからスムージング
*/
          material = data_list[tex];
          material.smooth = true;

        } else {
          // 形式 - col(1.000 1.000 0.000 1.000)
          var colorstr:String = getParam(line, "col");
          if (colorstr != null) {
            var color:Array = colorstr.match(/\d+\.\d+/g);
            var r:int = parseFloat(color[0]) * 255;
            var g:int = parseFloat(color[1]) * 255;
            var b:int = parseFloat(color[2]) * 255;
            var a:Number = parseFloat(color[3]) * 100;
            //trace("rgb = " + r + "," + g + "," + b);
            material = new ColorMaterial((r << 16) | (g << 8) | b);
          } else {
            material = MaterialObject3D.DEFAULT;
          }
        }
        
        material.doubleSided = this.doubleSided;
        material.interactive = this.interactive;
        material.name = name;
        
        materials.addMaterial(material, name);

      }
      
      return endLine;
    }
    
  }
}
  











  infoboard   管理者用   
このエントリーをはてなブックマークに追加





フリーフォントWEBサービス
SQLの窓WEBサービス

SQLの窓フリーソフト

素材

一般WEBツールリンク

SQLの窓

フリーソフト

JSライブラリ