Merge branch 'master' of https://github.com/jMonkeyEngine/jmonkeyengine.git
commit
dba5c2e8fb
@ -0,0 +1,13 @@ |
|||||||
|
apply plugin: 'com.android.application' |
||||||
|
|
||||||
|
group = 'com.jme3' |
||||||
|
version = jmeVersion + '-' + jmeVersionTag |
||||||
|
|
||||||
|
sourceCompatibility = '1.6' |
||||||
|
|
||||||
|
repositories { |
||||||
|
mavenCentral() |
||||||
|
maven { |
||||||
|
url "http://nifty-gui.sourceforge.net/nifty-maven-repo" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
dependencies { |
||||||
|
compile project(':jme3-core') |
||||||
|
compile project(':jme3-android') |
||||||
|
compile project(':jme3-effects') |
||||||
|
compile project(':jme3-bullet') |
||||||
|
compile project(':jme3-bullet-native-android') |
||||||
|
compile project(':jme3-networking') |
||||||
|
compile project(':jme3-niftygui') |
||||||
|
compile project(':jme3-plugins') |
||||||
|
compile project(':jme3-terrain') |
||||||
|
compile project(':jme3-testdata') |
||||||
|
} |
||||||
|
|
||||||
|
android { |
||||||
|
compileSdkVersion 10 |
||||||
|
buildToolsVersion "22.0.1" |
||||||
|
|
||||||
|
lintOptions { |
||||||
|
// Fix nifty gui referencing "java.awt" package. |
||||||
|
disable 'InvalidPackage' |
||||||
|
} |
||||||
|
|
||||||
|
defaultConfig { |
||||||
|
applicationId "com.jme3.android" |
||||||
|
minSdkVersion 10 // Android 2.3 GINGERBREAD |
||||||
|
targetSdkVersion 22 // Android 5.1 LOLLIPOP |
||||||
|
versionCode 1 |
||||||
|
versionName "1.0" // TODO: from settings.gradle |
||||||
|
} |
||||||
|
|
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
minifyEnabled false |
||||||
|
} |
||||||
|
debug { |
||||||
|
applicationIdSuffix ".debug" |
||||||
|
debuggable true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="com.jme3.android"> |
||||||
|
|
||||||
|
<!-- Tell the system that you need ES 2.0. --> |
||||||
|
<uses-feature android:glEsVersion="0x00020000" android:required="true" /> |
||||||
|
|
||||||
|
<!-- Tell the system that you need distinct touches (for the zoom gesture). --> |
||||||
|
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="true" /> |
||||||
|
|
||||||
|
<application android:label="@string/app_name" android:allowBackup="true"> |
||||||
|
<activity android:name="jme3test.android.TestChooserAndroid" |
||||||
|
android:label="@string/app_name"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
</application> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,12 @@ |
|||||||
|
package jme3test.android; |
||||||
|
|
||||||
|
import android.content.pm.ActivityInfo; |
||||||
|
import android.app.*; |
||||||
|
import android.os.Bundle; |
||||||
|
|
||||||
|
public class TestChooserAndroid extends Activity { |
||||||
|
@Override |
||||||
|
public void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<string name="app_name">JMEAndroidTest</string> |
||||||
|
<string name="about">About</string> |
||||||
|
<string name="quit">Quit</string> |
||||||
|
</resources> |
@ -1,686 +0,0 @@ |
|||||||
package com.jme3.input.android; |
|
||||||
|
|
||||||
import android.view.*; |
|
||||||
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.system.AppSettings; |
|
||||||
import com.jme3.util.RingBuffer; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
/** |
|
||||||
* <code>AndroidInput</code> is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs |
|
||||||
* @author larynx |
|
||||||
* |
|
||||||
*/ |
|
||||||
public class AndroidInput implements |
|
||||||
TouchInput, |
|
||||||
View.OnTouchListener, |
|
||||||
View.OnKeyListener, |
|
||||||
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<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS); |
|
||||||
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
|
||||||
// Internal
|
|
||||||
private View view; |
|
||||||
private ScaleGestureDetector scaledetector; |
|
||||||
private boolean scaleInProgress = false; |
|
||||||
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() { |
|
||||||
} |
|
||||||
|
|
||||||
public void setView(View view) { |
|
||||||
this.view = view; |
|
||||||
if (view != null) { |
|
||||||
detector = new GestureDetector(null, this, null, false); |
|
||||||
scaledetector = new ScaleGestureDetector(view.getContext(), this); |
|
||||||
view.setOnTouchListener(this); |
|
||||||
view.setOnKeyListener(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; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onTouch gets called from android thread on touchpad events |
|
||||||
*/ |
|
||||||
public boolean onTouch(View view, MotionEvent event) { |
|
||||||
if (view != this.view) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
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); |
|
||||||
Vector2f lastPos = lastPositions.get(pointerId); |
|
||||||
|
|
||||||
// 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), view.getHeight() - event.getY(pointerIndex), 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
lastPos = new Vector2f(event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex)); |
|
||||||
lastPositions.put(pointerId, lastPos); |
|
||||||
|
|
||||||
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), view.getHeight() - event.getY(pointerIndex), 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
processEvent(touch); |
|
||||||
lastPositions.remove(pointerId); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_MOVE: |
|
||||||
// Convert all pointers into events
|
|
||||||
for (int p = 0; p < event.getPointerCount(); p++) { |
|
||||||
lastPos = lastPositions.get(event.getPointerId(p)); |
|
||||||
if (lastPos == null) { |
|
||||||
lastPos = new Vector2f(event.getX(p), view.getHeight() - event.getY(p)); |
|
||||||
lastPositions.put(event.getPointerId(p), lastPos); |
|
||||||
} |
|
||||||
|
|
||||||
float dX = event.getX(p) - lastPos.x; |
|
||||||
float dY = view.getHeight() - event.getY(p) - lastPos.y; |
|
||||||
if (dX != 0 || dY != 0) { |
|
||||||
touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.MOVE, event.getX(p), view.getHeight() - event.getY(p), dX, dY); |
|
||||||
touch.setPointerId(event.getPointerId(p)); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(p)); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
lastPos.set(event.getX(p), view.getHeight() - event.getY(p)); |
|
||||||
} |
|
||||||
} |
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_OUTSIDE: |
|
||||||
break; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// Try to detect gestures
|
|
||||||
this.detector.onTouchEvent(event); |
|
||||||
this.scaledetector.onTouchEvent(event); |
|
||||||
|
|
||||||
return bWasHandled; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onKey gets called from android thread on key events |
|
||||||
*/ |
|
||||||
public boolean onKey(View view, int keyCode, KeyEvent event) { |
|
||||||
if (view != this.view) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
|
||||||
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; |
|
||||||
} |
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP) { |
|
||||||
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; |
|
||||||
} |
|
||||||
} else { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void loadSettings(AppSettings settings) { |
|
||||||
mouseEventsEnabled = settings.isEmulateMouse(); |
|
||||||
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
|
||||||
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
|
||||||
} |
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// 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(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
this.view = null; |
|
||||||
} |
|
||||||
|
|
||||||
@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) { |
|
||||||
//Discarding events when the ring buffer is full to avoid buffer overflow.
|
|
||||||
if(eventQueue.size()< MAX_EVENTS){ |
|
||||||
eventQueue.push(event); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// --------------- INSIDE GLThread ---------------
|
|
||||||
@Override |
|
||||||
public void update() { |
|
||||||
generateEvents(); |
|
||||||
} |
|
||||||
|
|
||||||
private void generateEvents() { |
|
||||||
if (listener != null) { |
|
||||||
TouchEvent event; |
|
||||||
MouseButtonEvent btn; |
|
||||||
MouseMotionEvent mot; |
|
||||||
int newX; |
|
||||||
int newY; |
|
||||||
|
|
||||||
while (!eventQueue.isEmpty()) { |
|
||||||
synchronized (eventQueue) { |
|
||||||
event = eventQueue.pop(); |
|
||||||
} |
|
||||||
if (event != null) { |
|
||||||
listener.onTouchEvent(event); |
|
||||||
|
|
||||||
if (mouseEventsEnabled) { |
|
||||||
if (mouseEventsInvertX) { |
|
||||||
newX = view.getWidth() - (int) event.getX(); |
|
||||||
} else { |
|
||||||
newX = (int) event.getX(); |
|
||||||
} |
|
||||||
|
|
||||||
if (mouseEventsInvertY) { |
|
||||||
newY = view.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 SCALE_MOVE: |
|
||||||
if (lastX != -1 && lastY != -1) { |
|
||||||
newX = lastX; |
|
||||||
newY = lastY; |
|
||||||
} |
|
||||||
int wheel = (int) (event.getScaleSpan() / 4f); // scale to match mouse wheel
|
|
||||||
int dwheel = (int) (event.getDeltaScaleSpan() / 4f); // scale to match mouse wheel
|
|
||||||
mot = new MouseMotionEvent(newX, newX, 0, 0, wheel, dwheel); |
|
||||||
mot.setTime(event.getTime()); |
|
||||||
listener.onMouseMotionEvent(mot); |
|
||||||
lastX = newX; |
|
||||||
lastY = newY; |
|
||||||
|
|
||||||
break; |
|
||||||
|
|
||||||
case MOVE: |
|
||||||
if (event.isScaleSpanInProgress()) { |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
int dx; |
|
||||||
int dy; |
|
||||||
if (lastX != -1) { |
|
||||||
dx = newX - lastX; |
|
||||||
dy = newY - lastY; |
|
||||||
} else { |
|
||||||
dx = 0; |
|
||||||
dy = 0; |
|
||||||
} |
|
||||||
|
|
||||||
mot = new MouseMotionEvent(newX, newY, dx, dy, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
|
||||||
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(), view.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(), view.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(), view.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) { |
|
||||||
scaleInProgress = true; |
|
||||||
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.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
// System.out.println("scaleBegin");
|
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onScale(ScaleGestureDetector scaleGestureDetector) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(scaleGestureDetector.getEventTime()); |
|
||||||
touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); |
|
||||||
touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
// System.out.println("scale");
|
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { |
|
||||||
scaleInProgress = false; |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(scaleGestureDetector.getEventTime()); |
|
||||||
touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); |
|
||||||
touch.setDeltaScaleSpan(scaleGestureDetector.getCurrentSpan() - scaleGestureDetector.getPreviousSpan()); |
|
||||||
touch.setScaleFactor(scaleGestureDetector.getScaleFactor()); |
|
||||||
touch.setScaleSpanInProgress(scaleInProgress); |
|
||||||
processEvent(touch); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { |
|
||||||
TouchEvent touch = getNextFreeTouchEvent(); |
|
||||||
touch.set(Type.SCROLL, e1.getX(), view.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(), view.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(), view.getHeight() - event.getY(), 0f, 0f); |
|
||||||
touch.setPointerId(0); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
processEvent(touch); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setSimulateKeyboard(boolean simulate) { |
|
||||||
keyboardEventsEnabled = simulate; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setOmitHistoricEvents(boolean dontSendHistory) { |
|
||||||
this.dontSendHistory = dontSendHistory; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @deprecated Use {@link #getSimulateMouse()}; |
|
||||||
*/ |
|
||||||
@Deprecated |
|
||||||
public boolean isMouseEventsEnabled() { |
|
||||||
return mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
@Deprecated |
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSimulateMouse(boolean simulate) { |
|
||||||
mouseEventsEnabled = simulate; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean getSimulateMouse() { |
|
||||||
return isSimulateMouse(); |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateMouse() { |
|
||||||
return mouseEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSimulateKeyboard() { |
|
||||||
return keyboardEventsEnabled; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,159 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.input.android; |
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView; |
||||||
|
import android.view.InputDevice; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* <code>AndroidInputHandler14</code> extends <code>AndroidInputHandler</code> to |
||||||
|
* add the onHover and onGenericMotion events that where added in Android rev 14 (Android 4.0).</br> |
||||||
|
* The onGenericMotion events are the main interface to Joystick axes. They |
||||||
|
* were actually released in Android rev 12. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidInputHandler14 extends AndroidInputHandler implements View.OnHoverListener, |
||||||
|
View.OnGenericMotionListener { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AndroidInputHandler14.class.getName()); |
||||||
|
|
||||||
|
public AndroidInputHandler14() { |
||||||
|
touchInput = new AndroidTouchInput14(this); |
||||||
|
joyInput = new AndroidJoyInput14(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void removeListeners(GLSurfaceView view) { |
||||||
|
super.removeListeners(view); |
||||||
|
view.setOnHoverListener(null); |
||||||
|
view.setOnGenericMotionListener(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void addListeners(GLSurfaceView view) { |
||||||
|
super.addListeners(view); |
||||||
|
view.setOnHoverListener(this); |
||||||
|
view.setOnGenericMotionListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onHover(View view, MotionEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onTouch source: {0}", source);
|
||||||
|
|
||||||
|
boolean isTouch = ((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN); |
||||||
|
// logger.log(Level.INFO, "onTouch source: {0}, isTouch: {1}",
|
||||||
|
// new Object[]{source, isTouch});
|
||||||
|
|
||||||
|
if (isTouch && touchInput != null) { |
||||||
|
// send the event to the touch processor
|
||||||
|
consumed = ((AndroidTouchInput14)touchInput).onHover(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onGenericMotion(View view, MotionEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onGenericMotion source: {0}", source);
|
||||||
|
|
||||||
|
boolean isJoystick = |
||||||
|
((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); |
||||||
|
|
||||||
|
if (isJoystick && joyInput != null) { |
||||||
|
// logger.log(Level.INFO, "onGenericMotion source: {0}, isJoystick: {1}",
|
||||||
|
// new Object[]{source, isJoystick});
|
||||||
|
// send the event to the touch processor
|
||||||
|
consumed = consumed || ((AndroidJoyInput14)joyInput).onGenericMotion(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKey(View view, int keyCode, KeyEvent event) { |
||||||
|
if (view != getView()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean consumed = false; |
||||||
|
|
||||||
|
// logger.log(Level.INFO, "onKey keyCode: {0}, action: {1}, event: {2}",
|
||||||
|
// new Object[]{KeyEvent.keyCodeToString(keyCode), event.getAction(), event});
|
||||||
|
int source = event.getSource(); |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}", source);
|
||||||
|
|
||||||
|
boolean isTouch = |
||||||
|
((source & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) || |
||||||
|
((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD); |
||||||
|
boolean isJoystick = |
||||||
|
((source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK); |
||||||
|
|
||||||
|
if (isTouch && touchInput != null) { |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}",
|
||||||
|
// new Object[]{source, isTouch});
|
||||||
|
consumed = touchInput.onKey(event); |
||||||
|
} |
||||||
|
if (isJoystick && joyInput != null) { |
||||||
|
// logger.log(Level.INFO, "onKey source: {0}, isJoystick: {1}",
|
||||||
|
// new Object[]{source, isJoystick});
|
||||||
|
// use inclusive OR to make sure the onKey method is called.
|
||||||
|
consumed = consumed | ((AndroidJoyInput14)joyInput).onKey(event); |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 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.input.android; |
||||||
|
|
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.Joystick; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* <code>AndroidJoyInput14</code> extends <code>AndroidJoyInput</code> |
||||||
|
* to include support for physical joysticks/gamepads.</br> |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidJoyInput14 extends AndroidJoyInput { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidJoyInput14.class.getName()); |
||||||
|
|
||||||
|
private AndroidJoystickJoyInput14 joystickJoyInput; |
||||||
|
|
||||||
|
public AndroidJoyInput14(AndroidInputHandler inputHandler) { |
||||||
|
super(inputHandler); |
||||||
|
joystickJoyInput = new AndroidJoystickJoyInput14(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pauses the joystick device listeners to save battery life if they are not needed. |
||||||
|
* Used to pause when the activity pauses |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void pauseJoysticks() { |
||||||
|
super.pauseJoysticks(); |
||||||
|
|
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.pauseJoysticks(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resumes the joystick device listeners. |
||||||
|
* Used to resume when the activity comes to the top of the stack |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void resumeJoysticks() { |
||||||
|
super.resumeJoysticks(); |
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.resumeJoysticks(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
super.destroy(); |
||||||
|
if (joystickJoyInput != null) { |
||||||
|
joystickJoyInput.destroy(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Joystick[] loadJoysticks(InputManager inputManager) { |
||||||
|
// load the simulated joystick for device orientation
|
||||||
|
super.loadJoysticks(inputManager); |
||||||
|
// load physical gamepads/joysticks
|
||||||
|
joystickList.addAll(joystickJoyInput.loadJoysticks(joystickList.size(), inputManager)); |
||||||
|
// return the list of joysticks back to InputManager
|
||||||
|
return joystickList.toArray( new Joystick[joystickList.size()] ); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onGenericMotion(MotionEvent event) { |
||||||
|
return joystickJoyInput.onGenericMotion(event); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
return joystickJoyInput.onKey(event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,416 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 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.input.android; |
||||||
|
|
||||||
|
import android.view.InputDevice; |
||||||
|
import android.view.InputDevice.MotionRange; |
||||||
|
import android.view.KeyCharacterMap; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import com.jme3.input.AbstractJoystick; |
||||||
|
import com.jme3.input.DefaultJoystickAxis; |
||||||
|
import com.jme3.input.DefaultJoystickButton; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.JoyInput; |
||||||
|
import com.jme3.input.Joystick; |
||||||
|
import com.jme3.input.JoystickAxis; |
||||||
|
import com.jme3.input.JoystickButton; |
||||||
|
import com.jme3.input.JoystickCompatibilityMappings; |
||||||
|
import com.jme3.input.event.JoyAxisEvent; |
||||||
|
import com.jme3.input.event.JoyButtonEvent; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Main class that creates and manages Android inputs for physical gamepads/joysticks. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidJoystickJoyInput14 { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidJoystickJoyInput14.class.getName()); |
||||||
|
|
||||||
|
private boolean loaded = false; |
||||||
|
private AndroidJoyInput joyInput; |
||||||
|
private Map<Integer, AndroidJoystick> joystickIndex = new HashMap<Integer, AndroidJoystick>(); |
||||||
|
|
||||||
|
private static int[] AndroidGamepadButtons = { |
||||||
|
// Dpad buttons
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN, |
||||||
|
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT, |
||||||
|
KeyEvent.KEYCODE_DPAD_CENTER, |
||||||
|
|
||||||
|
// pressing joystick down
|
||||||
|
KeyEvent.KEYCODE_BUTTON_THUMBL, KeyEvent.KEYCODE_BUTTON_THUMBR, |
||||||
|
|
||||||
|
// buttons
|
||||||
|
KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_BUTTON_B, |
||||||
|
KeyEvent.KEYCODE_BUTTON_X, KeyEvent.KEYCODE_BUTTON_Y, |
||||||
|
|
||||||
|
// buttons on back of device
|
||||||
|
KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_BUTTON_R1, |
||||||
|
KeyEvent.KEYCODE_BUTTON_L2, KeyEvent.KEYCODE_BUTTON_R2, |
||||||
|
|
||||||
|
// start / select buttons
|
||||||
|
KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_BUTTON_SELECT, |
||||||
|
KeyEvent.KEYCODE_BUTTON_MODE, |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
public AndroidJoystickJoyInput14(AndroidJoyInput joyInput) { |
||||||
|
this.joyInput = joyInput; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void pauseJoysticks() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void resumeJoysticks() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void destroy() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public List<Joystick> loadJoysticks(int joyId, InputManager inputManager) { |
||||||
|
logger.log(Level.INFO, "loading Joystick devices"); |
||||||
|
ArrayList<Joystick> joysticks = new ArrayList<Joystick>(); |
||||||
|
joysticks.clear(); |
||||||
|
joystickIndex.clear(); |
||||||
|
|
||||||
|
ArrayList gameControllerDeviceIds = new ArrayList(); |
||||||
|
int[] deviceIds = InputDevice.getDeviceIds(); |
||||||
|
for (int deviceId : deviceIds) { |
||||||
|
InputDevice dev = InputDevice.getDevice(deviceId); |
||||||
|
int sources = dev.getSources(); |
||||||
|
logger.log(Level.FINE, "deviceId[{0}] sources: {1}", new Object[]{deviceId, sources}); |
||||||
|
|
||||||
|
// Verify that the device has gamepad buttons, control sticks, or both.
|
||||||
|
if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || |
||||||
|
((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { |
||||||
|
// This device is a game controller. Store its device ID.
|
||||||
|
if (!gameControllerDeviceIds.contains(deviceId)) { |
||||||
|
gameControllerDeviceIds.add(deviceId); |
||||||
|
logger.log(Level.FINE, "Attempting to create joystick for device: {0}", dev); |
||||||
|
// Create an AndroidJoystick and store the InputDevice so we
|
||||||
|
// can later correspond the input from the InputDevice to the
|
||||||
|
// appropriate jME Joystick event
|
||||||
|
AndroidJoystick joystick = new AndroidJoystick(inputManager, |
||||||
|
joyInput, |
||||||
|
dev, |
||||||
|
joyId+joysticks.size(), |
||||||
|
dev.getName()); |
||||||
|
joystickIndex.put(deviceId, joystick); |
||||||
|
joysticks.add(joystick); |
||||||
|
|
||||||
|
// Each analog input is reported as a MotionRange
|
||||||
|
// The axis number corresponds to the type of axis
|
||||||
|
// The AndroidJoystick.addAxis(MotionRange) converts the axis
|
||||||
|
// type reported by Android into the jME Joystick axis
|
||||||
|
List<MotionRange> motionRanges = dev.getMotionRanges(); |
||||||
|
for (MotionRange motionRange: motionRanges) { |
||||||
|
logger.log(Level.INFO, "motion range: {0}", motionRange.toString()); |
||||||
|
logger.log(Level.INFO, "axis: {0}", motionRange.getAxis()); |
||||||
|
JoystickAxis axis = joystick.addAxis(motionRange); |
||||||
|
logger.log(Level.INFO, "added axis: {0}", axis); |
||||||
|
} |
||||||
|
|
||||||
|
// InputDevice has a method for determining if a keyCode is
|
||||||
|
// supported (InputDevice public boolean[] hasKeys (int... keys)).
|
||||||
|
// But this method wasn't added until rev 19 (Android 4.4)
|
||||||
|
// Therefore, we only can query the entire device and see if
|
||||||
|
// any InputDevice supports the keyCode. This may result in
|
||||||
|
// buttons being configured that don't exist on the specific
|
||||||
|
// device, but I haven't found a better way yet.
|
||||||
|
for (int keyCode: AndroidGamepadButtons) { |
||||||
|
logger.log(Level.INFO, "button[{0}]: {1}", |
||||||
|
new Object[]{keyCode, KeyCharacterMap.deviceHasKey(keyCode)}); |
||||||
|
if (KeyCharacterMap.deviceHasKey(keyCode)) { |
||||||
|
// add button even though we aren't sure if the button
|
||||||
|
// actually exists on this InputDevice
|
||||||
|
logger.log(Level.INFO, "button[{0}] exists somewhere", keyCode); |
||||||
|
JoystickButton button = joystick.addButton(keyCode); |
||||||
|
logger.log(Level.INFO, "added button: {0}", button); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
loaded = true; |
||||||
|
return joysticks; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onGenericMotion(MotionEvent event) { |
||||||
|
boolean consumed = false; |
||||||
|
// logger.log(Level.INFO, "onGenericMotion event: {0}", event);
|
||||||
|
event.getDeviceId(); |
||||||
|
event.getSource(); |
||||||
|
// logger.log(Level.INFO, "deviceId: {0}, source: {1}", new Object[]{event.getDeviceId(), event.getSource()});
|
||||||
|
AndroidJoystick joystick = joystickIndex.get(event.getDeviceId()); |
||||||
|
if (joystick != null) { |
||||||
|
for (int androidAxis: joystick.getAndroidAxes()) { |
||||||
|
String axisName = MotionEvent.axisToString(androidAxis); |
||||||
|
float value = event.getAxisValue(androidAxis); |
||||||
|
int action = event.getAction(); |
||||||
|
if (action == MotionEvent.ACTION_MOVE) { |
||||||
|
// logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}",
|
||||||
|
// new Object[]{androidAxis, axisName, value});
|
||||||
|
JoystickAxis axis = joystick.getAxis(androidAxis); |
||||||
|
if (axis != null) { |
||||||
|
// logger.log(Level.INFO, "MOVE axis num: {0}, axisName: {1}, value: {2}, deadzone: {3}",
|
||||||
|
// new Object[]{androidAxis, axisName, value, axis.getDeadZone()});
|
||||||
|
JoyAxisEvent axisEvent = new JoyAxisEvent(axis, value); |
||||||
|
joyInput.addEvent(axisEvent); |
||||||
|
consumed = true; |
||||||
|
} else { |
||||||
|
// logger.log(Level.INFO, "axis was null for axisName: {0}", axisName);
|
||||||
|
} |
||||||
|
} else { |
||||||
|
// logger.log(Level.INFO, "action: {0}", action);
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
boolean consumed = false; |
||||||
|
// logger.log(Level.INFO, "onKey event: {0}", event);
|
||||||
|
|
||||||
|
event.getDeviceId(); |
||||||
|
event.getSource(); |
||||||
|
AndroidJoystick joystick = joystickIndex.get(event.getDeviceId()); |
||||||
|
if (joystick != null) { |
||||||
|
JoystickButton button = joystick.getButton(event.getKeyCode()); |
||||||
|
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
||||||
|
if (button != null) { |
||||||
|
JoyButtonEvent buttonEvent = new JoyButtonEvent(button, pressed); |
||||||
|
joyInput.addEvent(buttonEvent); |
||||||
|
consumed = true; |
||||||
|
} else { |
||||||
|
JoystickButton newButton = joystick.addButton(event.getKeyCode()); |
||||||
|
JoyButtonEvent buttonEvent = new JoyButtonEvent(newButton, pressed); |
||||||
|
joyInput.addEvent(buttonEvent); |
||||||
|
consumed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return consumed; |
||||||
|
} |
||||||
|
|
||||||
|
protected class AndroidJoystick extends AbstractJoystick { |
||||||
|
|
||||||
|
private JoystickAxis nullAxis; |
||||||
|
private InputDevice device; |
||||||
|
private JoystickAxis xAxis; |
||||||
|
private JoystickAxis yAxis; |
||||||
|
private JoystickAxis povX; |
||||||
|
private JoystickAxis povY; |
||||||
|
private Map<Integer, JoystickAxis> axisIndex = new HashMap<Integer, JoystickAxis>(); |
||||||
|
private Map<Integer, JoystickButton> buttonIndex = new HashMap<Integer, JoystickButton>(); |
||||||
|
|
||||||
|
public AndroidJoystick( InputManager inputManager, JoyInput joyInput, InputDevice device, |
||||||
|
int joyId, String name ) { |
||||||
|
super( inputManager, joyInput, joyId, name ); |
||||||
|
|
||||||
|
this.device = device; |
||||||
|
|
||||||
|
this.nullAxis = new DefaultJoystickAxis( getInputManager(), this, -1, |
||||||
|
"Null", "null", false, false, 0 ); |
||||||
|
this.xAxis = nullAxis; |
||||||
|
this.yAxis = nullAxis; |
||||||
|
this.povX = nullAxis; |
||||||
|
this.povY = nullAxis; |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickAxis getAxis(int androidAxis) { |
||||||
|
return axisIndex.get(androidAxis); |
||||||
|
} |
||||||
|
|
||||||
|
protected Set<Integer> getAndroidAxes() { |
||||||
|
return axisIndex.keySet(); |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickButton getButton(int keyCode) { |
||||||
|
return buttonIndex.get(keyCode); |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickButton addButton( int keyCode ) { |
||||||
|
|
||||||
|
// logger.log(Level.FINE, "Adding button: {0}", keyCode);
|
||||||
|
|
||||||
|
String name = KeyEvent.keyCodeToString(keyCode); |
||||||
|
String original = KeyEvent.keyCodeToString(keyCode); |
||||||
|
// A/B/X/Y buttons
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BUTTON_Y) { |
||||||
|
original = JoystickButton.BUTTON_0; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_B) { |
||||||
|
original = JoystickButton.BUTTON_1; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_A) { |
||||||
|
original = JoystickButton.BUTTON_2; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_X) { |
||||||
|
original = JoystickButton.BUTTON_3; |
||||||
|
// Front buttons Some of these have the top ones and the bottoms ones flipped.
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L1) { |
||||||
|
original = JoystickButton.BUTTON_4; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R1) { |
||||||
|
original = JoystickButton.BUTTON_5; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_L2) { |
||||||
|
original = JoystickButton.BUTTON_6; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_R2) { |
||||||
|
original = JoystickButton.BUTTON_7; |
||||||
|
// // Dpad buttons
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_9;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_8;
|
||||||
|
// } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
||||||
|
// original = JoystickButton.BUTTON_9;
|
||||||
|
// Select and start buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_SELECT) { |
||||||
|
original = JoystickButton.BUTTON_8; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_START) { |
||||||
|
original = JoystickButton.BUTTON_9; |
||||||
|
// Joystick push buttons
|
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL) { |
||||||
|
original = JoystickButton.BUTTON_10; |
||||||
|
} else if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR) { |
||||||
|
original = JoystickButton.BUTTON_11; |
||||||
|
} |
||||||
|
|
||||||
|
String logicalId = JoystickCompatibilityMappings.remapComponent( getName(), original ); |
||||||
|
if( logicalId == null ? original != null : !logicalId.equals(original) ) { |
||||||
|
logger.log(Level.FINE, "Remapped: {0} to: {1}", |
||||||
|
new Object[]{original, logicalId}); |
||||||
|
} |
||||||
|
|
||||||
|
JoystickButton button = new DefaultJoystickButton( getInputManager(), this, getButtonCount(), |
||||||
|
name, logicalId ); |
||||||
|
addButton(button); |
||||||
|
buttonIndex.put( keyCode, button ); |
||||||
|
return button; |
||||||
|
} |
||||||
|
|
||||||
|
protected JoystickAxis addAxis(MotionRange motionRange) { |
||||||
|
|
||||||
|
String name = MotionEvent.axisToString(motionRange.getAxis()); |
||||||
|
|
||||||
|
String original = MotionEvent.axisToString(motionRange.getAxis()); |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_X) { |
||||||
|
original = JoystickAxis.X_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Y) { |
||||||
|
original = JoystickAxis.Y_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_Z) { |
||||||
|
original = JoystickAxis.Z_AXIS; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_RZ) { |
||||||
|
original = JoystickAxis.Z_ROTATION; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) { |
||||||
|
original = JoystickAxis.POV_X; |
||||||
|
} else if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) { |
||||||
|
original = JoystickAxis.POV_Y; |
||||||
|
} |
||||||
|
String logicalId = JoystickCompatibilityMappings.remapComponent( getName(), original ); |
||||||
|
if( logicalId == null ? original != null : !logicalId.equals(original) ) { |
||||||
|
logger.log(Level.FINE, "Remapped: {0} to: {1}", |
||||||
|
new Object[]{original, logicalId}); |
||||||
|
} |
||||||
|
|
||||||
|
JoystickAxis axis = new DefaultJoystickAxis(getInputManager(), |
||||||
|
this, |
||||||
|
getAxisCount(), |
||||||
|
name, |
||||||
|
logicalId, |
||||||
|
true, |
||||||
|
true, |
||||||
|
motionRange.getFlat()); |
||||||
|
|
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_X) { |
||||||
|
xAxis = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_Y) { |
||||||
|
yAxis = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_HAT_X) { |
||||||
|
povX = axis; |
||||||
|
} |
||||||
|
if (motionRange.getAxis() == MotionEvent.AXIS_HAT_Y) { |
||||||
|
povY = axis; |
||||||
|
} |
||||||
|
|
||||||
|
addAxis(axis); |
||||||
|
axisIndex.put(motionRange.getAxis(), axis); |
||||||
|
return axis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getXAxis() { |
||||||
|
return xAxis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getYAxis() { |
||||||
|
return yAxis; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getPovXAxis() { |
||||||
|
return povX; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoystickAxis getPovYAxis() { |
||||||
|
return povY; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getXAxisIndex(){ |
||||||
|
return xAxis.getAxisId(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getYAxisIndex(){ |
||||||
|
return yAxis.getAxisId(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,140 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2009-2012 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.input.android; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.view.KeyEvent; |
|
||||||
import android.view.View; |
|
||||||
import android.view.inputmethod.InputMethodManager; |
|
||||||
import com.jme3.input.event.KeyInputEvent; |
|
||||||
import com.jme3.input.event.TouchEvent; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
/** |
|
||||||
* AndroidKeyHandler recieves onKey events from the Android system and creates |
|
||||||
* the jME KeyEvents. onKey is used by Android to receive keys from the keyboard |
|
||||||
* or device buttons. All key events are consumed by jME except for the Volume |
|
||||||
* buttons and menu button. |
|
||||||
* |
|
||||||
* This class also provides the functionality to display or hide the soft keyboard |
|
||||||
* for inputing single key events. Use OGLESContext to display an dialog to type |
|
||||||
* in complete strings. |
|
||||||
* |
|
||||||
* @author iwgeric |
|
||||||
*/ |
|
||||||
public class AndroidKeyHandler implements View.OnKeyListener { |
|
||||||
private static final Logger logger = Logger.getLogger(AndroidKeyHandler.class.getName()); |
|
||||||
|
|
||||||
private AndroidInputHandler androidInput; |
|
||||||
private boolean sendKeyEvents = true; |
|
||||||
|
|
||||||
public AndroidKeyHandler(AndroidInputHandler androidInput) { |
|
||||||
this.androidInput = androidInput; |
|
||||||
} |
|
||||||
|
|
||||||
public void initialize() { |
|
||||||
} |
|
||||||
|
|
||||||
public void destroy() { |
|
||||||
} |
|
||||||
|
|
||||||
public void setView(View view) { |
|
||||||
if (view != null) { |
|
||||||
view.setOnKeyListener(this); |
|
||||||
} else { |
|
||||||
androidInput.getView().setOnKeyListener(null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onKey gets called from android thread on key events |
|
||||||
*/ |
|
||||||
public boolean onKey(View view, int keyCode, KeyEvent event) { |
|
||||||
if (androidInput.isInitialized() && view != androidInput.getView()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
TouchEvent evt; |
|
||||||
// TODO: get touch event from pool
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
|
||||||
evt = new TouchEvent(); |
|
||||||
evt.set(TouchEvent.Type.KEY_DOWN); |
|
||||||
evt.setKeyCode(keyCode); |
|
||||||
evt.setCharacters(event.getCharacters()); |
|
||||||
evt.setTime(event.getEventTime()); |
|
||||||
|
|
||||||
// Send the event
|
|
||||||
androidInput.addEvent(evt); |
|
||||||
|
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP) { |
|
||||||
evt = new TouchEvent(); |
|
||||||
evt.set(TouchEvent.Type.KEY_UP); |
|
||||||
evt.setKeyCode(keyCode); |
|
||||||
evt.setCharacters(event.getCharacters()); |
|
||||||
evt.setTime(event.getEventTime()); |
|
||||||
|
|
||||||
// Send the event
|
|
||||||
androidInput.addEvent(evt); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
if (androidInput.isSimulateKeyboard()) { |
|
||||||
KeyInputEvent kie; |
|
||||||
char unicodeChar = (char)event.getUnicodeChar(); |
|
||||||
int jmeKeyCode = AndroidKeyMapping.getJmeKey(keyCode); |
|
||||||
|
|
||||||
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
|
||||||
boolean repeating = pressed && event.getRepeatCount() > 0; |
|
||||||
|
|
||||||
kie = new KeyInputEvent(jmeKeyCode, unicodeChar, pressed, repeating); |
|
||||||
kie.setTime(event.getEventTime()); |
|
||||||
androidInput.addEvent(kie); |
|
||||||
// logger.log(Level.FINE, "onKey keyCode: {0}, jmeKeyCode: {1}, pressed: {2}, repeating: {3}",
|
|
||||||
// new Object[]{keyCode, jmeKeyCode, pressed, repeating});
|
|
||||||
// logger.log(Level.FINE, "creating KeyInputEvent: {0}", kie);
|
|
||||||
} |
|
||||||
|
|
||||||
// consume all keys ourself except Volume Up/Down and Menu
|
|
||||||
// Don't do Menu so that typical Android Menus can be created and used
|
|
||||||
// by the user in MainActivity
|
|
||||||
if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || |
|
||||||
(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || |
|
||||||
(keyCode == KeyEvent.KEYCODE_MENU)) { |
|
||||||
return false; |
|
||||||
} else { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,257 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2009-2012 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.input.android; |
|
||||||
|
|
||||||
import android.view.MotionEvent; |
|
||||||
import android.view.View; |
|
||||||
import com.jme3.input.event.InputEvent; |
|
||||||
import com.jme3.input.event.MouseButtonEvent; |
|
||||||
import com.jme3.input.event.MouseMotionEvent; |
|
||||||
import com.jme3.input.event.TouchEvent; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.DOWN; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.MOVE; |
|
||||||
import static com.jme3.input.event.TouchEvent.Type.UP; |
|
||||||
import com.jme3.math.Vector2f; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
/** |
|
||||||
* AndroidTouchHandler is the base class that receives touch inputs from the |
|
||||||
* Android system and creates the TouchEvents for jME. This class is designed |
|
||||||
* to handle the base touch events for Android rev 9 (Android 2.3). This is |
|
||||||
* extended by other classes to add features that were introducted after |
|
||||||
* Android rev 9. |
|
||||||
* |
|
||||||
* @author iwgeric |
|
||||||
*/ |
|
||||||
public class AndroidTouchHandler implements View.OnTouchListener { |
|
||||||
private static final Logger logger = Logger.getLogger(AndroidTouchHandler.class.getName()); |
|
||||||
|
|
||||||
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
|
||||||
|
|
||||||
protected int numPointers = 0; |
|
||||||
|
|
||||||
protected AndroidInputHandler androidInput; |
|
||||||
protected AndroidGestureHandler gestureHandler; |
|
||||||
|
|
||||||
public AndroidTouchHandler(AndroidInputHandler androidInput, AndroidGestureHandler gestureHandler) { |
|
||||||
this.androidInput = androidInput; |
|
||||||
this.gestureHandler = gestureHandler; |
|
||||||
} |
|
||||||
|
|
||||||
public void initialize() { |
|
||||||
} |
|
||||||
|
|
||||||
public void destroy() { |
|
||||||
setView(null); |
|
||||||
} |
|
||||||
|
|
||||||
public void setView(View view) { |
|
||||||
if (view != null) { |
|
||||||
view.setOnTouchListener(this); |
|
||||||
} else { |
|
||||||
androidInput.getView().setOnTouchListener(null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected int getPointerIndex(MotionEvent event) { |
|
||||||
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) |
|
||||||
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
|
||||||
} |
|
||||||
|
|
||||||
protected int getPointerId(MotionEvent event) { |
|
||||||
return event.getPointerId(getPointerIndex(event)); |
|
||||||
} |
|
||||||
|
|
||||||
protected int getAction(MotionEvent event) { |
|
||||||
return event.getAction() & MotionEvent.ACTION_MASK; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* onTouch gets called from android thread on touch events |
|
||||||
*/ |
|
||||||
public boolean onTouch(View view, MotionEvent event) { |
|
||||||
if (!androidInput.isInitialized() || view != androidInput.getView()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
boolean bWasHandled = false; |
|
||||||
TouchEvent touch = null; |
|
||||||
// System.out.println("native : " + event.getAction());
|
|
||||||
int action = getAction(event); |
|
||||||
int pointerIndex = getPointerIndex(event); |
|
||||||
int pointerId = getPointerId(event); |
|
||||||
Vector2f lastPos = lastPositions.get(pointerId); |
|
||||||
float jmeX; |
|
||||||
float jmeY; |
|
||||||
|
|
||||||
numPointers = event.getPointerCount(); |
|
||||||
|
|
||||||
// final int historySize = event.getHistorySize();
|
|
||||||
//final int pointerCount = event.getPointerCount();
|
|
||||||
switch (getAction(event)) { |
|
||||||
case MotionEvent.ACTION_POINTER_DOWN: |
|
||||||
case MotionEvent.ACTION_DOWN: |
|
||||||
jmeX = androidInput.getJmeX(event.getX(pointerIndex)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex))); |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
|
|
||||||
lastPos = new Vector2f(jmeX, jmeY); |
|
||||||
lastPositions.put(pointerId, lastPos); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_POINTER_UP: |
|
||||||
case MotionEvent.ACTION_CANCEL: |
|
||||||
case MotionEvent.ACTION_UP: |
|
||||||
jmeX = androidInput.getJmeX(event.getX(pointerIndex)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(pointerIndex))); |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0); |
|
||||||
touch.setPointerId(pointerId); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(pointerIndex)); |
|
||||||
lastPositions.remove(pointerId); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_MOVE: |
|
||||||
// Convert all pointers into events
|
|
||||||
for (int p = 0; p < event.getPointerCount(); p++) { |
|
||||||
jmeX = androidInput.getJmeX(event.getX(p)); |
|
||||||
jmeY = androidInput.invertY(androidInput.getJmeY(event.getY(p))); |
|
||||||
lastPos = lastPositions.get(event.getPointerId(p)); |
|
||||||
if (lastPos == null) { |
|
||||||
lastPos = new Vector2f(jmeX, jmeY); |
|
||||||
lastPositions.put(event.getPointerId(p), lastPos); |
|
||||||
} |
|
||||||
|
|
||||||
float dX = jmeX - lastPos.x; |
|
||||||
float dY = jmeY - lastPos.y; |
|
||||||
if (dX != 0 || dY != 0) { |
|
||||||
touch = androidInput.getFreeTouchEvent(); |
|
||||||
touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY); |
|
||||||
touch.setPointerId(event.getPointerId(p)); |
|
||||||
touch.setTime(event.getEventTime()); |
|
||||||
touch.setPressure(event.getPressure(p)); |
|
||||||
lastPos.set(jmeX, jmeY); |
|
||||||
|
|
||||||
processEvent(touch); |
|
||||||
|
|
||||||
bWasHandled = true; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_OUTSIDE: |
|
||||||
break; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// Try to detect gestures
|
|
||||||
if (gestureHandler != null) { |
|
||||||
gestureHandler.detectGesture(event); |
|
||||||
} |
|
||||||
|
|
||||||
return bWasHandled; |
|
||||||
} |
|
||||||
|
|
||||||
protected void processEvent(TouchEvent event) { |
|
||||||
// Add the touch event
|
|
||||||
androidInput.addEvent(event); |
|
||||||
// MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
|
|
||||||
if (androidInput.isSimulateMouse() && numPointers == 1) { |
|
||||||
InputEvent mouseEvent = generateMouseEvent(event); |
|
||||||
if (mouseEvent != null) { |
|
||||||
// Add the mouse event
|
|
||||||
androidInput.addEvent(mouseEvent); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// TODO: Ring Buffer for mouse events?
|
|
||||||
protected InputEvent generateMouseEvent(TouchEvent event) { |
|
||||||
InputEvent inputEvent = null; |
|
||||||
int newX; |
|
||||||
int newY; |
|
||||||
int newDX; |
|
||||||
int newDY; |
|
||||||
|
|
||||||
if (androidInput.isMouseEventsInvertX()) { |
|
||||||
newX = (int) (androidInput.invertX(event.getX())); |
|
||||||
newDX = (int)event.getDeltaX() * -1; |
|
||||||
} else { |
|
||||||
newX = (int) event.getX(); |
|
||||||
newDX = (int)event.getDeltaX(); |
|
||||||
} |
|
||||||
|
|
||||||
if (androidInput.isMouseEventsInvertY()) { |
|
||||||
newY = (int) (androidInput.invertY(event.getY())); |
|
||||||
newDY = (int)event.getDeltaY() * -1; |
|
||||||
} else { |
|
||||||
newY = (int) event.getY(); |
|
||||||
newDY = (int)event.getDeltaY(); |
|
||||||
} |
|
||||||
|
|
||||||
switch (event.getType()) { |
|
||||||
case DOWN: |
|
||||||
// Handle mouse down event
|
|
||||||
inputEvent = new MouseButtonEvent(0, true, newX, newY); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
|
|
||||||
case UP: |
|
||||||
// Handle mouse up event
|
|
||||||
inputEvent = new MouseButtonEvent(0, false, newX, newY); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
|
|
||||||
case HOVER_MOVE: |
|
||||||
case MOVE: |
|
||||||
inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
|
||||||
inputEvent.setTime(event.getTime()); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
return inputEvent; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,475 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.input.android; |
||||||
|
|
||||||
|
import android.view.GestureDetector; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.ScaleGestureDetector; |
||||||
|
import com.jme3.input.RawInputListener; |
||||||
|
import com.jme3.input.TouchInput; |
||||||
|
import com.jme3.input.event.InputEvent; |
||||||
|
import com.jme3.input.event.KeyInputEvent; |
||||||
|
import com.jme3.input.event.MouseButtonEvent; |
||||||
|
import com.jme3.input.event.MouseMotionEvent; |
||||||
|
import com.jme3.input.event.TouchEvent; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.DOWN; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.MOVE; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.UP; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* AndroidTouchInput is the base class that receives touch inputs from the |
||||||
|
* Android system and creates the TouchEvents for jME. This class is designed |
||||||
|
* to handle the base touch events for Android rev 9 (Android 2.3). This is |
||||||
|
* extended by other classes to add features that were introducted after |
||||||
|
* Android rev 9. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class AndroidTouchInput implements TouchInput { |
||||||
|
private static final Logger logger = Logger.getLogger(AndroidTouchInput.class.getName()); |
||||||
|
|
||||||
|
private boolean mouseEventsEnabled = true; |
||||||
|
private boolean mouseEventsInvertX = false; |
||||||
|
private boolean mouseEventsInvertY = false; |
||||||
|
private boolean keyboardEventsEnabled = false; |
||||||
|
private boolean dontSendHistory = false; |
||||||
|
|
||||||
|
protected int numPointers = 0; |
||||||
|
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
||||||
|
final private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>(); |
||||||
|
private final static int MAX_TOUCH_EVENTS = 1024; |
||||||
|
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); |
||||||
|
private float scaleX = 1f; |
||||||
|
private float scaleY = 1f; |
||||||
|
|
||||||
|
private boolean initialized = false; |
||||||
|
private RawInputListener listener = null; |
||||||
|
|
||||||
|
private GestureDetector gestureDetector; |
||||||
|
private ScaleGestureDetector scaleDetector; |
||||||
|
|
||||||
|
protected AndroidInputHandler androidInput; |
||||||
|
|
||||||
|
public AndroidTouchInput(AndroidInputHandler androidInput) { |
||||||
|
this.androidInput = androidInput; |
||||||
|
} |
||||||
|
|
||||||
|
public GestureDetector getGestureDetector() { |
||||||
|
return gestureDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public void setGestureDetector(GestureDetector gestureDetector) { |
||||||
|
this.gestureDetector = gestureDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public ScaleGestureDetector getScaleDetector() { |
||||||
|
return scaleDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public void setScaleDetector(ScaleGestureDetector scaleDetector) { |
||||||
|
this.scaleDetector = scaleDetector; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertX(float origX) { |
||||||
|
return getJmeX(androidInput.getView().getWidth()) - origX; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertY(float origY) { |
||||||
|
return getJmeY(androidInput.getView().getHeight()) - origY; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeX(float origX) { |
||||||
|
return origX * scaleX; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeY(float origY) { |
||||||
|
return origY * scaleY; |
||||||
|
} |
||||||
|
|
||||||
|
public void loadSettings(AppSettings settings) { |
||||||
|
keyboardEventsEnabled = settings.isEmulateKeyboard(); |
||||||
|
mouseEventsEnabled = settings.isEmulateMouse(); |
||||||
|
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
||||||
|
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
||||||
|
|
||||||
|
// view width and height are 0 until the view is displayed on the screen
|
||||||
|
if (androidInput.getView().getWidth() != 0 && androidInput.getView().getHeight() != 0) { |
||||||
|
scaleX = (float)settings.getWidth() / (float)androidInput.getView().getWidth(); |
||||||
|
scaleY = (float)settings.getHeight() / (float)androidInput.getView().getHeight(); |
||||||
|
} |
||||||
|
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}", |
||||||
|
new Object[]{scaleX, scaleY}); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected int getPointerIndex(MotionEvent event) { |
||||||
|
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) |
||||||
|
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT; |
||||||
|
} |
||||||
|
|
||||||
|
protected int getPointerId(MotionEvent event) { |
||||||
|
return event.getPointerId(getPointerIndex(event)); |
||||||
|
} |
||||||
|
|
||||||
|
protected int getAction(MotionEvent event) { |
||||||
|
return event.getAction() & MotionEvent.ACTION_MASK; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onTouch(MotionEvent event) { |
||||||
|
if (!isInitialized()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
boolean bWasHandled = false; |
||||||
|
TouchEvent touch = null; |
||||||
|
// System.out.println("native : " + event.getAction());
|
||||||
|
int action = getAction(event); |
||||||
|
int pointerIndex = getPointerIndex(event); |
||||||
|
int pointerId = getPointerId(event); |
||||||
|
Vector2f lastPos = lastPositions.get(pointerId); |
||||||
|
float jmeX; |
||||||
|
float jmeY; |
||||||
|
|
||||||
|
numPointers = event.getPointerCount(); |
||||||
|
|
||||||
|
// final int historySize = event.getHistorySize();
|
||||||
|
//final int pointerCount = event.getPointerCount();
|
||||||
|
switch (getAction(event)) { |
||||||
|
case MotionEvent.ACTION_POINTER_DOWN: |
||||||
|
case MotionEvent.ACTION_DOWN: |
||||||
|
jmeX = getJmeX(event.getX(pointerIndex)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(pointerIndex))); |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(pointerIndex)); |
||||||
|
|
||||||
|
lastPos = new Vector2f(jmeX, jmeY); |
||||||
|
lastPositions.put(pointerId, lastPos); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_POINTER_UP: |
||||||
|
case MotionEvent.ACTION_CANCEL: |
||||||
|
case MotionEvent.ACTION_UP: |
||||||
|
jmeX = getJmeX(event.getX(pointerIndex)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(pointerIndex))); |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(pointerIndex)); |
||||||
|
lastPositions.remove(pointerId); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_MOVE: |
||||||
|
// Convert all pointers into events
|
||||||
|
for (int p = 0; p < event.getPointerCount(); p++) { |
||||||
|
jmeX = getJmeX(event.getX(p)); |
||||||
|
jmeY = invertY(getJmeY(event.getY(p))); |
||||||
|
lastPos = lastPositions.get(event.getPointerId(p)); |
||||||
|
if (lastPos == null) { |
||||||
|
lastPos = new Vector2f(jmeX, jmeY); |
||||||
|
lastPositions.put(event.getPointerId(p), lastPos); |
||||||
|
} |
||||||
|
|
||||||
|
float dX = jmeX - lastPos.x; |
||||||
|
float dY = jmeY - lastPos.y; |
||||||
|
if (dX != 0 || dY != 0) { |
||||||
|
touch = getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY); |
||||||
|
touch.setPointerId(event.getPointerId(p)); |
||||||
|
touch.setTime(event.getEventTime()); |
||||||
|
touch.setPressure(event.getPressure(p)); |
||||||
|
lastPos.set(jmeX, jmeY); |
||||||
|
|
||||||
|
addEvent(touch); |
||||||
|
addEvent(generateMouseEvent(touch)); |
||||||
|
|
||||||
|
bWasHandled = true; |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_OUTSIDE: |
||||||
|
break; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// Try to detect gestures
|
||||||
|
if (gestureDetector != null) { |
||||||
|
gestureDetector.onTouchEvent(event); |
||||||
|
} |
||||||
|
if (scaleDetector != null) { |
||||||
|
scaleDetector.onTouchEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
return bWasHandled; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Ring Buffer for mouse events?
|
||||||
|
public InputEvent generateMouseEvent(TouchEvent event) { |
||||||
|
InputEvent inputEvent = null; |
||||||
|
int newX; |
||||||
|
int newY; |
||||||
|
int newDX; |
||||||
|
int newDY; |
||||||
|
|
||||||
|
// MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
|
||||||
|
if (!isSimulateMouse() || numPointers > 1) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if (isMouseEventsInvertX()) { |
||||||
|
newX = (int) (invertX(event.getX())); |
||||||
|
newDX = (int)event.getDeltaX() * -1; |
||||||
|
} else { |
||||||
|
newX = (int) event.getX(); |
||||||
|
newDX = (int)event.getDeltaX(); |
||||||
|
} |
||||||
|
|
||||||
|
if (isMouseEventsInvertY()) { |
||||||
|
newY = (int) (invertY(event.getY())); |
||||||
|
newDY = (int)event.getDeltaY() * -1; |
||||||
|
} else { |
||||||
|
newY = (int) event.getY(); |
||||||
|
newDY = (int)event.getDeltaY(); |
||||||
|
} |
||||||
|
|
||||||
|
switch (event.getType()) { |
||||||
|
case DOWN: |
||||||
|
// Handle mouse down event
|
||||||
|
inputEvent = new MouseButtonEvent(0, true, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case UP: |
||||||
|
// Handle mouse up event
|
||||||
|
inputEvent = new MouseButtonEvent(0, false, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case HOVER_MOVE: |
||||||
|
case MOVE: |
||||||
|
inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return inputEvent; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean onKey(KeyEvent event) { |
||||||
|
if (!isInitialized()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
TouchEvent evt; |
||||||
|
// TODO: get touch event from pool
|
||||||
|
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
||||||
|
evt = new TouchEvent(); |
||||||
|
evt.set(TouchEvent.Type.KEY_DOWN); |
||||||
|
evt.setKeyCode(event.getKeyCode()); |
||||||
|
evt.setCharacters(event.getCharacters()); |
||||||
|
evt.setTime(event.getEventTime()); |
||||||
|
|
||||||
|
// Send the event
|
||||||
|
addEvent(evt); |
||||||
|
|
||||||
|
} else if (event.getAction() == KeyEvent.ACTION_UP) { |
||||||
|
evt = new TouchEvent(); |
||||||
|
evt.set(TouchEvent.Type.KEY_UP); |
||||||
|
evt.setKeyCode(event.getKeyCode()); |
||||||
|
evt.setCharacters(event.getCharacters()); |
||||||
|
evt.setTime(event.getEventTime()); |
||||||
|
|
||||||
|
// Send the event
|
||||||
|
addEvent(evt); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (isSimulateKeyboard()) { |
||||||
|
KeyInputEvent kie; |
||||||
|
char unicodeChar = (char)event.getUnicodeChar(); |
||||||
|
int jmeKeyCode = AndroidKeyMapping.getJmeKey(event.getKeyCode()); |
||||||
|
|
||||||
|
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
||||||
|
boolean repeating = pressed && event.getRepeatCount() > 0; |
||||||
|
|
||||||
|
kie = new KeyInputEvent(jmeKeyCode, unicodeChar, pressed, repeating); |
||||||
|
kie.setTime(event.getEventTime()); |
||||||
|
addEvent(kie); |
||||||
|
// logger.log(Level.FINE, "onKey keyCode: {0}, jmeKeyCode: {1}, pressed: {2}, repeating: {3}",
|
||||||
|
// new Object[]{event.getKeyCode(), jmeKeyCode, pressed, repeating});
|
||||||
|
// logger.log(Level.FINE, "creating KeyInputEvent: {0}", kie);
|
||||||
|
} |
||||||
|
|
||||||
|
// consume all keys ourself except Volume Up/Down and Menu
|
||||||
|
// Don't do Menu so that typical Android Menus can be created and used
|
||||||
|
// by the user in MainActivity
|
||||||
|
if ((event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) || |
||||||
|
(event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) || |
||||||
|
(event.getKeyCode() == KeyEvent.KEYCODE_MENU)) { |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
// JME3 Input interface
|
||||||
|
@Override |
||||||
|
public void initialize() { |
||||||
|
touchEventPool.initialize(); |
||||||
|
|
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
initialized = false; |
||||||
|
|
||||||
|
touchEventPool.destroy(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInitialized() { |
||||||
|
return initialized; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setInputListener(RawInputListener listener) { |
||||||
|
this.listener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getInputTimeNanos() { |
||||||
|
return System.nanoTime(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update() { |
||||||
|
if (listener != null) { |
||||||
|
InputEvent inputEvent; |
||||||
|
|
||||||
|
while ((inputEvent = inputEventQueue.poll()) != null) { |
||||||
|
if (inputEvent instanceof TouchEvent) { |
||||||
|
listener.onTouchEvent((TouchEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseButtonEvent) { |
||||||
|
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseMotionEvent) { |
||||||
|
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof KeyInputEvent) { |
||||||
|
listener.onKeyEvent((KeyInputEvent)inputEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
public TouchEvent getFreeTouchEvent() { |
||||||
|
return touchEventPool.getNextFreeEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addEvent(InputEvent event) { |
||||||
|
if (event == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
logger.log(Level.INFO, "event: {0}", event); |
||||||
|
|
||||||
|
inputEventQueue.add(event); |
||||||
|
if (event instanceof TouchEvent) { |
||||||
|
touchEventPool.storeEvent((TouchEvent)event); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateMouse(boolean simulate) { |
||||||
|
this.mouseEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSimulateMouse() { |
||||||
|
return mouseEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertX() { |
||||||
|
return mouseEventsInvertX; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertY() { |
||||||
|
return mouseEventsInvertY; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateKeyboard(boolean simulate) { |
||||||
|
this.keyboardEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSimulateKeyboard() { |
||||||
|
return keyboardEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setOmitHistoricEvents(boolean dontSendHistory) { |
||||||
|
this.dontSendHistory = dontSendHistory; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,122 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 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.renderer.opengl; |
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Proxy; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
public class GLTiming implements InvocationHandler { |
||||||
|
|
||||||
|
private final Object obj; |
||||||
|
private final GLTimingState state; |
||||||
|
|
||||||
|
public GLTiming(Object obj, GLTimingState state) { |
||||||
|
this.obj = obj; |
||||||
|
this.state = state; |
||||||
|
} |
||||||
|
|
||||||
|
public static Object createGLTiming(Object glInterface, GLTimingState state, Class<?> ... glInterfaceClasses) { |
||||||
|
return Proxy.newProxyInstance(glInterface.getClass().getClassLoader(), |
||||||
|
glInterfaceClasses, |
||||||
|
new GLTiming(glInterface, state)); |
||||||
|
} |
||||||
|
|
||||||
|
private static class CallTimingComparator implements Comparator<Map.Entry<String, Long>> { |
||||||
|
@Override |
||||||
|
public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) { |
||||||
|
return (int) (o2.getValue() - o1.getValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
||||||
|
String methodName = method.getName(); |
||||||
|
if (methodName.equals("resetStats")) { |
||||||
|
if (state.lastPrintOutTime + 1000000000 <= System.nanoTime() && state.sampleCount > 0) { |
||||||
|
state.timeSpentInGL /= state.sampleCount; |
||||||
|
System.out.println("--- TOTAL TIME SPENT IN GL CALLS: " + (state.timeSpentInGL/1000) + "us"); |
||||||
|
|
||||||
|
Map.Entry<String, Long>[] callTimes = new Map.Entry[state.callTiming.size()]; |
||||||
|
int i = 0; |
||||||
|
for (Map.Entry<String, Long> callTime : state.callTiming.entrySet()) { |
||||||
|
callTimes[i++] = callTime; |
||||||
|
} |
||||||
|
Arrays.sort(callTimes, new CallTimingComparator()); |
||||||
|
int limit = 10; |
||||||
|
for (Map.Entry<String, Long> callTime : callTimes) { |
||||||
|
long val = callTime.getValue() / state.sampleCount; |
||||||
|
String name = callTime.getKey(); |
||||||
|
String pad = " ".substring(0, 30 - name.length()); |
||||||
|
System.out.println("\t" + callTime.getKey() + pad + (val/1000) + "us"); |
||||||
|
if (limit-- == 0) break; |
||||||
|
} |
||||||
|
for (Map.Entry<String, Long> callTime : callTimes) { |
||||||
|
state.callTiming.put(callTime.getKey(), Long.valueOf(0)); |
||||||
|
} |
||||||
|
|
||||||
|
state.sampleCount = 0; |
||||||
|
state.timeSpentInGL = 0; |
||||||
|
state.lastPrintOutTime = System.nanoTime(); |
||||||
|
} else { |
||||||
|
state.sampleCount++; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} else { |
||||||
|
Long currentTimeObj = state.callTiming.get(methodName); |
||||||
|
long currentTime = 0; |
||||||
|
if (currentTimeObj != null) currentTime = currentTimeObj; |
||||||
|
|
||||||
|
|
||||||
|
long startTime = System.nanoTime(); |
||||||
|
Object result = method.invoke(obj, args); |
||||||
|
long delta = System.nanoTime() - startTime; |
||||||
|
|
||||||
|
currentTime += delta; |
||||||
|
state.timeSpentInGL += delta; |
||||||
|
|
||||||
|
state.callTiming.put(methodName, currentTime); |
||||||
|
|
||||||
|
if (delta > 1000000 && !methodName.equals("glClear")) { |
||||||
|
// More than 1ms
|
||||||
|
// Ignore glClear as it cannot be avoided.
|
||||||
|
System.out.println("GL call " + methodName + " took " + (delta/1000) + "us to execute!"); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2015 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.renderer.opengl; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
|
||||||
|
public class GLTimingState { |
||||||
|
long timeSpentInGL = 0; |
||||||
|
int sampleCount = 0; |
||||||
|
long lastPrintOutTime = 0; |
||||||
|
final HashMap<String, Long> callTiming = new HashMap<String, Long>(); |
||||||
|
} |
@ -0,0 +1,140 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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.util; |
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.FastMath; |
||||||
|
import com.jme3.texture.Image; |
||||||
|
import com.jme3.texture.Image.Format; |
||||||
|
import com.jme3.texture.image.ImageRaster; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.ArrayList; |
||||||
|
|
||||||
|
public class MipMapGenerator { |
||||||
|
|
||||||
|
private MipMapGenerator() { |
||||||
|
} |
||||||
|
|
||||||
|
public static Image scaleImage(Image inputImage, int outputWidth, int outputHeight) { |
||||||
|
int size = outputWidth * outputHeight * inputImage.getFormat().getBitsPerPixel() / 8; |
||||||
|
ByteBuffer buffer = BufferUtils.createByteBuffer(size); |
||||||
|
Image outputImage = new Image(inputImage.getFormat(), |
||||||
|
outputWidth, |
||||||
|
outputHeight, |
||||||
|
buffer, |
||||||
|
inputImage.getColorSpace()); |
||||||
|
|
||||||
|
ImageRaster input = ImageRaster.create(inputImage, 0, 0, false); |
||||||
|
ImageRaster output = ImageRaster.create(outputImage, 0, 0, false); |
||||||
|
|
||||||
|
float xRatio = ((float)(input.getWidth() - 1)) / output.getWidth(); |
||||||
|
float yRatio = ((float)(input.getHeight() - 1)) / output.getHeight(); |
||||||
|
|
||||||
|
ColorRGBA outputColor = new ColorRGBA(); |
||||||
|
ColorRGBA bottomLeft = new ColorRGBA(); |
||||||
|
ColorRGBA bottomRight = new ColorRGBA(); |
||||||
|
ColorRGBA topLeft = new ColorRGBA(); |
||||||
|
ColorRGBA topRight = new ColorRGBA(); |
||||||
|
|
||||||
|
for (int y = 0; y < outputHeight; y++) { |
||||||
|
for (int x = 0; x < outputWidth; x++) { |
||||||
|
float x2f = x * xRatio; |
||||||
|
float y2f = y * yRatio; |
||||||
|
|
||||||
|
int x2 = (int)x2f; |
||||||
|
int y2 = (int)y2f; |
||||||
|
|
||||||
|
float xDiff = x2f - x2; |
||||||
|
float yDiff = y2f - y2; |
||||||
|
|
||||||
|
input.getPixel(x2, y2, bottomLeft); |
||||||
|
input.getPixel(x2 + 1, y2, bottomRight); |
||||||
|
input.getPixel(x2, y2 + 1, topLeft); |
||||||
|
input.getPixel(x2 + 1, y2 + 1, topRight); |
||||||
|
|
||||||
|
bottomLeft.multLocal( (1f - xDiff) * (1f - yDiff) ); |
||||||
|
bottomRight.multLocal( (xDiff) * (1f - yDiff) ); |
||||||
|
topLeft.multLocal( (1f - xDiff) * (yDiff) ); |
||||||
|
topRight.multLocal( (xDiff) * (yDiff) ); |
||||||
|
|
||||||
|
outputColor.set(bottomLeft).addLocal(bottomRight) |
||||||
|
.addLocal(topLeft).addLocal(topRight); |
||||||
|
|
||||||
|
output.setPixel(x, y, outputColor); |
||||||
|
} |
||||||
|
} |
||||||
|
return outputImage; |
||||||
|
} |
||||||
|
|
||||||
|
public static Image resizeToPowerOf2(Image original){ |
||||||
|
int potWidth = FastMath.nearestPowerOfTwo(original.getWidth()); |
||||||
|
int potHeight = FastMath.nearestPowerOfTwo(original.getHeight()); |
||||||
|
return scaleImage(original, potWidth, potHeight); |
||||||
|
} |
||||||
|
|
||||||
|
public static void generateMipMaps(Image image){ |
||||||
|
int width = image.getWidth(); |
||||||
|
int height = image.getHeight(); |
||||||
|
|
||||||
|
Image current = image; |
||||||
|
ArrayList<ByteBuffer> output = new ArrayList<ByteBuffer>(); |
||||||
|
int totalSize = 0; |
||||||
|
|
||||||
|
while (height >= 1 || width >= 1){ |
||||||
|
output.add(current.getData(0)); |
||||||
|
totalSize += current.getData(0).capacity(); |
||||||
|
|
||||||
|
if (height == 1 || width == 1) { |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
height /= 2; |
||||||
|
width /= 2; |
||||||
|
|
||||||
|
current = scaleImage(current, width, height); |
||||||
|
} |
||||||
|
|
||||||
|
ByteBuffer combinedData = BufferUtils.createByteBuffer(totalSize); |
||||||
|
int[] mipSizes = new int[output.size()]; |
||||||
|
for (int i = 0; i < output.size(); i++){ |
||||||
|
ByteBuffer data = output.get(i); |
||||||
|
data.clear(); |
||||||
|
combinedData.put(data); |
||||||
|
mipSizes[i] = data.capacity(); |
||||||
|
} |
||||||
|
combinedData.flip(); |
||||||
|
|
||||||
|
// insert mip data into image
|
||||||
|
image.setData(0, combinedData); |
||||||
|
image.setMipMapSizes(mipSizes); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
# When running this project we don't need javadoc to be built. |
||||||
|
buildJavaDoc = false |
||||||
|
|
||||||
|
# We want assertions, because this is the test project. |
||||||
|
assertions = true |
@ -1,152 +1,152 @@ |
|||||||
/* |
/* |
||||||
* Copyright (c) 2009-2012 jMonkeyEngine |
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
* All rights reserved. |
* All rights reserved. |
||||||
* |
* |
||||||
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
||||||
* modification, are permitted provided that the following conditions are |
* modification, are permitted provided that the following conditions are |
||||||
* met: |
* met: |
||||||
* |
* |
||||||
* * Redistributions of source code must retain the above copyright |
* * Redistributions of source code must retain the above copyright |
||||||
* notice, this list of conditions and the following disclaimer. |
* notice, this list of conditions and the following disclaimer. |
||||||
* |
* |
||||||
* * Redistributions in binary form must reproduce the above copyright |
* * Redistributions in binary form must reproduce the above copyright |
||||||
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
||||||
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
||||||
* |
* |
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
||||||
* without specific prior written permission. |
* without specific prior written permission. |
||||||
* |
* |
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
*/ |
*/ |
||||||
package jme3test.bullet; |
package jme3test.bullet; |
||||||
|
|
||||||
import com.jme3.app.SimpleApplication; |
import com.jme3.app.SimpleApplication; |
||||||
import com.jme3.bullet.BulletAppState; |
import com.jme3.bullet.BulletAppState; |
||||||
import com.jme3.bullet.PhysicsSpace; |
import com.jme3.bullet.PhysicsSpace; |
||||||
import com.jme3.bullet.collision.shapes.BoxCollisionShape; |
import com.jme3.bullet.collision.shapes.BoxCollisionShape; |
||||||
import com.jme3.bullet.collision.shapes.MeshCollisionShape; |
import com.jme3.bullet.collision.shapes.MeshCollisionShape; |
||||||
import com.jme3.bullet.collision.shapes.SphereCollisionShape; |
import com.jme3.bullet.collision.shapes.SphereCollisionShape; |
||||||
import com.jme3.bullet.control.RigidBodyControl; |
import com.jme3.bullet.control.RigidBodyControl; |
||||||
import com.jme3.input.MouseInput; |
import com.jme3.input.MouseInput; |
||||||
import com.jme3.input.controls.ActionListener; |
import com.jme3.input.controls.ActionListener; |
||||||
import com.jme3.input.controls.MouseButtonTrigger; |
import com.jme3.input.controls.MouseButtonTrigger; |
||||||
import com.jme3.material.Material; |
import com.jme3.material.Material; |
||||||
import com.jme3.math.ColorRGBA; |
import com.jme3.math.ColorRGBA; |
||||||
import com.jme3.math.Vector3f; |
import com.jme3.math.Vector3f; |
||||||
import com.jme3.renderer.RenderManager; |
import com.jme3.renderer.RenderManager; |
||||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
||||||
import com.jme3.scene.Geometry; |
import com.jme3.scene.Geometry; |
||||||
import com.jme3.scene.Node; |
import com.jme3.scene.Node; |
||||||
import com.jme3.scene.shape.Box; |
import com.jme3.scene.shape.Box; |
||||||
import com.jme3.scene.shape.Sphere; |
import com.jme3.scene.shape.Sphere; |
||||||
import com.jme3.scene.shape.Sphere.TextureMode; |
import com.jme3.scene.shape.Sphere.TextureMode; |
||||||
|
|
||||||
/** |
/** |
||||||
* |
* |
||||||
* @author normenhansen |
* @author normenhansen |
||||||
*/ |
*/ |
||||||
public class TestCcd extends SimpleApplication implements ActionListener { |
public class TestCcd extends SimpleApplication implements ActionListener { |
||||||
|
|
||||||
private Material mat; |
private Material mat; |
||||||
private Material mat2; |
private Material mat2; |
||||||
private Sphere bullet; |
private Sphere bullet; |
||||||
private SphereCollisionShape bulletCollisionShape; |
private SphereCollisionShape bulletCollisionShape; |
||||||
private BulletAppState bulletAppState; |
private BulletAppState bulletAppState; |
||||||
|
|
||||||
public static void main(String[] args) { |
public static void main(String[] args) { |
||||||
TestCcd app = new TestCcd(); |
TestCcd app = new TestCcd(); |
||||||
app.start(); |
app.start(); |
||||||
} |
} |
||||||
|
|
||||||
private void setupKeys() { |
private void setupKeys() { |
||||||
inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); |
inputManager.addMapping("shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); |
||||||
inputManager.addMapping("shoot2", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); |
inputManager.addMapping("shoot2", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT)); |
||||||
inputManager.addListener(this, "shoot"); |
inputManager.addListener(this, "shoot"); |
||||||
inputManager.addListener(this, "shoot2"); |
inputManager.addListener(this, "shoot2"); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleInitApp() { |
public void simpleInitApp() { |
||||||
bulletAppState = new BulletAppState(); |
bulletAppState = new BulletAppState(); |
||||||
stateManager.attach(bulletAppState); |
stateManager.attach(bulletAppState); |
||||||
bulletAppState.getPhysicsSpace().enableDebug(assetManager); |
bulletAppState.setDebugEnabled(true); |
||||||
bullet = new Sphere(32, 32, 0.4f, true, false); |
bullet = new Sphere(32, 32, 0.4f, true, false); |
||||||
bullet.setTextureMode(TextureMode.Projected); |
bullet.setTextureMode(TextureMode.Projected); |
||||||
bulletCollisionShape = new SphereCollisionShape(0.1f); |
bulletCollisionShape = new SphereCollisionShape(0.1f); |
||||||
setupKeys(); |
setupKeys(); |
||||||
|
|
||||||
mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); |
mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); |
||||||
mat.getAdditionalRenderState().setWireframe(true); |
mat.getAdditionalRenderState().setWireframe(true); |
||||||
mat.setColor("Color", ColorRGBA.Green); |
mat.setColor("Color", ColorRGBA.Green); |
||||||
|
|
||||||
mat2 = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); |
mat2 = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); |
||||||
mat2.getAdditionalRenderState().setWireframe(true); |
mat2.getAdditionalRenderState().setWireframe(true); |
||||||
mat2.setColor("Color", ColorRGBA.Red); |
mat2.setColor("Color", ColorRGBA.Red); |
||||||
|
|
||||||
// An obstacle mesh, does not move (mass=0)
|
// An obstacle mesh, does not move (mass=0)
|
||||||
Node node2 = new Node(); |
Node node2 = new Node(); |
||||||
node2.setName("mesh"); |
node2.setName("mesh"); |
||||||
node2.setLocalTranslation(new Vector3f(2.5f, 0, 0f)); |
node2.setLocalTranslation(new Vector3f(2.5f, 0, 0f)); |
||||||
node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(Vector3f.ZERO, 4, 4, 0.1f)), 0)); |
node2.addControl(new RigidBodyControl(new MeshCollisionShape(new Box(Vector3f.ZERO, 4, 4, 0.1f)), 0)); |
||||||
rootNode.attachChild(node2); |
rootNode.attachChild(node2); |
||||||
getPhysicsSpace().add(node2); |
getPhysicsSpace().add(node2); |
||||||
|
|
||||||
// The floor, does not move (mass=0)
|
// The floor, does not move (mass=0)
|
||||||
Node node3 = new Node(); |
Node node3 = new Node(); |
||||||
node3.setLocalTranslation(new Vector3f(0f, -6, 0f)); |
node3.setLocalTranslation(new Vector3f(0f, -6, 0f)); |
||||||
node3.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(100, 1, 100)), 0)); |
node3.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(100, 1, 100)), 0)); |
||||||
rootNode.attachChild(node3); |
rootNode.attachChild(node3); |
||||||
getPhysicsSpace().add(node3); |
getPhysicsSpace().add(node3); |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
private PhysicsSpace getPhysicsSpace() { |
private PhysicsSpace getPhysicsSpace() { |
||||||
return bulletAppState.getPhysicsSpace(); |
return bulletAppState.getPhysicsSpace(); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleUpdate(float tpf) { |
public void simpleUpdate(float tpf) { |
||||||
//TODO: add update code
|
//TODO: add update code
|
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleRender(RenderManager rm) { |
public void simpleRender(RenderManager rm) { |
||||||
//TODO: add render code
|
//TODO: add render code
|
||||||
} |
} |
||||||
|
|
||||||
public void onAction(String binding, boolean value, float tpf) { |
public void onAction(String binding, boolean value, float tpf) { |
||||||
if (binding.equals("shoot") && !value) { |
if (binding.equals("shoot") && !value) { |
||||||
Geometry bulletg = new Geometry("bullet", bullet); |
Geometry bulletg = new Geometry("bullet", bullet); |
||||||
bulletg.setMaterial(mat); |
bulletg.setMaterial(mat); |
||||||
bulletg.setName("bullet"); |
bulletg.setName("bullet"); |
||||||
bulletg.setLocalTranslation(cam.getLocation()); |
bulletg.setLocalTranslation(cam.getLocation()); |
||||||
bulletg.setShadowMode(ShadowMode.CastAndReceive); |
bulletg.setShadowMode(ShadowMode.CastAndReceive); |
||||||
bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); |
bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); |
||||||
bulletg.getControl(RigidBodyControl.class).setCcdMotionThreshold(0.1f); |
bulletg.getControl(RigidBodyControl.class).setCcdMotionThreshold(0.1f); |
||||||
bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); |
bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); |
||||||
rootNode.attachChild(bulletg); |
rootNode.attachChild(bulletg); |
||||||
getPhysicsSpace().add(bulletg); |
getPhysicsSpace().add(bulletg); |
||||||
} else if (binding.equals("shoot2") && !value) { |
} else if (binding.equals("shoot2") && !value) { |
||||||
Geometry bulletg = new Geometry("bullet", bullet); |
Geometry bulletg = new Geometry("bullet", bullet); |
||||||
bulletg.setMaterial(mat2); |
bulletg.setMaterial(mat2); |
||||||
bulletg.setName("bullet"); |
bulletg.setName("bullet"); |
||||||
bulletg.setLocalTranslation(cam.getLocation()); |
bulletg.setLocalTranslation(cam.getLocation()); |
||||||
bulletg.setShadowMode(ShadowMode.CastAndReceive); |
bulletg.setShadowMode(ShadowMode.CastAndReceive); |
||||||
bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); |
bulletg.addControl(new RigidBodyControl(bulletCollisionShape, 1)); |
||||||
bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); |
bulletg.getControl(RigidBodyControl.class).setLinearVelocity(cam.getDirection().mult(40)); |
||||||
rootNode.attachChild(bulletg); |
rootNode.attachChild(bulletg); |
||||||
getPhysicsSpace().add(bulletg); |
getPhysicsSpace().add(bulletg); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,98 +1,98 @@ |
|||||||
/* |
/* |
||||||
* Copyright (c) 2009-2012 jMonkeyEngine |
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
* All rights reserved. |
* All rights reserved. |
||||||
* |
* |
||||||
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
||||||
* modification, are permitted provided that the following conditions are |
* modification, are permitted provided that the following conditions are |
||||||
* met: |
* met: |
||||||
* |
* |
||||||
* * Redistributions of source code must retain the above copyright |
* * Redistributions of source code must retain the above copyright |
||||||
* notice, this list of conditions and the following disclaimer. |
* notice, this list of conditions and the following disclaimer. |
||||||
* |
* |
||||||
* * Redistributions in binary form must reproduce the above copyright |
* * Redistributions in binary form must reproduce the above copyright |
||||||
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
||||||
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
||||||
* |
* |
||||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
||||||
* without specific prior written permission. |
* without specific prior written permission. |
||||||
* |
* |
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
*/ |
*/ |
||||||
|
|
||||||
package jme3test.bullet; |
package jme3test.bullet; |
||||||
|
|
||||||
import com.jme3.app.SimpleApplication; |
import com.jme3.app.SimpleApplication; |
||||||
import com.jme3.bullet.BulletAppState; |
import com.jme3.bullet.BulletAppState; |
||||||
import com.jme3.bullet.PhysicsSpace; |
import com.jme3.bullet.PhysicsSpace; |
||||||
import com.jme3.bullet.collision.PhysicsCollisionEvent; |
import com.jme3.bullet.collision.PhysicsCollisionEvent; |
||||||
import com.jme3.bullet.collision.PhysicsCollisionListener; |
import com.jme3.bullet.collision.PhysicsCollisionListener; |
||||||
import com.jme3.bullet.collision.shapes.SphereCollisionShape; |
import com.jme3.bullet.collision.shapes.SphereCollisionShape; |
||||||
import com.jme3.renderer.RenderManager; |
import com.jme3.renderer.RenderManager; |
||||||
import com.jme3.scene.shape.Sphere; |
import com.jme3.scene.shape.Sphere; |
||||||
import com.jme3.scene.shape.Sphere.TextureMode; |
import com.jme3.scene.shape.Sphere.TextureMode; |
||||||
|
|
||||||
/** |
/** |
||||||
* |
* |
||||||
* @author normenhansen |
* @author normenhansen |
||||||
*/ |
*/ |
||||||
public class TestCollisionListener extends SimpleApplication implements PhysicsCollisionListener { |
public class TestCollisionListener extends SimpleApplication implements PhysicsCollisionListener { |
||||||
|
|
||||||
private BulletAppState bulletAppState; |
private BulletAppState bulletAppState; |
||||||
private Sphere bullet; |
private Sphere bullet; |
||||||
private SphereCollisionShape bulletCollisionShape; |
private SphereCollisionShape bulletCollisionShape; |
||||||
|
|
||||||
public static void main(String[] args) { |
public static void main(String[] args) { |
||||||
TestCollisionListener app = new TestCollisionListener(); |
TestCollisionListener app = new TestCollisionListener(); |
||||||
app.start(); |
app.start(); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleInitApp() { |
public void simpleInitApp() { |
||||||
bulletAppState = new BulletAppState(); |
bulletAppState = new BulletAppState(); |
||||||
stateManager.attach(bulletAppState); |
stateManager.attach(bulletAppState); |
||||||
bulletAppState.getPhysicsSpace().enableDebug(assetManager); |
bulletAppState.setDebugEnabled(true); |
||||||
bullet = new Sphere(32, 32, 0.4f, true, false); |
bullet = new Sphere(32, 32, 0.4f, true, false); |
||||||
bullet.setTextureMode(TextureMode.Projected); |
bullet.setTextureMode(TextureMode.Projected); |
||||||
bulletCollisionShape = new SphereCollisionShape(0.4f); |
bulletCollisionShape = new SphereCollisionShape(0.4f); |
||||||
|
|
||||||
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); |
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace()); |
||||||
PhysicsTestHelper.createBallShooter(this, rootNode, bulletAppState.getPhysicsSpace()); |
PhysicsTestHelper.createBallShooter(this, rootNode, bulletAppState.getPhysicsSpace()); |
||||||
|
|
||||||
// add ourselves as collision listener
|
// add ourselves as collision listener
|
||||||
getPhysicsSpace().addCollisionListener(this); |
getPhysicsSpace().addCollisionListener(this); |
||||||
} |
} |
||||||
|
|
||||||
private PhysicsSpace getPhysicsSpace(){ |
private PhysicsSpace getPhysicsSpace(){ |
||||||
return bulletAppState.getPhysicsSpace(); |
return bulletAppState.getPhysicsSpace(); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleUpdate(float tpf) { |
public void simpleUpdate(float tpf) { |
||||||
//TODO: add update code
|
//TODO: add update code
|
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void simpleRender(RenderManager rm) { |
public void simpleRender(RenderManager rm) { |
||||||
//TODO: add render code
|
//TODO: add render code
|
||||||
} |
} |
||||||
|
|
||||||
public void collision(PhysicsCollisionEvent event) { |
public void collision(PhysicsCollisionEvent event) { |
||||||
if ("Box".equals(event.getNodeA().getName()) || "Box".equals(event.getNodeB().getName())) { |
if ("Box".equals(event.getNodeA().getName()) || "Box".equals(event.getNodeB().getName())) { |
||||||
if ("bullet".equals(event.getNodeA().getName()) || "bullet".equals(event.getNodeB().getName())) { |
if ("bullet".equals(event.getNodeA().getName()) || "bullet".equals(event.getNodeB().getName())) { |
||||||
fpsText.setText("You hit the box!"); |
fpsText.setText("You hit the box!"); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue