[ヅ] はじめての OpenGL ES 1.0 for Android. 立方体を表示するサンプル (2013-08-16) を改造して作ってみた。
サンプル画像。
apkファイル: openglsample.apk
以下、延々とサンプルコード。
OpenGL0.java
package com.example.openglsample;
import net.shisashi.android.widget.LongClickRepeatAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
public class OpenGL0 extends Activity {
private TextView eyeText;
private Button eyeXPlusButton;
private Button eyeXMinusButton;
private Button eyeYPlusButton;
private Button eyeYMinusButton;
private Button eyeZPlusButton;
private Button eyeZMinusButton;
private MyGLView myGLView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGLView = new MyGLView(this);
eyeText = new TextView(this);
updateEyeText();
eyeXPlusButton = new Button(this);
eyeXPlusButton.setText("eyeX[+]");
eyeXPlusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeX(OpenGL0.this.myGLView.getMyRenderer().getEyeX() + 1.0f);
update();
}
});
eyeXMinusButton = new Button(this);
eyeXMinusButton.setText("eyeX[-]");
eyeXMinusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeX(OpenGL0.this.myGLView.getMyRenderer().getEyeX() - 1.0f);
update();
}
});
eyeYPlusButton = new Button(this);
eyeYPlusButton.setText("eyeY[+]");
eyeYPlusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeY(OpenGL0.this.myGLView.getMyRenderer().getEyeY() + 1.0f);
update();
}
});
eyeYMinusButton = new Button(this);
eyeYMinusButton.setText("eyeY[-]");
eyeYMinusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeY(OpenGL0.this.myGLView.getMyRenderer().getEyeY() - 1.0f);
update();
}
});
eyeZPlusButton = new Button(this);
eyeZPlusButton.setText("eyeZ[+]");
eyeZPlusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeZ(OpenGL0.this.myGLView.getMyRenderer().getEyeZ() + 1.0f);
update();
}
});
eyeZMinusButton = new Button(this);
eyeZMinusButton.setText("eyeZ[-]");
eyeZMinusButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
myGLView.getMyRenderer().setEyeZ(OpenGL0.this.myGLView.getMyRenderer().getEyeZ() - 1.0f);
update();
}
});
LinearLayout sideLayout = new LinearLayout(this);
sideLayout.setOrientation(LinearLayout.VERTICAL);
sideLayout.addView(eyeText);
sideLayout.addView(eyeXPlusButton);
sideLayout.addView(eyeXMinusButton);
sideLayout.addView(eyeYPlusButton);
sideLayout.addView(eyeYMinusButton);
sideLayout.addView(eyeZPlusButton);
sideLayout.addView(eyeZMinusButton);
// ボタンのキーリピートを実装
LongClickRepeatAdapter.bless(eyeXPlusButton);
LongClickRepeatAdapter.bless(eyeXMinusButton);
LongClickRepeatAdapter.bless(eyeYPlusButton);
LongClickRepeatAdapter.bless(eyeYMinusButton);
LongClickRepeatAdapter.bless(eyeZPlusButton);
LongClickRepeatAdapter.bless(eyeZMinusButton);
LinearLayout mainLayout = new LinearLayout(this);
mainLayout.setOrientation(LinearLayout.HORIZONTAL);
mainLayout.addView(sideLayout);
mainLayout.addView(myGLView);
setContentView(mainLayout);
}
@Override
protected void onResume() {
super.onResume();
myGLView.onResume();
}
@Override
protected void onPause() {
super.onPause();
myGLView.onPause();
}
private void update(){
updateEyeText();
}
private void updateEyeText(){
eyeText.setText(
"(" +
OpenGL0.this.myGLView.getMyRenderer().getEyeX() +
"," +
OpenGL0.this.myGLView.getMyRenderer().getEyeY() +
"," +
OpenGL0.this.myGLView.getMyRenderer().getEyeZ() +
")"
);
}
}
MyGLView.java
package com.example.openglsample;
import android.content.Context;
import android.opengl.GLSurfaceView;
public class MyGLView extends GLSurfaceView {
private MyRenderer myRenderer;
public MyGLView(Context context) {
super(context);
myRenderer = new MyRenderer();
setRenderer(myRenderer);
}
public MyRenderer getMyRenderer(){
return myRenderer;
}
}
MyRenderer.java
package com.example.openglsample;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
/**
* GLSurfaceView 内部から適切なタイミングで呼び出されるクラス。
*/
public class MyRenderer implements Renderer {
private MyCube cube = new MyCube();
private int viewportWidth;
private int viewportHeight;
// カメラの位置
private float eyeX = 0;
private float eyeY = 0;
private float eyeZ = 10.0f;
/**
* GLSurfaceView 用のメモリ確保が終了したタイミングで呼ばれるメソッド。
*/
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glEnable(GL10.GL_DEPTH_TEST);
// アルファブレンドを有効にする
gl.glEnable(GL10.GL_BLEND);
gl.glEnable(GL10.GL_ALPHA);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
// ライト
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
float[] lightColor = {1.0f, 0.0f, 0.0f, 0.5f}; // 赤いライト
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightColor, 0);
gl.glDepthFunc(GL10.GL_LEQUAL);
}
/**
* GLSurfaceView 用の画面サイズが変更されたタイミングで呼ばれるメソッド。
* @param width GLSurfaceView の縦ピクセル数
* @param height GLSurfaceView の横ピクセル数
*/
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
final int margin = 30;
viewportWidth = width - (margin * 2);
viewportHeight = height - (margin * 2);
gl.glViewport(0 + margin, 0 + margin, viewportWidth, viewportHeight);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45f, (float) width / height, 1f, 50f);
}
/**
* GLSurfaceView の再描画が必要なタイミングで呼ばれるメソッド。
*/
@Override
public void onDrawFrame(GL10 gl) {
gl.glClearColor(0.5f, 1.0f, 1.0f, 1.0f); // 背景を水色に
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// カメラ
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity(); // 行列をリセット
float fovy = 45.0f; // Y方向の画角
float aspect = (float)viewportWidth / (float)viewportHeight; // 画面の縦横比
float zNear = 0.01f; // ニアクリップ。これよりカメラに近いオブジェクトはカメラに映らない
float zFar = 100.0f; // ファークリップ。これより遠いオブジェクトはカメラに映らない
GLU.gluPerspective(gl, fovy, aspect, zNear, zFar);
// 注視位置(被写体)
float centerX = 0;
float centerY = 0;
float centerZ = 0;
// カメラの天井方向を示すベクトル
float upX = 0;
float upY = 1;
float upZ = 0;
GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // 行列をリセット
gl.glTranslatef(0, 0, -3f);
gl.glRotatef(30f, 0.8f, 1, 0);
// 3Dオブジェクトの描画
cube.draw(gl);
}
public float getEyeX() {
return eyeX;
}
public void setEyeX(float eyeX) {
this.eyeX = eyeX;
}
public float getEyeY() {
return eyeY;
}
public void setEyeY(float eyeY) {
this.eyeY = eyeY;
}
public float getEyeZ() {
return eyeZ;
}
public void setEyeZ(float eyeZ) {
this.eyeZ = eyeZ;
}
}
MyCube.java
package com.example.openglsample;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
public class MyCube {
private final FloatBuffer mVertexBuffer;
public MyCube() {
float vertices[] = {
// 前
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// 後
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// 左
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
// 右
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
// 上
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// 底
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f
};
// OpenGL は CPU ごとのネイティブエンディアンでデータを指定する必要がある
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
mVertexBuffer = vbb.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
}
public void draw(GL10 gl) {
//gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f); // 赤で描画
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
// Front
gl.glNormal3f(0, 0, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
// Back
gl.glNormal3f(0, 0, -1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
// Left
gl.glNormal3f(-1.0f, 0, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
// Right
gl.glNormal3f(1.0f, 0, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
// Top
gl.glNormal3f(0, 1.0f, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
// Right
gl.glNormal3f(0, -1.0f, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
}
}
LongClickRepeatAdapter.java
AndroidのViewに、長押ししたらクリック処理をリピートする処理を付加するアダプタ をそのまま利用。
package net.shisashi.android.widget;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
public class LongClickRepeatAdapter {
/**
* 連続してボタンを押す間隔のデフォルト値 (ms)
*/
private static final int REPEAT_INTERVAL = 100;
/**
* Viewに長押し時のリピート処理を付加する。 リピート間隔は100ms。
*
* @param view
* 付加対象のView
*/
public static void bless(View view) {
bless(REPEAT_INTERVAL, view);
}
/**
* リピート間隔を指定して、Viewに長押しリピート処理を付加する
*
* @param repeatInterval
* 連続してボタンを押す間隔(ms)
* @param view
* 付加対象のView
*/
public static void bless(final int repeatInterval, final View view) {
final Handler handler = new Handler();
final BooleanWrapper isContinue = new BooleanWrapper(false);
final Runnable repeatRunnable = new Runnable() {
@Override
public void run() {
// 連打フラグをみて処理を続けるか判断する
if (!isContinue.value) {
return;
}
// クリック処理を実行する
view.performClick();
// 連打間隔を過ぎた後に、再び自分を呼び出す
handler.postDelayed(this, repeatInterval);
}
};
view.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
isContinue.value = true;
// 長押しをきっかけに連打を開始する
handler.post(repeatRunnable);
return true;
}
});
// タッチイベントを乗っ取る
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// キーから指が離されたら連打をオフにする
if (event.getAction() == MotionEvent.ACTION_UP) {
isContinue.value = false;
}
return false;
}
});
}
private static class BooleanWrapper {
public boolean value;
public BooleanWrapper(boolean value) {
this.value = value;
}
}
}
Ref. [ヅ] はじめての OpenGL ES 1.0 for Android. 立方体を表示するサンプル (2013-08-16)
tags: android opengl
Posted by NI-Lab. (@nilab)