JavaScript で型判別

ActionScript 3 なら is 演算子で一発な型判別。JavaScript では is 演算子が使えないのでそうもいかず、typeof だと null が object として扱われる(Array とか自作クラスも同じ)し、instanceof ではすべてのクラスが Object のインスタンスとして判別されるため、この二つは役不足。なにか方法がないかと模索してみた結果、constructor プロパティで判別するのが良さそうです。

以下、テストコード。

JavaScript
function Test() {};
var test = new Test();

alert(test.constructor == Object); // false
alert(test.constructor == Test); // true
alert(null.constructor); // TypeError: null has no properties
alert(undefined.constructor); // TypeError: undefined has no properties

InternetExplorer, Firefox, Safari などのブラウザですべて同じ動作なので、これが試した限りでは一番確実っぽいです。他に良い方法があればコメント欄で教えてください。

カテゴリー: JavaScript タグ:

ActionScript 3 での色々な文字列の扱い方

2008 年 10 月 28 日 muta244@admin コメント 8 件

ActionScript 内で JavaScript を操作する時には ExternalInterface を使いますが、複雑なことをする時にはどうしても以下のような感じになります。

ActionScript
ExternalInterface.call(
    "function ()" +
    "{" +
        "var temp = 'test';" +
        "temp += 'string';" +
        "alert(temp);" +
    "}"
);

これだと文字列の連結が多すぎで分かりにくくなってしまうんですが、ActionScript は CDATA セクションを文字列として扱うためこんなやり方もあります。

ActionScript
ExternalInterface.call(<![CDATA[
    function ()
    {
        var temp = "test";
        temp += "string";
        alert(temp);
    }
]]>);

カテゴリー: Flash (ActionScript) タグ: ,

AS3 での Singleton パターン実装

2008 年 10 月 23 日 muta244@admin コメント 4 件

AS3 での Singleton パターン実装はなかなか面倒くさいやり方が多いですが、ちょっとシンプルな実装法を思いついたので紹介します。

ActionScript
package
{
    public class Singleton
    {
        private static var _instance:Singleton = new Singleton();

        public function Singleton():void
        {
            if (_instance)
            {
                throw new ArgumentError("Singleton クラスは外部からインスタンス化できません.");
            }
        }

        public static function get instance():Singleton
        {
            return _instance;
        }
    }
}

※ 08.10.23 追記:
コンストラクタ内部で _instance = this をしていましたが、コメントを受けて修正しました。

内部で最初に new してしまっておくだけなんですが、今まで思いつきませんでした。問題になりそうな点があったらコメントお願いします。

FlashDevelop on Mac (Linux) の可能性が出てきた?

ネットサーフィン(って最近聞かないですね)してたら気になる情報が。

Mono 2.0 がリリースされたことにより FlashDevelop on Mac (Linux) の可能性が出てきたっぽいです。要は FlashDevelop は .NET で作られてるので、Mac 上で .NET が動かせる Mono により移植出来るようになったと。実際に Linux 上で動いている FlashDevelop の画像もあるので期待出来そうですね。

ただ、最初のリンク内で FlashDevelop 開発者の Mika さんがコメントされているように、肝心な構文解析やエディタ部分のエンジンが .NET ではないため、そこの移植はセカンドチーム(募集中?)次第みたいです。

エディタの善し悪しで作業効率が全然違うので、FlashDevelop on Mac が出来たら FlashDevelop on VMWare Fusion なんかとっととサヨナラするぐらい個人的にはテンション上がります。最後に、りちゃさん情報ありがとうございました!

カテゴリー: Flash (ActionScript) タグ:

Pixel Bender で放射状ブラー(ズーム&回転)

困った beinteractive さんの発言を受けて Pixel Bender で放射状ブラーを作ってみました。パラメータいじれるようにと思って Flex Builder に初挑戦してみたんですが、これのせいで余計に時間が掛かってしまった・・・。

放射状ブラーのデモ
放射状ブラーのデモ(※ 要 Flash Player 10)

関連ファイルはスパークプロジェクトの RadialBlur に一式上げてます。簡単に説明をすると、対象のピクセル間近 9 つのポイントをサンプリング&加重移動平均法を使って平滑化し、ピクセル色として適用しています。Pixel Bender はループ処理とか関数が使えない(Flash Player 向けの場合)ので、同じような文章が並んでかなり不格好ですが・・・。Pixel Bender の更なるバージョンアップに期待。

あと、Saqoosha さんも同じ事に挑戦されてました。違うアプローチで面白い。

カテゴリー: Flash (ActionScript) タグ:

WordPress へ移行

WordPress へ移行しました。これからはちゃんとエントリーを・・・していけたらいいな。

カテゴリー: Other タグ:

[Flash Player 10 #7] シェーダ (Pixel Bender) を使った頂点計算の最適化 2

2008 年 5 月 29 日 muta244@admin コメント 4 件

前回のエントリーでは複雑なことをしてシェーダにデータを渡そうとしていましたが、Saqoosha さんからコメント欄で教えていただいた boostworthyisryantaylor というサイトの情報(ShaderJob クラスなど)を元に、シェーダでの頂点情報の計算に成功しました。

フレームレートが 20 を切る分割数を計測(Z ソートは今回無し)

従来の通りの頂点計算 => 分割数 75、頂点数 5625
シェーダを使った頂点計算 => 分割数 80、頂点数 6400

こんな感じで、望んでいたような劇的な変化はありませんでした。自分の環境は普通の MacBook ですので GPU は搭載されていませんが、GPU がある環境では wmode を gpu とかにすれば結果は変わってくるんでしょう。試してないですが。

従来の通りの頂点計算デモはこちら
シェーダを使った頂点計算デモはこちら

※ 要 Flash Player 10
※ 左右キーで分割数、上下キーで視野角を変更できます。

boostworthyisryantaylor さんでも書かれているように、現在はバグなのか、ShaderInput に Vector.<number> を渡すとエラーになるので ByteArray で渡しています(ドキュメントでは渡せると書いてあります)。この問題が直れば幾分は良くなるでしょうが、あまり期待はできないのかも。引き続き、調査は続けていくつもりです。とりあえずは Vector.<number> が渡せるようになるのを待つつもりですが。

http://www.libspark.org/svn/as3/Astro/VertexShader_01/

に今回のコードを上げましたので必要な方はチェックアウトしてください。

[Flash Player 10 #6] シェーダ (Pixel Bender) を使った頂点計算の最適化 1

2008 年 5 月 28 日 muta244@admin コメント 2 件

3D でボトルネックになるのは描画と頂点情報の計算などです。描画については drawTriangles という便利なメソッドがあるのでまだ良いとして、頂点情報については for で回して計算するのが常套手段ですが、最近はシェーダ(Pixel Bender)を使っての最適化に挑戦しています。

‘08 5.29 追記:
Saqoosha さんからコメント欄で頂いた情報を元に新しいエントリーを投稿しました。このエントリーでしているような複雑なことをしなくても、シェーダにデータを渡せますのでそちらを参照ください。
—–

そのためにまず必要になるのが、どのようにシェーダ側にデータを渡すかというところ。シーンの行列などはパラメータで渡せるのですが、頂点の情報量は不定のためパラメータとしては渡せません(そもそも、シェーダは Flash 用に書き出す設定では配列に対応していませんし)。ですので、ピクセルに頂点座標を埋め込もうとしたのですが、これも中々うまくいかず、現状はここで止まってます。

流れを追って説明すると以下のような感じ。

1. Flash 側 − ビットマップに頂点情報を埋め込む。

浮動小数点数な頂点情報を、ビットマップに 15.15 形式の固定小数点数な uint(32 bit) として埋め込む。(ビットマップに書き込む際にアルファ値が 0 だと他の色情報まで 0 になってしまうため、32 bit 目は 1 で固定。また、31 bit 目は正負を表すために 15.15 形式)

例えば {x:100, y:0, z:0} の頂点一つのデータを埋め込むコードは以下。

ActionScript
var vector:Vector. = Vector.([
    // 100 &lt;&lt; 15 | 0x80000000 でも良い。
    // ただ、ビット演算は計算によってはオーバーフローを起こすので注意。
    // ちなみに 0x80000000 は 32 bit 目を 1 にするため。
    100 * 0x8000 + 0x80000000, 0, 0
]);
var data:BitmapData = new BitmapData(3, vector.length / 3);
data.setVector(data.rect, vector);

2. シェーダ側 − ピクセルから頂点情報を抜き出す。

シェーダ側でピクセルをサンプリングすると float4(a, r, g, b) の形になるので、これをもう一度固定小数点数に戻す。ただし、Pixel Bender の int 型は 16 bit なので float 型で取り扱う。

コードは以下。

ActionScript
// BIT_24 は 16777216.0、BIT_16 は 65536.0、BIT_08 は 256.0 をそれぞれ定数化したもの
pixel4 tmp = sampleNearest(src, outCoord());
float n = floor(tmp.a * 255.0) * BIT_24
        + floor(tmp.r * 255.0) * BIT_16
        + floor(tmp.g * 255.0) * BIT_08
        + floor(tmp.b * 255.0);

3. シェーダ側 − 頂点情報を計算。

パラメータで受け取った行列などを元に、頂点情報を計算する。ここは実際には試していないが、大した問題ではないはず。

4. シェーダ側 − ピクセルに埋め込むために各色情報を分解。

Pixel Bender はビット演算が行えないため、乗算・除算を使って分解します。

コードは以下。

ActionScript
float a = floor(n / BIT_24);
float r = floor(n / BIT_16) - (a * BIT_08);
float g = floor(n / BIT_08) - (a * BIT_16 + r * BIT_08);
float b = floor(n         ) - (a * BIT_24 + r * BIT_16 + g * BIT_08);

いま、つまづいているのがまさにここ。例えば、n が 4294770688.0({a:255, r:253, g:0, b:0})の時は誤差が生じて r 成分が 254 になってしまいます。試しに、ActionScript で同様のコードを実行しても誤差は生じず・・・。

同様のコード。

ActionScript
var BIT_24:Number = 16777216.0;
var BIT_16:Number = 65536.0;
var BIT_08:Number = 256.0;

var BYTE:Number = 255.0;

var dst:Object = {a:255/255, r:253/255, g:0/255, b:0/255};

var n:Number = Math.floor(dst.a * BYTE) * BIT_24
             + Math.floor(dst.r * BYTE) * BIT_16
             + Math.floor(dst.g * BYTE) * BIT_08
             + Math.floor(dst.b * BYTE);

trace(n); // 出力 =&gt; 4294770688

var a:Number = Math.floor(n / BIT_24);
var r:Number = Math.floor(n / BIT_16) - (a * BIT_08);
var g:Number = Math.floor(n / BIT_08) - (a * BIT_16 + r * BIT_08);
var b:Number = Math.floor(n         ) - (a * BIT_24 + r * BIT_16 + g * BIT_08);

trace(dst.a, dst.r, dst.g, dst.b); // 出力 =&gt; 1 0.9921568627450981 0 0
trace(aa / BYTE, rr / BYTE, gg / BYTE, bb / BYTE); // 出力 =&gt; 1 0.9921568627450981 0 0

色々とデバッグ(Pixel Bender はデバック面倒過ぎ!)して分かったことは、除算を行うと何故か誤差が生じてしまい、うまく分解できていないということ。内部の計算に使用できる bit 数が異なるために起こる誤差なのか、何なのか・・・。誰か助けていただけませんか。

[Flash Player 10 #5] 3D ドーナッツで Z ソート

3D のパフォーマンステストには最適なドーナッツのプリミティブで Z ソートを実装しました。

※ 要 Flash Player 10

デモはこちら(左右キーで分割数を変更できます)
Z ソートはこんな感じの実装。

drawTriangles はやっぱり凄い、分割数を結構上げてもサクサク動く。巷で言われている通り、3D ライブラリは軒並み性能アップするでしょうね。

カテゴリー: Flash (ActionScript) タグ: ,

[Flash Player 10 #4] PixelBender のファイルを使わずにカスタムフィルターを定義

すっかり FlashPlayer 10 の魅力に取り付かれています。

‘08.10.09 追記:
CS4 からはメタデータを使ってファイルの埋め込みができるようになるようなので、こんな面倒臭いことしなくても大丈夫です。

通常、Shader を使用するときは pbj 形式のファイルが必要ですが、今回はこのファイルを使用せずにカスタムフィルターを作成するという試み。結果から言うと大成功でした。これで他の BitmapFilter 同様、import するだけでカスタムフィルターが使用できます。このやり方は流行ると思うなぁ。Adobe の人もこういう使い方を想定しているんでしょう、きっと。

まずはカスタムフィルターのコード。

package
{
    import flash.display.Shader;
    import flash.filters.ShaderFilter;
    import flash.utils.ByteArray;

    public class ColorizeFilter extends ShaderFilter
    {
        // ここが重要!
        // あらかじめ、PixelBender のバイナリデータをベクター情報として格納しておく。
        private static var _data:Vector.<int> = Vector.<int>([-91,1,0,0,0,-92,11,0,67,111,108,111,114,70,105,108,116,101,114,-96,12,110,97,109,101,115,112,97,99,101,0,109,117,116,97,0,-96,12,118,101,110,100,111,114,0,109,117,116,97,0,-96,8,118,101,114,115,105,111,110,0,1,0,-96,12,100,101,115,99,114,105,112,116,105,111,110,0,84,104,105,115,32,102,105,108,116,101,114,32,70,105,108,108,32,99,111,108,111,114,46,0,-95,1,2,0,0,12,95,79,117,116,67,111,111,114,100,0,-95,1,4,1,0,15,99,111,108,111,114,0,-94,4,100,101,102,97,117,108,116,86,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,63,-128,0,0,-94,12,100,101,115,99,114,105,112,116,105,111,110,0,99,111,108,111,114,0,-93,0,4,115,114,99,0,-95,2,4,2,0,15,100,115,116,0,48,3,0,-15,0,0,16,0,29,4,0,-13,3,0,27,0,1,4,0,-13,1,0,27,0,29,2,0,-13,4,0,27,0]);
        private static var _byteCode:ByteArray;

        private var _color:uint;

        public function ColorizeFilter(color:uint):void
        {
            // ムービーを通して初めての new 時のみ、Vector を ByteArray に変換する。
            if (_byteCode == null)
            {
                _byteCode = new ByteArray();

                for (var i:int = 0, l:int = _data.length; i < l; i++)
                {
                    _byteCode.writeByte(_data[i]);
                }
            }

            super(new Shader(_byteCode));

            this.color = color;
        }

        public function get color():uint
        {
            return _color;
        }

        public function set color(value:uint):void
        {
            _color = value;
            // プロパティのセッター内で Shader にデータを渡す。
            shader.data.color.value = [value >> 16, value >> 8 & 0xFF, value & 0xFF];
        }
    }
}

実際に使用するときのコード。

var data:BitmapData = Bitmap(new image()).bitmapData;

data.applyFilter(
    data,
    data.rect,
    new Point(),
    new ColorizeFilter(0xFF0000)
);

addChild(new Bitmap(data));

こんな感じで通常のフィルターと同じように import して new するだけで使用できます。今回のコード一式も例のごとく libspark に上げてますので、必要な方は http://www.libspark.org/svn/as3/Astro/ShaderFilter/CustomFilter/ 以下をチェックアウトしてください。

カテゴリー: Flash (ActionScript) タグ: , ,