Android
* Enable checking of errors per frame (if checkErrors is disabled) * Formatting and javadoc fixes in AndroidHarness * AndroidHarness.reportError() rewritten to for clarity * OGLESContext will report OpenGL2 failure directly to app through handleError instead of continuing execution * OGLESContext will register uncaught exception handler only for current thread * Formatting and javadoc fixes in OGLESContext git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9142 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
65c27304be
commit
8652b1f759
@ -26,97 +26,108 @@ import com.jme3.system.android.AndroidConfigChooser.ConfigType;
|
||||
import com.jme3.system.android.JmeAndroidSystem;
|
||||
import com.jme3.system.android.OGLESContext;
|
||||
import com.jme3.util.JmeFormatter;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* <code>AndroidHarness</code> wraps a jme application object and runs it on Android
|
||||
* <code>AndroidHarness</code> wraps a jme application object and runs it on
|
||||
* Android
|
||||
*
|
||||
* @author Kirill
|
||||
* @author larynx
|
||||
*/
|
||||
public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener {
|
||||
|
||||
protected final static Logger logger = Logger.getLogger(AndroidHarness.class.getName());
|
||||
|
||||
/**
|
||||
* The application class to start
|
||||
*/
|
||||
protected String appClass = "jme3test.android.Test";
|
||||
|
||||
/**
|
||||
* The jme3 application object
|
||||
*/
|
||||
protected Application app = null;
|
||||
|
||||
/**
|
||||
* ConfigType.FASTEST is RGB565, GLSurfaceView default
|
||||
* ConfigType.BEST is RGBA8888 or better if supported by the hardware
|
||||
* ConfigType.FASTEST is RGB565, GLSurfaceView default ConfigType.BEST is
|
||||
* RGBA8888 or better if supported by the hardware
|
||||
*/
|
||||
protected ConfigType eglConfigType = ConfigType.FASTEST;
|
||||
|
||||
/**
|
||||
* If true all valid and not valid egl configs are logged
|
||||
*/
|
||||
protected boolean eglConfigVerboseLogging = false;
|
||||
|
||||
/**
|
||||
* If true MouseEvents are generated from TouchEvents
|
||||
*/
|
||||
protected boolean mouseEventsEnabled = true;
|
||||
|
||||
/**
|
||||
* Flip X axis
|
||||
*/
|
||||
protected boolean mouseEventsInvertX = true;
|
||||
|
||||
/**
|
||||
* Flip Y axis
|
||||
*/
|
||||
protected boolean mouseEventsInvertY = true;
|
||||
|
||||
/**
|
||||
* Title of the exit dialog, default is "Do you want to exit?"
|
||||
*/
|
||||
protected String exitDialogTitle = "Do you want to exit?";
|
||||
/**
|
||||
* Message of the exit dialog, default is "Use your home key to bring this app into the background or exit to terminate it."
|
||||
*/
|
||||
protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it.";
|
||||
|
||||
/**
|
||||
* Set the screen window size
|
||||
* if screenFullSize is true, then the notification bar and title bar are
|
||||
* removed and the screen covers the entire display
|
||||
* if screenFullSize is false, then the notification bar remains visible
|
||||
* if screenShowTitle is true while screenFullScreen is false, then the
|
||||
* title bar is also displayed under the notification bar
|
||||
*/
|
||||
* Message of the exit dialog, default is "Use your home key to bring this
|
||||
* app into the background or exit to terminate it."
|
||||
*/
|
||||
protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it.";
|
||||
/**
|
||||
* Set the screen window mode.
|
||||
* If screenFullSize is true, then the notification bar and title bar are
|
||||
* removed and the screen covers the entire display.
|
||||
* If screenFullSize is false, then the notification bar remains visible if
|
||||
* screenShowTitle is true while screenFullScreen is false,
|
||||
* then the title bar is also displayed under the notification bar.
|
||||
*/
|
||||
protected boolean screenFullScreen = true;
|
||||
|
||||
/**
|
||||
* if screenShowTitle is true while screenFullScreen is false, then the
|
||||
* title bar is also displayed under the notification bar
|
||||
* title bar is also displayed under the notification bar
|
||||
*/
|
||||
protected boolean screenShowTitle = true;
|
||||
|
||||
/**
|
||||
* Splash Screen picture Resource ID. If a Splash Screen is desired, set
|
||||
* splashPicID to the value of the Resource ID (i.e. R.drawable.picname).
|
||||
* If splashPicID = 0, then no splash screen will be displayed.
|
||||
* Splash Screen picture Resource ID. If a Splash Screen is desired, set
|
||||
* splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If
|
||||
* splashPicID = 0, then no splash screen will be displayed.
|
||||
*/
|
||||
protected int splashPicID = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Set the screen orientation, default is SENSOR
|
||||
* ActivityInfo.SCREEN_ORIENTATION_* constants
|
||||
* package android.content.pm.ActivityInfo
|
||||
*
|
||||
* SCREEN_ORIENTATION_UNSPECIFIED
|
||||
* SCREEN_ORIENTATION_LANDSCAPE
|
||||
* SCREEN_ORIENTATION_PORTRAIT
|
||||
* SCREEN_ORIENTATION_USER
|
||||
* SCREEN_ORIENTATION_BEHIND
|
||||
* SCREEN_ORIENTATION_SENSOR (default)
|
||||
* SCREEN_ORIENTATION_NOSENSOR
|
||||
* ActivityInfo.SCREEN_ORIENTATION_* constants package
|
||||
* android.content.pm.ActivityInfo
|
||||
*
|
||||
* SCREEN_ORIENTATION_UNSPECIFIED SCREEN_ORIENTATION_LANDSCAPE
|
||||
* SCREEN_ORIENTATION_PORTRAIT SCREEN_ORIENTATION_USER
|
||||
* SCREEN_ORIENTATION_BEHIND SCREEN_ORIENTATION_SENSOR (default)
|
||||
* SCREEN_ORIENTATION_NOSENSOR
|
||||
*/
|
||||
protected int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
||||
protected OGLESContext ctx;
|
||||
protected GLSurfaceView view = null;
|
||||
protected boolean isGLThreadPaused = true;
|
||||
private ImageView splashImageView = null;
|
||||
private ImageView splashImageView = null;
|
||||
private FrameLayout frameLayout = null;
|
||||
final private String ESCAPE_EVENT = "TouchEscape";
|
||||
|
||||
@ -193,7 +204,6 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
||||
logger.log(Level.INFO, "Settings: Width {0} Height {1}", new Object[]{s.getWidth(), s.getHeight()});
|
||||
|
||||
layoutDisplay();
|
||||
|
||||
} catch (Exception ex) {
|
||||
handleError("Class " + appClass + " init failed", ex);
|
||||
setContentView(new TextView(this));
|
||||
@ -246,8 +256,8 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
||||
if (app != null) {
|
||||
app.stop(!isGLThreadPaused);
|
||||
}
|
||||
super.onDestroy();
|
||||
logger.info("onDestroy");
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public Application getJmeApplication() {
|
||||
@ -255,43 +265,44 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an error has occured. This is typically
|
||||
* invoked when an uncaught exception is thrown in the render thread.
|
||||
* @param errorMsg The error message, if any, or null.
|
||||
* @param t Throwable object, or null.
|
||||
* Called when an error has occurred.
|
||||
* By default, will show an error message to the user
|
||||
* and print the exception/error to the log.
|
||||
*/
|
||||
public void handleError(final String errorMsg, final Throwable t) {
|
||||
String sTrace = "";
|
||||
if (t != null && t.getStackTrace() != null) {
|
||||
for (StackTraceElement ste : t.getStackTrace()) {
|
||||
sTrace += "\tat " + ste.getClassName() + "." + ste.getMethodName() + "(";
|
||||
if (ste.isNativeMethod()){
|
||||
sTrace += "Native";
|
||||
}else{
|
||||
sTrace += ste.getLineNumber();
|
||||
}
|
||||
sTrace += ")\n";
|
||||
}
|
||||
String stackTrace = "";
|
||||
String title = "Error";
|
||||
|
||||
if (t != null){
|
||||
// Convert exception to string
|
||||
StringWriter sw = new StringWriter(100);
|
||||
t.printStackTrace(new PrintWriter(sw));
|
||||
stackTrace = sw.toString();
|
||||
title = t.toString();
|
||||
}
|
||||
|
||||
final String finalTitle = title;
|
||||
final String finalMsg = (errorMsg != null ? errorMsg : "Uncaught Exception")
|
||||
+ "\n" + stackTrace;
|
||||
|
||||
final String stackTrace = sTrace;
|
||||
logger.log(Level.SEVERE, finalMsg);
|
||||
|
||||
logger.log(Level.SEVERE, t != null ? t.toString() : "OpenGL Exception");
|
||||
logger.log(Level.SEVERE, "{0}{1}", new Object[]{errorMsg != null ? errorMsg + ": " : "", stackTrace});
|
||||
|
||||
this.runOnUiThread(new Runnable() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon)
|
||||
.setTitle(t != null ? (t.getMessage() != null ? (t.getMessage() + ": " + t.getClass().getName()) : t.getClass().getName()) : "OpenGL Exception").setPositiveButton("Kill", AndroidHarness.this).setMessage((errorMsg != null ? errorMsg + ": " : "") + stackTrace).create();
|
||||
.setTitle(finalTitle)
|
||||
.setPositiveButton("Kill", AndroidHarness.this)
|
||||
.setMessage(finalMsg).create();
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the android alert dialog, terminate the activity and OpenGL rendering
|
||||
* Called by the android alert dialog, terminate the activity and OpenGL
|
||||
* rendering
|
||||
*
|
||||
* @param dialog
|
||||
* @param whichButton
|
||||
*/
|
||||
@ -312,53 +323,51 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
||||
if (name.equals(ESCAPE_EVENT)) {
|
||||
switch (evt.getType()) {
|
||||
case KEY_UP:
|
||||
this.runOnUiThread(new Runnable() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon)
|
||||
.setTitle(exitDialogTitle).setPositiveButton("Yes", AndroidHarness.this).setNegativeButton("No", AndroidHarness.this).setMessage(exitDialogMessage).create();
|
||||
.setTitle(exitDialogTitle)
|
||||
.setPositiveButton("Yes", AndroidHarness.this)
|
||||
.setNegativeButton("No", AndroidHarness.this)
|
||||
.setMessage(exitDialogMessage).create();
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void layoutDisplay() {
|
||||
logger.log(Level.INFO, "Splash Screen Picture Resource ID: {0}", splashPicID);
|
||||
if (splashPicID != 0) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||
LayoutParams.FILL_PARENT,
|
||||
LayoutParams.FILL_PARENT,
|
||||
Gravity.CENTER
|
||||
);
|
||||
logger.log(Level.INFO, "Splash Screen Picture Resource ID: {0}", splashPicID);
|
||||
if (splashPicID != 0) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
|
||||
LayoutParams.FILL_PARENT,
|
||||
LayoutParams.FILL_PARENT,
|
||||
Gravity.CENTER);
|
||||
|
||||
frameLayout = new FrameLayout(this);
|
||||
frameLayout = new FrameLayout(this);
|
||||
splashImageView = new ImageView(this);
|
||||
|
||||
splashImageView = new ImageView(this);
|
||||
|
||||
Drawable drawable = this.getResources().getDrawable(splashPicID);
|
||||
if (drawable instanceof NinePatchDrawable) {
|
||||
splashImageView.setBackgroundDrawable(drawable);
|
||||
} else {
|
||||
splashImageView.setImageResource(splashPicID);
|
||||
}
|
||||
|
||||
frameLayout.addView(view);
|
||||
frameLayout.addView(splashImageView, lp);
|
||||
|
||||
setContentView(frameLayout);
|
||||
logger.log(Level.INFO, "Splash Screen Created");
|
||||
Drawable drawable = this.getResources().getDrawable(splashPicID);
|
||||
if (drawable instanceof NinePatchDrawable) {
|
||||
splashImageView.setBackgroundDrawable(drawable);
|
||||
} else {
|
||||
logger.log(Level.INFO, "Splash Screen Skipped.");
|
||||
setContentView(view);
|
||||
splashImageView.setImageResource(splashPicID);
|
||||
}
|
||||
|
||||
frameLayout.addView(view);
|
||||
frameLayout.addView(splashImageView, lp);
|
||||
|
||||
setContentView(frameLayout);
|
||||
logger.log(Level.INFO, "Splash Screen Created");
|
||||
} else {
|
||||
logger.log(Level.INFO, "Splash Screen Skipped.");
|
||||
setContentView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSplashScreen() {
|
||||
@ -367,6 +376,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
||||
if (frameLayout != null) {
|
||||
if (splashImageView != null) {
|
||||
this.runOnUiThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
splashImageView.setVisibility(View.INVISIBLE);
|
||||
|
||||
@ -739,8 +739,14 @@ public class OGLESShaderRenderer implements Renderer {
|
||||
}
|
||||
|
||||
public void onFrame() {
|
||||
if (!checkErrors){
|
||||
int error = GLES20.glGetError();
|
||||
if (error != GLES20.GL_NO_ERROR){
|
||||
throw new RendererException("OpenGL Error " + error + ". Enable error checking for more info.");
|
||||
}
|
||||
}
|
||||
objManager.deleteUnused(this);
|
||||
// statistics.clearFrame();
|
||||
// statistics.clearFrame();
|
||||
}
|
||||
|
||||
public void setWorldMatrix(Matrix4f worldMatrix) {
|
||||
|
||||
@ -29,7 +29,6 @@
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.system.android;
|
||||
|
||||
import android.app.Activity;
|
||||
@ -60,268 +59,239 @@ import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
|
||||
public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
||||
{
|
||||
public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
|
||||
|
||||
protected final AtomicBoolean created = new AtomicBoolean(false);
|
||||
protected final AtomicBoolean renderable = new AtomicBoolean(false);
|
||||
protected final AtomicBoolean needClose = new AtomicBoolean(false);
|
||||
|
||||
protected final AppSettings settings = new AppSettings(true);
|
||||
|
||||
/* >= OpenGL ES 2.0 (Android 2.2+) */
|
||||
protected OGLESShaderRenderer renderer;
|
||||
|
||||
/*
|
||||
* >= OpenGL ES 2.0 (Android 2.2+)
|
||||
*/
|
||||
protected OGLESShaderRenderer renderer;
|
||||
protected Timer timer;
|
||||
protected SystemListener listener;
|
||||
|
||||
|
||||
protected boolean wasActive = false;
|
||||
protected boolean autoFlush = true;
|
||||
|
||||
protected AndroidInput view;
|
||||
private boolean firstDrawFrame = true;
|
||||
|
||||
private long milliStart;
|
||||
private long milliDelta;
|
||||
protected int frameRate = 33;
|
||||
|
||||
//protected int minFrameDuration = 1000 / frameRate; // Set a max FPS of 33
|
||||
protected int minFrameDuration = 0; // No FPS cap
|
||||
|
||||
/**
|
||||
* EGL_RENDERABLE_TYPE: EGL_OPENGL_ES_BIT = OpenGL ES 1.0 | EGL_OPENGL_ES2_BIT = OpenGL ES 2.0
|
||||
* EGL_RENDERABLE_TYPE: EGL_OPENGL_ES_BIT = OpenGL ES 1.0 |
|
||||
* EGL_OPENGL_ES2_BIT = OpenGL ES 2.0
|
||||
*/
|
||||
protected int clientOpenGLESVersion = 1;
|
||||
|
||||
protected boolean verboseLogging = false;
|
||||
|
||||
final private String ESCAPE_EVENT = "TouchEscape";
|
||||
|
||||
public OGLESContext() { }
|
||||
|
||||
public OGLESContext() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType()
|
||||
{
|
||||
public Type getType() {
|
||||
return Type.Display;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>createView</code>
|
||||
* @param activity The Android activity which is parent for the GLSurfaceView
|
||||
* <code>createView</code>
|
||||
*
|
||||
* @param activity The Android activity which is parent for the
|
||||
* GLSurfaceView
|
||||
* @return GLSurfaceView The newly created view
|
||||
*/
|
||||
public GLSurfaceView createView(Activity activity)
|
||||
{
|
||||
return createView(new AndroidInput(activity));
|
||||
public GLSurfaceView createView(Activity activity) {
|
||||
return createView(new AndroidInput(activity));
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>createView</code>
|
||||
* @param view The Android input which will be used as the GLSurfaceView for this context
|
||||
* <code>createView</code>
|
||||
*
|
||||
* @param view The Android input which will be used as the GLSurfaceView for
|
||||
* this context
|
||||
* @return GLSurfaceView The newly created view
|
||||
*/
|
||||
public GLSurfaceView createView(AndroidInput view)
|
||||
{
|
||||
public GLSurfaceView createView(AndroidInput view) {
|
||||
return createView(view, ConfigType.FASTEST, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <code>createView</code> initializes the GLSurfaceView
|
||||
* @param view The Android input which will be used as the GLSurfaceView for this context
|
||||
* @param configType ConfigType.FASTEST (Default) | ConfigType.LEGACY | ConfigType.BEST
|
||||
*
|
||||
* @param view The Android input which will be used as the GLSurfaceView for
|
||||
* this context
|
||||
* @param configType ConfigType.FASTEST (Default) | ConfigType.LEGACY |
|
||||
* ConfigType.BEST
|
||||
* @param eglConfigVerboseLogging if true show all found configs
|
||||
* @return GLSurfaceView The newly created view
|
||||
*/
|
||||
public GLSurfaceView createView(AndroidInput view, ConfigType configType, boolean eglConfigVerboseLogging)
|
||||
{
|
||||
*/
|
||||
public GLSurfaceView createView(AndroidInput view, ConfigType configType, boolean eglConfigVerboseLogging) {
|
||||
// Start to set up the view
|
||||
this.view = view;
|
||||
this.view = view;
|
||||
verboseLogging = eglConfigVerboseLogging;
|
||||
|
||||
if (configType == ConfigType.LEGACY)
|
||||
{
|
||||
if (configType == ConfigType.LEGACY) {
|
||||
// Hardcoded egl setup
|
||||
clientOpenGLESVersion = 2;
|
||||
clientOpenGLESVersion = 2;
|
||||
view.setEGLContextClientVersion(2);
|
||||
//RGB565, Depth16
|
||||
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
|
||||
logger.info("ConfigType.LEGACY using RGB565");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
|
||||
int[] version = new int[2];
|
||||
if (egl.eglInitialize(display, version) == true)
|
||||
{
|
||||
if (egl.eglInitialize(display, version) == true) {
|
||||
logger.info("Display EGL Version: " + version[0] + "." + version[1]);
|
||||
}
|
||||
|
||||
// Create a config chooser
|
||||
AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging);
|
||||
// Init chooser
|
||||
if (!configChooser.findConfig(egl, display))
|
||||
{
|
||||
logger.severe("Unable to find suitable EGL config");
|
||||
}
|
||||
|
||||
clientOpenGLESVersion = configChooser.getClientOpenGLESVersion();
|
||||
if (clientOpenGLESVersion < 2)
|
||||
{
|
||||
logger.severe("OpenGL ES 2.0 is not supported on this device");
|
||||
}
|
||||
|
||||
if (display != null)
|
||||
egl.eglTerminate(display);
|
||||
|
||||
|
||||
/*
|
||||
* Requesting client version from GLSurfaceView which is extended by
|
||||
* AndroidInput.
|
||||
*/
|
||||
view.setEGLContextClientVersion(clientOpenGLESVersion);
|
||||
view.setEGLConfigChooser(configChooser);
|
||||
view.getHolder().setFormat(configChooser.getPixelFormat());
|
||||
try {
|
||||
// Create a config chooser
|
||||
AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging);
|
||||
// Init chooser
|
||||
if (!configChooser.findConfig(egl, display)) {
|
||||
listener.handleError("Unable to find suitable EGL config", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
clientOpenGLESVersion = configChooser.getClientOpenGLESVersion();
|
||||
if (clientOpenGLESVersion < 2) {
|
||||
listener.handleError("OpenGL ES 2.0 is not supported on this device", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Requesting client version from GLSurfaceView which is extended by
|
||||
// AndroidInput.
|
||||
view.setEGLContextClientVersion(clientOpenGLESVersion);
|
||||
view.setEGLConfigChooser(configChooser);
|
||||
view.getHolder().setFormat(configChooser.getPixelFormat());
|
||||
} finally {
|
||||
if (display != null) {
|
||||
egl.eglTerminate(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
view.setFocusableInTouchMode(true);
|
||||
view.setFocusable(true);
|
||||
view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||
view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
||||
view.setRenderer(this);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
// renderer:initialize
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig cfg)
|
||||
{
|
||||
|
||||
if (created.get() && renderer != null)
|
||||
{
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig cfg) {
|
||||
|
||||
if (created.get() && renderer != null) {
|
||||
renderer.resetGLObjects();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!created.get())
|
||||
{
|
||||
logger.info("GL Surface created, doing JME3 init");
|
||||
} else {
|
||||
if (!created.get()) {
|
||||
logger.info("GL Surface created, doing JME3 init");
|
||||
initInThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
logger.warning("GL Surface already created");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void initInThread()
|
||||
{
|
||||
created.set(true);
|
||||
|
||||
|
||||
protected void initInThread() {
|
||||
created.set(true);
|
||||
|
||||
logger.info("OGLESContext create");
|
||||
logger.info("Running on thread: "+Thread.currentThread().getName());
|
||||
logger.info("Running on thread: " + Thread.currentThread().getName());
|
||||
|
||||
final Context ctx = this.view.getContext();
|
||||
|
||||
|
||||
// Setup unhandled Exception Handler
|
||||
if (ctx instanceof AndroidHarness)
|
||||
{
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
if (ctx instanceof AndroidHarness) {
|
||||
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread thread, Throwable thrown) {
|
||||
((AndroidHarness)ctx).handleError("Exception thrown in " + thread.toString(), thrown);
|
||||
((AndroidHarness) ctx).handleError("Exception thrown in " + thread.toString(), thrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
} else {
|
||||
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread thread, Throwable thrown) {
|
||||
listener.handleError("Exception thrown in " + thread.toString(), thrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (clientOpenGLESVersion < 2)
|
||||
{
|
||||
|
||||
if (clientOpenGLESVersion < 2) {
|
||||
throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device");
|
||||
}
|
||||
|
||||
timer = new AndroidTimer();
|
||||
|
||||
timer = new AndroidTimer();
|
||||
renderer = new OGLESShaderRenderer();
|
||||
|
||||
|
||||
renderer.setUseVA(true);
|
||||
renderer.setVerboseLogging(verboseLogging);
|
||||
|
||||
|
||||
renderer.initialize();
|
||||
listener.initialize();
|
||||
|
||||
|
||||
// Setup exit hook
|
||||
if (ctx instanceof AndroidHarness)
|
||||
{
|
||||
Application app = ((AndroidHarness)ctx).getJmeApplication();
|
||||
if (app.getInputManager() != null)
|
||||
{
|
||||
if (ctx instanceof AndroidHarness) {
|
||||
Application app = ((AndroidHarness) ctx).getJmeApplication();
|
||||
if (app.getInputManager() != null) {
|
||||
app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK));
|
||||
app.getInputManager().addListener((AndroidHarness)ctx, new String[]{ESCAPE_EVENT});
|
||||
app.getInputManager().addListener((AndroidHarness) ctx, new String[]{ESCAPE_EVENT});
|
||||
}
|
||||
}
|
||||
|
||||
needClose.set(false);
|
||||
|
||||
needClose.set(false);
|
||||
renderable.set(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-initialize in the OpenGL thread.
|
||||
*/
|
||||
protected void deinitInThread()
|
||||
{
|
||||
if (renderable.get())
|
||||
{
|
||||
protected void deinitInThread() {
|
||||
if (renderable.get()) {
|
||||
created.set(false);
|
||||
if (renderer != null)
|
||||
if (renderer != null) {
|
||||
renderer.cleanup();
|
||||
|
||||
}
|
||||
|
||||
listener.destroy();
|
||||
|
||||
|
||||
listener = null;
|
||||
renderer = null;
|
||||
timer = null;
|
||||
|
||||
renderer = null;
|
||||
timer = null;
|
||||
|
||||
// do android specific cleaning here
|
||||
logger.info("Display destroyed.");
|
||||
|
||||
|
||||
renderable.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
|
||||
{
|
||||
|
||||
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) {
|
||||
logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]");
|
||||
logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]");
|
||||
renderer.setUseVA(settings.getBoolean("USE_VA"));
|
||||
renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
|
||||
}
|
||||
|
||||
protected void applySettings(AppSettings settings)
|
||||
{
|
||||
|
||||
protected void applySettings(AppSettings settings) {
|
||||
setSettings(settings);
|
||||
if (renderer != null)
|
||||
applySettingsToRenderer(renderer, this.settings);
|
||||
if (renderer != null) {
|
||||
applySettingsToRenderer(renderer, this.settings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSettings(AppSettings settings)
|
||||
{
|
||||
public void setSettings(AppSettings settings) {
|
||||
this.settings.copyFrom(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemListener(SystemListener listener){
|
||||
public void setSystemListener(SystemListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@ -344,7 +314,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
||||
public KeyInput getKeyInput() {
|
||||
return new DummyKeyInput();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JoyInput getJoyInput() {
|
||||
return null;
|
||||
@ -354,35 +324,29 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
||||
public TouchInput getTouchInput() {
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Timer getTimer()
|
||||
{
|
||||
public Timer getTimer() {
|
||||
return timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title)
|
||||
{
|
||||
public void setTitle(String title) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isCreated()
|
||||
{
|
||||
public boolean isCreated() {
|
||||
return created.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoFlushFrames(boolean enabled)
|
||||
{
|
||||
public void setAutoFlushFrames(boolean enabled) {
|
||||
this.autoFlush = enabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SystemListener:reshape
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height)
|
||||
{
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
logger.info("GL Surface changed, width: " + width + " height: " + height);
|
||||
settings.setResolution(width, height);
|
||||
listener.reshape(width, height);
|
||||
@ -390,101 +354,84 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
||||
|
||||
// SystemListener:update
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl)
|
||||
{
|
||||
|
||||
|
||||
if (needClose.get())
|
||||
{
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
if (needClose.get()) {
|
||||
deinitInThread();
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderable.get())
|
||||
{
|
||||
|
||||
if (!created.get())
|
||||
if (renderable.get()) {
|
||||
if (!created.get()) {
|
||||
throw new IllegalStateException("onDrawFrame without create");
|
||||
}
|
||||
|
||||
milliStart = System.currentTimeMillis();
|
||||
|
||||
long milliStart = System.currentTimeMillis();
|
||||
|
||||
|
||||
listener.update();
|
||||
|
||||
// call to AndroidHarness to remove the splash screen, if present.
|
||||
// call after listener.update() to make sure no gap between
|
||||
// splash screen going away and app display being shown.
|
||||
if (firstDrawFrame) {
|
||||
|
||||
// call to AndroidHarness to remove the splash screen, if present.
|
||||
// call after listener.update() to make sure no gap between
|
||||
// splash screen going away and app display being shown.
|
||||
if (firstDrawFrame) {
|
||||
final Context ctx = this.view.getContext();
|
||||
if (ctx instanceof AndroidHarness) {
|
||||
((AndroidHarness)ctx).removeSplashScreen();
|
||||
((AndroidHarness) ctx).removeSplashScreen();
|
||||
}
|
||||
firstDrawFrame = false;
|
||||
}
|
||||
|
||||
if (autoFlush)
|
||||
{
|
||||
firstDrawFrame = false;
|
||||
}
|
||||
|
||||
if (autoFlush) {
|
||||
renderer.onFrame();
|
||||
}
|
||||
|
||||
milliDelta = System.currentTimeMillis() - milliStart;
|
||||
|
||||
|
||||
long milliDelta = System.currentTimeMillis() - milliStart;
|
||||
|
||||
// Enforce a FPS cap
|
||||
if (milliDelta < minFrameDuration)
|
||||
{
|
||||
if (milliDelta < minFrameDuration) {
|
||||
//logger.log(Level.INFO, "Time per frame {0}", milliDelta);
|
||||
try {
|
||||
Thread.sleep(minFrameDuration - milliDelta);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRenderable()
|
||||
{
|
||||
public boolean isRenderable() {
|
||||
return renderable.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void create(boolean waitFor)
|
||||
{
|
||||
if (waitFor)
|
||||
public void create(boolean waitFor) {
|
||||
if (waitFor) {
|
||||
waitFor(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void create()
|
||||
{
|
||||
|
||||
public void create() {
|
||||
create(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void restart()
|
||||
{
|
||||
|
||||
public void restart() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy(boolean waitFor)
|
||||
{
|
||||
public void destroy(boolean waitFor) {
|
||||
needClose.set(true);
|
||||
if (waitFor)
|
||||
if (waitFor) {
|
||||
waitFor(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
|
||||
public void destroy() {
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
protected void waitFor(boolean createdVal)
|
||||
{
|
||||
while (renderable.get() != createdVal){
|
||||
|
||||
protected void waitFor(boolean createdVal) {
|
||||
while (renderable.get() != createdVal) {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ex) {
|
||||
@ -492,9 +439,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
||||
}
|
||||
}
|
||||
|
||||
public int getClientOpenGLESVersion()
|
||||
{
|
||||
public int getClientOpenGLESVersion() {
|
||||
return clientOpenGLESVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user