/*
* PROJECT: NyARToolkit for Android SDK
* --------------------------------------------------------------------------------
* This work is based on the original ARToolKit developed by
* Hirokazu Kato
* Mark Billinghurst
* HITLab, University of Washington, Seattle
* http://www.hitl.washington.edu/artoolkit/
*
* NyARToolkit for Android SDK
* Copyright (C)2010 NyARToolkit for Android team
* Copyright (C)2010 R.Iizuka(nyatla)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* For further information please contact.
* http://sourceforge.jp/projects/nyartoolkit-and/
*
* This work is based on the NyARToolKit developed by
* R.Iizuka (nyatla)
* http://nyatla.jp/nyatoolkit/
*
* contributor(s)
* noritsuna
*/
package jp.androidgroup.nyartoolkit;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.io.Serializable;
import jp.nyatla.kGLModel.KGLException;
import jp.nyatla.kGLModel.KGLModelData;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
/**
* Rendering 3DModels.
*
* @author noritsuna
*
*/
public class ModelRenderer implements GLSurfaceView.Renderer
{
//回転
public float xrot = 0;
public float yrot = 0;
public float zrot = 0;
public float xpos = 0;
public float ypos = 0;
public float zpos = 0;
//3DCGの表示スケール初期化
public float scale = 2f;
public int STATE = STATE_DYNAMIC;
public static final int STATE_DYNAMIC = 0;
public static final int STATE_FINALIZED = 1;
private static final int PATT_MAX = 2;
private static final int MARKER_MAX = 8;
private int found_markers;
private int [] ar_code_index = new int[MARKER_MAX];
private float [][] resultf = new float[MARKER_MAX][16];
private float [] cameraRHf = new float[16];
private boolean useRHfp = false;
private boolean drawp = false;
// metaseq
private KGLModelData[] model = new KGLModelData[PATT_MAX];
private AssetManager am;
private String[] modelName = new String[PATT_MAX];
private float[] modelScale = new float[PATT_MAX];
public int mWidth;
public int mHeight;
Timer timer = new Timer();
public void setScale(float f) {
this.scale += f;
if(this.scale < 0.0001f)
this.scale = 0.0001f;
}
public void setXrot(float dY) {
this.xrot += dY;
}
public void setYrot(float dX) {
this.yrot += dX;
}
public void setXpos(float f) {
this.xpos += f;
}
public void setYpos(float f) {
this.ypos += f;
}
public ModelRenderer(AssetManager am, String[] modelName, float[] modelScale) {
this.am = am;
cameraReset();
for (int i = 0; i < PATT_MAX; i++) {
this.modelName[i] = modelName[i];
this.modelScale[i] = modelScale[i];
//System.out.println("マーカーname " + modelName[i]);
}
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
/*
* By default, OpenGL enables features that improve quality
* but reduce performance. One might want to tweak that
* especially on software renderer.
*/
gl.glDisable(GL10.GL_DITHER);
/*
* Some one-time OpenGL initialization can be made here
* probably based on features of this particular context
*/
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(0,0,0,0);
initModel(gl);
cameraChangep = true;
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
mWidth = width;
mHeight = height;
gl.glViewport(0, 0, width, height);
/*
* Set our projection matrix. This doesn't have to be done
* each time we draw, but usually a new projection needs to
* be set when the viewport is resized.
*/
ratio = (float) width / height;
cameraChangep = true;
}
public void onDrawFrame(GL10 gl) {
//3DCG表示時間の計測開始
timer.start();
/*
* Usually, the first thing one might want to do is to clear
* the screen. The most efficient way of doing this is to use
* glClear().
*/
//gl.glClearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
if (drawp) {
// camera
if (useRHfp) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadMatrixf(cameraRHf, 0);
} else if (cameraChangep) {
cameraSetup(gl);
}
// FIXME: Draw detected marker only.
for (int i = 0; i < MARKER_MAX; i++) {
gl.glMatrixMode(GL10.GL_MODELVIEW);
if (useRHfp) {
gl.glLoadMatrixf(resultf[i], 0);
// 位置調整
gl.glTranslatef(this.xpos, this.ypos, this.zpos);
// OpenGL座標系→ARToolkit座標系
gl.glRotatef(this.xrot, 1.0f,0.0f,0.0f);
gl.glRotatef(this.yrot, 0.0f,1.0f,0.0f);
gl.glRotatef(this.zrot, 0.0f,0.0f,1.0f);
gl.glScalef(this.scale, this.scale, this.scale);
} else {
gl.glLoadIdentity();
}
Log.d("ModelRenderer", "onDrawFrame: " + i + ",model: "+ ar_code_index[i]);
if (lightp)
lightSetup(gl);
model[ar_code_index[i]].enables(gl, 1.0f);
model[ar_code_index[i]].draw(gl);
model[ar_code_index[i]].disables(gl);
//System.out.println("マーカーname " + ar_code_index[i]);
if (lightp)
lightCleanup(gl);
}
} else {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadMatrixf(cameraRHf, 0);
gl.glEnable(GL10.GL_DEPTH_TEST);
}
makeFramerate();
//3DCG表示時間の計測終了
timer.end();
}
private Handler mainHandler;
public void setMainHandler(Handler handler) {
mainHandler = handler;
}
public void initModel(GL10 gl) {
if (mainHandler != null) {
mainHandler.sendMessage
(mainHandler.obtainMessage
(NyARToolkitAndroidActivity.SHOW_LOADING));
}
Log.d("ModelRenderer", "initModel");
for (int i = 0; i < PATT_MAX; i++) {
if (model[i] != null) {
model[i].Clear(gl);
model[i] = null;
//System.out.println("マーカーname " + model[i]);
}
if (modelName[i] != null) {
try {
model[i] = KGLModelData.createGLModel
(gl, null, am, modelName[i], modelScale[i]);
} catch (KGLException e) {
Log.e("ModelRenderer", "KGLModelData error", e);
}
}
}
if (mainHandler != null) {
mainHandler.sendMessage
(mainHandler.obtainMessage
(NyARToolkitAndroidActivity.HIDE_LOADING));
}
}
public void objectClear() {
drawp = false;
}
public float [] zoomV = new float[4];
public float [] upOriV = { 0.0f, 1.0f, 0.0f, 0.0f };
public float [] lookV = new float[4];
public float [] camRmtx = new float[16];
public float [] camV = new float[4];
public float [] upV = new float[4];
public float ratio;
// Temporary
private float [] mtx = new float[16];
private boolean cameraChangep;
private void cameraSetup(GL10 gl) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
// gl.glFrustumf(-ratio, ratio, -1, 1, 1, 1000);
GLU.gluPerspective(gl, 45, ratio, 1.0f, 10000.0f);
GLU.gluLookAt(gl,
camV[0], camV[1], camV[2],
lookV[0], lookV[1], lookV[2],
upV[0], upV[1], upV[2]);
cameraChangep = false;
}
private void cameraMake() {
Matrix.setIdentityM(mtx, 0);
Matrix.translateM(mtx, 0, lookV[0], lookV[1], lookV[2]);
Matrix.multiplyMM(mtx, 0, camRmtx, 0, mtx, 0);
Matrix.multiplyMV(camV, 0, mtx, 0, zoomV, 0);
Matrix.multiplyMV(upV, 0, camRmtx, 0, upOriV, 0);
cameraChangep = true;
}
public void cameraReset() {
zoomV[0] = zoomV[1] = camV[0] = camV[1] = 0.0f;
zoomV[2] = camV[2] = -500.0f;
lookV[0] = lookV[1] = lookV[2] = 0.0f;
upV[0] = upV[2] = 0.0f;
upV[1] = 1.0f;
Matrix.setIdentityM(camRmtx, 0);
cameraChangep = true;
}
public void cameraRotate(float rot, float x, float y, float z,
float [] sMtx) {
float [] vec = { x, y, z, 0 };
Matrix.setIdentityM(mtx, 0);
Matrix.rotateM(mtx, 0, rot, vec[0], vec[1], vec[2]);
Matrix.multiplyMM(camRmtx, 0, sMtx, 0, mtx, 0);
cameraMake();
}
public void cameraZoom(float z) {
zoomV[2] += z;
cameraMake();
}
public void cameraMove(float x, float y, float z) {
float [] vec = { x, y, z, 0 };
Matrix.multiplyMV(vec, 0, camRmtx, 0, vec, 0);
for (int i = 0; i < 3; i++) {
lookV[i] += vec[i];
}
cameraMake();
}
public void objectPointChanged(int found_markers, int [] ar_code_index, float[][] resultf,
float[] cameraRHf) {
synchronized (this) {
this.found_markers = found_markers;
for (int i = 0; i < MARKER_MAX; i++) {
this.ar_code_index[i] = ar_code_index[i];
System.arraycopy(resultf[i], 0, this.resultf[i], 0, 16);
//System.out.println("マーカーname " + ar_code_index[i]);
}
System.arraycopy(cameraRHf, 0, this.cameraRHf, 0, 16);
}
useRHfp = true;
drawp = true;
}
// Light
public boolean lightCamp = false;
public boolean lightp = true;
public boolean speLightp = false;
float[] lightPos0 = { 1000, 1000, 1000, 0 };
float[] lightPos1 = { 1000, 1000, 1000, 0 };
float[] lightPos2 = { 1000, 1000, 1000, 0 };
float[] lightDif = { 0.6f, 0.6f, 0.6f, 1 };
float[] lightSpe = { 1.0f, 1.0f, 1.0f, 1 };
float[] lightAmb = { 0.01f, 0.01f, 0.01f, 1 };
private void lightSetup(GL10 gl) {
if (lightCamp) {
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, camV, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDif, 0);
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, camV, 0);
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmb, 0);
if (speLightp) {
gl.glLightfv(GL10.GL_LIGHT2, GL10.GL_POSITION, camV, 0);
gl.glLightfv(GL10.GL_LIGHT2, GL10.GL_SPECULAR, lightSpe, 0);
}
} else {
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos0, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDif, 0);
gl.glLightfv(GL10.GL_LIGHT1,GL10.GL_POSITION, lightPos2, 0);
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmb, 0);
if (speLightp) {
gl.glLightfv(GL10.GL_LIGHT2, GL10.GL_POSITION, lightPos1, 0);
gl.glLightfv(GL10.GL_LIGHT2, GL10.GL_SPECULAR, lightSpe, 0);
}
}
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
gl.glEnable(GL10.GL_LIGHT1);
if (speLightp)
gl.glEnable(GL10.GL_LIGHT2);
}
private void lightCleanup(GL10 gl) {
gl.glDisable(GL10.GL_LIGHTING);
gl.glDisable(GL10.GL_LIGHT0);
gl.glDisable(GL10.GL_LIGHT1);
gl.glDisable(GL10.GL_LIGHT2);
}
private int mFrames = 0;
private float mFramerate;
private long mStartTime;
public float getFramerate() {
return mFramerate;
}
public float getStartTime() {
return mStartTime;
}
private void makeFramerate() {
long time = SystemClock.uptimeMillis();
synchronized (this) {
mFrames++;
if (mStartTime == 0) {
mStartTime = time;
}
if (time - mStartTime >= 1) {
mFramerate = (float)(1000 * mFrames)
/ (float)(time - mStartTime);
Log.d("ModelRenderer", "Framerate: " + mFramerate + " (" + (time - mStartTime) + "ms)");
mFrames = 0;
mStartTime = time;
}
}
}
}