ホーム > デベロッパ > BREW プログラミング入門 > さらに描画のおはなし > - 2 / 2 -

さらに描画のおはなし - 2 / 2 -

トランスレートとは?

ここまでは、クリッピングについて解説してきました。ここからはトランスレートについて解説していきます。

トランスレートとは、端的に言えば原点移動です。描画する前に原点移動させてから描画 API を呼び出すと原点移動させた分だけ画面上でオフセットがかかります。

トランスレートの効果
トランスレートの効果

BREW でもトランスレートをサポートしており IGraphics インタフェースの Translate 関数を使用して設定できます。ここでトランスレート関連の API を一覧にまとめておきます。

IGraphics
関数名 解説
Translate 移動量を設定します

上記表にある通り、現状の BREW ではトランスレート量を設定することしかできません。また、 IDisplay インタフェースにはトランスレート機能はありませんので、 IGraphics と IDisplay を混在させて使用するときなど微妙に使い勝手が悪くなってしまいます。これは本来 BREW のトランスレート機能が IGraphics のビューポートという機構のために用意されているからでしょう。

ビューポートに関してはここでは詳しく解説しませんが、トランスレート機能は便利なだけにもう少し機能が強化されることに期待したいとおもいます。

トランスレートを使ってみる

それでは、 IGraphics インタフェースのトランスレート機能を使用してみましょう。下記のコードは、トランスレートする前と後での描画結果の違いが分かります。

IGraphics*  graphics = app->g;
// 四角形を描画
rect.x = 10;
rect.y = 10;
rect.dx = 60;
rect.dy = 50;
IGRAPHICS_DrawRect(graphics,&rect);
// トランスレート量を設定
IGRAPHICS_Translate(graphics,-40,-40);
// 四角形を描画
IGRAPHICS_DrawRect(graphics,&rect);
// トランスレートをリセット
IGRAPHICS_Translate(graphics,40,40);
// 画面更新
IGRAPHICS_Update(graphics);

※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。

実際に描画されると以下の図のようになります。

トランスレートする前と後での違い
トランスレートする前と後での違い

クリッピングとトランスレート、何が便利なの?

ここまでで、クリッピングとトランスレートの具体例は終わりにしたいとおもいます。では、いったいクリッピングとトランスレートを使用したときと使用しなかったときで何が変わるのでしょうか?

画面が絶対座標上で動かないデザインや、絶対に全ての範囲が描画されることが分かっている場合には、クリッピングやトランスレートを使用する必要はありません。

しかし画面が絶対座標上で移動する場合、例えばウィンドウを表示させてその中にコンテンツを描画する場合など、ウィンドウの位置が変わるとウィンドウ内部のコンテンツの絶対座標が変わってしまいます。また、ウィンドウの大きさが変われば表示されている範囲が変わるかもしれません。

このような状況では、クリッピングやトランスレートを使用しないで描画するのは至難の業です。例えば、トランスレート機能を使用してウィンドウの中身を描画すれば、ウィンドウのコンテンツはウィンドウ上の原点からの相対座標で表現でき、いちいち絶対座標に変換する複雑な計算を省略することができます。

またクリッピングに対しても同様なことがいえます。つまり、複雑な計算を行わなくても複雑な描画処理を記述できるようになるのです。

もし全ての描画を絶対座標で記述していたなら、完成した後で「もう少し全体的に下にして欲しい」とか、「この範囲は見えなくしてほしい」などの要求があった時に書き直すのが大変です。下手をすると、描画周りのコードを作り直さなければならなくなってしまいます。

クリッピングとトランスレートが便利であるということは理解してもらえたかと思いますが、 BREW でそれらを使用するのは面倒くさそうだということも上記のサンプルコードなどを見てもらえれば分かるかとおもいます。

一つの解決策として IGraphics と IDisplay を抽象化して、数値の扱い方や設定の方法を共通にすることです。そのようなライブラリを独自に開発してもよいですが、現在ではそれらを行うライブラリ製品などが既に開発されています。

既存の物を利用してしまえば、わざわざ内部の複雑な計算をいちから考えなくて良くなるので便利かとおもいます。

ビットマップの変形

最後に少し話は変わりますが描画つながりということで、ビットマップの拡大と縮小や変形の方法を解説したいと思います。

BREW では ITransform インタフェースを使用してビットマップの変形や複雑な転送操作を行うことができます。具体的にはビットマップを拡大したり縮小したりして表示することや、 90 度回転や鏡像を作ることなどができます。また、行列指定でより複雑な変形を行うこともできます。

2 倍、 4 倍や 1/2 倍、 1/4 倍、 90 度回転、鏡像などは ITransform インタフェースの TransformBltSimple 関数により実現可能です。また、 1.5 倍や 60 度回転などは TransformBltComplex 関数により実現可能です。

ところで、 TransformBltSimple 関数、 TransformBltComplex 関数ともに変形元のビットマップを引数として必要とします。変形元のビットマップのクローンを作成してから処理を行ってはくれないようなので、変形元と変形先を同じビットマップにするとおかしな結果が得られてしまいますので注意が必要です。

ビットマップの変形を行ってみる

ところで、 ITransform インタフェースは IBitmap インタフェースの QueryInterface 関数を使用して作成します。 ITransform インタフェースを単体で使用することはありません。

それでは、まず TransformBltSimple 関数を使用したコードを以下に示します。

IShell*  shell = app->a.m_pIShell;
IDisplay*  display = app->a.m_pIDisplay;
// デバイスのビットマップを取得
IDISPLAY_GetDeviceBitmap(display,&dev);
// デバイスビットマップと互換性のある作業用ビットマップを作成
IBITMAP_CreateCompatibleBitmap(dev,&tmp,100,100);
// 作業用ビットマップにビットマップを描画
IBITMAP_BltIn(tmp,0,0,100,100,bmp,0,0,AEE_RO_COPY);
// デバイスビットマップから ITransform インタフェースを作成
IBITMAP_QueryInterface(dev,AEECLSID_TRANSFORM,&transform);
// 作業用ビットマップからデバイスビットマップへ変形転送
ITRANSFORM_TransformBltSimple(
    transform,          // オブジェクト
    0,                  // 転送先の X 座標
    0,                  // 転送先の Y 座標
    tmp,                // 転送元のビットマップ
    0,                  // 転送元の転送開始 X 座標
    0,                  // 転送元の転送開始 Y 座標
    100,                // 転送元の幅
    100,                // 転送元の高さ
    TRANSFORM_ROTATE_90 | TRANSFORM_SCALE_2,   // 変形方法
    COMPOSITE_OPAQUE);  // 転送モード
// 画面更新
IDISPLAY_Update(display);

※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。

※転送先の X 座標や転送先の Y 座標は、実際にはもう少しややこしい動作を行います。詳しくは BREW API リファレンスを参照してください。

上記のコードでは、まず作業用のビットマップを作成してそこに画像を描き、 TransformBltSimple 関数を使用して画像を 90 度回転させ 2 倍に拡大した後、画面に描画しています。このように、 TransformBltSimple 関数では拡大縮小と回転などを同時に適応することが可能です。

標準転送と変形転送 (TransformBltSimple)
標準転送と変形転送 (TransformBltSimple)

では次に、 TransformBltComplex 関数を使用してより複雑な処理を行ってみましょう。

IShell*  shell = app->a.m_pIShell;
IDisplay*  display = app->a.m_pIDisplay;
AEETransformMatrix  matrix;
// デバイスのビットマップを取得
IDISPLAY_GetDeviceBitmap(display,&dev);
// デバイスビットマップと互換性のある作業用ビットマップを作成
IBITMAP_CreateCompatibleBitmap(dev,&tmp,100,100);
// 作業用ビットマップにビットマップを描画
IBITMAP_BltIn(tmp,0,0,100,100,bmp,0,0,AEE_RO_COPY);
// デバイスビットマップから ITransform インタフェースを作成
IBITMAP_QueryInterface(dev,AEECLSID_TRANSFORM,&transform);
// 変形マトリックスを設定
matrix.A = 192;   // 256 * 1.5 * cos(60)
matrix.B = 332;   // 256 * 1.5 * sin(60)
matrix.C = -332;  // 256 * 1.5 * -sin(60)
matrix.D = 192;   // 256 * 1.5 * cos(60)
// 作業用ビットマップからデバイスビットマップへ変形転送
ITRANSFORM_TransformBltComplex(
    transform,         // オブジェクト
    0,                 // 転送先の X 座標
    0,                 // 転送先の Y 座標
    tmp,               // 転送元のビットマップ
    0,                 // 転送元の転送開始 X 座標
    0,                 // 転送元の転送開始 Y 座標
    100,               // 転送元の幅
    100,               // 転送元の高さ
    &matrix,           // 変形マトリックス
    COMPOSITE_OPAQUE); // 転送モード
// 画面更新
IDISPLAY_Update(display);

※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。

※転送先の X 座標や転送先の Y 座標は、実際にはもう少しややこしい動作を行います。詳しくは BREW API リファレンスを参照してください。

上記のコードでは、まず作業用のビットマップを作成してそこに画像を描き、 TransformBltComplex 関数を使用して画像を 1.5 倍に拡大して 60 度回転させています。このように、 TransformBltComplex 関数の変形規則は行列を使用することになります。

より詳しい、変形マトリックスの設定の方法は BREW API リファレンスなどを参照してください。

標準転送と変形転送 (TransformBltComplex)
標準転送と変形転送 (TransformBltComplex)

まとめ

今回はクリッピングやトランスレートの詳細と、ビットマップの変形について解説しました。第 3 回の「画面に描画してみよう!」前回の「ビットマップを描画してみよう」と合わせて BREW での描画についてはほぼ解説しました。

あとは、ゲーム用に ISprite というスプライトエンジンのインタフェースが存在したりします。

アプリケーションにとって、見た目や操作性は非常に重要な要素です。処理の内容やアルゴリズムも重要な要素ですが、ユーザインタフェースいかんによってそのアプリがユーザーに長く使われるかどうかが決まってきます。

インタフェースを全て画像で作ることもできますが、現状の携帯電話などのモバイル機器のメモリ容量などを考えるとそれも不可能です。ある程度はコーディングで表現することになりますので、そのような時に今回解説したような事柄が重要になってくるとおもいます。