diff --git a/engine/src/android/com/jme3/app/AndroidHarness.java b/engine/src/android/com/jme3/app/AndroidHarness.java index 36397338b..d292daf17 100644 --- a/engine/src/android/com/jme3/app/AndroidHarness.java +++ b/engine/src/android/com/jme3/app/AndroidHarness.java @@ -46,6 +46,11 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt * ConfigType.BEST is RGBA8888 or better if supported by the hardware */ protected ConfigType eglConfigType = ConfigType.FASTEST; + + /** + * If true all valid and not valid egl configs are logged + */ + protected boolean eglConfigVerboseLogging = false; /** * Title of the exit dialog, default is "Do you want to exit?" @@ -68,6 +73,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt super.onCreate(savedInstanceState); JmeSystem.setResources(getResources()); + JmeSystem.setActivity(this); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, @@ -88,7 +94,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt app.setSettings(settings); app.start(); ctx = (OGLESContext) app.getContext(); - view = ctx.createView(input, eglConfigType); + view = ctx.createView(input, eglConfigType, eglConfigVerboseLogging); setContentView(view); } @@ -129,8 +135,8 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt @Override protected void onDestroy(){ - super.onDestroy(); - app.stop(); + app.stop(true); + super.onDestroy(); logger.info("onDestroy"); } @@ -138,6 +144,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt { return app; } + /** * Called when an error has occured. This is typically * invoked when an uncought exception is thrown in the render thread. @@ -186,7 +193,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt { if (whichButton != -2) { - app.stop(); + app.stop(true); this.finish(); } } diff --git a/engine/src/android/com/jme3/asset/AndroidAssetManager.java b/engine/src/android/com/jme3/asset/AndroidAssetManager.java index d9e87203b..88f24ff4f 100644 --- a/engine/src/android/com/jme3/asset/AndroidAssetManager.java +++ b/engine/src/android/com/jme3/asset/AndroidAssetManager.java @@ -39,6 +39,7 @@ import java.util.logging.Logger; import com.jme3.asset.plugins.AndroidLocator; import com.jme3.asset.plugins.ClasspathLocator; +import com.jme3.audio.plugins.AndroidAudioLoader; /** * AndroidAssetManager is an implementation of DesktopAssetManager for Android @@ -72,7 +73,8 @@ public class AndroidAssetManager extends DesktopAssetManager { // Set Default Android config this.registerLocator("", AndroidLocator.class); this.registerLocator("", ClasspathLocator.class); - this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg"); + this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg"); + this.registerLoader(AndroidAudioLoader.class, "ogg", "mp3"); this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m"); this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md"); this.registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt"); diff --git a/engine/src/android/com/jme3/audio/android/AndroidAudioData.java b/engine/src/android/com/jme3/audio/android/AndroidAudioData.java new file mode 100644 index 000000000..39f729154 --- /dev/null +++ b/engine/src/android/com/jme3/audio/android/AndroidAudioData.java @@ -0,0 +1,54 @@ +package com.jme3.audio.android; + +import com.jme3.asset.AssetKey; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioRenderer; + +public class AndroidAudioData extends AudioData +{ + protected AssetKey assetKey; + protected int soundId = 0; + + public AssetKey getAssetKey() { + return assetKey; + } + + public void setAssetKey(AssetKey assetKey) { + this.assetKey = assetKey; + } + + public int getSoundId() { + return soundId; + } + + public void setSoundId(int soundId) { + this.soundId = soundId; + } + + @Override + public DataType getDataType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public float getDuration() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void resetObject() { + // TODO Auto-generated method stub + + } + + @Override + public void deleteObject(AudioRenderer r) { + // TODO Auto-generated method stub + + } + + + +} diff --git a/engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java b/engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java new file mode 100644 index 000000000..b9afae089 --- /dev/null +++ b/engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.audio.android; + +import android.app.Activity; +import android.content.Context; +import android.content.res.AssetManager; +import android.media.AudioManager; +import android.media.SoundPool; + +import com.jme3.audio.ListenerParam; +import com.jme3.audio.AudioParam; +import com.jme3.audio.AudioBuffer; +import com.jme3.audio.AudioData; +import com.jme3.audio.AudioRenderer; +import com.jme3.audio.AudioNode; +import com.jme3.audio.AudioNode.Status; +import com.jme3.audio.AudioStream; +import com.jme3.audio.Environment; +import com.jme3.audio.Filter; +import com.jme3.audio.Listener; +import com.jme3.audio.LowPassFilter; +import com.jme3.math.Vector3f; +import com.jme3.util.BufferUtils; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + + +/** + * This class is the android implementation for {@link AudioRenderer} + * @author larynx + * + */ +public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener +{ + + private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName()); + private final static int MAX_NUM_CHANNELS = 16; + + private SoundPool soundPool = null; + private final AudioManager manager; + private final Context context; + private final AssetManager am; + + private HashMap mapLoadingAudioNodes = new HashMap(); + + private final AtomicBoolean lastLoadCompleted = new AtomicBoolean(); + + + private Listener listener; + private boolean audioDisabled = false; + + + + public AndroidAudioRenderer(Activity context) + { + this.context = context; + manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); + context.setVolumeControlStream(AudioManager.STREAM_MUSIC); + am = context.getAssets(); + } + + @Override + public void initialize() + { + soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, 0); + soundPool.setOnLoadCompleteListener(this); + } + + + private void updateFilter(Filter f) + { + throw new UnsupportedOperationException("Filter type unsupported: " + f.getClass().getName()); + } + + @Override + public void updateSourceParam(AudioNode src, AudioParam param) + { + if (audioDisabled) + return; + + if (src.getChannel() < 0) + return; + + assert src.getChannel() >= 0; + + + switch (param){ + case Position: + if (!src.isPositional()) + return; + + Vector3f pos = src.getWorldTranslation(); + break; + case Velocity: + if (!src.isPositional()) + return; + + Vector3f vel = src.getVelocity(); + break; + case MaxDistance: + if (!src.isPositional()) + return; + break; + case RefDistance: + if (!src.isPositional()) + return; + break; + case ReverbFilter: + if (!src.isPositional() || !src.isReverbEnabled()) + return; + break; + case ReverbEnabled: + if (!src.isPositional()) + return; + + if (src.isReverbEnabled()){ + updateSourceParam(src, AudioParam.ReverbFilter); + } + break; + case IsPositional: + break; + case Direction: + if (!src.isDirectional()) + return; + + Vector3f dir = src.getDirection(); + break; + case InnerAngle: + if (!src.isDirectional()) + return; + break; + case OuterAngle: + if (!src.isDirectional()) + return; + break; + case IsDirectional: + if (src.isDirectional()){ + updateSourceParam(src, AudioParam.Direction); + updateSourceParam(src, AudioParam.InnerAngle); + updateSourceParam(src, AudioParam.OuterAngle); + }else{ + } + break; + case DryFilter: + if (src.getDryFilter() != null){ + Filter f = src.getDryFilter(); + if (f.isUpdateNeeded()){ + updateFilter(f); + + } + } + break; + case Looping: + if (src.isLooping()){ + } + break; + case Volume: + + soundPool.setVolume(src.getChannel(), src.getVolume(), src.getVolume()); + + break; + case Pitch: + + break; + } + + } + + @Override + public void updateListenerParam(Listener listener, ListenerParam param) + { + if (audioDisabled) + return; + + switch (param){ + case Position: + Vector3f pos = listener.getLocation(); + + break; + case Rotation: + Vector3f dir = listener.getDirection(); + Vector3f up = listener.getUp(); + + break; + case Velocity: + Vector3f vel = listener.getVelocity(); + + break; + case Volume: + //alListenerf(AL_GAIN, listener.getVolume()); + break; + } + + } + + + public void update(float tpf) + { + // does nothing + } + + public void updateInThread(float tpf) + { + if (audioDisabled) + return; + if (!audioDisabled) + return; + + } + + public void setListener(Listener listener) + { + if (audioDisabled) + return; + + if (this.listener != null){ + // previous listener no longer associated with current + // renderer + this.listener.setRenderer(null); + } + + this.listener = listener; + this.listener.setRenderer(this); + + } + + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) + { + //lastLoadCompleted.set(true); + + if (status == 0) + { + AudioNode src = mapLoadingAudioNodes.get(sampleId); + if (src.getAudioData() instanceof AndroidAudioData) + { + AndroidAudioData audioData = (AndroidAudioData)src.getAudioData(); + + int channelIndex; + channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f); + src.setChannel(channelIndex); + // Playing started ? + if (src.getChannel() > 0) + { + src.setStatus(Status.Playing); + } + } + else + { + throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString()); + } + } + } + + @Override + public void cleanup() + { + if (soundPool != null) + { + for (AudioNode src: mapLoadingAudioNodes.values()) + { + if ((src.getStatus() == Status.Playing) && (src.getChannel() > 0)) + { + soundPool.stop(src.getChannel()); + } + + if (src.getAudioData() instanceof AndroidAudioData) + { + AndroidAudioData audioData = (AndroidAudioData)src.getAudioData(); + if (audioData.getSoundId() > 0) + { + soundPool.unload(audioData.getSoundId()); + } + } + } + + soundPool.release(); + soundPool = null; + } + } + + public void playSourceInstance(AudioNode src) + { + if (audioDisabled) + return; + + AndroidAudioData audioData; + int soundId = 0; + + if (src.getAudioData() instanceof AndroidAudioData) + { + audioData = (AndroidAudioData)src.getAudioData(); + if (audioData.isUpdateNeeded() || (audioData.getSoundId() == 0)) + { + if (audioData.getSoundId() > 0) + { + if (src.getChannel() > 0) + { + soundPool.stop(src.getChannel()); + src.setChannel(-1); + } + soundPool.unload(audioData.getSoundId()); + } + + try + { + soundId = soundPool.load(am.openFd(audioData.getAssetKey().getName()), 1); + } + catch (IOException e) + { + logger.log(Level.SEVERE, "Failed to load sound " + audioData.getAssetKey().getName(), e); + soundId = -1; + } + audioData.setSoundId(soundId); + } + } + else + { + throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString()); + } + + // Sound failed to load ? + if (audioData.getSoundId() <= 0) + { + throw new IllegalArgumentException("Failed to load: " + audioData.getAssetKey().getName()); + } + else + { + int channelIndex; + channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f); + if (channelIndex == 0) + { + // Loading is not finished + // Store the soundId and the AudioNode for async loading and later play start + mapLoadingAudioNodes.put(audioData.getSoundId(), src); + } + src.setChannel(channelIndex); + } + + // Playing started ? + if (src.getChannel() > 0) + { + src.setStatus(Status.Playing); + } + + } + + + public void playSource(AudioNode src) + { + if (audioDisabled) + return; + + //assert src.getStatus() == Status.Stopped || src.getChannel() == -1; + + if (src.getStatus() == Status.Playing) + { + return; + } + else if (src.getStatus() == Status.Stopped) + { + playSourceInstance(src); + } + + + } + + + public void pauseSource(AudioNode src) + { + if (audioDisabled) + return; + + if (src.getStatus() == Status.Playing) + { + assert src.getChannel() != -1; + + if (src.getChannel() > 0) + { + soundPool.pause(src.getChannel()); + } + src.setStatus(Status.Paused); + } + + } + + + public void stopSource(AudioNode src) + { + if (audioDisabled) + return; + + if (src.getStatus() != Status.Stopped){ + int chan = src.getChannel(); + assert chan != -1; // if it's not stopped, must have id + + if (src.getChannel() > 0) + { + soundPool.stop(src.getChannel()); + src.setChannel(-1); + } + + src.setStatus(Status.Stopped); + } + + AndroidAudioData audioData; + if (src.getAudioData() instanceof AndroidAudioData) + { + audioData = (AndroidAudioData)src.getAudioData(); + if (audioData.getSoundId() > 0) + { + soundPool.unload(audioData.getSoundId()); + } + audioData.setSoundId(0); + + } + else + { + throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString()); + } + + + } + + private int convertFormat(AudioData ad) + { + /* + switch (ad.getBitsPerSample()){ + case 8: + if (ad.getChannels() == 1) + return AL_FORMAT_MONO8; + else if (ad.getChannels() == 2) + return AL_FORMAT_STEREO8; + + break; + case 16: + if (ad.getChannels() == 1) + return AL_FORMAT_MONO16; + else + return AL_FORMAT_STEREO16; + } + */ + throw new UnsupportedOperationException("Unsupported channels/bits combination: "+ + "bits="+ad.getBitsPerSample()+", channels="+ad.getChannels()); + } + + public void updateAudioData(AndroidAudioData data) + { + throw new UnsupportedOperationException("updateAudioData"); + } + + @Override + public void deleteAudioData(AudioData ad) + { + if (ad instanceof AndroidAudioData) + { + if (((AndroidAudioData)ad).getSoundId() > 0) + { + soundPool.unload(((AndroidAudioData)ad).getSoundId()); + } + ((AndroidAudioData)ad).setSoundId(0); + + } + else + { + throw new IllegalArgumentException("AudioData is not of type AndroidAudioData in deleteAudioData"); + } + } + + @Override + public void setEnvironment(Environment env) { + // TODO Auto-generated method stub + + } + + + + +} diff --git a/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java new file mode 100644 index 000000000..4c20619c7 --- /dev/null +++ b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java @@ -0,0 +1,27 @@ +package com.jme3.audio.plugins; + +import java.io.IOException; +import java.io.InputStream; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetLoader; +import com.jme3.audio.android.AndroidAudioData; + +public class AndroidAudioLoader implements AssetLoader +{ + + @Override + public Object load(AssetInfo assetInfo) throws IOException + { + + InputStream in = assetInfo.openStream(); + if (in != null) + { + in.close(); + } + AndroidAudioData result = new AndroidAudioData(); + result.setAssetKey( assetInfo.getKey() ); + return result; + } + +} diff --git a/engine/src/android/com/jme3/system/JmeSystem.java b/engine/src/android/com/jme3/system/JmeSystem.java index 2628b31fb..a7481e975 100644 --- a/engine/src/android/com/jme3/system/JmeSystem.java +++ b/engine/src/android/com/jme3/system/JmeSystem.java @@ -1,6 +1,7 @@ package com.jme3.system; +import android.app.Activity; import android.content.res.Resources; import com.jme3.util.AndroidLogHandler; import com.jme3.asset.AndroidAssetManager; @@ -12,6 +13,7 @@ import com.jme3.audio.AudioRenderer; import com.jme3.audio.Environment; import com.jme3.audio.Listener; import com.jme3.audio.ListenerParam; +import com.jme3.audio.android.AndroidAudioRenderer; //import com.jme3.audio.DummyAudioRenderer; import com.jme3.system.JmeContext.Type; import com.jme3.system.android.OGLESContext; @@ -93,9 +95,11 @@ public class JmeSystem private static boolean initialized = false; private static boolean lowPermissions = false; private static Resources res; + private static Activity activity; public static void initialize(AppSettings settings) { + if (initialized) return; @@ -116,7 +120,7 @@ public class JmeSystem public static String getFullName() { - return "jMonkey Engine 3 ALPHA 0.6 Android"; + return "jMonkey Engine 3 ALPHA 0.7 Android"; } public static void setLowPermissions(boolean lowPerm) @@ -137,28 +141,7 @@ public class JmeSystem public static AudioRenderer newAudioRenderer(AppSettings settings) { - return new AudioRenderer() - { - public void setListener(Listener listener) {} - public void setEnvironment(Environment env) {} - public void playSourceInstance(AudioNode src) {} - public void playSource(AudioNode src) {} - public void pauseSource(AudioNode src) {} - public void stopSource(AudioNode src) {} - public void deleteAudioData(AudioData ad) {} - public void initialize() {} - public void update(float tpf) {} - public void cleanup() {} - public void updateListenerParam(Listener listener, - ListenerParam param) { - // TODO Auto-generated method stub - - } - public void updateSourceParam(AudioNode src, AudioParam param) { - // TODO Auto-generated method stub - - } - }; + return new AndroidAudioRenderer(activity); } public static void setResources(Resources res) @@ -171,6 +154,17 @@ public class JmeSystem return res; } + public static void setActivity(Activity activity) + { + JmeSystem.activity = activity; + } + + public static Activity getActivity() + { + return activity; + } + + public static AssetManager newAssetManager() { logger.info("newAssetManager()"); diff --git a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java index 12d8f593f..f082b5f79 100644 --- a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java +++ b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java @@ -25,6 +25,8 @@ public class AndroidConfigChooser implements EGLConfigChooser protected ConfigType type; protected int pixelFormat; + protected boolean verbose = false; + private final static int EGL_OPENGL_ES2_BIT = 4; public enum ConfigType @@ -39,9 +41,10 @@ public class AndroidConfigChooser implements EGLConfigChooser BEST } - public AndroidConfigChooser(ConfigType type) + public AndroidConfigChooser(ConfigType type, boolean verbose) { this.type = type; + this.verbose = verbose; } /** @@ -69,10 +72,15 @@ public class AndroidConfigChooser implements EGLConfigChooser //Querying actual configurations EGLConfig[] conf = new EGLConfig[configurations]; egl.eglGetConfigs(display, conf, configurations, num_conf); - - + int[] value = new int[1]; - + + + if (configurations <= 0) + { + logger.severe("###ERROR### ZERO EGL Configurations found, This Is a Problem"); + } + // Loop over all configs to get the best for(int i = 0; i < configurations; i++) { @@ -94,27 +102,57 @@ public class AndroidConfigChooser implements EGLConfigChooser bestConfig = better(bestConfig, conf[i], egl, display); fastestConfig = faster(fastestConfig, conf[i], egl, display); - logger.info("Supported EGL Configuration #" + i ); - logEGLConfig(conf[i], display, egl); + if (verbose) + { + logger.info("** Supported EGL Configuration #" + i ); + logEGLConfig(conf[i], display, egl); + } + } + else + { + if (verbose) + { + logger.info("NOT Supported EGL Configuration #" + i + " EGL_OPENGL_ES2_BIT not set"); + logEGLConfig(conf[i], display, egl); + } + } + } + else + { + if (verbose) + { + logger.info("NOT Supported EGL Configuration #" + i + " EGL_DEPTH_SIZE != 16"); + logEGLConfig(conf[i], display, egl); } } } + else + { + if (verbose) + { + logger.info("NOT Supported EGL Configuration #" + i + " EGL_WINDOW_BIT not set"); + logEGLConfig(conf[i], display, egl); + } + } } else { - break; + logger.severe("###ERROR### EGL Configuration #" + i + " is NULL"); } } if ((type == ConfigType.BEST) && (bestConfig != null)) { - logger.info("### JME3 ### using best EGL configuration available here: "); + logger.info("JME3 using best EGL configuration available here: "); choosenConfig = bestConfig; } else { - logger.info("### JME3 ### using fastest EGL configuration available here: "); + if (fastestConfig != null) + { + logger.info("JME3 using fastest EGL configuration available here: "); + } choosenConfig = fastestConfig; } @@ -127,7 +165,7 @@ public class AndroidConfigChooser implements EGLConfigChooser } else { - logger.severe("Unable to get a valid OpenGL ES 2.0 config"); + logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this."); clientOpenGLESVersion = 1; pixelFormat = PixelFormat.UNKNOWN; return false; diff --git a/engine/src/android/com/jme3/system/android/OGLESContext.java b/engine/src/android/com/jme3/system/android/OGLESContext.java index a75dd8096..bedc9e634 100644 --- a/engine/src/android/com/jme3/system/android/OGLESContext.java +++ b/engine/src/android/com/jme3/system/android/OGLESContext.java @@ -75,7 +75,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer protected final AtomicBoolean created = new AtomicBoolean(false); protected final AtomicBoolean renderable = new AtomicBoolean(false); protected final AtomicBoolean needClose = new AtomicBoolean(false); - protected final Object createdLock = new Object(); + protected final AppSettings settings = new AppSettings(true); /* >= OpenGL ES 2.0 (Android 2.2+) */ @@ -127,7 +127,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer */ public GLSurfaceView createView(AndroidInput view) { - return createView(view, ConfigType.FASTEST); + return createView(view, ConfigType.FASTEST, false); } /** @@ -136,7 +136,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer * @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS * @return GLSurfaceView The newly created view */ - public GLSurfaceView createView(AndroidInput view, ConfigType configType) + public GLSurfaceView createView(AndroidInput view, ConfigType configType, boolean eglConfigVerboseLogging) { EGL10 egl = (EGL10) EGLContext.getEGL(); EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); @@ -151,7 +151,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer this.view = view; // Create a config chooser - AndroidConfigChooser configChooser = new AndroidConfigChooser(configType); + AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging); // Init chooser if (!configChooser.findConfig(egl, display)) { @@ -239,18 +239,24 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer * De-initialize in the OpenGL thread. */ protected void deinitInThread() - { - if (renderer != null) - renderer.cleanup(); - - listener.destroy(); - - // do android specific cleaning here - logger.info("Display destroyed."); - renderable.set(false); - created.set(false); - renderer = null; - timer = null; + { + if (renderable.get()) + { + renderable.set(false); + if (renderer != null) + renderer.cleanup(); + + listener.destroy(); + + listener = null; + renderer = null; + timer = null; + + // do android specific cleaning here + logger.info("Display destroyed."); + + created.set(false); + } } protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) @@ -441,12 +447,10 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer protected void waitFor(boolean createdVal) { - synchronized (createdLock){ - while (created.get() != createdVal){ - try { - createdLock.wait(); - } catch (InterruptedException ex) { - } + while (created.get() != createdVal){ + try { + Thread.sleep(10); + } catch (InterruptedException ex) { } } }