/**
* Copyright (C) 2013 Gundog Studios LLC.
*
* 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/>.
*/
package com.godsandtowers.graphics.menu.layouts;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLES11;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.view.MotionEvent;
import com.godsandtowers.graphics.ModelFetcher;
import com.godsandtowers.messaging.ApplicationMessageProcessor;
import com.gundogstudios.gl.Actions;
import com.gundogstudios.gl.CombinedModel;
import com.gundogstudios.modules.AndroidGLUtils;
import com.gundogstudios.modules.Modules;
public class AlmanacModelView extends GLSurfaceView implements Renderer {
private static final String TAG = "ModelView";
private float xRot = -90f;
private float zRot = -90f;
private float xTrans = 0f;
private float yTrans = -1f;
private float zTrans = -3f;
private int currentAction = Actions.IDLE;
private CombinedModel model;
private String name;
private ModelFetcher modelFetcher;
private long lastRender = 0;
private Executor executor;
private boolean loading = false;
public AlmanacModelView(Context context) {
super(context);
executor = Executors.newSingleThreadExecutor();
// Turn on error-checking and logging
// this.setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
// this.setDebugFlags(DEBUG_LOG_GL_CALLS);
this.setRenderer(this);
this.requestFocus();
this.setFocusableInTouchMode(true);
super.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
@Override
public void onSurfaceCreated(GL10 UNUSED, EGLConfig config) {
Modules.GLUTIL = new AndroidGLUtils(UNUSED);
GLES11.glClearColor(0f, 0f, 0f, 1.0f);
GLES11.glShadeModel(GLES11.GL_SMOOTH);
GLES11.glClearDepthf(1.0f);
GLES11.glEnable(GLES11.GL_DEPTH_TEST);
GLES11.glDepthFunc(GLES11.GL_LESS);
GLES11.glHint(GLES11.GL_PERSPECTIVE_CORRECTION_HINT, GLES11.GL_NEAREST);
GLES11.glEnable(GLES11.GL_BLEND);
GLES11.glBlendFunc(GLES11.GL_SRC_ALPHA, GLES11.GL_ONE_MINUS_SRC_ALPHA);
GLES11.glEnable(GLES11.GL_ALPHA_TEST);
GLES11.glAlphaFunc(GLES11.GL_GREATER, .01f);
long start = System.currentTimeMillis();
modelFetcher = new ModelFetcher();
Modules.LOG.info(TAG, "Took: " + (System.currentTimeMillis() - start) + " ms to load");
}
public void release() {
super.queueEvent(new Runnable() {
@Override
public void run() {
if (modelFetcher != null) {
try {
Modules.LOG.info(TAG, "Releasing all VBOs and Textures");
modelFetcher.release();
Modules.LOG.info(TAG, "Released all VBOs and Textures");
} catch (Exception e) {
Modules.LOG.error(TAG, "Error releasing VBOs and Textures: " + e);
}
modelFetcher = null;
}
}
});
}
public void setModel(String name) {
this.name = name;
this.model = null;
}
@Override
public void onDrawFrame(GL10 UNUSED) {
if (modelFetcher == null) {
Modules.LOG.info("AlmanacModelView", "modelFetcher was released, unable to render");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
return;
}
long currentTime = System.currentTimeMillis();
int timePassed = (int) (currentTime - lastRender);
if (timePassed < 0 || timePassed > 10000) {
timePassed = 20;
}
lastRender = currentTime;
modelFetcher.loadVBOandTextures();
GLES11.glClear(GLES11.GL_COLOR_BUFFER_BIT | GLES11.GL_DEPTH_BUFFER_BIT);
if (name == null) {
return;
} else if (loading) {
return;
} else if (model == null) {
loading = true;
executor.execute(new Runnable() {
@Override
public void run() {
try {
model = modelFetcher.getModel(name);
loading = false;
} catch (OutOfMemoryError e) {
Modules.MESSENGER.submit(ApplicationMessageProcessor.ID,
ApplicationMessageProcessor.LOWER_GRAPHICS);
}
}
});
return;
}
GLES11.glMatrixMode(GLES11.GL_MODELVIEW);
GLES11.glLoadIdentity();
GLES11.glPushMatrix();
GLES11.glTranslatef(xTrans, yTrans, zTrans);
GLES11.glRotatef(xRot, 1, 0, 0);
GLES11.glRotatef(zRot, 0, 0, 1);
GLES11.glPushMatrix();
if (model != null)
model.draw(timePassed);
GLES11.glPopMatrix();
zRot = (zRot + 25f * (((float) timePassed) / 1000f)) % 360;
Modules.PROFILER.updateRenderFPS();
Thread.yield();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES11.glViewport(0, 0, width, height);
GLES11.glMatrixMode(GLES11.GL_PROJECTION);
GLES11.glLoadIdentity();
float ratio = (float) width / (float) height;
GLU.gluPerspective(gl, 45.0f, ratio, 0.01f, 10.0f);
GLES11.glMatrixMode(GLES11.GL_MODELVIEW);
GLES11.glLoadIdentity();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (model != null && event.getAction() == MotionEvent.ACTION_DOWN) {
switch (currentAction) {
case Actions.IDLE:
model.setAction(Actions.MOVE);
currentAction = Actions.MOVE;
Modules.LOG.info(TAG, "Displaying Model: " + name + " MOVE");
break;
case Actions.MOVE:
model.setAction(Actions.ATTACK);
currentAction = Actions.ATTACK;
Modules.LOG.info(TAG, "Displaying Model: " + name + " ATTACK");
break;
case Actions.ATTACK:
model.setAction(Actions.DEATH);
currentAction = Actions.DEATH;
Modules.LOG.info(TAG, "Displaying Model: " + name + " DEATH");
break;
case Actions.DEATH:
model.setAction(Actions.IDLE);
currentAction = Actions.IDLE;
Modules.LOG.info(TAG, "Displaying Model: " + name + " IDLE");
break;
default:
Modules.LOG.error(TAG, "Unknown Action");
}
}
return true;
}
}