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.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;
59 public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
62 private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
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);
70 /* >= OpenGL ES 2.0 (Android 2.2+) */
71 protected OGLESShaderRenderer renderer;
73 protected Timer timer;
74 protected SystemListener listener;
77 protected boolean wasActive = false;
78 protected boolean autoFlush = true;
80 protected AndroidInput view;
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
88 public OGLESContext() { }
97 * <code>createView</code>
98 * @param activity The Android activity which is parent for the GLSurfaceView
99 * @return GLSurfaceView The newly created view
101 public GLSurfaceView createView(Activity activity)
103 return createView(new AndroidInput(activity));
106 * <code>createView</code>
107 * @param AndroidInput The Android input which must be bound to an activity
108 * @return GLSurfaceView The newly created view
110 public GLSurfaceView createView(AndroidInput view)
112 return createView(view, 0);
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
121 public GLSurfaceView createView(AndroidInput view, int debugflags)
126 * Requesting client version from GLSurfaceView which is extended by
128 * This is required to get OpenGL ES 2.0
130 view.setEGLContextClientVersion(2);
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);
143 protected void initInThread()
145 logger.info("OGLESContext create");
146 logger.info("Running on thread: "+Thread.currentThread().getName());
148 final Context ctx = this.view.getContext();
150 // Setup unhandled Exception Handler
151 if (ctx instanceof AndroidHarness)
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);
161 Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
162 public void uncaughtException(Thread thread, Throwable thrown) {
163 listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
168 timer = new AndroidTimer();
170 renderer = new OGLESShaderRenderer();
172 renderer.setUseVA(true);
173 renderer.setVerboseLogging(false);
175 renderer.initialize();
176 listener.initialize();
179 needClose.set(false);
183 * De-initialize in the OpenGL thread.
185 protected void deinitInThread()
187 if (renderer != null)
192 // do android specific cleaning here
193 logger.info("Display destroyed.");
194 renderable.set(false);
200 protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
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"));
208 protected void applySettings(AppSettings setting)
210 if (renderer != null)
211 applySettingsToRenderer(renderer, settings);
215 public void setSettings(AppSettings settings)
217 this.settings.copyFrom(settings);
221 public void setSystemListener(SystemListener listener){
222 this.listener = listener;
226 public AppSettings getSettings() {
231 public com.jme3.renderer.Renderer getRenderer() {
236 public MouseInput getMouseInput() {
237 return new DummyMouseInput();
241 public KeyInput getKeyInput() {
242 return new DummyKeyInput();
246 public JoyInput getJoyInput() {
251 public TouchInput getTouchInput() {
256 public Timer getTimer()
262 public void setTitle(String title)
267 public boolean isCreated()
269 return created.get();
272 public void setAutoFlushFrames(boolean enabled)
274 this.autoFlush = enabled;
277 // renderer:initialize
279 public void onSurfaceCreated(GL10 gl, EGLConfig cfg)
281 if (created.get() && renderer != null)
283 renderer.resetGLObjects();
287 logger.info("GL Surface created");
289 renderable.set(true);
293 // SystemListener:reshape
295 public void onSurfaceChanged(GL10 gl, int width, int height)
297 settings.setResolution(width, height);
298 listener.reshape(width, height);
301 // SystemListener:update
303 public void onDrawFrame(GL10 gl)
313 if (renderable.get())
317 throw new IllegalStateException("onDrawFrame without create");
319 milliStart = System.currentTimeMillis();
331 milliDelta = System.currentTimeMillis() - milliStart;
334 if (milliDelta < minFrameDuration)
336 //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
338 Thread.sleep(minFrameDuration - milliDelta);
339 } catch (InterruptedException e) {
349 public boolean isRenderable()
351 return renderable.get();
355 public void create(boolean waitFor)
367 public void restart()
373 public void destroy(boolean waitFor)
380 public void destroy()
385 protected void waitFor(boolean createdVal)
387 synchronized (createdLock){
388 while (created.get() != createdVal){
391 } catch (InterruptedException ex) {