OSDN Git Service

Add AndroidTGALoader
[mikumikustudio/MikuMikuStudio.git] / engine / src / android / com / jme3 / system / android / OGLESContext.java
index 26ac788..e74091e 100644 (file)
 package com.jme3.system.android;
 
 import android.app.Activity;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.EGLConfigChooser;
 import android.view.SurfaceHolder;
+
+import com.jme3.app.AndroidHarness;
+import com.jme3.app.Application;
 import com.jme3.input.JoyInput;
 import com.jme3.input.KeyInput;
 import com.jme3.input.MouseInput;
+import com.jme3.input.TouchInput;
 import com.jme3.input.android.AndroidInput;
-//import com.jme3.renderer.android.OGLESRenderer;
+import com.jme3.input.controls.TouchTrigger;
+import com.jme3.input.dummy.DummyKeyInput;
+import com.jme3.input.dummy.DummyMouseInput;
 import com.jme3.renderer.android.OGLESShaderRenderer;
 import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.SystemListener;
 import com.jme3.system.Timer;
+import com.jme3.system.android.AndroidConfigChooser.ConfigType;
+
 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;
 
 
-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 AtomicBoolean created = new AtomicBoolean(false);
-    protected AppSettings settings = new AppSettings(true);
+    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 * */
-       //protected OGLESRenderer renderer;
        /* >= OpenGL ES 2.0 (Android 2.2+) */
        protected OGLESShaderRenderer renderer;
 
     protected Timer timer;
     protected SystemListener listener;
 
-    protected AtomicBoolean needClose = new AtomicBoolean(false);
+    
     protected boolean wasActive = false;
-    protected int frameRate = 0;
     protected boolean autoFlush = true;
 
     protected AndroidInput view;
+    
+    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 
+     */
+    protected int clientOpenGLESVersion = 1;
+    
+    protected boolean verboseLogging = false;
+    
+    final private String ESCAPE_EVENT = "TouchEscape";
+    
+    public OGLESContext() { }
 
-    public OGLESContext(){
-    }
-
-    public Type getType() {
+    @Override
+    public Type getType() 
+    {
         return Type.Display;
     }
-
-    public GLSurfaceView createView(Activity activity){
-        view = new AndroidInput(activity);
-
-       /*
-        * Requesting client version from GLSurfaceView which is extended by
-        * AndroidInput.
-        * This is required to get OpenGL ES 2.0
-        */
-
-       logger.info("setEGLContextClientVersion(2)");
-       view.setEGLContextClientVersion(2);
-       logger.info("setEGLContextClientVersion(2) ... done.");
-
-        //RGB565, Depth16
-        view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
+    
+    /**
+     * <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));        
+    }
+    /**
+     * <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)
+    {
+        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 eglConfigVerboseLogging if true show all found configs
+     * @return GLSurfaceView The newly created view
+     */    
+    public GLSurfaceView createView(AndroidInput view, ConfigType configType, boolean eglConfigVerboseLogging)
+    {                    
+        // Start to set up the view
+        this.view = view;    
+        verboseLogging = eglConfigVerboseLogging;
+
+        if (configType == ConfigType.LEGACY)
+        {
+            // Hardcoded egl setup
+            clientOpenGLESVersion = 2;            
+            view.setEGLContextClientVersion(2);
+            //RGB565, Depth16
+//            view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
+            logger.info("ConfigType.LEGACY using RGB565");
+        view.setEGLConfigChooser(8, 8, 8, 8, 16, 0);    
+        view.getHolder().setFormat(PixelFormat.TRANSLUCENT);            
+        view.setZOrderOnTop(true);
+        }
+        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)
+            {
+                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());            
+        view.setEGLConfigChooser(8, 8, 8, 8, 16, 0);    
+        view.getHolder().setFormat(PixelFormat.TRANSLUCENT);           
+        view.setZOrderOnTop(true);
+        }
+        
         view.setFocusableInTouchMode(true);
         view.setFocusable(true);
-        view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
-//        view.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR);
-//                         | GLSurfaceView.DEBUG_LOG_GL_CALLS);
-               view.setRenderer(this);
-        return view;
-
-    }
+        view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);            
+        view.setRenderer(this);
 
-    protected void applySettings(AppSettings setting){
+        return view;
     }
-
-    protected void initInThread(GL10 gl){
-        logger.info("Display created.");
-        logger.fine("Running on thread: "+Thread.currentThread().getName());
-
-        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
-            public void uncaughtException(Thread thread, Throwable thrown) {
-                listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
+    
+    // renderer:initialize
+    @Override
+    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");                
+                initInThread();
             }
-        });
-
-        created.set(true);
+            else
+            {
+                logger.warning("GL Surface already created");
+            }
+        }
+    }
+    
+    protected void initInThread()
+    {
+        created.set(true);   
+        
+        logger.info("OGLESContext create");
+        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() {
+                public void uncaughtException(Thread thread, Throwable thrown) {
+                    ((AndroidHarness)ctx).handleError("Exception thrown in " + thread.toString(), thrown);
+                }
+            });
+        }
+        else
+        {
+            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+                public void uncaughtException(Thread thread, Throwable 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(gl);
-       applySettingsToRenderer(renderer, settings);
-
+        renderer = new OGLESShaderRenderer();
+    
+//        renderer.setUseVA(true);
+        renderer.setVerboseLogging(verboseLogging);
+        
         renderer.initialize();
         listener.initialize();
-
-       // OGLESShaderRenderer does not support guiView yet
-       // forcefully remove all gui nodes
-
-       if (listener instanceof com.jme3.app.SimpleApplication) {
-               ((com.jme3.app.SimpleApplication) listener).getGuiNode().detachAllChildren();
-       }
+        
+        // Setup exit hook
+        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});
+            }
+        }
+                     
+        needClose.set(false);    
+        renderable.set(true);
     }
 
     /**
      * De-initialize in the OpenGL thread.
      */
-    protected void deinitInThread(){
-        listener.destroy();
-       if (renderer != null) {
-               renderer.cleanup();
-               // do android specific cleaning here
-
-               logger.info("Display destroyed.");
-               created.set(false);
-               renderer = null;
-               timer = null;
-       }
+    protected void deinitInThread()
+    {   
+        if (renderable.get())
+        {
+            created.set(false);
+            if (renderer != null) 
+                renderer.cleanup();
+                
+            listener.destroy();
+                                       
+            listener = null;
+               renderer = null;
+               timer = null;
+               
+            // do android specific cleaning here
+            logger.info("Display destroyed.");
+            
+            renderable.set(false);
+        }
+    }
+    
+    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)
+    {
+        setSettings(settings);
+        if (renderer != null)
+            applySettingsToRenderer(renderer, this.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"));
-       }
-
-       @Override
-    public void setSettings(AppSettings settings) {
-               this.settings.copyFrom(settings);
-
-               // XXX This code should be somewhere else
-               if (renderer != null)
-                       applySettingsToRenderer(renderer, this.settings);
+    @Override
+    public void setSettings(AppSettings settings) 
+    {
+        this.settings.copyFrom(settings);
     }
 
+    @Override
     public void setSystemListener(SystemListener listener){
         this.listener = listener;
     }
 
+    @Override
     public AppSettings getSettings() {
         return settings;
     }
 
+    @Override
     public com.jme3.renderer.Renderer getRenderer() {
         return renderer;
     }
 
+    @Override
     public MouseInput getMouseInput() {
-        return view;
+        return new DummyMouseInput();
     }
 
+    @Override
     public KeyInput getKeyInput() {
-        return view;
+        return new DummyKeyInput();
     }
-
+    
+    @Override
     public JoyInput getJoyInput() {
         return null;
     }
 
-    public Timer getTimer() {
+    @Override
+    public TouchInput getTouchInput() {
+        return view;
+    }
+    
+    @Override
+    public Timer getTimer() 
+    {
         return timer;
     }
 
-    public void setTitle(String title) {
+    @Override
+    public void setTitle(String title) 
+    {
     }
-
-    public boolean isCreated(){
+    
+    @Override
+    public boolean isCreated()
+    {
         return created.get();
     }
-
-    public void setAutoFlushFrames(boolean enabled){
+    @Override
+    public void setAutoFlushFrames(boolean enabled)
+    {
         this.autoFlush = enabled;
     }
 
-    // renderer:initialize
-    public void onSurfaceCreated(GL10 gl, EGLConfig cfg) {
-        logger.info("Using Android");
-        initInThread(gl);
-    }
+
 
     // SystemListener:reshape
-    public void onSurfaceChanged(GL10 gl, int width, int height) {
+    @Override
+    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);
     }
 
     // SystemListener:update
-    public void onDrawFrame(GL10 gl) {
-        if (needClose.get()){
-            deinitInThread(); // ???
+    @Override
+    public void onDrawFrame(GL10 gl) 
+    {
+        
+        
+        if (needClose.get())
+        {
+            deinitInThread();
             return;
         }
+        
+        if (renderable.get())
+        {
 
-//        if (wasActive != Display.isActive()){
-//            if (!wasActive){
-//                listener.gainFocus();
-//                wasActive = true;
-//            }else{
-//                listener.loseFocus();
-//                wasActive = false;
-//            }
-//        }
-
-               if (!created.get())
-            throw new IllegalStateException();
+            if (!created.get())
+                throw new IllegalStateException("onDrawFrame without create");
 
-        listener.update();
+            milliStart = System.currentTimeMillis();
+                    
 
-        // swap buffers
-        
-        if (frameRate > 0){
-//            Display.sync(frameRate);
-            // synchronzie to framerate
+    
+            listener.update();
+            
+            
+            if (autoFlush)
+            {
+                renderer.onFrame();
+            }
+            
+            milliDelta = System.currentTimeMillis() - milliStart;
+            
+            // Enforce a FPS cap
+            if (milliDelta < minFrameDuration) 
+            {
+                //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
+                try {
+                    Thread.sleep(minFrameDuration - milliDelta);
+                } catch (InterruptedException e) {
+                }
+            }
+            
         }
-
-        if (autoFlush)
-            renderer.onFrame();
+//        if (renderer.adreno_finish_bug) {
+//            GLES20.glFinish();
+//        }
     }
-
-    /**
-     * TODO: get these methods to follow the spec
-     * @param waitFor
-     */
-    public void create(boolean waitFor) {
-        if (created.get()){
-            logger.warning("create() called when display is already created!");
-            return;
-        }
+    
+    @Override
+    public boolean isRenderable()
+    {
+        return renderable.get();
     }
-
-    public void create(){
-        create(false);
+    
+    @Override
+    public void create(boolean waitFor)
+    {
+        if (waitFor)
+            waitFor(true);
     }
-
-    public void restart() {
+    
+    public void create()
+    {
+        create(false);
     }
-
-    public boolean isRenderable() {
-       // TODO isRenderable
-        return true;
+    
+    @Override
+    public void restart() 
+    {
+        
     }
     
-    /**
-     * TODO: get these methods to follow the spec
-     * @param waitFor
-     */
-    public void destroy(boolean waitFor) {
+    @Override
+    public void destroy(boolean waitFor) 
+    {
         needClose.set(true);
+        if (waitFor)
+            waitFor(false);
+    }
+           
+    public void destroy()
+    {
+        destroy(true);
+    }
+    
+    protected void waitFor(boolean createdVal)
+    {
+        while (renderable.get() != createdVal){
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException ex) {
+            }
+        }
     }
 
-    public void destroy(){
-        destroy(false);
+    public int getClientOpenGLESVersion() 
+    {
+        return clientOpenGLESVersion;
     }
 
 }