IMG_0410

iPhoneのOpenGLで文字を書くのAndroid版です。例によって、OpenGLにはフォント命令が無いので、自由に文字を書く場合は、テクスチャに文字を書いて、それをポリゴンで描画する必要があります。

基本は、プログラム全体で一度、

 m_texture.image = Bitmap.createBitmap(m_texture.width, m_texture.height, Config.ALPHA_8);

のように文字を書く先のBitmapを確保して、フレーム毎に

 Canvas canvas = new Canvas(m_texture.image);
 Paint paint = new Paint();
 paint.setTextSize(14);
 paint.setARGB(0xff, 0x00, 0x00, 0x00);
 canvas.drawText(line, 0, y+in_block_y+y_unit-4, paint);

とCanvasでBitmapに文字を描画して、

 GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, m_texture.image);

と文字を書いたBitmapでテクスチャを更新してしまえばよいです。

ただし、一人で悔やむ: AndroidのView.onDrawで、改行する。で書かれているように、自動的に折り返して文字を描画する命令が無いので、paint.breakTextを使って一行ずつに切り分けて、一行ずつ描画する必要があります。

また、drawTextで指定する座標が、左上座標ではなく、文字のベースライン(下線)座標なので、そのままUV値を計算すると文字がずれるので注意です。ベースライン座標から上と下に何ピクセル存在するかは、FontMetricsを使って取得することができます。(参考:テキストの描画(FontMetrics) - Android Wiki*

 FontMetrics fontMetrics = m_paint.getFontMetrics();
 m_font_top_offset = (int)Math.ceil(0 + fontMetrics.top); //ベースライン上ピクセル(負数)
 m_font_bottom_offset = (int)Math.ceil(0 + fontMetrics.bottom); //ベースライン下ピクセル(正数)


ソースコードはhttp://www.abars.biz/blog/FontTexture.javaからどうぞ。

このコードでは、最初に1024x1024 pixelの巨大なテクスチャを確保します。その後、毎フレーム、先行して現在のフレームに必要な文字を全て描画し、texSubImage2Dでテクスチャを更新します。

現在のフレームに必要な文字を全て描画した後は、一般的なオブジェクトを描画しながら、必要なタイミングで必要な文字を描画します。一枚の巨大なテクスチャに文字が格納されているので、次のように、必要な文字に応じてUV座標を変更しながら描画します。

 no=mFontTexture.getTexture();
 sx=mFontTexture.getWidth();
 sy=mFontTexture.getHeight();
 offset=mFontTexture.getOffset();
 GraphicUtil.drawTexture(gl,x,y,sx,sy,no, 0,offset/1024.0f,sx/1024.0f, sy/1024.0f, r,g,b, 1.0f);
 mFontTexture.nextReadPoint();

今回の描画文字に対するuのレンジは0〜sx/1024、vのレンジはoffset/1024〜offset/1024+sy/1024です。

texSubImage2Dで1024x1024ピクセルの画像を転送するのにかかる時間は、XperiaArcで3〜5msec、Xoomで7〜18msecでした。PowerVRよりもTegra2の方が、テクスチャの転送には時間がかかるみたいですね。