/*
* Copyright (C) 2011 QSDN,Inc.
* Copyright (C) 2011 Atsushi Konno
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.co.qsdn.android.iwashi3d;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.Matrix;
import android.os.Bundle;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import jp.co.qsdn.android.iwashi3d.model.Background;
import jp.co.qsdn.android.iwashi3d.model.Ground;
import jp.co.qsdn.android.iwashi3d.model.Iwashi;
import jp.co.qsdn.android.iwashi3d.model.IwashiData;
import jp.co.qsdn.android.iwashi3d.model.Wave;
import jp.co.qsdn.android.iwashi3d.setting.Prefs;
import jp.co.qsdn.android.iwashi3d.util.CoordUtil;
public class GLRenderer {
private static final boolean _debug = false;
private static final String TAG = GLRenderer.class.getName();
public static final int MAX_IWASHI_COUNT = 200;
private final Background background = new Background();
private final Ground ground = new Ground();
private final Wave wave = new Wave();
private Iwashi[] iwashi = null;
private int iwashi_count = 1;
private boolean enableIwashiBoids = true;
private float iwashi_speed = 0.03f;
private float[] camera = {0f,0f,0f};
private float[] org_camera = {0f,0f,0f};
private boolean cameraMode = false;
private float cameraDistance = 10f;
private float zFar = 50.0f;
private float zNear = 1.0f;
private float perspectiveAngle = 45.0f;
public long prevTick = 0L;
private BaitManager baitManager = new BaitManager();
private float baseAngle = 0f;
private float[] mScratch32 = new float[32];
private float[] mScratch4f = new float[4];
public static GLRenderer glRenderer = null;
float[] schoolCenter = {0f,0f,0f};
private CoordUtil coordUtil = new CoordUtil();
private GLRenderer(Context context) {
iwashi_count = Prefs.getInstance(context).getIwashiCount();
iwashi_speed = ((float)Prefs.getInstance(context).getIwashiSpeed() / 50f) * Iwashi.DEFAULT_SPEED;
enableIwashiBoids = Prefs.getInstance(context).getIwashiBoids();
cameraDistance = (float)Prefs.getInstance(context).getCameraDistance();
cameraMode = Prefs.getInstance(context).getCameraMode();
IwashiData.init();
iwashi = new Iwashi[MAX_IWASHI_COUNT];
for (int ii=0; ii<MAX_IWASHI_COUNT; ii++) {
iwashi[ii] = new Iwashi(ii);
}
for (int ii=0; ii<MAX_IWASHI_COUNT; ii++) {
iwashi[ii].setEnableBoids(enableIwashiBoids);
iwashi[ii].setSpecies(iwashi);
iwashi[ii].setSpeed(iwashi_speed);
iwashi[ii].setIwashiCount(iwashi_count);
iwashi[ii].setBaitManager(baitManager);
}
}
public static GLRenderer getInstance(Context context) {
if (_debug) Log.d(TAG, "start getInstance()");
if (glRenderer == null) {
if (_debug) Log.d(TAG, "new GLRenderer");
glRenderer = new GLRenderer(context);
}
if (_debug) Log.d(TAG, "end getInstance()");
return glRenderer;
}
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig, Context context) {
if (_debug) Log.d(TAG, "start onSurfaceCreated()");
gl10.glEnable(GL10.GL_DEPTH_TEST);
gl10.glDepthFunc(GL10.GL_LEQUAL);
gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl10.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl10.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl10.glEnable(GL10.GL_CULL_FACE);
gl10.glEnable(GL10.GL_DITHER);
gl10.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl10.glEnable(GL10.GL_TEXTURE_2D);
Background.loadTexture(gl10, context, R.drawable.background);
Ground.loadTexture(gl10, context, R.drawable.sand);
Wave.loadTexture(gl10, context, R.drawable.wave);
Iwashi.loadTexture(gl10, context, R.drawable.iwashi);
org_camera[0] = camera[0] = 0f;
org_camera[1] = camera[1] = 0f;
org_camera[2] = camera[2] = Aquarium.max_z + zNear;
setupFog(gl10);
gl10.glEnable(GL10.GL_NORMALIZE) ;
gl10.glEnable(GL10.GL_RESCALE_NORMAL);
gl10.glShadeModel(GL10.GL_SMOOTH);
gl10.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl10.glClearDepthf(1.0f);
if (_debug) Log.d(TAG, "end onSurfaceCreated()");
}
public void onSurfaceDestroyed(GL10 gl10) {
Background.deleteTexture(gl10);
Ground.deleteTexture(gl10);
Wave.deleteTexture(gl10);
Iwashi.deleteTexture(gl10);
}
/**
*/
public void setupLighting1(GL10 gl10) {
gl10.glEnable(GL10.GL_LIGHTING);
gl10.glEnable(GL10.GL_LIGHT0);
gl10.glEnable(GL10.GL_LIGHT1);
}
public void setupLighting2(GL10 gl10) {
{
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f) {
mScratch4f[0] = 1.0f;
mScratch4f[1] = 1.0f;
mScratch4f[2] = 1.0f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f) {
mScratch4f[0] = 1.0f;
mScratch4f[1] = 1.0f;
mScratch4f[2] = 1.0f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f){
mScratch4f[0] = 1.0f;
mScratch4f[1] = 1.0f;
mScratch4f[2] = 1.0f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f){
mScratch4f[0] = 0.0f;
mScratch4f[1] = 10.0f;
mScratch4f[2] = 0.0f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f) {
mScratch4f[0] = 0.0f;
mScratch4f[1] = -1.0f;
mScratch4f[2] = 0.0f;
mScratch4f[3] = 0.0f;
gl10.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION, mScratch4f, 0);
}
gl10.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 90);
gl10.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_EXPONENT, 0);
/*=======================================================================*/
/*=======================================================================*/
gl10.glLightf(GL10.GL_LIGHT0, GL10.GL_CONSTANT_ATTENUATION, 0.2f);
gl10.glLightf(GL10.GL_LIGHT0, GL10.GL_LINEAR_ATTENUATION, 0.002f);
gl10.glLightf(GL10.GL_LIGHT0, GL10.GL_QUADRATIC_ATTENUATION, 0.0f);
}
{
/*=======================================================================*/
/*=======================================================================*/
synchronized(mScratch4f) {
mScratch4f[0] = 0.019f * 0.6f;
mScratch4f[1] = 0.9606f * 0.6f;
mScratch4f[2] = 1.0f * 0.6f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, mScratch4f, 0);
/*=======================================================================*/
/*=======================================================================*/
gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, mScratch4f, 0);
/*=======================================================================*/
/*=======================================================================*/
mScratch4f[0] *= 0.5f;
mScratch4f[1] *= 0.5f;
mScratch4f[2] *= 0.5f;
gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_SPECULAR, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized (mScratch4f) {
mScratch4f[0] = 0.0f;
mScratch4f[1] = -10.0f;
mScratch4f[2] = 0.0f;
mScratch4f[3] = 1.0f;
gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, mScratch4f, 0);
}
/*=======================================================================*/
/*=======================================================================*/
synchronized (mScratch4f) {
mScratch4f[0] = 0.0f;
mScratch4f[1] = 1.0f;
mScratch4f[2] = 0.0f;
mScratch4f[3] = 0.0f;
gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_SPOT_DIRECTION, mScratch4f, 0);
}
gl10.glLightf(GL10.GL_LIGHT1, GL10.GL_SPOT_CUTOFF, 90);
gl10.glLightf(GL10.GL_LIGHT1, GL10.GL_SPOT_EXPONENT, 0);
/*=======================================================================*/
/*=======================================================================*/
gl10.glLightf(GL10.GL_LIGHT1, GL10.GL_CONSTANT_ATTENUATION, 0.2f);
gl10.glLightf(GL10.GL_LIGHT1, GL10.GL_LINEAR_ATTENUATION, 0.002f);
gl10.glLightf(GL10.GL_LIGHT1, GL10.GL_QUADRATIC_ATTENUATION, 0.0f);
}
}
/**
*/
public void setupFog(GL10 gl10) {
gl10.glEnable(GL10.GL_FOG);
gl10.glFogf(GL10.GL_FOG_MODE, GL10.GL_LINEAR);
gl10.glFogf(GL10.GL_FOG_START, 7f + (cameraDistance - 5f));
gl10.glFogf(GL10.GL_FOG_END, 26.0f + (cameraDistance - 5f));
synchronized (mScratch4f) {
mScratch4f[0] = 0.011f;
mScratch4f[1] = 0.4218f;
mScratch4f[2] = 0.6445f;
mScratch4f[3] = 1.0f;
gl10.glFogfv(GL10.GL_FOG_COLOR, mScratch4f, 0);
}
}
public void setupFog2(GL10 gl10) {
gl10.glEnable(GL10.GL_FOG);
gl10.glFogf(GL10.GL_FOG_MODE, GL10.GL_LINEAR);
gl10.glFogf(GL10.GL_FOG_START, cameraDistance + 1f);
gl10.glFogf(GL10.GL_FOG_END, cameraDistance + 10f);
synchronized (mScratch4f) {
mScratch4f[0] = 1.0f;
mScratch4f[1] = 1.0f;
mScratch4f[2] = 1.0f;
mScratch4f[3] = 1.0f;
gl10.glFogfv(GL10.GL_FOG_COLOR, mScratch4f, 0);
}
}
public void updateSetting(Context context) {
if (iwashi == null) {
return;
}
int _iwashi_count = Prefs.getInstance(context).getIwashiCount();
float _iwashi_speed = ((float)Prefs.getInstance(context).getIwashiSpeed() / 50f) * Iwashi.DEFAULT_SPEED;
boolean _iwashi_boids = Prefs.getInstance(context).getIwashiBoids();
boolean _camera_mode = Prefs.getInstance(context).getCameraMode();
float _camera_distance = (float)Prefs.getInstance(context).getCameraDistance();
if (_debug) Log.d(TAG, "Now Speed:[" + _iwashi_speed + "]");
if (_debug) Log.d(TAG,"Now BOIDS:[" + _iwashi_boids + "]");
if (_iwashi_count != iwashi_count) {
synchronized (this) {
iwashi_count = _iwashi_count;
for (int ii=0; ii<MAX_IWASHI_COUNT; ii++) {
if (iwashi[ii] != null) {
iwashi[ii].setIwashiCount(iwashi_count);
}
}
}
}
if (_iwashi_speed != iwashi_speed) {
synchronized (this) {
for (int ii=0; ii<MAX_IWASHI_COUNT; ii++) {
if (iwashi[ii] != null) {
iwashi[ii].setSpeed(_iwashi_speed);
}
}
iwashi_speed = _iwashi_speed;
}
}
if (_iwashi_boids != enableIwashiBoids) {
synchronized (this) {
for (int ii=0; ii<MAX_IWASHI_COUNT; ii++) {
if (iwashi[ii] != null) {
iwashi[ii].setEnableBoids(_iwashi_boids);
}
}
enableIwashiBoids = _iwashi_boids;
}
}
if (_camera_mode != cameraMode) {
cameraMode = _camera_mode;
}
if (_camera_distance != cameraDistance) {
cameraDistance = _camera_distance;
}
Prefs.getInstance(context).setUpdateSetting(false);
}
private int screen_width =0;
private int screen_height = 0;
public void onSurfaceChanged(GL10 gl10, int width, int height) {
if (_debug) Log.d(TAG, "start onSurfaceChanged()");
gl10.glViewport(0,0,width,height);
gl10.glMatrixMode(GL10.GL_PROJECTION);
gl10.glLoadIdentity();
float ratio = (float) width / height;
CoordUtil.perspective(gl10,perspectiveAngle, ratio, zNear, zFar);
this.screen_width = width;
this.screen_height = height;
if (_debug) Log.d(TAG, "end onSurfaceChanged()");
}
public void onOffsetsChanged(GL10 gl10, float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixelOffset, int yPixelOffset) {
if (_debug) Log.d(TAG, "start onOffsetsChanged()");
if (_debug) {
Log.d(TAG,
"xOffset:[" + xOffset + "]:"
+ "yOffset:[" + yOffset + "]:"
+ "xOffsetStep:[" + xOffsetStep + "]:"
+ "yOffsetStep:[" + yOffsetStep + "]:"
+ "xPixelOffset:[" + xPixelOffset + "]:"
+ "yPixelOffset:[" + yPixelOffset + "]:");
}
synchronized(this) {
float xx = (float)xPixelOffset / 480f;
baseAngle = xx * 180f + 90f;
}
if (_debug) {
Log.d(TAG,
"end onOffsetsChanged():"
+ "new baseAngle:[" + baseAngle + "]"
);
}
}
public void onCommand(GL10 gl10, String action, int x, int y, int z, Bundle extras, boolean resultRequested) {
if (_debug) Log.d(TAG, "start onCommand");
if (cameraMode) {
/* 鰯視点モードのため、何もしない */
return ;
}
/*=======================================================================*/
/*=======================================================================*/
/*=======================================================================*/
/*=======================================================================*/
float[] modelview = new float[16];
((GL11)gl10).glGetFloatv(GL10.GL_MODELVIEW, modelview, 0);
float[] projection = new float[16];
((GL11)gl10).glGetFloatv(GL10.GL_PROJECTION, projection, 0);
float[] viewport = new float[16];
((GL11)gl10).glGetFloatv(GL11.GL_VIEWPORT, viewport, 0);
float[] view = new float[16];
System.arraycopy(CoordUtil.viewMatrix, 0, view, 0, 16);
float nx = 0f;
float ny = 0f;
float nz = 0f;
{
float[] ret = new float[4];
float dist_from_camera = 0.0f;
dist_from_camera = cameraDistance;
if (dist_from_camera < 0.0f) {
dist_from_camera = 0.0f;
}
else {
dist_from_camera = (dist_from_camera / (zFar - zNear));
if (dist_from_camera > 1.0f) {
dist_from_camera = 1.0f;
}
}
GLU.gluUnProject((float)x, (float)y, dist_from_camera, view, 0, projection, 0, new int[]{0, 0, screen_width, screen_height}, 0, ret, 0);
if (_debug) Log.d(TAG,"result (UnProject):[" + ret[0] + "][" + ret[1] + "][" + ret[2] + "][" + ret[3] + "]");
{
float bb = (cameraDistance == 0.0f) ? 0.1f : cameraDistance;
nx = ret[0] * bb / ret[3];
ny = ret[1] * -bb / ret[3];
nz = ret[2] / ret[3];
}
if (_debug) {
Log.d(TAG,"result"
+ "dist:[" + dist_from_camera + "] "
+ "x:[" + nx + "] "
+ "y:[" + ny + "] "
+ "z:[" + nz + "] "
);
}
}
synchronized (mScratch4f) {
coordUtil.setMatrixRotateY(-baseAngle);
coordUtil.affine(nx,ny, nz, mScratch4f);
nx = mScratch4f[0];
ny = mScratch4f[1];
nz = mScratch4f[2];
}
{
float tmp = 0f;
if (nx > Aquarium.max_x.floatValue() - 0.2f) {
tmp = (Aquarium.max_x.floatValue() - 0.2f) / nx;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
if (ny > Aquarium.max_y.floatValue() - 0.2f) {
tmp = (Aquarium.max_y.floatValue() - 0.2f) / ny;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
if (nz > Aquarium.max_z.floatValue() - 0.2f) {
tmp = (Aquarium.max_z.floatValue() - 0.2f) / nz;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
if (nx < Aquarium.min_x.floatValue() + 0.2f) {
tmp = (Aquarium.min_x.floatValue() + 0.2f) / nx;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
if (ny < Aquarium.min_y.floatValue() + 0.2f) {
tmp = (Aquarium.min_y.floatValue() + 0.2f) / ny;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
if (nz < Aquarium.min_z.floatValue() + 0.2f) {
tmp = (Aquarium.min_z.floatValue() + 0.2f) / nz;
nx *= tmp;
ny *= tmp;
nz *= tmp;
}
}
baitManager.addBait(nx,ny,nz);
if (_debug) Log.d(TAG, "end onCommand");
}
public synchronized void onDrawFrame(GL10 gl10) {
setupFog(gl10);
gl10.glMatrixMode(GL10.GL_MODELVIEW);
gl10.glPushMatrix();
gl10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl10.glMatrixMode(GL10.GL_MODELVIEW);
gl10.glLoadIdentity();
if (cameraMode) {
float c_x = iwashi[0].getX();
float c_y = iwashi[0].getY();
float c_z = iwashi[0].getZ();
CoordUtil.lookAt(gl10,
c_x - iwashi[0].getDirectionX(),
c_y - iwashi[0].getDirectionY(),
c_z - iwashi[0].getDirectionZ(),
c_x + iwashi[0].getDirectionX(),
c_y + iwashi[0].getDirectionY(),
c_z + iwashi[0].getDirectionZ(),
0,1,0);
}
else {
CoordUtil.lookAt(gl10,
camera[0],camera[1],camera[2]+cameraDistance,
camera[0],camera[1],-10f,
0,1,0);
}
gl10.glPushMatrix();
gl10.glRotatef(baseAngle, 0.0f, 1.0f, 0.0f);
/*=======================================================================*/
/*=======================================================================*/
setupLighting2(gl10);
setupLighting1(gl10);
gl10.glDisable(GL10.GL_DEPTH_TEST);
synchronized (this) {
for (int ii=0; ii<iwashi_count; ii++) {
iwashi[ii].calc();
}
}
background.draw(gl10);
ground.draw(gl10, iwashi);
wave.calc();
wave.draw(gl10);
gl10.glEnable(GL10.GL_DEPTH_TEST);
synchronized (this) {
for (int ii=0; ii<iwashi_count; ii++) {
if (cameraMode == false || (cameraMode == true && ii != 0)) {
iwashi[ii].draw(gl10);
}
}
}
gl10.glDisable(GL10.GL_DEPTH_TEST);
gl10.glPopMatrix();
gl10.glPopMatrix();
}
public void onDestroy() {
}
}