2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
33 package com.jme3.system.android;
35 import android.app.Activity;
36 import android.content.Context;
37 import android.opengl.GLSurfaceView;
38 import android.view.SurfaceHolder;
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;
56 public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
59 private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
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);
67 /* >= OpenGL ES 2.0 (Android 2.2+) */
68 protected OGLESShaderRenderer renderer;
70 protected Timer timer;
71 protected SystemListener listener;
74 protected boolean wasActive = false;
75 protected boolean autoFlush = true;
77 protected AndroidInput view;
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
85 public OGLESContext() { }
94 * <code>createView</code>
95 * @param activity The Android activity which is parent for the GLSurfaceView
96 * @return GLSurfaceView The newly created view
98 public GLSurfaceView createView(Activity activity)
100 return createView(new AndroidInput(activity));
103 * <code>createView</code>
104 * @param AndroidInput The Android input which must be bound to an activity
105 * @return GLSurfaceView The newly created view
107 public GLSurfaceView createView(AndroidInput view)
109 return createView(view, 0);
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
118 public GLSurfaceView createView(AndroidInput view, int debugflags)
123 * Requesting client version from GLSurfaceView which is extended by
125 * This is required to get OpenGL ES 2.0
127 view.setEGLContextClientVersion(2);
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);
140 protected void initInThread()
142 logger.info("OGLESContext create");
143 logger.info("Running on thread: "+Thread.currentThread().getName());
145 final Context ctx = this.view.getContext();
147 // Setup unhandled Exception Handler
148 if (ctx instanceof AndroidHarness)
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);
158 Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
159 public void uncaughtException(Thread thread, Throwable thrown) {
160 listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
165 timer = new AndroidTimer();
167 renderer = new OGLESShaderRenderer();
169 renderer.setUseVA(true);
170 renderer.setVerboseLogging(false);
172 renderer.initialize();
173 listener.initialize();
176 needClose.set(false);
180 * De-initialize in the OpenGL thread.
182 protected void deinitInThread()
184 if (renderer != null)
189 // do android specific cleaning here
190 logger.info("Display destroyed.");
191 renderable.set(false);
197 protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
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"));
205 protected void applySettings(AppSettings setting)
207 if (renderer != null)
208 applySettingsToRenderer(renderer, settings);
212 public void setSettings(AppSettings settings)
214 this.settings.copyFrom(settings);
218 public void setSystemListener(SystemListener listener){
219 this.listener = listener;
223 public AppSettings getSettings() {
228 public com.jme3.renderer.Renderer getRenderer() {
233 public MouseInput getMouseInput() {
238 public KeyInput getKeyInput() {
243 public JoyInput getJoyInput() {
248 public Timer getTimer()
254 public void setTitle(String title)
259 public boolean isCreated()
261 return created.get();
264 public void setAutoFlushFrames(boolean enabled)
266 this.autoFlush = enabled;
269 // renderer:initialize
271 public void onSurfaceCreated(GL10 gl, EGLConfig cfg)
273 if (created.get() && renderer != null)
275 renderer.resetGLObjects();
279 logger.info("GL Surface created");
281 renderable.set(true);
285 // SystemListener:reshape
287 public void onSurfaceChanged(GL10 gl, int width, int height)
289 settings.setResolution(width, height);
290 listener.reshape(width, height);
293 // SystemListener:update
295 public void onDrawFrame(GL10 gl)
299 throw new IllegalStateException("onDrawFrame without create");
307 if (renderable.get())
309 milliStart = System.currentTimeMillis();
321 milliDelta = System.currentTimeMillis() - milliStart;
324 if (milliDelta < minFrameDuration)
326 //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
328 Thread.sleep(minFrameDuration - milliDelta);
329 } catch (InterruptedException e) {
339 public boolean isRenderable()
341 return renderable.get();
345 public void create(boolean waitFor)
357 public void restart()
363 public void destroy(boolean waitFor)
370 public void destroy()
375 protected void waitFor(boolean createdVal)
377 synchronized (createdLock){
378 while (created.get() != createdVal){
381 } catch (InterruptedException ex) {