From a6b44658eb1c55295f132a36233a11aa2bd8f9cf Mon Sep 17 00:00:00 2001 From: Scott Barta Date: Fri, 9 Mar 2012 13:52:20 -0800 Subject: New drop of the jmonkeyengine library A new drop of the jmonkeyengine library sources, based on a 2012-03-05 snapshot. Fixes a few unnecessary memory allocations in the main rendering loop. Change-Id: I51ac0942fe87204df102cfdce746b59a5cb5ff85 --- .../src/android/com/jme3/app/AndroidHarness.java | 12 +- .../com/jme3/asset/AndroidAssetManager.java | 51 +- .../com/jme3/asset/plugins/AndroidLocator.java | 5 +- .../com/jme3/audio/plugins/AndroidAudioLoader.java | 13 +- .../com/jme3/input/android/AndroidInput.java | 1239 +++++------ .../input/android/AndroidTouchInputListener.java | 11 +- .../jme3/renderer/android/OGLESShaderRenderer.java | 30 +- .../com/jme3/renderer/android/TextureUtil.java | 4 +- .../jme3/system/android/AndroidConfigChooser.java | 359 ++- .../com/jme3/system/android/OGLESContext.java | 94 +- .../android/com/jme3/util/AndroidLogHandler.java | 16 +- engine/src/android/com/jme3/util/RingBuffer.java | 21 +- engine/src/android/res/layout/about.xml | 32 +- engine/src/android/res/layout/tests.xml | 18 +- .../scene/plugins/blender/meshes/MeshHelper.java | 15 +- .../textures/blending/TextureBlenderAWT.java | 4 +- .../core-data/Common/MatDefs/Light/Lighting.frag | 4 + .../core-data/Common/MatDefs/Misc/Particle.j3md | 26 + .../Common/MatDefs/Misc/SoftParticle.frag | 50 + .../Common/MatDefs/Misc/SoftParticle.vert | 53 + .../jme3/post/filters/TranslucentBucketFilter.java | 75 + .../com/jme3/asset/plugins/HttpZipLocator.java~ | 355 --- .../com/jme3/scene/plugins/OBJLoader.java | 6 +- engine/src/core/com/jme3/app/Application.java | 15 + engine/src/core/com/jme3/app/ResetStatsState.java | 60 + .../src/core/com/jme3/app/SimpleApplication.java | 7 - engine/src/core/com/jme3/app/StatsView.java | 2 +- .../core/com/jme3/app/state/AppStateManager.java | 6 + engine/src/core/com/jme3/input/InputManager.java | 1773 +++++++-------- .../core/com/jme3/input/SoftTextDialogInput.java | 13 + engine/src/core/com/jme3/input/TouchInput.java | 6 + .../controls/SoftTextDialogInputListener.java | 44 + engine/src/core/com/jme3/math/Transform.java | 636 +++--- engine/src/core/com/jme3/post/Filter.java | 13 +- .../core/com/jme3/post/FilterPostProcessor.java | 25 +- .../src/core/com/jme3/renderer/RenderManager.java | 2348 ++++++++++---------- engine/src/core/com/jme3/scene/BatchNode.java | 13 +- engine/src/core/com/jme3/scene/Mesh.java | 153 +- .../src/core/com/jme3/shader/UniformBinding.java | 338 +-- engine/src/core/com/jme3/system/JmeSystem.java | 283 +-- .../core/com/jme3/system/JmeSystemDelegate.java | 289 +-- engine/src/core/com/jme3/util/BufferUtils.java | 75 +- engine/src/core/com/jme3/util/IntMap.java | 7 +- .../com/jme3/util/TangentBinormalGenerator.java | 12 +- .../com/jme3/texture/plugins/AWTLoader.java | 14 +- .../src/niftygui/Common/MatDefs/Nifty/Nifty.frag | 13 - .../src/niftygui/Common/MatDefs/Nifty/Nifty.j3md | 21 - .../src/niftygui/Common/MatDefs/Nifty/Nifty.vert | 16 - .../niftygui/Common/MatDefs/Nifty/NiftyQuad.frag | 6 + .../niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md | 19 + .../niftygui/Common/MatDefs/Nifty/NiftyQuad.vert | 9 + .../Common/MatDefs/Nifty/NiftyQuadGrad.frag | 6 + .../Common/MatDefs/Nifty/NiftyQuadGrad.j3md | 18 + .../Common/MatDefs/Nifty/NiftyQuadGrad.vert | 14 + .../niftygui/Common/MatDefs/Nifty/NiftyTex.frag | 10 + .../niftygui/Common/MatDefs/Nifty/NiftyTex.j3md | 20 + .../niftygui/Common/MatDefs/Nifty/NiftyTex.vert | 13 + .../niftygui/com/jme3/niftygui/InputSystemJme.java | 507 +++-- .../com/jme3/niftygui/RenderDeviceJme.java | 289 ++- .../com/jme3/scene/plugins/ogre/MeshLoader.java | 5 +- .../com/jme3/terrain/geomipmap/LODGeomap.java | 27 +- .../com/jme3/terrain/geomipmap/TerrainPatch.java | 248 +-- .../com/jme3/terrain/geomipmap/TerrainQuad.java | 3 +- .../test/jme3test/app/TestAppStateLifeCycle.java | 126 ++ .../test/jme3test/effect/TestSoftParticles.java | 130 ++ .../test/jme3test/helloworld/HelloMaterial.java | 3 +- .../jme3test/model/shape/TestExpandingTorus.java | 45 + .../jme3tools/converters/model/ModelConverter.java | 4 +- .../jme3tools/optimize/GeometryBatchFactory.java | 38 +- 69 files changed, 5377 insertions(+), 4838 deletions(-) create mode 100644 engine/src/core-data/Common/MatDefs/Misc/SoftParticle.frag create mode 100644 engine/src/core-data/Common/MatDefs/Misc/SoftParticle.vert delete mode 100644 engine/src/core-plugins/com/jme3/asset/plugins/HttpZipLocator.java~ create mode 100644 engine/src/core/com/jme3/app/ResetStatsState.java create mode 100644 engine/src/core/com/jme3/input/SoftTextDialogInput.java create mode 100644 engine/src/core/com/jme3/input/controls/SoftTextDialogInputListener.java delete mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag delete mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md delete mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.frag create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.vert create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.frag create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.j3md create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.vert create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.frag create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.j3md create mode 100644 engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.vert create mode 100644 engine/src/test/jme3test/app/TestAppStateLifeCycle.java create mode 100644 engine/src/test/jme3test/effect/TestSoftParticles.java create mode 100644 engine/src/test/jme3test/model/shape/TestExpandingTorus.java diff --git a/engine/src/android/com/jme3/app/AndroidHarness.java b/engine/src/android/com/jme3/app/AndroidHarness.java index 6631003..0ad2ba1 100644 --- a/engine/src/android/com/jme3/app/AndroidHarness.java +++ b/engine/src/android/com/jme3/app/AndroidHarness.java @@ -69,6 +69,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt * Flip Y axis */ protected boolean mouseEventsInvertY = true; + /** + * if true finish this activity when the jme app is stopped + */ + protected boolean finishOnAppStop = true; /** * Title of the exit dialog, default is "Do you want to exit?" */ @@ -131,7 +135,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt boolean bIsLogFormatSet = false; do { if (log.getHandlers().length == 0) { - log = logger.getParent(); + log = log.getParent(); if (log != null) { for (Handler h : log.getHandlers()) { //h.setFormatter(new SimpleFormatter()); @@ -395,4 +399,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt } } } + + public boolean isFinishOnAppStop() { + return finishOnAppStop; + } + + } diff --git a/engine/src/android/com/jme3/asset/AndroidAssetManager.java b/engine/src/android/com/jme3/asset/AndroidAssetManager.java index c6f0b17..b2140dd 100644 --- a/engine/src/android/com/jme3/asset/AndroidAssetManager.java +++ b/engine/src/android/com/jme3/asset/AndroidAssetManager.java @@ -37,6 +37,7 @@ import com.jme3.audio.plugins.AndroidAudioLoader; import com.jme3.texture.Texture; import com.jme3.texture.plugins.AndroidImageLoader; import java.net.URL; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -57,6 +58,14 @@ public class AndroidAssetManager extends DesktopAssetManager { //this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg")); this(null); } + + private void registerLoaderSafe(Class loaderClass, String ... extensions) { + try { + registerLoader(loaderClass, extensions); + } catch (Exception e){ + logger.log(Level.WARNING, "Failed to load AssetLoader", e); + } + } /** * AndroidAssetManager constructor @@ -67,25 +76,29 @@ public class AndroidAssetManager extends DesktopAssetManager { System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver"); // Set Default Android config - this.registerLocator("", AndroidLocator.class); - this.registerLocator("", ClasspathLocator.class); - this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg"); - this.registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav"); - 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"); - this.registerLoader(com.jme3.texture.plugins.DDSLoader.class, "dds"); - this.registerLoader(com.jme3.texture.plugins.PFMLoader.class, "pfm"); - this.registerLoader(com.jme3.texture.plugins.HDRLoader.class, "hdr"); - this.registerLoader(com.jme3.texture.plugins.TGALoader.class, "tga"); - this.registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o"); - this.registerLoader(com.jme3.scene.plugins.OBJLoader.class, "obj"); - this.registerLoader(com.jme3.scene.plugins.MTLLoader.class, "mtl"); - this.registerLoader(com.jme3.scene.plugins.ogre.MeshLoader.class, "meshxml", "mesh.xml"); - this.registerLoader(com.jme3.scene.plugins.ogre.SkeletonLoader.class, "skeletonxml", "skeleton.xml"); - this.registerLoader(com.jme3.scene.plugins.ogre.MaterialLoader.class, "material"); - this.registerLoader(com.jme3.scene.plugins.ogre.SceneLoader.class, "scene"); - this.registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib"); + registerLocator("", AndroidLocator.class); + registerLocator("", ClasspathLocator.class); + + registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg"); + registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav"); + registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m"); + registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md"); + registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib"); + registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o"); + registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt"); + + // Less common loaders (especially on Android) + registerLoaderSafe(com.jme3.texture.plugins.DDSLoader.class, "dds"); + registerLoaderSafe(com.jme3.texture.plugins.PFMLoader.class, "pfm"); + registerLoaderSafe(com.jme3.texture.plugins.HDRLoader.class, "hdr"); + registerLoaderSafe(com.jme3.texture.plugins.TGALoader.class, "tga"); + registerLoaderSafe(com.jme3.scene.plugins.OBJLoader.class, "obj"); + registerLoaderSafe(com.jme3.scene.plugins.MTLLoader.class, "mtl"); + registerLoaderSafe(com.jme3.scene.plugins.ogre.MeshLoader.class, "mesh.xml"); + registerLoaderSafe(com.jme3.scene.plugins.ogre.SkeletonLoader.class, "skeleton.xml"); + registerLoaderSafe(com.jme3.scene.plugins.ogre.MaterialLoader.class, "material"); + registerLoaderSafe(com.jme3.scene.plugins.ogre.SceneLoader.class, "scene"); + logger.info("AndroidAssetManager created."); } diff --git a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java b/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java index 01b1cab..225faf3 100644 --- a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java +++ b/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java @@ -4,9 +4,6 @@ import com.jme3.asset.*; import com.jme3.system.android.JmeAndroidSystem; import java.io.IOException; import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.util.logging.Level; import java.util.logging.Logger; public class AndroidLocator implements AssetLocator { @@ -80,7 +77,7 @@ public class AndroidLocator implements AssetLocator { assetPath = assetPath.replace("//", "/"); try { return create(manager, key, assetPath); - }catch (IOException ex){ + } catch (IOException ex) { // This is different handling than URL locator // since classpath locating would return null at the getResource() // call, otherwise there's a more critical error... diff --git a/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java index fc9c03e..a11425b 100644 --- a/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java +++ b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java @@ -5,15 +5,16 @@ import com.jme3.asset.AssetLoader; import com.jme3.audio.android.AndroidAudioData; import java.io.IOException; -public class AndroidAudioLoader implements AssetLoader -{ +/** + * AndroidAudioLoader will create an + * {@link AndroidAudioData} object with the specified asset key. + */ +public class AndroidAudioLoader implements AssetLoader { @Override - public Object load(AssetInfo assetInfo) throws IOException - { + public Object load(AssetInfo assetInfo) throws IOException { AndroidAudioData result = new AndroidAudioData(); - result.setAssetKey( assetInfo.getKey() ); + result.setAssetKey(assetInfo.getKey()); return result; } - } diff --git a/engine/src/android/com/jme3/input/android/AndroidInput.java b/engine/src/android/com/jme3/input/android/AndroidInput.java index ca1141d..9bbbe4e 100644 --- a/engine/src/android/com/jme3/input/android/AndroidInput.java +++ b/engine/src/android/com/jme3/input/android/AndroidInput.java @@ -1,619 +1,620 @@ -package com.jme3.input.android; - -import android.content.Context; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import com.jme3.input.KeyInput; -import com.jme3.input.RawInputListener; -import com.jme3.input.TouchInput; -import com.jme3.input.event.MouseButtonEvent; -import com.jme3.input.event.MouseMotionEvent; -import com.jme3.input.event.TouchEvent; -import com.jme3.input.event.TouchEvent.Type; -import com.jme3.math.Vector2f; -import com.jme3.util.RingBuffer; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * AndroidInput is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs - * @author larynx - * - */ -public class AndroidInput extends GLSurfaceView implements TouchInput, - GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener { - - final private static int MAX_EVENTS = 1024; - // Custom settings - public boolean mouseEventsEnabled = true; - public boolean mouseEventsInvertX = false; - public boolean mouseEventsInvertY = false; - public boolean keyboardEventsEnabled = false; - public boolean dontSendHistory = false; - // Used to transfer events from android thread to GLThread - final private RingBuffer eventQueue = new RingBuffer(MAX_EVENTS); - final private RingBuffer eventPoolUnConsumed = new RingBuffer(MAX_EVENTS); - final private RingBuffer eventPool = new RingBuffer(MAX_EVENTS); - final private HashMap lastPositions = new HashMap(); - // Internal - private ScaleGestureDetector scaledetector; - private GestureDetector detector; - private int lastX; - private int lastY; - private final static Logger logger = Logger.getLogger(AndroidInput.class.getName()); - private boolean isInitialized = false; - private RawInputListener listener = null; - private static final int[] ANDROID_TO_JME = { - 0x0, // unknown - 0x0, // key code soft left - 0x0, // key code soft right - KeyInput.KEY_HOME, - KeyInput.KEY_ESCAPE, // key back - 0x0, // key call - 0x0, // key endcall - KeyInput.KEY_0, - KeyInput.KEY_1, - KeyInput.KEY_2, - KeyInput.KEY_3, - KeyInput.KEY_4, - KeyInput.KEY_5, - KeyInput.KEY_6, - KeyInput.KEY_7, - KeyInput.KEY_8, - KeyInput.KEY_9, - KeyInput.KEY_MULTIPLY, - 0x0, // key pound - KeyInput.KEY_UP, - KeyInput.KEY_DOWN, - KeyInput.KEY_LEFT, - KeyInput.KEY_RIGHT, - KeyInput.KEY_RETURN, // dpad center - 0x0, // volume up - 0x0, // volume down - KeyInput.KEY_POWER, // power (?) - 0x0, // camera - 0x0, // clear - KeyInput.KEY_A, - KeyInput.KEY_B, - KeyInput.KEY_C, - KeyInput.KEY_D, - KeyInput.KEY_E, - KeyInput.KEY_F, - KeyInput.KEY_G, - KeyInput.KEY_H, - KeyInput.KEY_I, - KeyInput.KEY_J, - KeyInput.KEY_K, - KeyInput.KEY_L, - KeyInput.KEY_M, - KeyInput.KEY_N, - KeyInput.KEY_O, - KeyInput.KEY_P, - KeyInput.KEY_Q, - KeyInput.KEY_R, - KeyInput.KEY_S, - KeyInput.KEY_T, - KeyInput.KEY_U, - KeyInput.KEY_V, - KeyInput.KEY_W, - KeyInput.KEY_X, - KeyInput.KEY_Y, - KeyInput.KEY_Z, - KeyInput.KEY_COMMA, - KeyInput.KEY_PERIOD, - KeyInput.KEY_LMENU, - KeyInput.KEY_RMENU, - KeyInput.KEY_LSHIFT, - KeyInput.KEY_RSHIFT, - // 0x0, // fn - // 0x0, // cap (?) - - KeyInput.KEY_TAB, - KeyInput.KEY_SPACE, - 0x0, // sym (?) symbol - 0x0, // explorer - 0x0, // envelope - KeyInput.KEY_RETURN, // newline/enter - KeyInput.KEY_DELETE, - KeyInput.KEY_GRAVE, - KeyInput.KEY_MINUS, - KeyInput.KEY_EQUALS, - KeyInput.KEY_LBRACKET, - KeyInput.KEY_RBRACKET, - KeyInput.KEY_BACKSLASH, - KeyInput.KEY_SEMICOLON, - KeyInput.KEY_APOSTROPHE, - KeyInput.KEY_SLASH, - KeyInput.KEY_AT, // at (@) - KeyInput.KEY_NUMLOCK, //0x0, // num - 0x0, //headset hook - 0x0, //focus - KeyInput.KEY_ADD, - KeyInput.KEY_LMETA, //menu - 0x0,//notification - 0x0,//search - 0x0,//media play/pause - 0x0,//media stop - 0x0,//media next - 0x0,//media previous - 0x0,//media rewind - 0x0,//media fastforward - 0x0,//mute - }; - - public AndroidInput(Context ctx, AttributeSet attribs) { - super(ctx, attribs); - detector = new GestureDetector(null, this, null, false); - scaledetector = new ScaleGestureDetector(ctx, this); - - } - - public AndroidInput(Context ctx) { - super(ctx); - detector = new GestureDetector(null, this, null, false); - scaledetector = new ScaleGestureDetector(ctx, this); - } - - private TouchEvent getNextFreeTouchEvent() { - return getNextFreeTouchEvent(false); - } - - /** - * Fetches a touch event from the reuse pool - * @param wait if true waits for a reusable event to get available/released by an other thread, if false returns a new one if needed - * @return a usable TouchEvent - */ - private TouchEvent getNextFreeTouchEvent(boolean wait) { - TouchEvent evt = null; - synchronized (eventPoolUnConsumed) { - int size = eventPoolUnConsumed.size(); - while (size > 0) { - evt = eventPoolUnConsumed.pop(); - if (!evt.isConsumed()) { - eventPoolUnConsumed.push(evt); - evt = null; - } else { - break; - } - size--; - } - } - - - if (evt == null) { - if (eventPool.isEmpty() && wait) { - logger.warning("eventPool buffer underrun"); - boolean isEmpty; - do { - synchronized (eventPool) { - isEmpty = eventPool.isEmpty(); - } - try { - Thread.sleep(50); - } catch (InterruptedException e) { - } - } while (isEmpty); - synchronized (eventPool) { - evt = eventPool.pop(); - } - } else if (eventPool.isEmpty()) { - evt = new TouchEvent(); - logger.warning("eventPool buffer underrun"); - } else { - synchronized (eventPool) { - evt = eventPool.pop(); - } - } - } - return evt; - } - - /** - * onTouchEvent gets called from android thread on touchpad events - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean bWasHandled = false; - TouchEvent touch; - // System.out.println("native : " + event.getAction()); - int action = event.getAction() & MotionEvent.ACTION_MASK; - int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndex); - - // final int historySize = event.getHistorySize(); - //final int pointerCount = event.getPointerCount(); - - - switch (action) { - - case MotionEvent.ACTION_POINTER_DOWN: - case MotionEvent.ACTION_DOWN: - - - touch = getNextFreeTouchEvent(); - touch.set(Type.DOWN, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); - touch.setPointerId(pointerId); - touch.setTime(event.getEventTime()); - touch.setPressure(event.getPressure(pointerIndex)); - processEvent(touch); - - bWasHandled = true; - break; - - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - - touch = getNextFreeTouchEvent(); - touch.set(Type.UP, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); - touch.setPointerId(pointerId); - touch.setTime(event.getEventTime()); - touch.setPressure(event.getPressure(pointerIndex)); - processEvent(touch); - - - bWasHandled = true; - break; - case MotionEvent.ACTION_MOVE: - - - // Convert all pointers into events - for (int p = 0; p < event.getPointerCount(); p++) { - Vector2f lastPos = lastPositions.get(pointerIndex); - if (lastPos == null) { - lastPos = new Vector2f(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex)); - lastPositions.put(pointerId, lastPos); - } - touch = getNextFreeTouchEvent(); - touch.set(Type.MOVE, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), event.getX(pointerIndex) - lastPos.x, this.getHeight() - event.getY(pointerIndex) - lastPos.y); - touch.setPointerId(pointerId); - touch.setTime(event.getEventTime()); - touch.setPressure(event.getPressure(pointerIndex)); - processEvent(touch); - lastPos.set(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex)); - } - bWasHandled = true; - break; - - - case MotionEvent.ACTION_OUTSIDE: - break; - - } - - // Try to detect gestures - this.detector.onTouchEvent(event); - this.scaledetector.onTouchEvent(event); - - return bWasHandled; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - TouchEvent evt; - evt = getNextFreeTouchEvent(); - evt.set(TouchEvent.Type.KEY_DOWN); - evt.setKeyCode(keyCode); - evt.setCharacters(event.getCharacters()); - evt.setTime(event.getEventTime()); - - // Send the event - processEvent(evt); - - // Handle all keys ourself except Volume Up/Down - if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { - return false; - } else { - return true; - } - - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - TouchEvent evt; - evt = getNextFreeTouchEvent(); - evt.set(TouchEvent.Type.KEY_UP); - evt.setKeyCode(keyCode); - evt.setCharacters(event.getCharacters()); - evt.setTime(event.getEventTime()); - - // Send the event - processEvent(evt); - - // Handle all keys ourself except Volume Up/Down - if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { - return false; - } else { - return true; - } - } - - // ----------------------------------------- - // JME3 Input interface - @Override - public void initialize() { - TouchEvent item; - for (int i = 0; i < MAX_EVENTS; i++) { - item = new TouchEvent(); - eventPool.push(item); - } - isInitialized = true; - } - - @Override - public void destroy() { - isInitialized = false; - - // Clean up queues - while (!eventPool.isEmpty()) { - eventPool.pop(); - } - while (!eventQueue.isEmpty()) { - eventQueue.pop(); - } - } - - @Override - public boolean isInitialized() { - return isInitialized; - } - - @Override - public void setInputListener(RawInputListener listener) { - this.listener = listener; - } - - @Override - public long getInputTimeNanos() { - return System.nanoTime(); - } - // ----------------------------------------- - - private void processEvent(TouchEvent event) { - synchronized (eventQueue) { - eventQueue.push(event); - } - } - - // --------------- INSIDE GLThread --------------- - @Override - public void update() { - generateEvents(); - } - - private void generateEvents() { - if (listener != null) { - TouchEvent event; - MouseButtonEvent btn; - int newX; - int newY; - - while (!eventQueue.isEmpty()) { - synchronized (eventQueue) { - event = eventQueue.pop(); - } - if (event != null) { - listener.onTouchEvent(event); - - if (mouseEventsEnabled) { - if (mouseEventsInvertX) { - newX = this.getWidth() - (int) event.getX(); - } else { - newX = (int) event.getX(); - } - - if (mouseEventsInvertY) { - newY = this.getHeight() - (int) event.getY(); - } else { - newY = (int) event.getY(); - } - - switch (event.getType()) { - case DOWN: - // Handle mouse down event - btn = new MouseButtonEvent(0, true, newX, newY); - btn.setTime(event.getTime()); - listener.onMouseButtonEvent(btn); - // Store current pos - lastX = -1; - lastY = -1; - break; - - case UP: - // Handle mouse up event - btn = new MouseButtonEvent(0, false, newX, newY); - btn.setTime(event.getTime()); - listener.onMouseButtonEvent(btn); - // Store current pos - lastX = -1; - lastY = -1; - break; - - case MOVE: - int dx; - int dy; - if (lastX != -1) { - dx = newX - lastX; - dy = newY - lastY; - } else { - dx = 0; - dy = 0; - } - MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0); - mot.setTime(event.getTime()); - listener.onMouseMotionEvent(mot); - lastX = newX; - lastY = newY; - break; - } - - - } - } - - if (event.isConsumed() == false) { - synchronized (eventPoolUnConsumed) { - eventPoolUnConsumed.push(event); - } - - } else { - synchronized (eventPool) { - eventPool.push(event); - } - } - } - - } - } - // --------------- ENDOF INSIDE GLThread --------------- - - // --------------- Gesture detected callback events --------------- - public boolean onDown(MotionEvent event) { - return false; - } - - public void onLongPress(MotionEvent event) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.LONGPRESSED, event.getX(), this.getHeight() - event.getY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(event.getEventTime()); - processEvent(touch); - } - - public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.FLING, event.getX(), this.getHeight() - event.getY(), vx, vy); - touch.setPointerId(0); - touch.setTime(event.getEventTime()); - processEvent(touch); - - return true; - } - - public boolean onSingleTapConfirmed(MotionEvent event) { - //Nothing to do here the tap has already been detected. - return false; - } - - public boolean onDoubleTap(MotionEvent event) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.DOUBLETAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(event.getEventTime()); - processEvent(touch); - return true; - } - - public boolean onDoubleTapEvent(MotionEvent event) { - return false; - } - - public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(scaleGestureDetector.getEventTime()); - touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); - touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); - processEvent(touch); - // System.out.println("scaleBegin"); - - return true; - } - - public boolean onScale(ScaleGestureDetector scaleGestureDetector) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(scaleGestureDetector.getEventTime()); - touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); - touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); - processEvent(touch); - // System.out.println("scale"); - - return false; - } - - public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(scaleGestureDetector.getEventTime()); - touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); - touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); - processEvent(touch); - } - - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCROLL, e1.getX(), this.getHeight() - e1.getY(), distanceX, distanceY * (-1)); - touch.setPointerId(0); - touch.setTime(e1.getEventTime()); - processEvent(touch); - //System.out.println("scroll " + e1.getPointerCount()); - return false; - } - - public void onShowPress(MotionEvent event) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SHOWPRESS, event.getX(), this.getHeight() - event.getY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(event.getEventTime()); - processEvent(touch); - } - - public boolean onSingleTapUp(MotionEvent event) { - TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.TAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); - touch.setPointerId(0); - touch.setTime(event.getEventTime()); - processEvent(touch); - return true; - } - - @Override - public void setSimulateMouse(boolean simulate) { - mouseEventsEnabled = simulate; - } - - @Override - public void setSimulateKeyboard(boolean simulate) { - keyboardEventsEnabled = simulate; - } - - @Override - public void setOmitHistoricEvents(boolean dontSendHistory) { - this.dontSendHistory = dontSendHistory; - } - - // TODO: move to TouchInput - public boolean isMouseEventsEnabled() { - return mouseEventsEnabled; - } - - public void setMouseEventsEnabled(boolean mouseEventsEnabled) { - this.mouseEventsEnabled = mouseEventsEnabled; - } - - public boolean isMouseEventsInvertY() { - return mouseEventsInvertY; - } - - public void setMouseEventsInvertY(boolean mouseEventsInvertY) { - this.mouseEventsInvertY = mouseEventsInvertY; - } - - public boolean isMouseEventsInvertX() { - return mouseEventsInvertX; - } - - public void setMouseEventsInvertX(boolean mouseEventsInvertX) { - this.mouseEventsInvertX = mouseEventsInvertX; - } -} +package com.jme3.input.android; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import com.jme3.input.KeyInput; +import com.jme3.input.RawInputListener; +import com.jme3.input.TouchInput; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.event.TouchEvent.Type; +import com.jme3.math.Vector2f; +import com.jme3.util.RingBuffer; +import java.util.HashMap; +import java.util.logging.Logger; + +/** + * AndroidInput is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs + * @author larynx + * + */ +public class AndroidInput extends GLSurfaceView implements + TouchInput, + GestureDetector.OnGestureListener, + GestureDetector.OnDoubleTapListener, + ScaleGestureDetector.OnScaleGestureListener { + + final private static int MAX_EVENTS = 1024; + // Custom settings + public boolean mouseEventsEnabled = true; + public boolean mouseEventsInvertX = false; + public boolean mouseEventsInvertY = false; + public boolean keyboardEventsEnabled = false; + public boolean dontSendHistory = false; + // Used to transfer events from android thread to GLThread + final private RingBuffer eventQueue = new RingBuffer(MAX_EVENTS); + final private RingBuffer eventPoolUnConsumed = new RingBuffer(MAX_EVENTS); + final private RingBuffer eventPool = new RingBuffer(MAX_EVENTS); + final private HashMap lastPositions = new HashMap(); + // Internal + private ScaleGestureDetector scaledetector; + private GestureDetector detector; + private int lastX; + private int lastY; + private final static Logger logger = Logger.getLogger(AndroidInput.class.getName()); + private boolean isInitialized = false; + private RawInputListener listener = null; + private static final int[] ANDROID_TO_JME = { + 0x0, // unknown + 0x0, // key code soft left + 0x0, // key code soft right + KeyInput.KEY_HOME, + KeyInput.KEY_ESCAPE, // key back + 0x0, // key call + 0x0, // key endcall + KeyInput.KEY_0, + KeyInput.KEY_1, + KeyInput.KEY_2, + KeyInput.KEY_3, + KeyInput.KEY_4, + KeyInput.KEY_5, + KeyInput.KEY_6, + KeyInput.KEY_7, + KeyInput.KEY_8, + KeyInput.KEY_9, + KeyInput.KEY_MULTIPLY, + 0x0, // key pound + KeyInput.KEY_UP, + KeyInput.KEY_DOWN, + KeyInput.KEY_LEFT, + KeyInput.KEY_RIGHT, + KeyInput.KEY_RETURN, // dpad center + 0x0, // volume up + 0x0, // volume down + KeyInput.KEY_POWER, // power (?) + 0x0, // camera + 0x0, // clear + KeyInput.KEY_A, + KeyInput.KEY_B, + KeyInput.KEY_C, + KeyInput.KEY_D, + KeyInput.KEY_E, + KeyInput.KEY_F, + KeyInput.KEY_G, + KeyInput.KEY_H, + KeyInput.KEY_I, + KeyInput.KEY_J, + KeyInput.KEY_K, + KeyInput.KEY_L, + KeyInput.KEY_M, + KeyInput.KEY_N, + KeyInput.KEY_O, + KeyInput.KEY_P, + KeyInput.KEY_Q, + KeyInput.KEY_R, + KeyInput.KEY_S, + KeyInput.KEY_T, + KeyInput.KEY_U, + KeyInput.KEY_V, + KeyInput.KEY_W, + KeyInput.KEY_X, + KeyInput.KEY_Y, + KeyInput.KEY_Z, + KeyInput.KEY_COMMA, + KeyInput.KEY_PERIOD, + KeyInput.KEY_LMENU, + KeyInput.KEY_RMENU, + KeyInput.KEY_LSHIFT, + KeyInput.KEY_RSHIFT, + // 0x0, // fn + // 0x0, // cap (?) + + KeyInput.KEY_TAB, + KeyInput.KEY_SPACE, + 0x0, // sym (?) symbol + 0x0, // explorer + 0x0, // envelope + KeyInput.KEY_RETURN, // newline/enter + KeyInput.KEY_DELETE, + KeyInput.KEY_GRAVE, + KeyInput.KEY_MINUS, + KeyInput.KEY_EQUALS, + KeyInput.KEY_LBRACKET, + KeyInput.KEY_RBRACKET, + KeyInput.KEY_BACKSLASH, + KeyInput.KEY_SEMICOLON, + KeyInput.KEY_APOSTROPHE, + KeyInput.KEY_SLASH, + KeyInput.KEY_AT, // at (@) + KeyInput.KEY_NUMLOCK, //0x0, // num + 0x0, //headset hook + 0x0, //focus + KeyInput.KEY_ADD, + KeyInput.KEY_LMETA, //menu + 0x0,//notification + 0x0,//search + 0x0,//media play/pause + 0x0,//media stop + 0x0,//media next + 0x0,//media previous + 0x0,//media rewind + 0x0,//media fastforward + 0x0,//mute + }; + + public AndroidInput(Context ctx, AttributeSet attribs) { + super(ctx, attribs); + detector = new GestureDetector(null, this, null, false); + scaledetector = new ScaleGestureDetector(ctx, this); + + } + + public AndroidInput(Context ctx) { + super(ctx); + detector = new GestureDetector(null, this, null, false); + scaledetector = new ScaleGestureDetector(ctx, this); + } + + private TouchEvent getNextFreeTouchEvent() { + return getNextFreeTouchEvent(false); + } + + /** + * Fetches a touch event from the reuse pool + * @param wait if true waits for a reusable event to get available/released + * by an other thread, if false returns a new one if needed. + * + * @return a usable TouchEvent + */ + private TouchEvent getNextFreeTouchEvent(boolean wait) { + TouchEvent evt = null; + synchronized (eventPoolUnConsumed) { + int size = eventPoolUnConsumed.size(); + while (size > 0) { + evt = eventPoolUnConsumed.pop(); + if (!evt.isConsumed()) { + eventPoolUnConsumed.push(evt); + evt = null; + } else { + break; + } + size--; + } + } + + if (evt == null) { + if (eventPool.isEmpty() && wait) { + logger.warning("eventPool buffer underrun"); + boolean isEmpty; + do { + synchronized (eventPool) { + isEmpty = eventPool.isEmpty(); + } + try { + Thread.sleep(50); + } catch (InterruptedException e) { + } + } while (isEmpty); + synchronized (eventPool) { + evt = eventPool.pop(); + } + } else if (eventPool.isEmpty()) { + evt = new TouchEvent(); + logger.warning("eventPool buffer underrun"); + } else { + synchronized (eventPool) { + evt = eventPool.pop(); + } + } + } + return evt; + } + + /** + * onTouchEvent gets called from android thread on touchpad events + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean bWasHandled = false; + TouchEvent touch; + // System.out.println("native : " + event.getAction()); + int action = event.getAction() & MotionEvent.ACTION_MASK; + int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + int pointerId = event.getPointerId(pointerIndex); + + // final int historySize = event.getHistorySize(); + //final int pointerCount = event.getPointerCount(); + + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_DOWN: + touch = getNextFreeTouchEvent(); + touch.set(Type.DOWN, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); + touch.setPointerId(pointerId); + touch.setTime(event.getEventTime()); + touch.setPressure(event.getPressure(pointerIndex)); + processEvent(touch); + + bWasHandled = true; + break; + + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + + touch = getNextFreeTouchEvent(); + touch.set(Type.UP, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); + touch.setPointerId(pointerId); + touch.setTime(event.getEventTime()); + touch.setPressure(event.getPressure(pointerIndex)); + processEvent(touch); + + + bWasHandled = true; + break; + case MotionEvent.ACTION_MOVE: + + + // Convert all pointers into events + for (int p = 0; p < event.getPointerCount(); p++) { + Vector2f lastPos = lastPositions.get(pointerIndex); + if (lastPos == null) { + lastPos = new Vector2f(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex)); + lastPositions.put(pointerId, lastPos); + } + touch = getNextFreeTouchEvent(); + touch.set(Type.MOVE, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), event.getX(pointerIndex) - lastPos.x, this.getHeight() - event.getY(pointerIndex) - lastPos.y); + touch.setPointerId(pointerId); + touch.setTime(event.getEventTime()); + touch.setPressure(event.getPressure(pointerIndex)); + processEvent(touch); + lastPos.set(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex)); + } + bWasHandled = true; + break; + case MotionEvent.ACTION_OUTSIDE: + break; + + } + + // Try to detect gestures + this.detector.onTouchEvent(event); + this.scaledetector.onTouchEvent(event); + + return bWasHandled; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + TouchEvent evt; + evt = getNextFreeTouchEvent(); + evt.set(TouchEvent.Type.KEY_DOWN); + evt.setKeyCode(keyCode); + evt.setCharacters(event.getCharacters()); + evt.setTime(event.getEventTime()); + + // Send the event + processEvent(evt); + + // Handle all keys ourself except Volume Up/Down + if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { + return false; + } else { + return true; + } + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + TouchEvent evt; + evt = getNextFreeTouchEvent(); + evt.set(TouchEvent.Type.KEY_UP); + evt.setKeyCode(keyCode); + evt.setCharacters(event.getCharacters()); + evt.setTime(event.getEventTime()); + + // Send the event + processEvent(evt); + + // Handle all keys ourself except Volume Up/Down + if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) { + return false; + } else { + return true; + } + } + + // ----------------------------------------- + // JME3 Input interface + @Override + public void initialize() { + TouchEvent item; + for (int i = 0; i < MAX_EVENTS; i++) { + item = new TouchEvent(); + eventPool.push(item); + } + isInitialized = true; + } + + @Override + public void destroy() { + isInitialized = false; + + // Clean up queues + while (!eventPool.isEmpty()) { + eventPool.pop(); + } + while (!eventQueue.isEmpty()) { + eventQueue.pop(); + } + } + + @Override + public boolean isInitialized() { + return isInitialized; + } + + @Override + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + @Override + public long getInputTimeNanos() { + return System.nanoTime(); + } + // ----------------------------------------- + + private void processEvent(TouchEvent event) { + synchronized (eventQueue) { + eventQueue.push(event); + } + } + + // --------------- INSIDE GLThread --------------- + @Override + public void update() { + generateEvents(); + } + + private void generateEvents() { + if (listener != null) { + TouchEvent event; + MouseButtonEvent btn; + int newX; + int newY; + + while (!eventQueue.isEmpty()) { + synchronized (eventQueue) { + event = eventQueue.pop(); + } + if (event != null) { + listener.onTouchEvent(event); + + if (mouseEventsEnabled) { + if (mouseEventsInvertX) { + newX = this.getWidth() - (int) event.getX(); + } else { + newX = (int) event.getX(); + } + + if (mouseEventsInvertY) { + newY = this.getHeight() - (int) event.getY(); + } else { + newY = (int) event.getY(); + } + + switch (event.getType()) { + case DOWN: + // Handle mouse down event + btn = new MouseButtonEvent(0, true, newX, newY); + btn.setTime(event.getTime()); + listener.onMouseButtonEvent(btn); + // Store current pos + lastX = -1; + lastY = -1; + break; + + case UP: + // Handle mouse up event + btn = new MouseButtonEvent(0, false, newX, newY); + btn.setTime(event.getTime()); + listener.onMouseButtonEvent(btn); + // Store current pos + lastX = -1; + lastY = -1; + break; + + case MOVE: + int dx; + int dy; + if (lastX != -1) { + dx = newX - lastX; + dy = newY - lastY; + } else { + dx = 0; + dy = 0; + } + MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0); + mot.setTime(event.getTime()); + listener.onMouseMotionEvent(mot); + lastX = newX; + lastY = newY; + break; + } + + + } + } + + if (event.isConsumed() == false) { + synchronized (eventPoolUnConsumed) { + eventPoolUnConsumed.push(event); + } + + } else { + synchronized (eventPool) { + eventPool.push(event); + } + } + } + + } + } + // --------------- ENDOF INSIDE GLThread --------------- + + // --------------- Gesture detected callback events --------------- + public boolean onDown(MotionEvent event) { + return false; + } + + public void onLongPress(MotionEvent event) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.LONGPRESSED, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(event.getEventTime()); + processEvent(touch); + } + + public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.FLING, event.getX(), this.getHeight() - event.getY(), vx, vy); + touch.setPointerId(0); + touch.setTime(event.getEventTime()); + processEvent(touch); + + return true; + } + + public boolean onSingleTapConfirmed(MotionEvent event) { + //Nothing to do here the tap has already been detected. + return false; + } + + public boolean onDoubleTap(MotionEvent event) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.DOUBLETAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(event.getEventTime()); + processEvent(touch); + return true; + } + + public boolean onDoubleTapEvent(MotionEvent event) { + return false; + } + + public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(scaleGestureDetector.getEventTime()); + touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); + touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); + processEvent(touch); + // System.out.println("scaleBegin"); + + return true; + } + + public boolean onScale(ScaleGestureDetector scaleGestureDetector) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(scaleGestureDetector.getEventTime()); + touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); + touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); + processEvent(touch); + // System.out.println("scale"); + + return false; + } + + public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(scaleGestureDetector.getEventTime()); + touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); + touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); + processEvent(touch); + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.SCROLL, e1.getX(), this.getHeight() - e1.getY(), distanceX, distanceY * (-1)); + touch.setPointerId(0); + touch.setTime(e1.getEventTime()); + processEvent(touch); + //System.out.println("scroll " + e1.getPointerCount()); + return false; + } + + public void onShowPress(MotionEvent event) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.SHOWPRESS, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(event.getEventTime()); + processEvent(touch); + } + + public boolean onSingleTapUp(MotionEvent event) { + TouchEvent touch = getNextFreeTouchEvent(); + touch.set(Type.TAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.setPointerId(0); + touch.setTime(event.getEventTime()); + processEvent(touch); + return true; + } + + @Override + public void setSimulateMouse(boolean simulate) { + mouseEventsEnabled = simulate; + } + @Override + public boolean getSimulateMouse() { + return mouseEventsEnabled; + } + + @Override + public void setSimulateKeyboard(boolean simulate) { + keyboardEventsEnabled = simulate; + } + + @Override + public void setOmitHistoricEvents(boolean dontSendHistory) { + this.dontSendHistory = dontSendHistory; + } + + // TODO: move to TouchInput + public boolean isMouseEventsEnabled() { + return mouseEventsEnabled; + } + + public void setMouseEventsEnabled(boolean mouseEventsEnabled) { + this.mouseEventsEnabled = mouseEventsEnabled; + } + + public boolean isMouseEventsInvertY() { + return mouseEventsInvertY; + } + + public void setMouseEventsInvertY(boolean mouseEventsInvertY) { + this.mouseEventsInvertY = mouseEventsInvertY; + } + + public boolean isMouseEventsInvertX() { + return mouseEventsInvertX; + } + + public void setMouseEventsInvertX(boolean mouseEventsInvertX) { + this.mouseEventsInvertX = mouseEventsInvertX; + } +} diff --git a/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java b/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java index 34e4592..c8b2228 100644 --- a/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java +++ b/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java @@ -6,14 +6,17 @@ import com.jme3.input.RawInputListener; import com.jme3.input.event.TouchEvent; /** - * AndroidTouchInputListener is an inputlistener interface which defines callbacks/events for android touch screens - * For use with class AndroidInput + * AndroidTouchInputListener is an inputlistener interface which defines + * callbacks/events for android touch screens For use with class AndroidInput + * * @author larynx * */ -public interface AndroidTouchInputListener extends RawInputListener -{ +public interface AndroidTouchInputListener extends RawInputListener { + public void onTouchEvent(TouchEvent evt); + public void onMotionEvent(MotionEvent evt); + public void onAndroidKeyEvent(KeyEvent evt); } diff --git a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java index b5a8c14..7e7af29 100644 --- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java @@ -31,9 +31,7 @@ */ package com.jme3.renderer.android; -import android.graphics.Bitmap; import android.opengl.GLES10; -import android.opengl.GLES11; import android.opengl.GLES20; import android.os.Build; import com.jme3.asset.AndroidImageInfo; @@ -60,14 +58,11 @@ import com.jme3.texture.Texture.WrapAxis; import com.jme3.util.BufferUtils; import com.jme3.util.ListMap; import com.jme3.util.NativeObjectManager; -import com.jme3.util.SafeArrayList; import java.nio.*; -import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.microedition.khronos.opengles.GL10; public class OGLESShaderRenderer implements Renderer { @@ -360,25 +355,10 @@ public class OGLESShaderRenderer implements Renderer { } applyRenderState(RenderState.DEFAULT); -// GLES20.glClearDepthf(1.0f); - - if (verboseLogging) { - logger.info("GLES20.glDisable(GL10.GL_DITHER)"); - } - - GLES20.glDisable(GL10.GL_DITHER); + GLES20.glDisable(GLES20.GL_DITHER); checkGLError(); - if (verboseLogging) { - logger.info("GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST)"); - } - - //It seems that GL10.GL_PERSPECTIVE_CORRECTION_HINT gives invalid_enum error on android. -// GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); - -// checkGLError(); - useVBO = false; // NOTE: SDK_INT is only available since 1.6, @@ -1779,10 +1759,8 @@ public class OGLESShaderRenderer implements Renderer { private int convertWrapMode(Texture.WrapMode mode) { switch (mode) { -// case BorderClamp: -// return GLES20.GL_CLAMP_TO_BORDER; -// case Clamp: -// return GLES20.GL_CLAMP; + case BorderClamp: + case Clamp: case EdgeClamp: return GLES20.GL_CLAMP_TO_EDGE; case Repeat: @@ -2557,7 +2535,7 @@ public class OGLESShaderRenderer implements Renderer { logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount}); } - GLES11.glDrawElements( + GLES20.glDrawElements( convertElementMode(mesh.getMode()), indexBuf.getData().capacity(), convertFormat(indexBuf.getFormat()), diff --git a/engine/src/android/com/jme3/renderer/android/TextureUtil.java b/engine/src/android/com/jme3/renderer/android/TextureUtil.java index 53b96b4..4a60d6b 100644 --- a/engine/src/android/com/jme3/renderer/android/TextureUtil.java +++ b/engine/src/android/com/jme3/renderer/android/TextureUtil.java @@ -70,7 +70,7 @@ public class TextureUtil { width /= 2; Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); - bitmap.recycle(); + //bitmap.recycle(); bitmap = bitmap2; } } @@ -94,7 +94,7 @@ public class TextureUtil { width = FastMath.nearestPowerOfTwo(width); height = FastMath.nearestPowerOfTwo(height); Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); - bitmap.recycle(); + //bitmap.recycle(); bitmap = bitmap2; } } diff --git a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java index e55fa55..56ed415 100644 --- a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java +++ b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java @@ -2,6 +2,7 @@ package com.jme3.system.android; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView.EGLConfigChooser; +import java.util.logging.Level; import java.util.logging.Logger; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -9,26 +10,23 @@ import javax.microedition.khronos.egl.EGLDisplay; /** * AndroidConfigChooser is used to determine the best suited EGL Config - * @author larynx * + * @author larynx */ -public class AndroidConfigChooser implements EGLConfigChooser -{ +public class AndroidConfigChooser implements EGLConfigChooser { + private static final Logger logger = Logger.getLogger(AndroidConfigChooser.class.getName()); - protected int clientOpenGLESVersion = 0; protected EGLConfig bestConfig = null; protected EGLConfig fastestConfig = null; protected EGLConfig choosenConfig = null; protected ConfigType type; protected int pixelFormat; - protected boolean verbose = false; - private final static int EGL_OPENGL_ES2_BIT = 4; - public enum ConfigType - { + public enum ConfigType { + /** * RGB565, 0 alpha, 16 depth, 0 stencil */ @@ -39,94 +37,79 @@ public class AndroidConfigChooser implements EGLConfigChooser BEST, /** * Turn off config chooser and use hardcoded - * setEGLContextClientVersion(2); - * setEGLConfigChooser(5, 6, 5, 0, 16, 0); + * setEGLContextClientVersion(2); setEGLConfigChooser(5, 6, 5, 0, 16, + * 0); */ LEGACY } - - public AndroidConfigChooser(ConfigType type, boolean verbose) - { + + public AndroidConfigChooser(ConfigType type) { this.type = type; - this.verbose = verbose; } - + /** * Gets called by the GLSurfaceView class to return the best config - */ + */ @Override - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) - { + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { logger.info("GLSurfaceView asks for egl config, returning: "); logEGLConfig(choosenConfig, display, egl); return choosenConfig; } - + /** * findConfig is used to locate the best config and init the chooser with + * * @param egl * @param display * @return true if successfull, false if no config was found */ - public boolean findConfig(EGL10 egl, EGLDisplay display) - { - - if (type == ConfigType.BEST) - { - ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0); - choosenConfig = compChooser.chooseConfig(egl, display); + public boolean findConfig(EGL10 egl, EGLDisplay display) { + + if (type == ConfigType.BEST) { + ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0); + choosenConfig = compChooser.chooseConfig(egl, display); - if (choosenConfig == null) - { + if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 0, 32, 0); choosenConfig = compChooser.chooseConfig(egl, display); - if (choosenConfig == null) - { + if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 8, 16, 0); choosenConfig = compChooser.chooseConfig(egl, display); - if (choosenConfig == null) - { + if (choosenConfig == null) { compChooser = new ComponentSizeChooser(8, 8, 8, 0, 16, 0); choosenConfig = compChooser.chooseConfig(egl, display); } } - } - + } + logger.info("JME3 using best EGL configuration available here: "); - } - else - { - ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0); - choosenConfig = compChooser.chooseConfig(egl, display); + } else { + ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0); + choosenConfig = compChooser.chooseConfig(egl, display); logger.info("JME3 using fastest EGL configuration available here: "); } - - if (choosenConfig != null) - { - logger.info("JME3 using choosen config: "); - logEGLConfig(choosenConfig, display, egl); + + if (choosenConfig != null) { + logger.info("JME3 using choosen config: "); + logEGLConfig(choosenConfig, display, egl); pixelFormat = getPixelFormat(choosenConfig, display, egl); clientOpenGLESVersion = getOpenGLVersion(choosenConfig, display, egl); return true; - } - else - { + } else { 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; - } + } } - - - private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) - { + + private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; - int result = PixelFormat.RGB_565; + int result = PixelFormat.RGB_565; egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); - if (value[0] == 8) - { + if (value[0] == 8) { result = PixelFormat.RGBA_8888; /* egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); @@ -139,165 +122,163 @@ public class AndroidConfigChooser implements EGLConfigChooser result = PixelFormat.RGB_888; }*/ } - - if (verbose) - { - logger.info("Using PixelFormat " + result); + + if (verbose) { + logger.log(Level.INFO, "Using PixelFormat {0}", result); } - + //return result; TODO Test pixelformat return PixelFormat.TRANSPARENT; } - - private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) - { + + private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; int result = 1; - + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); // Check if conf is OpenGL ES 2.0 - if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) - { + if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) { result = 2; } - return result; + return result; } - + /** * log output with egl config details + * * @param conf * @param display * @param egl */ - public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) - { + public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) { int[] value = new int[1]; egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value); - logger.info(String.format("EGL_RED_SIZE = %d", value[0] ) ); - + logger.info(String.format("EGL_RED_SIZE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value); - logger.info(String.format("EGL_GREEN_SIZE = %d", value[0] ) ); - + logger.info(String.format("EGL_GREEN_SIZE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value); - logger.info(String.format("EGL_BLUE_SIZE = %d", value[0] ) ); - + logger.info(String.format("EGL_BLUE_SIZE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value); - logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0] ) ); - + logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value); - logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0] ) ); - + logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value); - logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0] ) ); + logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0])); egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value); - logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0] ) ); - + logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0])); + egl.eglGetConfigAttrib(display, conf, EGL10.EGL_SURFACE_TYPE, value); - logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0] ) ); + logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0])); } - - public int getClientOpenGLESVersion() - { + + public int getClientOpenGLESVersion() { return clientOpenGLESVersion; } - public void setClientOpenGLESVersion(int clientOpenGLESVersion) - { + public void setClientOpenGLESVersion(int clientOpenGLESVersion) { this.clientOpenGLESVersion = clientOpenGLESVersion; } - - public int getPixelFormat() - { + + public int getPixelFormat() { return pixelFormat; } - - - - private abstract class BaseConfigChooser implements EGLConfigChooser - { + + private abstract class BaseConfigChooser implements EGLConfigChooser { + private boolean bClientOpenGLESVersionSet; - - public BaseConfigChooser(int[] configSpec) - { - bClientOpenGLESVersionSet = false; - mConfigSpec = filterConfigSpec(configSpec); - } - - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) - { - int[] num_config = new int[1]; - if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, - num_config)) { - throw new IllegalArgumentException("eglChooseConfig failed"); - } - - int numConfigs = num_config[0]; - - if (numConfigs <= 0) - { - //throw new IllegalArgumentException("No configs match configSpec"); - - return null; - } - - EGLConfig[] configs = new EGLConfig[numConfigs]; - if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, - num_config)) { - throw new IllegalArgumentException("eglChooseConfig#2 failed"); - } - EGLConfig config = chooseConfig(egl, display, configs); - //if (config == null) { - // throw new IllegalArgumentException("No config chosen"); - //} - return config; - } - - abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, - EGLConfig[] configs); - - protected int[] mConfigSpec; - - private int[] filterConfigSpec(int[] configSpec) - { - if (bClientOpenGLESVersionSet == true) { - return configSpec; - } - /* We know none of the subclasses define EGL_RENDERABLE_TYPE. - * And we know the configSpec is well formed. - */ - int len = configSpec.length; - int[] newConfigSpec = new int[len + 2]; - System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1); - newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE; - newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */ - newConfigSpec[len+1] = EGL10.EGL_NONE; - - bClientOpenGLESVersionSet = true; - - return newConfigSpec; - } + + public BaseConfigChooser(int[] configSpec) { + bClientOpenGLESVersionSet = false; + mConfigSpec = filterConfigSpec(configSpec); + } + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + int[] num_config = new int[1]; + if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, + num_config)) { + throw new IllegalArgumentException("eglChooseConfig failed"); + } + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + //throw new IllegalArgumentException("No configs match configSpec"); + + return null; + } + + EGLConfig[] configs = new EGLConfig[numConfigs]; + if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, + num_config)) { + throw new IllegalArgumentException("eglChooseConfig#2 failed"); + } + EGLConfig config = chooseConfig(egl, display, configs); + //if (config == null) { + // throw new IllegalArgumentException("No config chosen"); + //} + return config; + } + + abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs); + protected int[] mConfigSpec; + + private int[] filterConfigSpec(int[] configSpec) { + if (bClientOpenGLESVersionSet == true) { + return configSpec; + } + /* + * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we + * know the configSpec is well formed. + */ + int len = configSpec.length; + int[] newConfigSpec = new int[len + 2]; + System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1); + newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE; + newConfigSpec[len] = 4; /* + * EGL_OPENGL_ES2_BIT + */ + newConfigSpec[len + 1] = EGL10.EGL_NONE; + + bClientOpenGLESVersionSet = true; + + return newConfigSpec; + } } - + /** - * Choose a configuration with exactly the specified r,g,b,a sizes, - * and at least the specified depth and stencil sizes. + * Choose a configuration with exactly the specified r,g,b,a sizes, and at + * least the specified depth and stencil sizes. */ - private class ComponentSizeChooser extends BaseConfigChooser - { + private class ComponentSizeChooser extends BaseConfigChooser { + + private int[] mValue; + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + public ComponentSizeChooser(int redSize, int greenSize, int blueSize, - int alphaSize, int depthSize, int stencilSize) - { - super(new int[] { - EGL10.EGL_RED_SIZE, redSize, - EGL10.EGL_GREEN_SIZE, greenSize, - EGL10.EGL_BLUE_SIZE, blueSize, - EGL10.EGL_ALPHA_SIZE, alphaSize, - EGL10.EGL_DEPTH_SIZE, depthSize, - EGL10.EGL_STENCIL_SIZE, stencilSize, - EGL10.EGL_NONE}); + int alphaSize, int depthSize, int stencilSize) { + super(new int[]{ + EGL10.EGL_RED_SIZE, redSize, + EGL10.EGL_GREEN_SIZE, greenSize, + EGL10.EGL_BLUE_SIZE, blueSize, + EGL10.EGL_ALPHA_SIZE, alphaSize, + EGL10.EGL_DEPTH_SIZE, depthSize, + EGL10.EGL_STENCIL_SIZE, stencilSize, + EGL10.EGL_NONE}); mValue = new int[1]; mRedSize = redSize; mGreenSize = greenSize; @@ -305,25 +286,22 @@ public class AndroidConfigChooser implements EGLConfigChooser mAlphaSize = alphaSize; mDepthSize = depthSize; mStencilSize = stencilSize; - } + } @Override - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) - { - for (EGLConfig config : configs) - { + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { + for (EGLConfig config : configs) { int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); - if ((d >= mDepthSize) && (s >= mStencilSize)) - { + if ((d >= mDepthSize) && (s >= mStencilSize)) { int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); int g = findConfigAttrib(egl, display, config, - EGL10.EGL_GREEN_SIZE, 0); + EGL10.EGL_GREEN_SIZE, 0); int b = findConfigAttrib(egl, display, config, - EGL10.EGL_BLUE_SIZE, 0); + EGL10.EGL_BLUE_SIZE, 0); int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); if ((r == mRedSize) && (g == mGreenSize) @@ -336,27 +314,12 @@ public class AndroidConfigChooser implements EGLConfigChooser } private int findConfigAttrib(EGL10 egl, EGLDisplay display, - EGLConfig config, int attribute, int defaultValue) - { + EGLConfig config, int attribute, int defaultValue) { - if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) - { + if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { return mValue[0]; } return defaultValue; } - - private int[] mValue; - // Subclasses can adjust these values: - protected int mRedSize; - protected int mGreenSize; - protected int mBlueSize; - protected int mAlphaSize; - protected int mDepthSize; - protected int mStencilSize; } - - - - } diff --git a/engine/src/android/com/jme3/system/android/OGLESContext.java b/engine/src/android/com/jme3/system/android/OGLESContext.java index 668b68d..1ecf2e1 100644 --- a/engine/src/android/com/jme3/system/android/OGLESContext.java +++ b/engine/src/android/com/jme3/system/android/OGLESContext.java @@ -32,26 +32,37 @@ package com.jme3.system.android; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.opengl.GLSurfaceView; +import android.text.InputType; +import android.view.Gravity; import android.view.SurfaceHolder; +import android.view.ViewGroup.LayoutParams; +import android.widget.EditText; +import android.widget.FrameLayout; import com.jme3.app.AndroidHarness; import com.jme3.app.Application; import com.jme3.input.JoyInput; import com.jme3.input.KeyInput; import com.jme3.input.MouseInput; +import com.jme3.input.SoftTextDialogInput; import com.jme3.input.TouchInput; import com.jme3.input.android.AndroidInput; +import com.jme3.input.controls.SoftTextDialogInputListener; import com.jme3.input.controls.TouchTrigger; import com.jme3.input.dummy.DummyKeyInput; import com.jme3.input.dummy.DummyMouseInput; import com.jme3.renderer.android.OGLESShaderRenderer; import com.jme3.system.AppSettings; import com.jme3.system.JmeContext; +import com.jme3.system.JmeSystem; import com.jme3.system.SystemListener; import com.jme3.system.Timer; import com.jme3.system.android.AndroidConfigChooser.ConfigType; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; import java.util.logging.Logger; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -59,7 +70,7 @@ import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; -public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { +public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTextDialogInput { private static final Logger logger = Logger.getLogger(OGLESContext.class.getName()); protected final AtomicBoolean created = new AtomicBoolean(false); @@ -76,7 +87,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { protected boolean autoFlush = true; protected AndroidInput view; private boolean firstDrawFrame = true; - //protected int minFrameDuration = 1000 / frameRate; // Set a max FPS of 33 protected int minFrameDuration = 0; // No FPS cap /** @@ -145,12 +155,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { int[] version = new int[2]; if (egl.eglInitialize(display, version) == true) { - logger.info("Display EGL Version: " + version[0] + "." + version[1]); + logger.log(Level.INFO, "Display EGL Version: {0}.{1}", new Object[]{version[0], version[1]}); } try { // Create a config chooser - AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging); + AndroidConfigChooser configChooser = new AndroidConfigChooser(configType); // Init chooser if (!configChooser.findConfig(egl, display)) { listener.handleError("Unable to find suitable EGL config", null); @@ -162,7 +172,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { listener.handleError("OpenGL ES 2.0 is not supported on this device", null); return null; } - + // Requesting client version from GLSurfaceView which is extended by // AndroidInput. view.setEGLContextClientVersion(clientOpenGLESVersion); @@ -210,12 +220,14 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { // Setup unhandled Exception Handler if (ctx instanceof AndroidHarness) { Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread thread, Throwable thrown) { ((AndroidHarness) ctx).handleError("Exception thrown in " + thread.toString(), thrown); } }); } else { Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + public void uncaughtException(Thread thread, Throwable thrown) { listener.handleError("Exception thrown in " + thread.toString(), thrown); } @@ -244,6 +256,8 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { } } + JmeSystem.setSoftTextDialogInput(this); + needClose.set(false); renderable.set(true); } @@ -268,6 +282,13 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { logger.info("Display destroyed."); renderable.set(false); + final Context ctx = this.view.getContext(); + if (ctx instanceof AndroidHarness) { + AndroidHarness harness = (AndroidHarness) ctx; + if (harness.isFinishOnAppStop()) { + harness.finish(); + } + } } } @@ -442,4 +463,67 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { public int getClientOpenGLESVersion() { return clientOpenGLESVersion; } + + public void requestDialog(final int id, final String title, final String initialValue, final SoftTextDialogInputListener listener) { + logger.log(Level.INFO, "requestDialog: title: {0}, initialValue: {1}", + new Object[]{title, initialValue}); + + JmeAndroidSystem.getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + + final FrameLayout layoutTextDialogInput = new FrameLayout(JmeAndroidSystem.getActivity()); + final EditText editTextDialogInput = new EditText(JmeAndroidSystem.getActivity()); + editTextDialogInput.setWidth(LayoutParams.FILL_PARENT); + editTextDialogInput.setHeight(LayoutParams.FILL_PARENT); + editTextDialogInput.setPadding(20, 20, 20, 20); + editTextDialogInput.setGravity(Gravity.FILL_HORIZONTAL); + + editTextDialogInput.setText(initialValue); + + switch (id) { + case SoftTextDialogInput.TEXT_ENTRY_DIALOG: + + editTextDialogInput.setInputType(InputType.TYPE_CLASS_TEXT); + break; + + case SoftTextDialogInput.NUMERIC_ENTRY_DIALOG: + + editTextDialogInput.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED); + break; + + case SoftTextDialogInput.NUMERIC_KEYPAD_DIALOG: + + editTextDialogInput.setInputType(InputType.TYPE_CLASS_PHONE); + break; + + default: + break; + } + + layoutTextDialogInput.addView(editTextDialogInput); + + AlertDialog dialogTextInput = new AlertDialog.Builder(JmeAndroidSystem.getActivity()).setTitle(title).setView(layoutTextDialogInput).setPositiveButton("OK", + new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int whichButton) { + /* User clicked OK, send COMPLETE action + * and text */ + listener.onSoftText(SoftTextDialogInputListener.COMPLETE, editTextDialogInput.getText().toString()); + } + }).setNegativeButton("Cancel", + new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int whichButton) { + /* User clicked CANCEL, send CANCEL action + * and text */ + listener.onSoftText(SoftTextDialogInputListener.CANCEL, editTextDialogInput.getText().toString()); + } + }).create(); + + dialogTextInput.show(); + } + }); + } } diff --git a/engine/src/android/com/jme3/util/AndroidLogHandler.java b/engine/src/android/com/jme3/util/AndroidLogHandler.java index 8fb21c2..1da1299 100644 --- a/engine/src/android/com/jme3/util/AndroidLogHandler.java +++ b/engine/src/android/com/jme3/util/AndroidLogHandler.java @@ -4,7 +4,12 @@ import android.util.Log; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; +import java.util.logging.Logger; +/** + * Converts from Java based logging ({@link Logger} to Android based + * logging {@link Log}. + */ public class AndroidLogHandler extends Handler { @Override @@ -21,17 +26,16 @@ public class AndroidLogHandler extends Handler { String clsName = record.getSourceClassName(); String msg = record.getMessage(); Throwable t = record.getThrown(); - if (level == Level.INFO){ + if (level == Level.INFO) { Log.i(clsName, msg, t); - }else if (level == Level.SEVERE){ + } else if (level == Level.SEVERE) { Log.e(clsName, msg, t); - }else if (level == Level.WARNING){ + } else if (level == Level.WARNING) { Log.w(clsName, msg, t); - }else if (level == Level.CONFIG){ + } else if (level == Level.CONFIG) { Log.d(clsName, msg, t); - }else if (level == Level.FINE || level == Level.FINER || level == Level.FINEST){ + } else if (level == Level.FINE || level == Level.FINER || level == Level.FINEST) { Log.v(clsName, msg, t); } } - } diff --git a/engine/src/android/com/jme3/util/RingBuffer.java b/engine/src/android/com/jme3/util/RingBuffer.java index 786417b..1d3c22d 100644 --- a/engine/src/android/com/jme3/util/RingBuffer.java +++ b/engine/src/android/com/jme3/util/RingBuffer.java @@ -4,20 +4,21 @@ import java.util.Iterator; import java.util.NoSuchElementException; /** - * Ring buffer (fixed size queue) implementation using a circular array (array with wrap-around). + * Ring buffer (fixed size queue) implementation using a circular array (array + * with wrap-around). */ // suppress unchecked warnings in Java 1.5.0_6 and later @SuppressWarnings("unchecked") -public class RingBuffer implements Iterable { +public class RingBuffer implements Iterable { - private Item[] buffer; // queue elements + private T[] buffer; // queue elements private int count = 0; // number of elements on queue private int indexOut = 0; // index of first element of queue private int indexIn = 0; // index of next available slot // cast needed since no generic array creation in Java public RingBuffer(int capacity) { - buffer = (Item[]) new Object[capacity]; + buffer = (T[]) new Object[capacity]; } public boolean isEmpty() { @@ -28,7 +29,7 @@ public class RingBuffer implements Iterable { return count; } - public void push(Item item) { + public void push(T item) { if (count == buffer.length) { throw new RuntimeException("Ring buffer overflow"); } @@ -37,23 +38,23 @@ public class RingBuffer implements Iterable { count++; } - public Item pop() { + public T pop() { if (isEmpty()) { throw new RuntimeException("Ring buffer underflow"); } - Item item = buffer[indexOut]; + T item = buffer[indexOut]; buffer[indexOut] = null; // to help with garbage collection count--; indexOut = (indexOut + 1) % buffer.length; // wrap-around return item; } - public Iterator iterator() { + public Iterator iterator() { return new RingBufferIterator(); } // an iterator, doesn't implement remove() since it's optional - private class RingBufferIterator implements Iterator { + private class RingBufferIterator implements Iterator { private int i = 0; @@ -65,7 +66,7 @@ public class RingBuffer implements Iterable { throw new UnsupportedOperationException(); } - public Item next() { + public T next() { if (!hasNext()) { throw new NoSuchElementException(); } diff --git a/engine/src/android/res/layout/about.xml b/engine/src/android/res/layout/about.xml index 1d8c2b0..ca249e7 100644 --- a/engine/src/android/res/layout/about.xml +++ b/engine/src/android/res/layout/about.xml @@ -1,29 +1,29 @@ + android:id="@+id/buttonsContainer" + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > diff --git a/engine/src/android/res/layout/tests.xml b/engine/src/android/res/layout/tests.xml index 70bd5ec..f38e233 100644 --- a/engine/src/android/res/layout/tests.xml +++ b/engine/src/android/res/layout/tests.xml @@ -1,17 +1,17 @@ + android:id="@+id/buttonsContainer" + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent">