今回は、ビットマップ (テクスチャ) の表示方法です。Starling では、ビットマップか、前回までのように矩形を使って画面を構成します。
記事の後半では、動的にピットマップを更新する方法もご紹介します。
(注:以下の文章では、"テクスチャ = ビットマップ" と思ってお読みください)
Image と Texture クラス
Starling フレームワークでは、ビットマップを表示するのに Image を使います。Image は Quad のサブクラスです。Quad にビットマップを扱う機能を追加したものが Image という位置づけです。
Flash Player の表示オブジェクトでは Bitmap に BitmapData があるように、Starling では Image に Texture があります。Image が表示オブジェクトとして使われて、データの実体は Texture が持つ、という関係です。
Texture に読み込めるイメージフォーマットは、PNG, JPEG, JPEG-XR, ATF の 4 種類です。それぞれのフォーマットごとに、専用の読み込み関数が用意されています。
例えば、Bitmap オブジェクトから Texture オブジェクトを作る場合は、以下のようになります。
var myTexture:Texture = Texture.fromBitmap(myBitmap);
あとは、生成した Texture から Image オブジェクトを生成し、表示リストに追加するだけで、画面にビットマップが表示されます。
下は、myBitmap.png というファイルを表示するサンプルです。埋め込んだビットマップを扱う箇所を除けば、矩形を表示するサンプルのコードとほぼ同じです。
import flash.display.Bitmap; import starling.display.Image; import starling.textures.Texture; import starling.display.Sprite; import starling.events.Event; public class MyStarlingSprite extends Sprite { // PNGファイルを埋め込む [Embed(source = "myBitmap.png")] private static const MyBitmap:Class; private var myImage:Image; public function MyStarlingSprite() { addEventListener(Event.ADDED_TO_STAGE, onAdded); } private function onAddedToStage(e:Event):void { var myBitmap:Bitmap = new MyBitmap(); // BitmapからTextureオブジェクトを生成 var myTexture:Texture = Texture.fromBitmap(myBitmap); // Imageオブジェクトを生成 myImage = new Image(myTexture); // 表示リストに追加 addChild(myImage); } }
Starling の Texture は縦と横のピクセル数が 2 の階乗 (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048) を前提としているようです。それ以外の大きさのビットマップから Texture を生成すると、Starling は自動的に、最も近い大きさに合わせて Texture を作り直します。
ベクタ画像をテクスチャとして表示する
Flash Player の表示オブジェクトは、ベクターのデータをビットマップ化する機能を持っています。これを利用すると、AS3 や Flash Professional の機能を使って描いたベクタ画像から、Image オブジェクトを生成できます。
処理効率を考えると、わざわざ実行時にビットマップを生成するよりは、事前にビットマップ化しておいた方が良いはずです。従って、この方法は、動的にテクスチャを生成する必要がある場合向け、と言えそうです。
具体的な例を紹介します。下は、Sprite の graphic 属性に描いた円を、テクスチャに変換して Image を使って表示する例です。
private function onAddedToStage(e:Event):void { var radius:uint = 100; // Flash PlayerのSpriteを生成 var shape:flash.display.Sprite = new flash.display.Sprite(); // ランダムに色を決めてgraphics属性に円を描く var color:uint = Math.random() * 0xFFFFFF; shape.graphics.beginFill(color); shape.graphics.drawCircle(radius, radius, radius); shape.graphics.endFill(); // SpriteをBitmapDataに変換 var buffer:BitmapData = new BitmapData(radius * 2, radius * 2, true, color); buffer.draw(shape); // BitmapDataからTextureを作成 var myTexture:Texture = Texture.fromBitmapData(buffer); // TextureからImageを作成 myImage = new Image(myTexture); // 表示リストに追加 addChild(myImage); }
この場合、コード内では Flash Player の表示オブジェクトを使うことになるので、Starling の表示オブジェクトと混同しないように、注意が必要です。
動的なテクスチャの更新
上の方法を使えば、動的に生成したビットマップを表示できます。しかし、一旦表示したビットマップを更新するには、ベクター画像の作成からやり直しです。
つまり CPU 描画と GPU 描画の両方が行われるわけで、あまり効率が良い手段では無さそうです。 (常に避けるべき、という意味では無いです)
こんな時は、RenderTexture クラスが役に立つかもしれません。RenderTexture は Texture のサブクラスで、"Starling の表示オブジェクト" を既存の Image オブジェクトに描き込む機能を提供します。描画は GPU の機能だけで行われるため効率的です。
RenderTexture は "Flash Player の表示オブジェクト" を扱えるわけではないので、既に用意されている Image オブジェクトをビットマップに合成するという使い方が基本になります。とすると、特に、事前に表示するグラフィックが分かっている場合に有効そうです。
RenderTexture のコンストラクタには、描画領域の大きさだけ指定します。この時点では、RenderTexture はまだ真っ白 (というか透明) です。
次に RenderTextire のインスタンスを使って Image のインスタンスを生成する、という手順は Texture のときと同じです。下はそのサンプルです。
import starling.textures.RenderTexture; private var myRenderTexture:RenderTexture; private function onAddedToStage(e:Event):void { // RenderTextureオブジェクトを生成 myRenderTexture = new RenderTexture(320, 480); // RenderTextureからImageを作成 var canvas:Image = new Image(myRenderTexture); // 表示リストに追加 addChild(canvas); }
これで描画領域の指定が完了しました。
あとは、RenderTexture を更新すれば、画面の表示も自動的に更新されます。
RenderTexuture に Starling の表示オブジェクトを描くには、draw() メソッドを使います。描画する表示オブジェクトには、位置、スケール、角度、アルファを指定できます。下の例では、RenderTexture 内の x 座標と y 座標を指定しています。
myImage.x = 10; myImage.y = 20; myRenderTexture.draw(myImage);
たくさんの表示オブジェクトを描画したい場合のために、drawBundled() というメソッドも用意されています。これは、複数の表示オブジェクトの描画を一括して行うことで、処理効率の向上を狙ったものです。GPU を効率的に使う上で、GPU に対する描画要求の回数を減らすのは重要です。
drawBundled() の引数には関数を指定します。その関数内で呼んだ draw() はまとめて処理されます。
下は、画像を少しずつ回転させながら書く例です。
myRenderTexture.drawBundled(function():void { var count:int = 30; var diff:Number = 2 * Math.PI / count; for (var i:int=0; i<count; ++i) { myImage.rotation = diff * i; myRenderTexture.draw(myImage); } });
実行すると下のようになります。画像は Starling のサンプルに含まれるものを使ってみました。
RenderTexture に描画された内容を全て消去したい場合は、clear() メソッドを使います。
リソースの開放
不要になったテクスチャがあるときは、dispose() でリソースを開放します。特に、RenderTexture は一時的な利用が多いと思われるので、お忘れなく。
public override function dispose():void { myRenderTexture.dispose(); super.dispose(); }
次回は、パラパラ漫画によるアニメーションの実現方法をご紹介する予定です。
コメントする