さらに描画のおはなし - 1 / 2 -
今回解説する内容は描画関係の事柄なので、関連するインタフェースは主に IGraphics, IDisplay, IBitmap, ITransform などです。
クリッピングとは?
画像を表示したり、図形を描画したりする時に描画範囲をマスクすることをクリッピングといいます。描画範囲をクリッピングしてから描画関連の API を呼び出すと、クリッピングした領域の内部しか描画が行われません。無駄な領域の描画を行いたくないときや、あらかじめ無駄な部分を描画しないように計算してから描画することが困難な場合に、威力を発揮します。
BREW でもクリッピングをサポートしており、 IGraphics インタフェースの SetClip 関数や IDisplay インタフェースの SetClipRect 関数などを使用して設定できます。ここでクリッピング関連のAPIを一覧にまとめておきます。
関数名 | 解説 |
---|---|
SetClip | クリッピング領域を設定します |
GetClip | クリッピング領域を取得します |
関数名 | 解説 |
SetClipRect | クリッピング領域(矩形)を設定します |
GetClipRect | クリッピング領域(矩形)を取得します |
クリッピングの前提事項と制約
上記の表で、 IGraphics インタフェースの API と IDisplay インタフェースの API が、それぞれ存在することが分かってもらえると思いますが、 IGraphics に設定したクリッピング領域は IGraphics の描画 API にのみ有効で、 IDisplay に設定したクリッピング領域は IDisplay の描画 API にのみ有効です。そして、 IGraphics に設定できるクリッピング領域は矩形以外の円や楕円も設定できるのに対して、 IDisplay に設定できるのは矩形のみです。このことは少々面倒くさい事態を招きます。
BREW で文字列を描画するには IDisplay インタフェースを使用し、図形を描画するには IGraphics インタフェースを使用します (IDisplay インタフェースにも若干の図形描画 API は存在しますが、 IGraphics インタフェースの API のほうが使いやすいと思います。詳しくは BREW API リファレンスなどを参照してください)。
ということは、文字列と図形両方に対してクリッピングを行いたい場合は IDisplay と IGraphics 両方に対してクリッピングの設定をしてやらなければなりません。また、 IDisplay の方は矩形しか扱えないため、矩形以外のクリッピング領域は文字列には適応できないことになります。
実現可能な例と不可能な例
IGraphics インタフェースのクリッピングを使ってみる
それでは、クリッピングの前提事項と制約を説明したところで、クリッピングとはどのような物なのか実際に実験してみましょう。
まずは、 IGraphics インタフェースのみを使用して図形を描いてみましょう。以下のコードは、矩形領域でクリッピングしてから、四角形と円を描いています。
IGraphics* graphics = app->g; // クリッピング領域を矩形に設定 clip.type = CLIPPING_RECT; clip.shape.rect.x = 20; clip.shape.rect.y = 20; clip.shape.rect.dx = 80; clip.shape.rect.dy = 80; IGRAPHICS_SetClip(graphics,&clip,0); // 四角形を描画 rect.x = 10; rect.y = 10; rect.dx = 60; rect.dy = 50; IGRAPHICS_DrawRect(graphics,&rect); // 円を描画 circle.cx = 80; circle.cy = 70; circle.r = 40; IGRAPHICS_DrawCircle(graphics,&circle); // クリッピング領域をリセット IGRAPHICS_SetClip(graphics,NULL,0); // 画面更新 IGRAPHICS_Update(graphics);
※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。
IGRAPHICS_SetClip(graphics,&clip,0); のクリッピング領域を設定している行をコメントアウトするとクリッピングされなくなります。どのようにクリッピングが働くのかは以下の図を参照してください。
クリッピングを使用したときとそうでないとき(矩形領域)
次に、円領域でクリッピングしてから、四角形と円を描いてみます。
IGraphics* graphics = app->g; // クリッピング領域を円に設定 clip.type = CLIPPING_CIRCLE; clip.shape.circle.cx = 60; clip.shape.circle.cy = 60; clip.shape.circle.r = 40; IGRAPHICS_SetClip(graphics,&clip,0); // 四角形を描画 rect.x = 10; rect.y = 10; rect.dx = 60; rect.dy = 50; IGRAPHICS_DrawRect(graphics,&rect); // 円を描画 circle.cx = 80; circle.cy = 70; circle.r = 40; IGRAPHICS_DrawCircle(graphics,&circle); // クリッピング領域をリセット IGRAPHICS_SetClip(graphics,NULL,0); // 画面更新 IGRAPHICS_Update(graphics);
※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。
矩形領域でのクリッピングの時と同様に IGRAPHICS_SetClip(graphics,&clip,0); の行をコメントアウトするとクリッピングされなくなります。
クリッピングを使用したときとそうでないとき(円領域)
IGraphics インタフェースではこのほかにも、楕円領域でのクリッピングが可能です(ほかにも、クリッピングに設定できる領域は定義されていますが、現在の BREW ではサポートしていないようです)。
IDisplay インタフェースのクリッピングを使ってみる
では次に、 IDisplay インタフェースを使用して文字列と図形を描いてみましょう。以下のコードは、矩形領域でクリッピングしてから、文字列と四角形を描いています。
IDisplay* display = app->a.m_pIDisplay; const AECHAR str[] = {'B','R','E','W',' ', 'B','R','E','W',' ','B','R','E','W','\0'}; // クリッピング領域を矩形に設定 clip.x = 20; clip.y = 20; clip.dx = 80; clip.dy = 80; IDISPLAY_SetClipRect(display,&clip); // 描画色を赤色で四角形を描画 rect.x = 10; rect.y = 10; rect.dx = 60; rect.dy = 50; IDISPLAY_DrawRect(display,&rect, MAKE_RGB(0xFF,0x88,0x88),MAKE_RGB(0xFF,0xCC,0xCC), IDF_RECT_FRAME | IDF_RECT_FILL); // 文字列を描画 IDISPLAY_DrawText(display,AEE_FONT_NORMAL, str,-1,0,55,NULL,IDF_TEXT_TRANSPARENT); IDISPLAY_DrawText(display,AEE_FONT_NORMAL, str,-1,20,70,NULL,IDF_TEXT_TRANSPARENT); // クリッピング領域をリセット IDISPLAY_SetClipRect(display,NULL); // 画面更新 IDISPLAY_Update(display);
※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。
IDISPLAY_SetClipRect(display,&clip); のクリッピング領域を設定しているコードをコメントアウトするとクリッピングされなくなります。
クリッピングを使用したときとそうでないとき (IDisplay)
実際のアプリでのクリッピング
ここまでは、 IGraphics と IDisplay を単独で使用したときの処理を例に示してみましたが、実際のアプリでは IGraphics と IDisplay を混在させて使用する事が多いと思います。例えば、以下のようなデザインを表示させる時には混在させて使用しなければなりません。
IGraphics と IDisplay を混在させなければならないとき
また、クリッピングの制約でも示しましたが、文字列を矩形以外でクリッピングすることは不可能です。同様に、 IDisplay を使用するビットマップの描画時も矩形以外でクリッピングすることはできません。どうしても矩形以外でクリッピングしたいときは、ビットマップレベルで透過色で処理する方法があります。
では、上の図に示したデザインを表示するコードを下に示します。
IGraphics* graphics = app->g; IShell* shell = app->a.m_pIShell; IDisplay* display = app->a.m_pIDisplay; const AECHAR str[] = {'B','R','E','W',' ', 'B','R','E','W',' ','B','R','E','W','\0'}; // クリッピング領域を矩形に設定 clip.type = CLIPPING_RECT; clip.shape.rect.x = 20; clip.shape.rect.y = 20; clip.shape.rect.dx = 80; clip.shape.rect.dy = 80; IGRAPHICS_SetClip(graphics,&clip,0); IDISPLAY_SetClipRect(display,&clip.shape.rect); // ビットマップを描画 IDISPLAY_BitBlt(display,0,0,100,100,bmp,0,0,AEE_RO_COPY); // 円を描画 circle.cx = 80; circle.cy = 70; circle.r = 40; IGRAPHICS_DrawCircle(graphics,&circle); // 文字列を描画 IDISPLAY_DrawText(display,AEE_FONT_NORMAL, str,-1,0,55,NULL,IDF_TEXT_TRANSPARENT); IDISPLAY_DrawText(display,AEE_FONT_NORMAL, str,-1,20,70,NULL,IDF_TEXT_TRANSPARENT); // クリッピング領域をリセット IGRAPHICS_SetClip(graphics,NULL,0); IDISPLAY_SetClipRect(display,NULL); // 画面更新 IGRAPHICS_Update(graphics); IDISPLAY_Update(display);
※一部省略されています。完全なコードはこちらを参照してください(クリックで別ウィンドウにソースコード表示)。