@ -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" ) ;
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 ) ;
}
}
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 ( ) ) ;
}
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 ;
}
}