|
|
|
@ -34,6 +34,7 @@ package com.jme3.system.android; |
|
|
|
|
|
|
|
|
|
import android.app.Activity; |
|
|
|
|
import android.content.Context; |
|
|
|
|
import android.opengl.GLES20; |
|
|
|
|
import android.opengl.GLSurfaceView; |
|
|
|
|
import android.view.SurfaceHolder; |
|
|
|
|
|
|
|
|
@ -52,7 +53,11 @@ import com.jme3.system.SystemListener; |
|
|
|
|
import com.jme3.system.Timer; |
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean; |
|
|
|
|
import java.util.logging.Logger; |
|
|
|
|
|
|
|
|
|
import javax.microedition.khronos.egl.EGL10; |
|
|
|
|
import javax.microedition.khronos.egl.EGLConfig; |
|
|
|
|
import javax.microedition.khronos.egl.EGLContext; |
|
|
|
|
import javax.microedition.khronos.egl.EGLDisplay; |
|
|
|
|
import javax.microedition.khronos.opengles.GL10; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -84,7 +89,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
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 |
|
|
|
|
*/ |
|
|
|
|
protected int clientOpenGLESVersion = 1; |
|
|
|
|
|
|
|
|
|
public OGLESContext() { } |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@ -104,7 +114,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* <code>createView</code> |
|
|
|
|
* @param AndroidInput The Android input which must be bound to an activity |
|
|
|
|
* @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) |
|
|
|
@ -114,30 +124,190 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* <code>createView</code> |
|
|
|
|
* @param AndroidInput The Android input which must be bound to an activity |
|
|
|
|
* @param view The Android input which will be used as the GLSurfaceView for this context |
|
|
|
|
* @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS |
|
|
|
|
* @return GLSurfaceView The newly created view |
|
|
|
|
*/ |
|
|
|
|
public GLSurfaceView createView(AndroidInput view, int debugflags) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
EGL10 egl = (EGL10) EGLContext.getEGL(); |
|
|
|
|
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); |
|
|
|
|
|
|
|
|
|
int[] version = new int[2]; |
|
|
|
|
if (egl.eglInitialize(display, version) == true) |
|
|
|
|
{ |
|
|
|
|
logger.info("Display EGL Version: " + version[0] + "." + version[1]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//Querying number of configurations
|
|
|
|
|
int[] num_conf = new int[1]; |
|
|
|
|
egl.eglGetConfigs(display, null, 0, num_conf); //if configuration array is null it still returns the number of configurations
|
|
|
|
|
int configurations = num_conf[0]; |
|
|
|
|
|
|
|
|
|
//Querying actual configurations
|
|
|
|
|
EGLConfig[] conf = new EGLConfig[configurations]; |
|
|
|
|
egl.eglGetConfigs(display, conf, configurations, num_conf); |
|
|
|
|
|
|
|
|
|
EGLConfig bestConfig = null; |
|
|
|
|
int[] value = new int[1]; |
|
|
|
|
int EGL_OPENGL_ES2_BIT = 4; |
|
|
|
|
|
|
|
|
|
// Loop over all configs to get the best
|
|
|
|
|
for(int i = 0; i < configurations; i++) |
|
|
|
|
{ |
|
|
|
|
//logger.info("Supported EGL Configuration #" + i );
|
|
|
|
|
|
|
|
|
|
if (conf[i] != null) |
|
|
|
|
{ |
|
|
|
|
//logger.info(String.format("conf[%d] = %s", i, conf[i].toString() ) );
|
|
|
|
|
//logEGLConfig(conf[i], display, egl);
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf[i], EGL10.EGL_RENDERABLE_TYPE, value); |
|
|
|
|
if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) |
|
|
|
|
{ |
|
|
|
|
clientOpenGLESVersion = 2; // OpenGL ES 2.0 detected
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bestConfig = better(bestConfig, conf[i], egl, display); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (clientOpenGLESVersion < 2) |
|
|
|
|
{ |
|
|
|
|
logger.severe("OpenGL ES 2.0 is not supported on this device"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
logger.info("JME3 using best EGL configuration available here: "); |
|
|
|
|
logEGLConfig(bestConfig, display, egl); |
|
|
|
|
|
|
|
|
|
// Finished querying the configs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start to set up the view
|
|
|
|
|
this.view = view; |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
* Requesting client version from GLSurfaceView which is extended by |
|
|
|
|
* AndroidInput. |
|
|
|
|
* This is required to get OpenGL ES 2.0 |
|
|
|
|
*/ |
|
|
|
|
view.setEGLContextClientVersion(2); |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
* Requesting client version from GLSurfaceView which is extended by |
|
|
|
|
* AndroidInput. |
|
|
|
|
*/ |
|
|
|
|
view.setEGLContextClientVersion(clientOpenGLESVersion); |
|
|
|
|
|
|
|
|
|
//RGB565, Depth16
|
|
|
|
|
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0); |
|
|
|
|
//view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
|
|
|
|
|
|
|
|
|
|
// Choose best config
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_RED_SIZE, value); |
|
|
|
|
int redSize = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_GREEN_SIZE, value); |
|
|
|
|
int greenSize = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_BLUE_SIZE, value); |
|
|
|
|
int blueSize = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_ALPHA_SIZE, value); |
|
|
|
|
int alphaSize = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_DEPTH_SIZE, value); |
|
|
|
|
int depthSize = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, bestConfig, EGL10.EGL_STENCIL_SIZE, value); |
|
|
|
|
int stencilSize = value[0]; |
|
|
|
|
|
|
|
|
|
view.setEGLConfigChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize); |
|
|
|
|
|
|
|
|
|
view.setFocusableInTouchMode(true); |
|
|
|
|
view.setFocusable(true); |
|
|
|
|
view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); |
|
|
|
|
view.setDebugFlags(debugflags); |
|
|
|
|
view.setRenderer(this); |
|
|
|
|
// view.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);
|
|
|
|
|
// | GLSurfaceView.DEBUG_LOG_GL_CALLS);
|
|
|
|
|
view.setRenderer(this); |
|
|
|
|
return view; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the best of the two EGLConfig passed according to depth and colours |
|
|
|
|
* @param a The first candidate |
|
|
|
|
* @param b The second candidate |
|
|
|
|
* @return The chosen candidate |
|
|
|
|
*/ |
|
|
|
|
private EGLConfig better(EGLConfig a, EGLConfig b, EGL10 egl, EGLDisplay display) |
|
|
|
|
{ |
|
|
|
|
if(a == null) return b; |
|
|
|
|
|
|
|
|
|
EGLConfig result = null; |
|
|
|
|
|
|
|
|
|
int[] value = new int[1]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, a, EGL10.EGL_DEPTH_SIZE, value); |
|
|
|
|
int depthA = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, b, EGL10.EGL_DEPTH_SIZE, value); |
|
|
|
|
int depthB = value[0]; |
|
|
|
|
|
|
|
|
|
if(depthA > depthB) |
|
|
|
|
result = a; |
|
|
|
|
else if(depthA < depthB) |
|
|
|
|
result = b; |
|
|
|
|
else //if depthA == depthB
|
|
|
|
|
{ |
|
|
|
|
egl.eglGetConfigAttrib(display, a, EGL10.EGL_RED_SIZE, value); |
|
|
|
|
int redA = value[0]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, b, EGL10.EGL_RED_SIZE, value); |
|
|
|
|
int redB = value[0]; |
|
|
|
|
|
|
|
|
|
if(redA > redB) |
|
|
|
|
result = a; |
|
|
|
|
else if(redA < redB) |
|
|
|
|
result = b; |
|
|
|
|
else //if redA == redB
|
|
|
|
|
{ |
|
|
|
|
// Don't care
|
|
|
|
|
result = a; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* log output with egl config details |
|
|
|
|
* @param conf |
|
|
|
|
* @param display |
|
|
|
|
* @param egl |
|
|
|
|
*/ |
|
|
|
|
private void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) |
|
|
|
|
{ |
|
|
|
|
int[] value = new int[1]; |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_RED_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_BLUE_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_GREEN_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value); |
|
|
|
|
logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); |
|
|
|
|
logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0] ) ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void initInThread() |
|
|
|
@ -152,7 +322,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
{ |
|
|
|
|
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { |
|
|
|
|
public void uncaughtException(Thread thread, Throwable thrown) { |
|
|
|
|
((AndroidHarness)ctx).handleError("Uncaught exception thrown in "+thread.toString(), thrown); |
|
|
|
|
((AndroidHarness)ctx).handleError("Exception thrown in " + thread.toString(), thrown); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
@ -160,11 +330,16 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
{ |
|
|
|
|
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { |
|
|
|
|
public void uncaughtException(Thread thread, Throwable thrown) { |
|
|
|
|
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown); |
|
|
|
|
listener.handleError("Exception thrown in " + thread.toString(), thrown); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (clientOpenGLESVersion < 2) |
|
|
|
|
{ |
|
|
|
|
throw new UnsupportedOperationException("OpenGL ES 2.0 is not supported on this device"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
timer = new AndroidTimer(); |
|
|
|
|
|
|
|
|
|
renderer = new OGLESShaderRenderer(); |
|
|
|
@ -278,6 +453,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
@Override |
|
|
|
|
public void onSurfaceCreated(GL10 gl, EGLConfig cfg) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
if (created.get() && renderer != null) |
|
|
|
|
{ |
|
|
|
|
renderer.resetGLObjects(); |
|
|
|
@ -394,5 +570,9 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public int getClientOpenGLESVersion() |
|
|
|
|
{ |
|
|
|
|
return clientOpenGLESVersion; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|