雑文発散

«前の日記(2015-06-16) 最新 次の日記(2015-06-18)» 編集
過去の日記

2015-06-17 [長年日記]

[Pebble] Pebble アプリのグラフィック部分を学ぶ #2

昨日の日記からの続き。今日は、Pebble Time / Pebble Time Steel 用のプラットフォーム(Basalt)で拡張されたグラフィック描画処理を触っていく。テキストは昨日に引き続き「Drawing Graphics」で、今日は「Advanced Features」の章から始める。

アンチエイリアス

Basalt ではアンチエイリアスが使えるようになって、よりスムーズなラインが引けるようになり、また隣接するカラーもエッジが目立たなくなるようだ。SDK 3.0 からはデフォルトでアンチエイリアスが効くようになっていて、graphics_context_set_antialiased() でそのコントロールができるとのこと。引数が true でアンチエイリアスが ON、false で OFF という制御になっている。

アンチエイリアスが効くのは次の関数とのこと。

  • graphics_draw_rect()
  • graphics_fill_rect()
  • graphics_draw_circle()
  • graphics_fill_circle()
  • graphics_draw_line() (昨日使った関数)
  • gpath_draw_outline()

一方で、アンチエイリアスが効かない関数もあるそうだ。

  • graphics_draw_pixel()
  • gpath_draw_filled()
  • graphics_draw_text() (昨日使った関数)

ふむ、graphics_draw_text() はアンチエイリアスが効かないのか。テキストもアンチエイリアスが効くようになるといいな。

ではアンチエイリアスの ON / OFF による描画の違いを体験してみよう。昨日までのソースコードから、昨日追加した分をいったん削除して、そこにアンチエイリアスのサンプルとして載っているコードを追加してみる。

static void layer_update_proc(Layer *layer, GContext *ctx) {
  // Draw an antialiased circle with smoothed edges
  graphics_draw_circle(ctx, GPoint(35, 35), 30);

  // Disable antialiasing
  graphics_context_set_antialiased(ctx, false);

  // Draw a regular circle
  graphics_draw_circle(ctx, GPoint(110, 35), 30);
}

このコードが意味するところは、画面内に 2 つの円を描くこと。

  • x = 035, y = 35 の場所に半径 30 の円を描く(アンチエイリアス ON)
  • x = 110, y = 35 の場所に半径 30 の円を描く(アンチエイリアス OFF)

その他に必要な処理を付け加えて、build & install したものがこれ。

04-antialias-layer

表示を削除した分と追加した分がひとつの diff になっているけど、本当ならこれは commit を分けるべきだよな。Removed & Add という 2 つの目的が入っている良くない commit の例がこれだ。良い子は真似しちゃダメなタイプだよ、これ、きっと。

描画ラインの幅

graphics_context_set_stroke_width() 関数で、描画するラインの幅をセットできる。ひとつ注意点が書かれていて、いまのところラインの幅( stroke width )には奇数の値しかセットできないとのこと。

なんでそんな制限が?って思ったけど、恐らく中心線に 1 ドットあり、その左右(もしくは上下)に 1 ドットを引いた分の半分のサイズで描画しているんじゃないかな。例えば、graphics_context_set_stroke_width() で 3 を指定した場合は、(3 - 1) / 2 = 1 ドットを左右に描画している。5 を指定した場合は、(5 - 1) / 2 = 2 ドットを中心線の左右に描画している感じ。引数に偶数を指定した場合、例えば 2 とかだと、(2 - 1) / 2 = 0.5 ドットとなってしまい、いまの Pebble では 0.5 ドット単位の描画はできないという状態なのではなかろうか。本当かどうかは知らないけど(笑)

さて空想はここまでにして、サンプルを記述して実行してみる。

05-stroke-layer

またしても Remove & Add している commit なのでアレである。

ビットマップ画像のローテーション

次にビットマップ画像のローテーション方法を学ぶ。「ビットマップのローテーションは CPU パワーを食うので、バッテリの減りが速いぞ!」という注意書きがある。「できることなら Draw Commands とか GPaths を使った方がいいよ」的なアドバイスも書かれている。

とは言え、その方法は知っておいても良いだろうと思うので、試してみよう。画像は、前回使ったアイコンを再利用する。appinfo.json の設定はそのとき使った内容のままだ。

メインのコードはこのように説明されている。

static void update_proc(Layer *layer, GContext *ctx) {
  // Get image center
  GRect img_bounds = gbitmap_get_bounds(s_bitmap);
  GPoint src_ic = grect_center_point(&img_bounds);

  // Get context center
  GRect ctx_bounds = layer_get_bounds(layer);
  GPoint ctx_ic = grect_center_point(&ctx_bounds);

  // Angle of rotation
  int angle = (45 * TRIG_MAX_ANGLE) / 360;

  // Draw!
  graphics_draw_rotated_bitmap(ctx, s_bitmap, src_ic, angle, ctx_ic);
}

画像の回転を実行しているのは graphics_draw_rotated_bitmap() の部分。引数に「中心」を意味するものが 2 つあって、どういう意味なんだろ?と思っていたんだけど、画像の中心と、その画像の中心をレイヤーのどこに合わせるか?という指定みたいだ。

その他の実装も加えて実行してみたらこんな感じ。

06-canvas-layer

まとめのセクション

最後に「Pebble」の「P」を描くサンプルが掲載されているので実行してみる。これは、ここまでで学んだことをひとまとめにしたヤツなので、個別に解説するところは無さそう。実行してみるとこんな感じになった。

07-p

これで「Drawing Graphics」のページはひととおり終わり。次は「Animating Layers」あたりを学んでみようかな。