aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-03-24 05:18:34 +0100
committerSven Gothel <[email protected]>2013-03-24 05:18:34 +0100
commit654a678bd7171e81ec947cafa854dad366f5041e (patch)
treee8951df5e9e9b24c2666ad89a1a656146c3bcb08
parent18cb57246372eda72c25a5cd9a69a873bdf09489 (diff)
Android/NEWT MouseEvent: Fix Delivery of MultiTouch PRESSED/RELEASE; Fix Detection/Processing of 2-Finger-Scroll Gesture ; GearsES2: Add NEWT based 'zoom' gesture detection.
- Fix Delivery of MultiTouch PRESSED/RELEASE Adopting MouseEvent changes of commit 18cb57246372eda72c25a5cd9a69a873bdf09489 - Fix Detection/Processing of 2-Finger-Scroll Gesture Dropping utilization of Android's GestureDetector and implementing our own, which turns out to simplify keeping track of states. Our gesture detection works well w/ user NEWT based gesture detection (-> See GearsES2 zoom and rotate), using following criteria related to Android parameter: - ScaledDoubleTapSlop: - Max 2 finger distance - ScaledTouchSlop: - Min. movement w/ 2 pointer withing ScaledDoubleTapSlop starting 'scroll' mode - Max. change of finger distance in respect to initiating 2-finger distance (2x ScaledTouchSlop) - Max. distance growth in respect to initiating 2-finger distance. - GearsES2: Add NEWT based 'zoom' gesture detection.
-rw-r--r--src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java340
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java137
2 files changed, 305 insertions, 172 deletions
diff --git a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
index 5d2333c1f..83d3e7d90 100644
--- a/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
+++ b/src/newt/classes/jogamp/newt/driver/android/event/AndroidNewtEventFactory.java
@@ -28,20 +28,33 @@
package jogamp.newt.driver.android.event;
+import jogamp.newt.Debug;
+import android.view.MotionEvent;
+
import com.jogamp.common.os.AndroidVersion;
-import com.jogamp.newt.Window;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.NEWTEvent;
public class AndroidNewtEventFactory {
-
- private static final String names[] = { "DOWN" , "UP" , "MOVE", "CANCEL" , "OUTSIDE", // 0 - 4
- "POINTER_DOWN" , "POINTER_UP" , "HOVER_MOVE" , "SCROLL", // 5 - 8
- "HOVER_ENTER", "HOVER_EXIT" // 0 - 10
- };
+ private static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Android.MouseEvent");
+ private static final boolean DEBUG_KEY_EVENT = Debug.debug("Android.KeyEvent");
/** API Level 12: {@link android.view.MotionEvent#ACTION_SCROLL} = {@value} */
private static final int ACTION_SCROLL = 8;
+
+ private static final com.jogamp.newt.event.MouseEvent.PointerType aToolType2PointerType(int aToolType) {
+ switch( aToolType ) {
+ case MotionEvent.TOOL_TYPE_FINGER:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Touch;
+ case MotionEvent.TOOL_TYPE_MOUSE:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Mouse;
+ case MotionEvent.TOOL_TYPE_STYLUS:
+ case MotionEvent.TOOL_TYPE_ERASER:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Pen;
+ default:
+ return com.jogamp.newt.event.MouseEvent.PointerType.Undefined;
+ }
+ }
private static final short aMotionEventType2Newt(int aType) {
switch( aType ) {
@@ -174,7 +187,7 @@ public class AndroidNewtEventFactory {
} else {
res = null;
}
- if(Window.DEBUG_KEY_EVENT) {
+ if(DEBUG_KEY_EVENT) {
System.err.println("createKeyEvent0: "+aEvent+" -> "+res);
}
return res;
@@ -183,7 +196,7 @@ public class AndroidNewtEventFactory {
public static com.jogamp.newt.event.KeyEvent createKeyEvent(android.view.KeyEvent aEvent, short newtType, com.jogamp.newt.Window newtSource, boolean inclSysKeys) {
final short newtKeyCode = aKeyCode2NewtKeyCode(aEvent.getKeyCode(), inclSysKeys);
final com.jogamp.newt.event.KeyEvent res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource);
- if(Window.DEBUG_KEY_EVENT) {
+ if(DEBUG_KEY_EVENT) {
System.err.println("createKeyEvent1: newtType "+NEWTEvent.toHexString(newtType)+", "+aEvent+" -> "+res);
}
return res;
@@ -191,7 +204,7 @@ public class AndroidNewtEventFactory {
public static com.jogamp.newt.event.KeyEvent createKeyEvent(android.view.KeyEvent aEvent, short newtKeyCode, short newtType, com.jogamp.newt.Window newtSource) {
final com.jogamp.newt.event.KeyEvent res = createKeyEventImpl(aEvent, newtType, newtKeyCode, newtSource);
- if(Window.DEBUG_KEY_EVENT) {
+ if(DEBUG_KEY_EVENT) {
System.err.println("createKeyEvent2: newtType "+NEWTEvent.toHexString(newtType)+", "+aEvent+" -> "+res);
}
return res;
@@ -231,24 +244,39 @@ public class AndroidNewtEventFactory {
return maxPressure;
}
- private final NewtGestureListener gestureListener;
- private final android.view.GestureDetector gestureDetector;
- private final float touchSlop;
+ private final int touchSlop, touchSlop2x, touchSlopSquare, doubleTapSlop, doubleTapSlopSquare;
public AndroidNewtEventFactory(android.content.Context context, android.os.Handler handler) {
- gestureListener = new NewtGestureListener();
- gestureDetector = new android.view.GestureDetector(context, gestureListener, handler, false /* ignoreMultitouch */);
- gestureDetector.setIsLongpressEnabled(false); // favor scroll event!
final android.view.ViewConfiguration configuration = android.view.ViewConfiguration.get(context);
touchSlop = configuration.getScaledTouchSlop();
+ touchSlop2x = 2*touchSlop;
+ touchSlopSquare = touchSlop * touchSlop;
+ doubleTapSlop = configuration.getScaledDoubleTapSlop();
+ doubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("GestureListener touchSlop (scaled) "+touchSlop);
+ System.err.println("GestureListener doubleTapSlop (scaled) "+doubleTapSlop);
+ }
}
-
- private int gestureScrollPointerDown = 0;
-
+
+ private static void collectPointerData(MotionEvent e, int eIdx, int dIdx, final int[] x, final int[] y, final float[] pressure, short[] pointerIds, final com.jogamp.newt.event.MouseEvent.PointerType[] pointerTypes) {
+ x[dIdx] = (int)e.getX(eIdx);
+ y[dIdx] = (int)e.getY(eIdx);
+ pressure[dIdx] = e.getPressure(eIdx);
+ pointerIds[dIdx] = (short)e.getPointerId(eIdx);
+ if( pressure[dIdx] > maxPressure ) {
+ maxPressure = pressure[dIdx];
+ }
+ pointerTypes[dIdx] = aToolType2PointerType( e.getToolType(eIdx) );
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: ptr-data["+eIdx+" -> "+dIdx+"] "+x[dIdx]+"/"+y[dIdx]+", pressure "+pressure[dIdx]+", id "+pointerIds[dIdx]+", type "+pointerTypes[dIdx]);
+ }
+ }
+
public com.jogamp.newt.event.MouseEvent[] createMouseEvents(boolean isOnTouchEvent,
android.view.MotionEvent event, com.jogamp.newt.Window newtSource) {
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: "+toString(event));
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: isOnTouchEvent "+isOnTouchEvent+", "+event);
}
if( event.getPressure() > maxPressure ) {
@@ -261,49 +289,38 @@ public class AndroidNewtEventFactory {
final int aType;
final short nType;
float[] rotationXY = null;
- int rotationSource = 0; // 1 - Gesture, 2 - ACTION_SCROLL
- {
- final int pointerCount = event.getPointerCount();
- final boolean gestureEvent = isOnTouchEvent && pointerCount>1 && gestureDetector.onTouchEvent(event);
- int _aType = 0xFFFFFFFF;
- if( gestureEvent ) {
- rotationXY = gestureListener.getScrollDistanceXY();
- if( null != rotationXY) {
- final boolean skip = 0 == gestureScrollPointerDown; // skip 1st .. too bug distance
- gestureScrollPointerDown = pointerCount;
- if( skip ) {
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: GestureEvent Scroll Start - SKIP "+rotationXY[0]+"/"+rotationXY[1]+", gestureScrollPointerDown "+gestureScrollPointerDown);
- }
- return null;
- }
- _aType = ACTION_SCROLL; // 8
- rotationSource = 1;
- } else {
- throw new InternalError("Gesture Internal Error: consumed onTouchEvent, but no result (Scroll)");
+ int rotationSource = 0; // 1 - Gesture, 2 - ACTION_SCROLL
+ {
+ final int aType0 = event.getActionMasked();
+ if( isOnTouchEvent ) {
+ boolean action = false;
+ switch ( aType0 ) {
+ case MotionEvent.ACTION_DOWN:
+ action = true;
+ // fall through intended
+ case MotionEvent.ACTION_POINTER_DOWN:
+ gesture2FingerScrl.onDown(event, action);
+ break;
+ case MotionEvent.ACTION_UP:
+ action = true;
+ // fall through intended
+ case MotionEvent.ACTION_POINTER_UP:
+ gesture2FingerScrl.onUp(event, action);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ gesture2FingerScrl.onActionMove(event);
+ break;
}
}
- if( 0xFFFFFFFF == _aType ) {
- _aType = event.getActionMasked();
- }
- aType = _aType;
- nType = aMotionEventType2Newt(aType);
-
- //
- // Check whether events shall be skipped
- //
- if( !gestureEvent ) {
- // Scroll Gesture: Wait for all pointers up - ACTION_UP, ACTION_POINTER_UP
- if( 0 < gestureScrollPointerDown ) {
- if( com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED == nType ) {
- gestureScrollPointerDown--;
- }
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: !GestureEvent SKIP gestureScrollPointerDown "+gestureScrollPointerDown);
- }
- return null;
- }
+
+ if( gesture2FingerScrl.isWithinGesture() ) {
+ rotationXY = gesture2FingerScrl.getScrollDistanceXY();
+ aType = ACTION_SCROLL; // 8
+ rotationSource = 1;
+ } else {
+ aType = aType0;
}
+ nType = aMotionEventType2Newt(aType);
}
if( (short)0 != nType ) {
@@ -317,6 +334,7 @@ public class AndroidNewtEventFactory {
}
final float rotation;
+ final float rotationScale = touchSlop;
if( null != rotationXY ) {
final float _rotation;
if( rotationXY[0]*rotationXY[0] > rotationXY[1]*rotationXY[1] ) {
@@ -327,9 +345,9 @@ public class AndroidNewtEventFactory {
// Vertical
_rotation = rotationXY[1];
}
- rotation = _rotation / touchSlop;
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: Scroll "+rotationXY[0]+"/"+rotationXY[1]+" -> "+_rotation+" / "+touchSlop+" -> "+rotation+" scaled -- mods "+modifiers+", source "+rotationSource);
+ rotation = _rotation / rotationScale;
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: Scroll "+rotationXY[0]+"/"+rotationXY[1]+" -> "+_rotation+" / "+rotationScale+" -> "+rotation+" scaled -- mods "+modifiers+", source "+rotationSource);
}
} else {
rotation = 0.0f;
@@ -338,14 +356,12 @@ public class AndroidNewtEventFactory {
//
// Determine newt-button and whether dedicated pointer is pressed
//
- final int pCount;
final int pIndex;
final short button;
switch( aType ) {
case android.view.MotionEvent.ACTION_POINTER_DOWN:
case android.view.MotionEvent.ACTION_POINTER_UP: {
pIndex = event.getActionIndex();
- pCount = 1;
final int b = event.getPointerId(pIndex) + 1; // FIXME: Assumption that Pointer-ID starts w/ 0 !
if( com.jogamp.newt.event.MouseEvent.BUTTON1 <= b && b <= com.jogamp.newt.event.MouseEvent.BUTTON_NUMBER ) {
button = (short)b;
@@ -356,10 +372,10 @@ public class AndroidNewtEventFactory {
break;
default: {
pIndex = 0;
- pCount = event.getPointerCount(); // all
button = com.jogamp.newt.event.MouseEvent.BUTTON1;
}
}
+ final int pCount = event.getPointerCount(); // all
//
// Collect common data
@@ -368,25 +384,18 @@ public class AndroidNewtEventFactory {
final int[] y = new int[pCount];
final float[] pressure = new float[pCount];
final short[] pointerIds = new short[pCount];
- {
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: collect ptr-data ["+pIndex+".."+(pIndex+pCount-1)+", "+pCount+"], aType "+aType+", button "+button+", gestureScrollPointerDown "+gestureScrollPointerDown);
+ final com.jogamp.newt.event.MouseEvent.PointerType[] pointerTypes = new com.jogamp.newt.event.MouseEvent.PointerType[pCount];
+ if( 0 < pCount ) {
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println("createMouseEvent: collect ptr-data [0.."+(pCount-1)+", count "+pCount+", action "+pIndex+"], aType "+aType+", button "+button+", twoFingerScrollGesture "+gesture2FingerScrl);
}
- int i = pIndex;
- int j = 0;
- while(j < pCount) {
- x[j] = (int)event.getX(i);
- y[j] = (int)event.getY(i);
- pressure[j] = event.getPressure(i);
- pointerIds[j] = (short)event.getPointerId(i);
- if( pressure[j] > maxPressure ) {
- maxPressure = pressure[j];
- }
- if(Window.DEBUG_MOUSE_EVENT) {
- System.err.println("createMouseEvent: ptr-data["+i+" -> "+j+"] "+x[j]+"/"+y[j]+", pressure "+pressure[j]+", id "+pointerIds[j]);
+ int j = 0;
+ // Always put action-pointer data at index 0
+ collectPointerData(event, pIndex, j++, x, y, pressure, pointerIds, pointerTypes);
+ for(int i=0; i < pCount; i++) {
+ if( pIndex != i ) {
+ collectPointerData(event, i, j++, x, y, pressure, pointerIds, pointerTypes);
}
- i++;
- j++;
}
}
@@ -404,97 +413,136 @@ public class AndroidNewtEventFactory {
final com.jogamp.newt.event.MouseEvent me1 = new com.jogamp.newt.event.MouseEvent(
nType, src, unixTime,
- modifiers, x, y, pressure, maxPressure, pointerIds,
- clickCount, button, rotation);
+ modifiers, x, y, pressure, maxPressure, pointerTypes, pointerIds,
+ clickCount, button, rotation, rotationScale);
if( com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED == nType ) {
return new com.jogamp.newt.event.MouseEvent[] { me1,
new com.jogamp.newt.event.MouseEvent(
com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED,
- src, unixTime, modifiers, x, y, pressure, maxPressure, pointerIds,
- clickCount, button, rotation) };
+ src, unixTime, modifiers, x, y, pressure, maxPressure, pointerTypes, pointerIds,
+ clickCount, button, rotation, rotationScale) };
} else {
return new com.jogamp.newt.event.MouseEvent[] { me1 };
}
}
return null; // no mapping ..
}
-
-
- public static String toString(android.view.MotionEvent event) {
- StringBuilder sb = new StringBuilder();
- int action = event.getAction();
- int actionCode = action & android.view.MotionEvent.ACTION_MASK;
- sb.append("ACTION_" ).append(names[actionCode]);
- if (actionCode == android.view.MotionEvent.ACTION_POINTER_DOWN
- || actionCode == android.view.MotionEvent.ACTION_POINTER_UP) {
- sb.append("(pid " ).append(
- action >> android.view.MotionEvent.ACTION_POINTER_ID_SHIFT);
- sb.append(")" );
- }
- sb.append("[" );
- for (int i = 0; i < event.getPointerCount(); i++) {
- sb.append("#" ).append(i);
- sb.append("(pid " ).append(event.getPointerId(i));
- sb.append(")=" ).append((int) event.getX(i));
- sb.append("," ).append((int) event.getY(i));
- if (i + 1 < event.getPointerCount())
- sb.append(";" );
- }
- sb.append("]" );
- return sb.toString();
+
+ static interface GestureHandler {
+ /** Returns true if within the gesture */
+ public boolean isWithinGesture();
+ /** Returns distance of the last consecutive double-tab scrolling. */
+ public float[] getScrollDistanceXY();
+
+ public void onUp(android.view.MotionEvent e, boolean action);
+ public void onDown(android.view.MotionEvent e, boolean action);
+ public void onActionMove(android.view.MotionEvent e);
}
- class NewtGestureListener implements android.view.GestureDetector.OnGestureListener {
- private float[] scrollDistance;
+ /**
+ * Criteria related to Android parameter:
+ * - ScaledDoubleTapSlop:
+ * - Max 2 finger distance
+ *
+ * - ScaledTouchSlop:
+ * - Min. movement w/ 2 pointer withing ScaledDoubleTapSlop starting 'scroll' mode
+ * - Max. change of finger distance in respect to initiating 2-finger distance (2x ScaledTouchSlop)
+ * - Max. distance growth in respect to initiating 2-finger distance.
+ */
+ private final GestureHandler gesture2FingerScrl = new GestureHandler() {
+ private final float[] scrollDistance = new float[] { 0f, 0f };
+ private int dStartDist = 0;
+ private float dDownY = 0;
+ private float dDownX = 0;
+ private float dLastY = 0;
+ private float dLastX = 0;
+ private int pointerDownCount = 0;
+ private boolean dDownScroll = false;
- NewtGestureListener() {
- scrollDistance = null;
+ public String toString() {
+ return "Gesture2FingerScrl[in "+dDownScroll+", pc "+pointerDownCount+"]";
}
- /** Returns non null w/ 2 float values, XY, if storing onScroll's XY distance - otherwise null */
- public float[] getScrollDistanceXY() {
- float[] sd = scrollDistance;
- scrollDistance = null;
- return sd;
+ private final int getSquareDistance(float x1, float y1, float x2, float y2) {
+ final int deltaX = (int) x1 - (int) x2;
+ final int deltaY = (int) y1 - (int) y2;
+ return deltaX * deltaX + deltaY * deltaY;
}
- //
- // Simple feedback
- //
-
- @Override
- public void onShowPress(android.view.MotionEvent e) {
+ public boolean isWithinGesture() {
+ return dDownScroll;
}
-
@Override
- public void onLongPress(android.view.MotionEvent e) {
+ public final float[] getScrollDistanceXY() {
+ return scrollDistance;
}
-
+
@Override
- public boolean onSingleTapUp(android.view.MotionEvent e) {
- return false;
+ public void onDown(android.view.MotionEvent e, boolean action) {
+ pointerDownCount = e.getPointerCount();
+ if( 2 == pointerDownCount ) {
+ final int sqDist = getSquareDistance(e.getX(0), e.getY(0), e.getX(1), e.getY(1));
+ final boolean isDistWithinDoubleTapSlop = sqDist < doubleTapSlopSquare;
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println(this+".onDown: action "+action+", dist "+Math.sqrt(sqDist)+", distWithin2DTSlop "+isDistWithinDoubleTapSlop+", "+e);
+ }
+ if( isDistWithinDoubleTapSlop ) {
+ dDownX = e.getX();
+ dDownY = e.getY();
+ dLastX = dDownX;
+ dLastY = dDownY;
+ dStartDist = (int)Math.sqrt(sqDist);
+ }
+ }
}
- //
- // Consumed or not consumed !
- //
-
@Override
- public boolean onDown(android.view.MotionEvent e) {
- return false;
+ public void onUp(android.view.MotionEvent e, boolean action) {
+ pointerDownCount = e.getPointerCount();
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println(this+".onrUp: action "+action+", "+e);
+ }
+ if( 2 >= pointerDownCount ) {
+ dDownScroll = false;
+ }
+ pointerDownCount--; // lifted now!
+ if(!dDownScroll) {
+ dDownY = 0f;
+ dDownX = 0f;
+ dLastY = 0f;
+ dLastX = 0f;
+ }
}
-
+
@Override
- public boolean onScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float distanceX, float distanceY) {
- scrollDistance = new float[] { distanceX, distanceY };
- return true;
+ public void onActionMove(android.view.MotionEvent e) {
+ pointerDownCount = e.getPointerCount();
+ if( 2 <= pointerDownCount ) {
+ final int sqDist = getSquareDistance(e.getX(0), e.getY(0), e.getX(1), e.getY(1));
+ final int dist = (int)Math.sqrt(sqDist);
+ final float x = e.getX();
+ final float y = e.getY();
+ final boolean isDistWithinDoubleTapSlop = sqDist < doubleTapSlopSquare;
+ final boolean isDistDeltaWithinTouchSlop = Math.abs( dStartDist - dist ) <= touchSlop2x &&
+ dist - dStartDist <= touchSlop;
+ if( !isDistWithinDoubleTapSlop || !isDistDeltaWithinTouchSlop ) {
+ dDownScroll = false;
+ } else if( !dDownScroll ) {
+ final int dX = (int) (x - dDownX);
+ final int dY = (int) (y - dDownY);
+ final int d = (dX * dX) + (dY * dY);
+ dDownScroll = d > touchSlopSquare;
+ }
+ scrollDistance[0] = dLastX - x;
+ scrollDistance[1] = dLastY - y;
+ dLastX = x;
+ dLastY = y;
+ if(DEBUG_MOUSE_EVENT) {
+ System.err.println(this+".onActionMove: startDist "+dStartDist+", dist "+dist+", distWithin2DTSlop "+isDistWithinDoubleTapSlop+", distDeltaWithinTSlop "+isDistDeltaWithinTouchSlop+", d "+scrollDistance[0]+"/"+scrollDistance[1]+", "+e);
+ }
+ }
}
-
- @Override
- public boolean onFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY) {
- return false;
- }
};
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
index 99df7c102..c239a949b 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
@@ -54,7 +54,8 @@ public class GearsES2 implements GLEventListener {
private GLUniformData pmvMatrixUniform = null;
private GLUniformData colorU = null;
private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
- private float panX = 0.0f, panY = 0.0f;
+ private float panX = 0.0f, panY = 0.0f, panZ=0.0f;
+ private int drawableHeight = 1;
private GearsObjectES2 gear1=null, gear2=null, gear3=null;
private float angle = 0.0f;
private int swapInterval = 0;
@@ -63,7 +64,6 @@ public class GearsES2 implements GLEventListener {
public MouseListener gearsMouse = new GearsMouseAdapter();
public KeyListener gearsKeys = new GearsKeyAdapter();
- private int prevMouseX, prevMouseY;
private boolean doRotate = true;
private boolean ignoreFocus = false;
private boolean clearBuffers = true;
@@ -210,6 +210,9 @@ public class GearsES2 implements GLEventListener {
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.err.println(Thread.currentThread()+" GearsES2.reshape "+x+"/"+y+" "+width+"x"+height+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle()));
+
+ drawableHeight = height;
+
// Thread.dumpStack();
GL2ES2 gl = drawable.getGL().getGL2ES2();
@@ -223,10 +226,10 @@ public class GearsES2 implements GLEventListener {
if(height>width) {
float h = (float)height / (float)width;
- pmvMatrix.glFrustumf(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
+ pmvMatrix.glFrustumf(-1.0f, 1.0f, -h, h, 5.0f, 200.0f);
} else {
float h = (float)width / (float)height;
- pmvMatrix.glFrustumf(-h, h, -1.0f, 1.0f, 5.0f, 60.0f);
+ pmvMatrix.glFrustumf(-h, h, -1.0f, 1.0f, 5.0f, 200.0f);
}
pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW);
@@ -302,7 +305,7 @@ public class GearsES2 implements GLEventListener {
st.useProgram(gl, true);
pmvMatrix.glPushMatrix();
- pmvMatrix.glTranslatef(panX, panY, 0.0f);
+ pmvMatrix.glTranslatef(panX, panY, panZ);
pmvMatrix.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
@@ -337,7 +340,71 @@ public class GearsES2 implements GLEventListener {
}
}
+ interface GestureHandler {
+ /** Returns true if within the gesture */
+ public boolean isWithinGesture();
+ /** Returns true if within the gesture */
+ public boolean onReleased(MouseEvent e);
+ /** Returns true if within the gesture */
+ public boolean onDragged(MouseEvent e);
+ }
+ final GestureHandler gesture2PtrZoom = new GestureHandler() {
+ private int zoomLastYDist;
+ private boolean zoomFirstTouch = true;
+ private boolean zoomMode = false;
+
+ @Override
+ public boolean isWithinGesture() {
+ return zoomMode;
+ }
+
+ @Override
+ public boolean onReleased(MouseEvent e) {
+ if( zoomMode && e.getPointerCount()==1 ) {
+ zoomFirstTouch = true;
+ zoomMode = false;
+ System.err.println("panZ.X: "+e);
+ }
+ return zoomMode;
+ }
+
+ @Override
+ public boolean onDragged(MouseEvent e) {
+ if( e.getPointerCount() >=2 ) {
+ // 2 pointers zoom .. [ -15 .. 15 ], range 30
+ /**
+ // Simple 1:1 Zoom: finger-distance to screen-coord
+ final int dy = Math.abs(e.getY(0)-e.getY(1));
+ float scale = (float)dy / (float)drawableHeight;
+ panZ = 30f * scale - 15f;
+ System.err.println("panZ: scale "+scale+" ["+dy+"/"+drawableHeight+"] -> "+panZ);
+ */
+ // Diff. 1:1 Zoom: finger-distance to screen-coord
+ if(zoomFirstTouch) {
+ zoomLastYDist = Math.abs(e.getY(0)-e.getY(1));
+ zoomFirstTouch=false;
+ zoomMode = true;
+ System.err.println("panZ: 1st pinch "+zoomLastYDist+", "+e);
+ } else if( zoomMode ) {
+ final int dy = Math.abs(e.getY(0)-e.getY(1));
+ final int ddy = dy - zoomLastYDist;
+
+ final float incr = ( (float)ddy / (float)drawableHeight ) * 15.0f;
+ panZ += incr;
+ if( e.getPointerCount() > 2 ) {
+ panZ += incr;
+ }
+ System.err.println("panZ.1: ddy "+ddy+", incr "+incr+" ["+dy+"/"+drawableHeight+"], dblZoom "+(e.getPointerCount() > 2)+" -> "+panZ);
+
+ zoomLastYDist = dy;
+ }
+ }
+ return zoomMode;
+ }
+ };
+
class GearsMouseAdapter implements MouseListener{
+ private int prevMouseX, prevMouseY;
@Override
public void mouseClicked(MouseEvent e) {
@@ -353,41 +420,58 @@ public class GearsES2 implements GLEventListener {
@Override
public void mouseWheelMoved(MouseEvent e) {
- float r = e.getWheelRotation() * 1.0f;
- if( e.isShiftDown() ) {
- // horizontal
- panX -= r; // positive -> left
+ float r = e.getWheelRotation() * 0.5f;
+ if( e.isControlDown() ) {
+ // alternative zoom
+ panZ += r;
+ if( e.isShiftDown() ) {
+ panZ += r;
+ }
+ System.err.println("panZ.2: incr "+r+", dblZoom "+e.isShiftDown()+" -> "+panZ);
} else {
- // vertical
- panY += r; // positive -> up
+ // panning
+ if( e.isShiftDown() ) {
+ // horizontal
+ panX -= r; // positive -> left
+ } else {
+ // vertical
+ panY += r; // positive -> up
+ }
}
}
public void mousePressed(MouseEvent e) {
- prevMouseX = e.getX();
- prevMouseY = e.getY();
- Object src = e.getSource();
- if(e.getPressure(true)>0.8f && src instanceof Window) { // show Keyboard
- ((Window) src).setKeyboardVisible(true);
- }
+ if( !gesture2PtrZoom.isWithinGesture() && e.getPointerCount()==1 ) {
+ prevMouseX = e.getX();
+ prevMouseY = e.getY();
+ Object src = e.getSource();
+ if(e.getPressure(true)>0.8f && src instanceof Window) { // show Keyboard
+ ((Window) src).setKeyboardVisible(true);
+ }
+ }
}
public void mouseReleased(MouseEvent e) {
+ gesture2PtrZoom.onReleased(e);
}
- public void mouseMoved(MouseEvent e) {
- if(e.isConfined()) {
- navigate(e);
- } else {
- // track prev. position so we don't have 'jumps'
- // in case we move to confined navigation.
- prevMouseX = e.getX();
- prevMouseY = e.getY();
+ public void mouseMoved(MouseEvent e) {
+ if( !gesture2PtrZoom.isWithinGesture() && e.getPointerCount()==1 ) {
+ if( e.isConfined() ) {
+ navigate(e);
+ } else {
+ // track prev. position so we don't have 'jumps'
+ // in case we move to confined navigation.
+ prevMouseX = e.getX();
+ prevMouseY = e.getY();
+ }
}
}
public void mouseDragged(MouseEvent e) {
- navigate(e);
+ if( !gesture2PtrZoom.onDragged(e) && e.getPointerCount()==1 ) {
+ navigate(e);
+ }
}
private void navigate(MouseEvent e) {
@@ -423,6 +507,7 @@ public class GearsES2 implements GLEventListener {
}
prevMouseX = x;
prevMouseY = y;
+ System.err.println("rotXY.1: "+view_rotx+"/"+view_roty+", source "+e);
}
}
}