AGAL1では条件でフロー分岐するプログラムは書けません。(AGAL2ではできます。)レジスタの値を比較して、0か1の値を得る事はできるので、そこをうまく利用して、if分岐したように動くコードを書く事になります。
AGAL1のif分岐 具体例
例として、ft0レジスタとft1レジスタのx値が等しかった場合にft1.xにft0.yの値をコピー、等しく無い場合にft0.zの値をコピーするコードは下記のようになります。
seq ft0.z ft0.x ft1.x // 等しければ ft0.z=1
sne ft0.w ft0.x ft1.x // 等しくなければft0.w=1
mul ft0.y ft0.y ft0.z // ft0.yの値がそのままキープされるかもしくは0に変化
mul ft0.z ft0.z ft0.w // ft0.zの値がそのままキープされるかもしくは0に変化
add ft1.x ft0.y ft0.z // ft0.yかft0.zどちらかの値をft1.xに代入
初見では頭がこんがらがりますね。他にも色々な書き方があると思いますが、どうであれ、その後演算したい値に比較結果のフラグを掛け合わせるとフラグが偽の場合0になって値が打ち消され、フラグが真の場合、×1となって値が変化しない事を利用します。
真偽両者の処理は片側が意味的に無意味だけれど、実行はされているのがポイントです。
この系統の命令は4つあります。
sge
: setIfGreaterEqual
の略、source1 >= source2 の場合1を返す、さもなくば0を返す
slt
: setIfLessThan
の略、source1 < source2 の場合1を返す、さもなくば0を返す
seq
: setIfEqual
の略、source1 == source2 の場合1を返す、さもなくば0を返す
sne
: setIfNotEqual
の略、source1 != source2 の場合1を返す、さもなくば0を返す
AGALのifで検索してみると、だいたい似たような例がヒットするのですが、実際にいくつかフィルタを作ってみて思ったのは、コード例ででてくるほど分岐後の処理が単純でない場合も多く、気をつけないと複雑怪奇なコードがすぐに出来上がる、という事です。かかった工数の半分ぐらいはif分岐処理のパズルを解いていたように思います。
AGAL2のif分岐命令
ife
: 等しい場合のifブロック開始 source1 == source2
ine
: 等しくない場合のifブロック開始 source1 != source2
ifg
: 値が等しいか大きい場合のifブロック開始 source1 >= source2
ifl
: 値が小さい場合のifブロック開始 source1 < source2
els
: elseブロック
eif
: ifブロックの終わり
実際に分岐が書けるのと(AGAL1の場合、0を足すなど、無効な命令を実行しているだけで実際に分岐はしていない)、余計な掛け算も必要ないので、見通しのよいコードをクイックに記述する事ができそうです。
まとめ
そもそもAGALはGLSLやUnityのシェーダなどと比べてそもそもの生産性が低いので、ifの分岐記述で苦労して工数を取られるような時間の浪費を避けたく思うわけで。
StarlingではAGAL2は利用されておらず、すべてAGAL1記述であるようですが、これはフレームワークという立ち位置上、なるべく多くの環境をサポートしたいという所からでしょう。積極的にAGAL2を使っても現状のスマホ大枠はカバーできるので、実質的に問題はないと思われます。
おまけ
という事で、自分は次回のAGALコーディングからはAGAL2のif分岐命令を積極的に使っていこうと思います。
もともとはpixelbender3Dという Stage3D用の高級シェーダー言語が作られていたはずなのですが、開発途中でお亡くなりになってしまったようですね。そちらがあればif分岐など楽に記述できたのではないだろうかと思うのですが、現在ダウンロードはできないようです。(どこかで手に入らないものだろうか。)Stage3Dリリース当時はそこまで利用できるスキルをもったユーザも少なかったのではなかろうかとか思ったり。
世界でAGALと戯れてる人たちは、自前のユーティリティやサブツールなどを使って生産性を上げていたりするみたいですね。具体的には忘れましたが、過去にチラホラみました。自分もそのような便利クラスを用意してAGALコードを書き出してみています。