第 5 章 グラフィックス 77
5.9 OpenGL ES
@Override
protected void onDraw(Canvas canvas) { Paint paint = new Paint();
paint.setColor(Color.rgb(255, 0, 128));
paint.setTextSize(24);
canvas.drawText("KeyCode=" + code, 10, 50, paint);
canvas.drawCircle(x, y, RADIUS, paint);
} }
これで完成です。実行して、キーを押してみてください。そうすると、押されたキーのキー コードがビューの上に描画されるはずです。また、矢印キーとセンターキーを押すことによって、
ビューの上に描画された円を移動させることもできるはずです。
5.9 OpenGL ES
5.9.1 OpenGL ESとは何か
Androidには、OpenGL ESと呼ばれるライブラリが搭載されています。
OpenGLというのは、Khronos Groupという標準化団体によって仕様が策定されている、2
次元または3次元のグラフィックスを描画するためのライブラリのことです。そして、OpenGL ES(OpenGL for Embedded Systems)というのは、組み込み機器で使われることを想定した
OpenGLのサブセットのことです。
この節では、Androidの上でOpenGL ESを使ってグラフィックスを描画する方法について説 明したいと思います。ただし、OpenGL ESについて詳細には説明しませんので、さらに深く勉 強したい人は、OpenGLに関する文献を参照してください。
5.9.2 OpenGL ESによるグラフィックスの描画に必要なオブジェクト
Androidの上でOpenGLによるグラフィックスの描画を実行するためには、最低限、次の二
つのオブジェクトが必要になります。
• サーフェスビュー(surface view)
• レンダラー(renderer)
サーフェスビューというのは、グラフィックスがその上に描画される「サーフェス」(surface) と呼ばれるものを表示するためのビューのことです。Androidには、
android.opengl.GLSurfaceView
という、OpenGLのためのサーフェスビューを生成するクラスが準備されています。
レンダラーというのは、描画を実行するメソッドを持っているオブジェクトのことです。Android
でOpenGLによる描画を実行する場合は、レンダラーとして、
android.opengl.GLSurfaceView.Renderer
というインターフェースを実装したクラスから生成されたオブジェクトを使います。OpenGLの ためのサーフェスビューに対して、
void setRenderer(GLSurfaceView.Renderer renderer)
というメソッドを使ってレンダラーを設定しておくと、そのレンダラーがサーフェスビューの上 にグラフィックスを描画することになります。
5.9.3 レンダラーを生成するクラス
GLSurfaceView.Rendererというインターフェースでは、次の三つのメソッドが宣言されてい
ます。
• void onSurfaceCreated(GL10 gl, EGLConfig config) サーフェスが生成されたときに呼び出されるメソッド。
• void onDrawFrame(GL10 gl) 描画を実行するメソッド。
• void onSurfaceChanged(GL10 gl, int width, int height) サーフェスの大きさが変化したときに呼び出されるメソッド。
レンダラーは、これらのメソッドを実装したクラスから生成されます。
5.9.4 OpenGL ESを使ってグラフィックスを描画するアプリケーションの例
それでは、OpenGL ESを使ってグラフィックスを描画するアプリケーションを作ってみま しょう。
まず最初に、次のようなプロジェクトを作成してください。
Project name opengl Application name OpenGL
Package name org.example.opengl Create Activity OpenGLActivity
次に、Triangleという名前の新しいクラスを作って、Triangle.javaの内容を次のように書 き換えてください。
プログラムの例 Triangle.java package org.example.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Triangle {
private final static int VSIZE = 3; // size of vertex private final static int CSIZE = 4; // size of color private final static int FSIZE = 4; // size of float private final static int VERTS = 3; // number of vertices private FloatBuffer vfb;
private FloatBuffer cfb;
Triangle() {
float vertices[] = { 0.2f, 0.2f, 0.0f, 0.8f, 0.2f, 0.0f, 0.5f, 0.5f, 0.0f };float colors[] = {
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f };ByteBuffer vbb =
ByteBuffer.allocateDirect(VSIZE * FSIZE * VERTS);
vbb.order(ByteOrder.nativeOrder());
vfb = vbb.asFloatBuffer();
vfb.put(vertices);
vfb.position(0);
ByteBuffer cbb =
ByteBuffer.allocateDirect(CSIZE * FSIZE * VERTS);
cbb.order(ByteOrder.nativeOrder());
cfb = cbb.asFloatBuffer();
cfb.put(colors);
cfb.position(0);
}
public void draw(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glVertexPointer(VSIZE, GL10.GL_FLOAT, 0, vfb);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glColorPointer(CSIZE, GL10.GL_FLOAT, 0, cfb);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
97 gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, VERTS);
} }
このクラスで定義されているdrawというメソッドは、白と黄色と赤で塗られた三角形を描画 します。
次に、GLSurfaceView.Rendererというインターフェースを実装する、TriangleRenderer という名前の新しいクラスを作って、TriangleRenderer.javaの内容を次のように書き換えて ください。
プログラムの例 TriangleRenderer.java package org.example.opengl;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class TriangleRenderer implements GLSurfaceView.Renderer { private Triangle triangle;
public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f, 0.0f, 0.4f, 1.0f);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0.0f, 1.0f, 0.0f, 1.0f);
triangle = new Triangle();
}
public void onDrawFrame(GL10 gl) { triangle.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height);
} }
最後に、OpenGLActivity.javaを次のように書き換えてください。
プログラムの例 OpenGLActivity.java package org.example.opengl;
import android.app.Activity;
import android.os.Bundle;
import android.opengl.GLSurfaceView;
public class OpenGLActivity extends Activity { private GLSurfaceView glSurfaceView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setRenderer(new TriangleRenderer());
setContentView(glSurfaceView);
} }
これで完成です。実行してみてください。そうすると、白と黄色と赤で塗られた三角形が描画 されるはずです。
第 6 章 データの永続化
6.1 ファイルへの書き込み
6.1.1 出力ストリームの生成
Androidのアプリケーションは、ファイルに対する読み書きを実行することができます。ただ
し、Androidでは、アプリケーションがアクセスすることのできるファイルは、自分がファイル を作る権限を持っているディレクトリに存在するものだけに限定されます。
ファイルへの書き込みを実行したいときは、そのための出力ストリームを生成する必要があり ます。Androidでは、
android.content.Context
というクラスを継承するクラス(Activityもそのひとつ)が持っている、
FileOutputStream openFileOutput(String name, int mode)
というメソッドを呼び出すことによって、出力ストリームを生成することができます。このメソッ ドに渡す引数の1個目は、そこにデータを書き込むファイルの名前です(パス名ではなくてファ イル名ですので、ディレクトリを指定することはできません)。引数の2個目は、「ファイル作成 モード」(file creation mode)と呼ばれる、書き込みやファイル作成のモードを指定するための整 数です。ファイル作成モードは、通常、
android.content.Context.MODE_PRIVATE という定数を指定します。
openFileOutputは、引数で指定された名前を持つファイルに対してデータを書き込むための
出力ストリームを生成して、それを戻り値として返します。指定されたファイルが存在しない場 合は、その名前を持つファイルが新しく作られます。
openFileOutputが戻り値として返すのは、
java.io.FileOutputStream
というクラスの出力ストリームです。この出力ストリームを使ってファイルにデータを書き込む 方法は、Androidアプリケーションではない普通のアプリケーションの場合と同じです。
6.1.2 ファイルにデータを書き込むアプリケーションの例
それでは、ファイルにデータを書き込むアプリケーションを作ってみましょう。
まず最初に、次のようなプロジェクトを作成してください。
Project name filewrite
Application name ファイルへの書き込み Package name org.example.filewrite Create Activity FileWriteActivity
次に、main.xmlを次のように書き換えてください。
レイアウトXMLの例 main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
<TableLayout>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1"
<TableRow>>
<TextView android:text="ファイル名"/>
<EditText android:id="@+id/filename"/>
</TableRow>
<TableRow>
<TextView android:text="文字列"/>
<EditText android:id="@+id/edittext"
6.1. ファイルへの書き込み 99 android:layout_height="260sp"
android:scrollbars="vertical"
android:gravity="top"
/>
</TableRow>
</TableLayout>
<Button android:id="@+id/write"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="書き込む"
/>
</LinearLayout>
次に、FileWriteActivity.javaを次のように書き換えてください。
プログラムの例 FileWriteActivity.java package org.example.filewrite;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Button;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
public class FileWriteActivity extends Activity { /** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button forward = (Button) findViewById(R.id.write);
forward.setOnClickListener(new OnClickListener() { public void onClick(View v) {
writeText();
}); } }
private void writeText() {
final EditText filename = (EditText) findViewById(R.id.filename);
final EditText edittext = (EditText) findViewById(R.id.edittext);
try {
FileOutputStream fos =
openFileOutput(filename.getText().toString(), Context.MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(edittext.getText().toString());
bw.flush();
bw.close();
} catch (IOException e) {
Log.d("FileWriteActivity", e.getMessage());
} } }
これで完成です。実行すると、2個のエディットテキストと1個のボタンが表示されるはずで すので、1個目のエディットテキストにファイル名、2個目のエディットテキストに文字列を入 力して、ボタンをクリックしてみてください。そうすると、このアプリケーションは、入力され
た文字列を、指定された名前を持つファイルに書き込みます。
6.1.3 ファイルの場所
Androidアプリケーションがファイルを作成する権限を持っているディレクトリというのは、
/data/data/パッケージ名/files
というディレクトリです。したがって、先ほど作ったアプリケーションは、
/data/data/org.example.filewrite/files というディレクトリにファイルを作っているはずです。
それでは、先ほど作ったアプリケーションが本当にファイルにデータを書き込んだかどうか、
Androidエミュレーターのシェルを使って確認してみましょう。まず、
adb shell
というコマンドでシェルを起動して、次に、
cat /data/data/org.example.filewrite/files/ファイル名
というコマンドを入力してください。そうすると、先ほどファイルに書き込んだ文字列が出力さ れるはずです。