次に、OpenGLを利用するために、GLSurfaceViewクラスの派生クラスを用意します。
コンストラクタ内部でsetRendererを使用し、Rendererを設定します。
package jp.co.yahoo.map.codezine_sample; import android.content.Context; import android.opengl.GLSurfaceView; public class GL20SurfaceView extends GLSurfaceView{ private GL20MyRenderer mRenderer = null; //描画処理本体 private Context mContext; //Context private MapView mMapView = null; //MapView //コンストラクタ public GL20SurfaceView(Context context, MapView mapView) { super(context.getApplicationContext()); mContext = context.getApplicationContext(); mMapView = mapView; //OpenGLES2.0の使用を宣言します。 setEGLContextClientVersion(2); //レンダラーを初期化し、ビューにセットします。 mRenderer = new GL20MyRenderer(mContext,this, mMapView); setRenderer(mRenderer); } }
次に、実際のレンダリングを行うためのRendererインターフェースを実装したRendererクラスを用意します。
Rendererクラスは、GLSurfaceViewにセットすることでイベントを受け取ります。
必須実装メソッドは、下記のとおりです。
- onSurfaceCreated:Surfaceが作成される際に呼ばれます。本実装では、カメラの設定などを行っています。
- onSurfaceChanged:画面の大きさや向きが変更された際に呼ばれます。ビューポートの設定やビューボリュームの設定を行います。
- onDrawFrame:実際の描画処理を行います。今回は指定した図形を線として描画を行っています。
package jp.co.yahoo.map.codezine_sample; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import jp.co.yahoo.map.codezine_sample.GL20SurfaceView; import jp.co.yahoo.map.codezine_sample.MapView; import jp.co.yahoo.map.codezine_sample.Shader; import android.annotation.SuppressLint; import android.content.Context; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; public class GL20MyRenderer implements GLSurfaceView.Renderer{ private MapView mMapView; //MapView private Context mContext; //Context private GL20SurfaceView mParentView; //親のSurfaceView private Shader mShader; //定義したShader private float[] mProjMatrix = new float[16]; //投影変換用行列 private int muProjMatrix; //投影変換用行列のハンドル private float[] mViewMatrix = new float[16]; //視点変換用行列 private int muViewMatrix; //視点変換用行列のハンドル private float[] mCoordList; //頂点データ private int mVertexId; //頂点データのVRAMの位置 private int mNumVertices; //頂点数 private float mEyeX = 140000.0f, mEyeY = 50000.0f, mEyeZ = 10000000.0f; //視点の座標 private int mAPosition; //位置ハンドル private final int FSIZE = Float.SIZE / Byte.SIZE; //floatのバイトサイズ //コンストラクタ public GL20MyRenderer(Context context, GL20SurfaceView parent , MapView mapView){ mContext = context; mParentView = parent; mMapView = mapView; mShader = new Shader(); mCoordList = mMapView.getCoordinateList(); } @Override public void onDrawFrame(GL10 arg0) { //背景色を設定します。 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); //線幅を設定します GLES20.glLineWidth(2.0f); //頂点バッファを設定します GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexId); GLES20.glVertexAttribPointer(mAPosition, 3, GLES20.GL_FLOAT, false, FSIZE*3, 0); //描画 GLES20.glDrawArrays(GLES20.GL_LINE_STRIP, 0, mNumVertices); } @Override public void onSurfaceChanged(GL10 arg0, int width, int height) { int size = (width <= height) ? width : height; //ビューポートの設定します。 GLES20.glViewport((width - size) / 2, (height - size) / 2, size, size); //ビューボリュームを設定します。 Matrix.orthoM(mProjMatrix, 0, -1000000.0f, 1000000.0f, -1000000.0f, 1000000.0f, 0.0f, 10000000.0f); GLES20.glUniformMatrix4fv(muProjMatrix, 1, false, mProjMatrix, 0); } @Override public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) { //位置ハンドル(a_Position)の取得と有効化。 int program = mShader.initShaders(); mAPosition = GLES20.glGetAttribLocation(program, "a_Position"); if (mAPosition == -1) { throw new RuntimeException("a_Positionの格納場所の取得に失敗"); } GLES20.glEnableVertexAttribArray(mAPosition); mNumVertices = initVertexBuffers(); //ビューボリュームと視点の格納場所を取得し、を登録します。 muViewMatrix = GLES20.glGetUniformLocation(program, "u_ViewMatrix"); muProjMatrix = GLES20.glGetUniformLocation(program, "u_ProjMatrix"); if (muViewMatrix == -1 || muProjMatrix == -1) { throw new RuntimeException("a_Positionの格納場所の取得に失敗"); } //視点(カメラ)の位置を設定します。 Matrix.setLookAtM(mViewMatrix, 0, mEyeX, mEyeY, mEyeZ, mEyeX, mEyeY, 0.0f, 0.0f, 1.0f, 0.0f); GLES20.glUniformMatrix4fv(muViewMatrix, 1, false, mViewMatrix, 0); } //描画用の頂点データを作成します。 @SuppressLint("NewApi") public int initVertexBuffers() { //FloatBufferオブジェクトを作成します。 FloatBuffer vertices = makeFloatBuffer(mCoordList); int vertex_num = mCoordList.length / 3; //頂点数 //VRAMにデータを設定します。 int[] vertexId = new int[1]; GLES20.glGenBuffers(1, vertexId, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexId[0]); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, FSIZE * vertices.limit(), vertices, GLES20.GL_STATIC_DRAW); mVertexId = vertexId[0]; return vertex_num; } //フロート配列からフロートバッファを作成します。 public FloatBuffer makeFloatBuffer(float[] array) { if (array == null) throw new IllegalArgumentException(); ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * array.length); byteBuffer.order(ByteOrder.nativeOrder()); FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); floatBuffer.put(array); floatBuffer.position(0); return floatBuffer; } }