OSDN Git Service

Android: Fixed app lifecycle. If you leave your activity with the back key the app...
[mikumikustudio/MikuMikuStudio.git] / engine / src / android / com / jme3 / system / android / OGLESContext.java
1 /*
2  * Copyright (c) 2003-2009 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 
17  *   may be used to endorse or promote products derived from this software 
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 package com.jme3.system.android;
34
35 import android.app.Activity;
36 import android.content.Context;
37 import android.opengl.GLSurfaceView;
38 import android.view.SurfaceHolder;
39
40 import com.jme3.app.AndroidHarness;
41 import com.jme3.input.JoyInput;
42 import com.jme3.input.KeyInput;
43 import com.jme3.input.MouseInput;
44 import com.jme3.input.android.AndroidInput;
45 import com.jme3.renderer.android.OGLESShaderRenderer;
46 import com.jme3.system.AppSettings;
47 import com.jme3.system.JmeContext;
48 import com.jme3.system.SystemListener;
49 import com.jme3.system.Timer;
50 import java.util.concurrent.atomic.AtomicBoolean;
51 import java.util.logging.Logger;
52 import javax.microedition.khronos.egl.EGLConfig;
53 import javax.microedition.khronos.opengles.GL10;
54
55
56 public class OGLESContext implements JmeContext, GLSurfaceView.Renderer 
57 {
58
59     private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
60
61     protected final AtomicBoolean created = new AtomicBoolean(false);
62     protected final AtomicBoolean renderable = new AtomicBoolean(false);
63     protected final AtomicBoolean needClose = new AtomicBoolean(false);
64     protected final Object createdLock = new Object();
65     protected final AppSettings settings = new AppSettings(true);
66
67         /* >= OpenGL ES 2.0 (Android 2.2+) */
68         protected OGLESShaderRenderer renderer;
69
70     protected Timer timer;
71     protected SystemListener listener;
72
73     
74     protected boolean wasActive = false;
75     protected boolean autoFlush = true;
76
77     protected AndroidInput view;
78     
79     private long milliStart;
80     private long milliDelta;
81     protected int frameRate = 33;
82     //protected int minFrameDuration = 1000 / frameRate;  // Set a max FPS of 33
83     protected int minFrameDuration = 0;                   // No FPS cap
84
85     public OGLESContext() { }
86
87     @Override
88     public Type getType() 
89     {
90         return Type.Display;
91     }
92     
93     /**
94      * <code>createView</code> 
95      * @param activity The Android activity which is parent for the GLSurfaceView  
96      * @return GLSurfaceView The newly created view
97      */
98     public GLSurfaceView createView(Activity activity)
99     {
100         return createView(new AndroidInput(activity));        
101     }
102     /**
103      * <code>createView</code> 
104      * @param AndroidInput The Android input which must be bound to an activity  
105      * @return GLSurfaceView The newly created view
106      */
107     public GLSurfaceView createView(AndroidInput view)
108     {
109         return createView(view, 0);
110     }
111     
112     /**
113      * <code>createView</code> 
114      * @param AndroidInput The Android input which must be bound to an activity  
115      * @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS
116      * @return GLSurfaceView The newly created view
117      */    
118     public GLSurfaceView createView(AndroidInput view, int debugflags)
119     {
120         this.view = view;    
121
122         /*
123          * Requesting client version from GLSurfaceView which is extended by
124          * AndroidInput.
125          * This is required to get OpenGL ES 2.0
126          */     
127         view.setEGLContextClientVersion(2);
128         
129         //RGB565, Depth16
130         view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
131         view.setFocusableInTouchMode(true);
132         view.setFocusable(true);
133         view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
134         view.setDebugFlags(debugflags);
135                 view.setRenderer(this);
136         return view;
137     }
138     
139
140     protected void initInThread()
141     {
142         logger.info("OGLESContext create");
143         logger.info("Running on thread: "+Thread.currentThread().getName());
144
145         final Context ctx = this.view.getContext();
146         
147         // Setup unhandled Exception Handler
148         if (ctx instanceof AndroidHarness)
149         {
150             Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
151                 public void uncaughtException(Thread thread, Throwable thrown) {
152                     ((AndroidHarness)ctx).handleError("Uncaught exception thrown in "+thread.toString(), thrown);
153                 }
154             });
155         }
156         else
157         {
158             Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
159                 public void uncaughtException(Thread thread, Throwable thrown) {
160                     listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
161                 }
162             });
163         }
164         
165         timer = new AndroidTimer();
166
167         renderer = new OGLESShaderRenderer();
168     
169         renderer.setUseVA(true);
170         renderer.setVerboseLogging(false);
171         
172         renderer.initialize();
173         listener.initialize();                
174         created.set(true);
175         
176         needClose.set(false);
177     }
178
179     /**
180      * De-initialize in the OpenGL thread.
181      */
182     protected void deinitInThread()
183     {        
184         if (renderer != null) 
185             renderer.cleanup();
186             
187         listener.destroy();
188         
189         // do android specific cleaning here
190                 logger.info("Display destroyed.");              
191                 renderable.set(false);
192                 created.set(false);
193                 renderer = null;
194                 timer = null;
195     }
196     
197     protected void  applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) 
198     {
199         logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]");
200         logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]");
201         renderer.setUseVA(settings.getBoolean("USE_VA"));
202         renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
203     }
204     
205     protected void applySettings(AppSettings setting)
206     {
207         if (renderer != null)
208             applySettingsToRenderer(renderer, settings);        
209     }
210
211     @Override
212     public void setSettings(AppSettings settings) 
213     {
214         this.settings.copyFrom(settings);
215     }
216
217     @Override
218     public void setSystemListener(SystemListener listener){
219         this.listener = listener;
220     }
221
222     @Override
223     public AppSettings getSettings() {
224         return settings;
225     }
226
227     @Override
228     public com.jme3.renderer.Renderer getRenderer() {
229         return renderer;
230     }
231
232     @Override
233     public MouseInput getMouseInput() {
234         return view;
235     }
236
237     @Override
238     public KeyInput getKeyInput() {
239         return view;
240     }
241     
242     @Override
243     public JoyInput getJoyInput() {
244         return null;
245     }
246     
247     @Override
248     public Timer getTimer() 
249     {
250         return timer;
251     }
252
253     @Override
254     public void setTitle(String title) 
255     {
256     }
257     
258     @Override
259     public boolean isCreated()
260     {
261         return created.get();
262     }
263     @Override
264     public void setAutoFlushFrames(boolean enabled)
265     {
266         this.autoFlush = enabled;
267     }
268
269     // renderer:initialize
270     @Override
271     public void onSurfaceCreated(GL10 gl, EGLConfig cfg) 
272     {
273         if (created.get() && renderer != null)
274         {
275             renderer.resetGLObjects();
276         }
277         else
278         {
279             logger.info("GL Surface created");
280             initInThread();
281             renderable.set(true);
282         }
283     }
284
285     // SystemListener:reshape
286     @Override
287     public void onSurfaceChanged(GL10 gl, int width, int height) 
288     {
289         settings.setResolution(width, height);
290         listener.reshape(width, height);
291     }
292
293     // SystemListener:update
294     @Override
295     public void onDrawFrame(GL10 gl) 
296     {
297         
298         if (!created.get())
299             throw new IllegalStateException("onDrawFrame without create");
300         
301         if (needClose.get())
302         {
303             deinitInThread();
304             return;
305         }
306         
307         if (renderable.get())
308         {
309             milliStart = System.currentTimeMillis();
310                     
311
312     
313             listener.update();
314             
315             
316             if (autoFlush)
317             {
318                 renderer.onFrame();
319             }
320             
321             milliDelta = System.currentTimeMillis() - milliStart;
322             
323             // Enforce a FPS cap
324             if (milliDelta < minFrameDuration) 
325             {
326                 //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
327                 try {
328                     Thread.sleep(minFrameDuration - milliDelta);
329                 } catch (InterruptedException e) {
330                 }
331             }
332             
333         }
334         
335         
336     }
337     
338     @Override
339     public boolean isRenderable()
340     {
341         return renderable.get();
342     }
343     
344     @Override
345     public void create(boolean waitFor)
346     {
347         if (waitFor)
348             waitFor(true);
349     }
350     
351     public void create()
352     {
353         create(false);
354     }
355     
356     @Override
357     public void restart() 
358     {
359         
360     }
361     
362     @Override
363     public void destroy(boolean waitFor) 
364     {
365         needClose.set(true);
366         if (waitFor)
367             waitFor(false);
368     }
369            
370     public void destroy()
371     {
372         destroy(false);
373     }
374     
375     protected void waitFor(boolean createdVal)
376     {
377         synchronized (createdLock){
378             while (created.get() != createdVal){
379                 try {
380                     createdLock.wait();
381                 } catch (InterruptedException ex) {
382                 }
383             }
384         }
385     }
386
387 }