この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Android OpenGL フレームワーク "Rajawali" と戯れるシリーズ
第 09 回目は、Android 標準のユーザーインターフェイス ( 以後 UI ) と OpenGL レンダラとの共存について解説します。
レイアウトの使用
Rajawali の基本アクティビティクラスである RajawaliFragmentActivity 上には、Android 標準の UI を配置することが可能です。厳密には RajawaliFragmentActivity が保持する FrameLayout(mLayout) に任意のレイアウトを addView() するという実装により実現できます。処理のすべてを Java のコードで記述することも可能ですが、LayoutInflater クラスを使用することで、レイアウト XML を使用したレイアウトも可能です。
RajawaliFragmentActivity サブクラス内における実装例
LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.main, mLayout, false); //main.xml
mLayout.addView(layout);
出力結果
以下のサンプルは、RajawaliFragmentActivity の FrameLayout に LinearLayout を追加して、LinearLayout 内にて定義済みのボタンとシークバーで 3D オブジェクトのパラメータを調整するものです。シークバーを操作するとき、値が常に更新されていることが確認できます。
ムービー
キャプチャ
ソース
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button" />
<SeekBar
android:id="@+id/xSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="359" />
<SeekBar
android:id="@+id/ySeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="359" />
<SeekBar
android:id="@+id/zSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="359" />
<TextView
android:id="@+id/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/textView"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
MainActivity.java
package jp.classmethod.sample;
import javax.microedition.khronos.opengles.GL10;
import rajawali.RajawaliFragmentActivity;
import rajawali.animation.mesh.VertexAnimationObject3D;
import rajawali.lights.DirectionalLight;
import rajawali.parser.MD2Parser;
import rajawali.renderer.RajawaliRenderer;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
* MainActivity
*/
public class MainActivity extends RajawaliFragmentActivity {
/** @private */
private Lesson07_01Renderer mRenderer;
/** @private */
private TextView textView;
/** @private */
private Button button;
/** @private */
private SeekBar xSeekBar;
/** @private */
private SeekBar ySeekBar;
/** @private */
private SeekBar zSeekBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRenderer = new Lesson07_01Renderer(this);
mRenderer.setSurfaceView(mSurfaceView);
setRenderer(mRenderer);
LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.main, mLayout, false);
mLayout.addView(layout);
textView = (TextView)layout.findViewById(R.id.textView);
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("Swing negi!!");
mRenderer.swingNegi();
}
};
button = (Button)layout.findViewById(R.id.button);
button.setOnClickListener(clickListener);
OnSeekBarChangeListener seekBarChangeListener = new OnSeekBarChangeListener() {
@Override
/** トラッキング開始 */
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
/** トラッキング中 */
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
setRotationBySeekBar();
}
@Override
/** トラッキング終了 */
public void onStopTrackingTouch(SeekBar seekBar) {
setRotationBySeekBar();
}
};
xSeekBar = (SeekBar)layout.findViewById(R.id.xSeekBar);
xSeekBar.setOnSeekBarChangeListener(seekBarChangeListener);
ySeekBar = (SeekBar)layout.findViewById(R.id.ySeekBar);
ySeekBar.setOnSeekBarChangeListener(seekBarChangeListener);
zSeekBar = (SeekBar)layout.findViewById(R.id.zSeekBar);
zSeekBar.setOnSeekBarChangeListener(seekBarChangeListener);
}
/** シークバーの値をレンダラに反映 */
private void setRotationBySeekBar() {
float rotX = (float)xSeekBar.getProgress();
float rotY = (float)ySeekBar.getProgress();
float rotZ = (float)zSeekBar.getProgress();
mRenderer.setRotation(rotX, rotY, rotZ);
textView.setText("rotX : " + Float.toString(rotX) + "\n" +
"rotY : " + Float.toString(rotY) + "\n" +
"rotZ : " + Float.toString(rotZ) );
}
/** RajawaliRenderer のサブクラス */
private class Lesson07_01Renderer extends RajawaliRenderer {
/** 3D オブジェクト */
protected VertexAnimationObject3D mObj;
/** コンストラクタ */
public Lesson07_01Renderer(Context context) {
super(context);
setFrameRate(60);
setBackgroundColor(0x999999);
}
@Override
/** シーン初期化 */
protected void initScene() {
Resources r = mContext.getResources();
DirectionalLight light = new DirectionalLight();
light.setPower(1.5f);
light.setColor(0xff9900);
light.setPosition(0f, 3f, -1f);
MD2Parser parser = new MD2Parser(r, mTextureManager, R.raw.r_miku_md2);
parser.parse();
mObj = (VertexAnimationObject3D)parser.getParsedAnimationObject();
mObj.addLight(light);
mObj.setY(-.75f);
mObj.setScale(.5f);
addChild(mObj);
}
@Override
/** フレーム描画 */
public void onDrawFrame(GL10 glUnused) {
super.onDrawFrame(glUnused);
}
/** 葱振り */
public void swingNegi() {
mObj.play("walk");
}
/** 3D オブジェクトの回転 */
public void setRotation(float rotX, float rotY, float rotZ) {
mObj.setRotation(rotX, rotY, rotZ);
}
}
}