OSDN Git Service

Android: preparation of android tree for jme input integration
[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.TouchInput;
45 import com.jme3.input.android.AndroidInput;
46 import com.jme3.input.dummy.DummyKeyInput;
47 import com.jme3.input.dummy.DummyMouseInput;
48 import com.jme3.renderer.android.OGLESShaderRenderer;
49 import com.jme3.system.AppSettings;
50 import com.jme3.system.JmeContext;
51 import com.jme3.system.SystemListener;
52 import com.jme3.system.Timer;
53 import java.util.concurrent.atomic.AtomicBoolean;
54 import java.util.logging.Logger;
55 import javax.microedition.khronos.egl.EGLConfig;
56 import javax.microedition.khronos.opengles.GL10;
57
58
59 public class OGLESContext implements JmeContext, GLSurfaceView.Renderer 
60 {
61
62     private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
63
64     protected final AtomicBoolean created = new AtomicBoolean(false);
65     protected final AtomicBoolean renderable = new AtomicBoolean(false);
66     protected final AtomicBoolean needClose = new AtomicBoolean(false);
67     protected final Object createdLock = new Object();
68     protected final AppSettings settings = new AppSettings(true);
69
70         /* >= OpenGL ES 2.0 (Android 2.2+) */
71         protected OGLESShaderRenderer renderer;
72
73     protected Timer timer;
74     protected SystemListener listener;
75
76     
77     protected boolean wasActive = false;
78     protected boolean autoFlush = true;
79
80     protected AndroidInput view;
81     
82     private long milliStart;
83     private long milliDelta;
84     protected int frameRate = 33;
85     //protected int minFrameDuration = 1000 / frameRate;  // Set a max FPS of 33
86     protected int minFrameDuration = 0;                   // No FPS cap
87
88     public OGLESContext() { }
89
90     @Override
91     public Type getType() 
92     {
93         return Type.Display;
94     }
95     
96     /**
97      * <code>createView</code> 
98      * @param activity The Android activity which is parent for the GLSurfaceView  
99      * @return GLSurfaceView The newly created view
100      */
101     public GLSurfaceView createView(Activity activity)
102     {
103         return createView(new AndroidInput(activity));        
104     }
105     /**
106      * <code>createView</code> 
107      * @param AndroidInput The Android input which must be bound to an activity  
108      * @return GLSurfaceView The newly created view
109      */
110     public GLSurfaceView createView(AndroidInput view)
111     {
112         return createView(view, 0);
113     }
114     
115     /**
116      * <code>createView</code> 
117      * @param AndroidInput The Android input which must be bound to an activity  
118      * @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS
119      * @return GLSurfaceView The newly created view
120      */    
121     public GLSurfaceView createView(AndroidInput view, int debugflags)
122     {
123         this.view = view;    
124
125         /*
126          * Requesting client version from GLSurfaceView which is extended by
127          * AndroidInput.
128          * This is required to get OpenGL ES 2.0
129          */     
130         view.setEGLContextClientVersion(2);
131         
132         //RGB565, Depth16
133         view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
134         view.setFocusableInTouchMode(true);
135         view.setFocusable(true);
136         view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
137         view.setDebugFlags(debugflags);
138                 view.setRenderer(this);
139         return view;
140     }
141     
142
143     protected void initInThread()
144     {
145         logger.info("OGLESContext create");
146         logger.info("Running on thread: "+Thread.currentThread().getName());
147
148         final Context ctx = this.view.getContext();
149         
150         // Setup unhandled Exception Handler
151         if (ctx instanceof AndroidHarness)
152         {
153             Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
154                 public void uncaughtException(Thread thread, Throwable thrown) {
155                     ((AndroidHarness)ctx).handleError("Uncaught exception thrown in "+thread.toString(), thrown);
156                 }
157             });
158         }
159         else
160         {
161             Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
162                 public void uncaughtException(Thread thread, Throwable thrown) {
163                     listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
164                 }
165             });
166         }
167         
168         timer = new AndroidTimer();
169
170         renderer = new OGLESShaderRenderer();
171     
172         renderer.setUseVA(true);
173         renderer.setVerboseLogging(false);
174         
175         renderer.initialize();
176         listener.initialize();                
177         created.set(true);
178         
179         needClose.set(false);
180     }
181
182     /**
183      * De-initialize in the OpenGL thread.
184      */
185     protected void deinitInThread()
186     {        
187         if (renderer != null) 
188             renderer.cleanup();
189             
190         listener.destroy();
191         
192         // do android specific cleaning here
193                 logger.info("Display destroyed.");              
194                 renderable.set(false);
195                 created.set(false);
196                 renderer = null;
197                 timer = null;
198     }
199     
200     protected void  applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) 
201     {
202         logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]");
203         logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]");
204         renderer.setUseVA(settings.getBoolean("USE_VA"));
205         renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
206     }
207     
208     protected void applySettings(AppSettings setting)
209     {
210         if (renderer != null)
211             applySettingsToRenderer(renderer, settings);        
212     }
213
214     @Override
215     public void setSettings(AppSettings settings) 
216     {
217         this.settings.copyFrom(settings);
218     }
219
220     @Override
221     public void setSystemListener(SystemListener listener){
222         this.listener = listener;
223     }
224
225     @Override
226     public AppSettings getSettings() {
227         return settings;
228     }
229
230     @Override
231     public com.jme3.renderer.Renderer getRenderer() {
232         return renderer;
233     }
234
235     @Override
236     public MouseInput getMouseInput() {
237         return new DummyMouseInput();
238     }
239
240     @Override
241     public KeyInput getKeyInput() {
242         return new DummyKeyInput();
243     }
244     
245     @Override
246     public JoyInput getJoyInput() {
247         return null;
248     }
249
250     @Override
251     public TouchInput getTouchInput() {
252         return view;
253     }
254     
255     @Override
256     public Timer getTimer() 
257     {
258         return timer;
259     }
260
261     @Override
262     public void setTitle(String title) 
263     {
264     }
265     
266     @Override
267     public boolean isCreated()
268     {
269         return created.get();
270     }
271     @Override
272     public void setAutoFlushFrames(boolean enabled)
273     {
274         this.autoFlush = enabled;
275     }
276
277     // renderer:initialize
278     @Override
279     public void onSurfaceCreated(GL10 gl, EGLConfig cfg) 
280     {
281         if (created.get() && renderer != null)
282         {
283             renderer.resetGLObjects();
284         }
285         else
286         {
287             logger.info("GL Surface created");
288             initInThread();
289             renderable.set(true);
290         }
291     }
292
293     // SystemListener:reshape
294     @Override
295     public void onSurfaceChanged(GL10 gl, int width, int height) 
296     {
297         settings.setResolution(width, height);
298         listener.reshape(width, height);
299     }
300
301     // SystemListener:update
302     @Override
303     public void onDrawFrame(GL10 gl) 
304     {
305         
306         
307         if (needClose.get())
308         {
309             deinitInThread();
310             return;
311         }
312         
313         if (renderable.get())
314         {
315
316             if (!created.get())
317                 throw new IllegalStateException("onDrawFrame without create");
318
319             milliStart = System.currentTimeMillis();
320                     
321
322     
323             listener.update();
324             
325             
326             if (autoFlush)
327             {
328                 renderer.onFrame();
329             }
330             
331             milliDelta = System.currentTimeMillis() - milliStart;
332             
333             // Enforce a FPS cap
334             if (milliDelta < minFrameDuration) 
335             {
336                 //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
337                 try {
338                     Thread.sleep(minFrameDuration - milliDelta);
339                 } catch (InterruptedException e) {
340                 }
341             }
342             
343         }
344         
345         
346     }
347     
348     @Override
349     public boolean isRenderable()
350     {
351         return renderable.get();
352     }
353     
354     @Override
355     public void create(boolean waitFor)
356     {
357         if (waitFor)
358             waitFor(true);
359     }
360     
361     public void create()
362     {
363         create(false);
364     }
365     
366     @Override
367     public void restart() 
368     {
369         
370     }
371     
372     @Override
373     public void destroy(boolean waitFor) 
374     {
375         needClose.set(true);
376         if (waitFor)
377             waitFor(false);
378     }
379            
380     public void destroy()
381     {
382         destroy(true);
383     }
384     
385     protected void waitFor(boolean createdVal)
386     {
387         synchronized (createdLock){
388             while (created.get() != createdVal){
389                 try {
390                     createdLock.wait();
391                 } catch (InterruptedException ex) {
392                 }
393             }
394         }
395     }
396
397
398 }