2
0
Эх сурвалжийг харах

Redesigned gestures system...

...and improved mouse gestures support
Some testing still required...
Ray 9 жил өмнө
parent
commit
728e1715cc
3 өөрчлөгдсөн 189 нэмэгдсэн , 163 устгасан
  1. 26 3
      src/core.c
  2. 152 148
      src/gestures.c
  3. 11 12
      src/raylib.h

+ 26 - 3
src/core.c

@@ -253,6 +253,7 @@ static void InitGamepad(void);                          // Init raw gamepad inpu
 static void ErrorCallback(int error, const char *description);                             // GLFW3 Error Callback, runs on GLFW3 error
 static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods);  // GLFW3 Keyboard Callback, runs on key pressed
 static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods);     // GLFW3 Mouse Button Callback, runs on mouse button pressed
+static void MouseCursorPosCallback(GLFWwindow *window, double x, double y);                // GLFW3 Cursor Position Callback, runs on mouse move
 static void CharCallback(GLFWwindow *window, unsigned int key);                            // GLFW3 Char Key Callback, runs on key pressed (get char value)
 static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel
 static void CursorEnterCallback(GLFWwindow *window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area
@@ -1415,6 +1416,7 @@ static void InitDisplay(int width, int height)
     glfwSetCursorEnterCallback(window, CursorEnterCallback);
     glfwSetKeyCallback(window, KeyCallback);
     glfwSetMouseButtonCallback(window, MouseButtonCallback);
+    glfwSetCursorPosCallback(window, MouseCursorPosCallback);    // Track mouse position changes
     glfwSetCharCallback(window, CharCallback);
     glfwSetScrollCallback(window, ScrollCallback);
     glfwSetWindowIconifyCallback(window, WindowIconifyCallback);
@@ -1677,7 +1679,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
     
     // Register touch actions
     if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN;
-    else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE;
+    //else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE;
     else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP;
     
     // Register touch points count
@@ -1685,7 +1687,28 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
     
     // Register touch points position, only one point registered
     gestureEvent.position[0] = GetMousePosition();
+	
+	// Gesture data is sent to gestures system for processing
+    ProcessGestureEvent(gestureEvent);
+#endif
+}
+
+// GLFW3 Cursor Position Callback, runs on mouse move
+static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
+{
+#define ENABLE_MOUSE_GESTURES
+#if defined(ENABLE_MOUSE_GESTURES)
+    // Process mouse events as touches to be able to use mouse-gestures
+    GestureEvent gestureEvent;
+
+    gestureEvent.touchAction = TOUCH_MOVE;
+
+    // Register touch points count
+    gestureEvent.pointCount = 1;
     
+    // Register touch points position, only one point registered
+    gestureEvent.position[0] = (Vector2){ (float)x, (float)y };
+
     // Gesture data is sent to gestures system for processing
     ProcessGestureEvent(gestureEvent);
 #endif
@@ -1934,7 +1957,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
     // Register touch points count
     gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
     
-    // Register touch points id DESKTOP
+    // Register touch points id
     gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0);
     gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1);
     
@@ -2496,7 +2519,7 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent
     // Register touch points count
     gestureEvent.pointCount = touchEvent->numTouches;
     
-    // Register touch points id WEB
+    // Register touch points id
     gestureEvent.pointerId[0] = touchEvent->touches[0].identifier;
     gestureEvent.pointerId[1] = touchEvent->touches[1].identifier;
     

+ 152 - 148
src/gestures.c

@@ -46,7 +46,11 @@
 // Defines and Macros
 //----------------------------------------------------------------------------------
 #define FORCE_TO_SWIPE          20
-#define TAP_TIMEOUT             300
+#define FORCE_TO_DRAG           20
+#define FORCE_TO_PINCH          5
+#define TAP_TIMEOUT             300     // Time in milliseconds
+#define PINCH_TIMEOUT           300     // Time in milliseconds
+#define DOUBLETAP_RANGE         30
 //#define MAX_TOUCH_POINTS        4
 
 //----------------------------------------------------------------------------------
@@ -61,10 +65,6 @@ typedef enum {
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static GestureType gestureType = TYPE_MOTIONLESS;
-static double eventTime = 0;
-//static int32_t touchId;               // Not used...
-
 // Tap gesture variables
 static Vector2 initialTapPosition = { 0, 0 };
 
@@ -78,6 +78,21 @@ static Vector2 endDragPosition = { 0, 0 };
 static Vector2 lastDragPosition = { 0, 0 };
 static Vector2 dragVector = { 0, 0 };
 
+// Albert&Ian
+static Vector2 touchDownPosition = { 0, 0 };
+static Vector2 touchDownPosition2 = { 0, 0 };
+static Vector2 touchUpPosition = { 0, 0 };
+static Vector2 moveDownPosition = { 0, 0 };
+static Vector2 moveDownPosition2 = { 0, 0 };
+
+static int numTap = 0;
+static int numHold = 0;
+static int numPinch = 0;
+static int pointCount = 0;
+static int touchId = -1;
+
+static double eventTime = 0;
+
 static float magnitude = 0;             // Distance traveled dragging
 static float angle = 0;                 // Angle direction of the drag
 static float intensity = 0;             // How fast we did the drag (pixels per frame)
@@ -95,7 +110,7 @@ static int previousGesture = GESTURE_NONE;
 static int currentGesture = GESTURE_NONE;
 
 // Enabled gestures flags, all gestures enabled by default 
-static unsigned int enabledGestures = 0b0000011111111111;   
+static unsigned int enabledGestures = 0b0000001111111111;   
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -105,6 +120,7 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, flo
 static float VectorDistance(Vector2 v1, Vector2 v2);
 static float VectorDotProduct(Vector2 v1, Vector2 v2);
 static double GetCurrentTime();
+static float Vector2Distance();
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition
@@ -119,173 +135,160 @@ void ProcessGestureEvent(GestureEvent event)
     
     previousGesture = currentGesture;
     
-    switch (gestureType)
-    {
-        case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events
+    pointCount = event.pointCount;
+    
+    // Albert&Ian
+    if (pointCount < 2)
+    {      
+        touchId = event.pointerId[0];
+        if (event.touchAction == TOUCH_DOWN)
         {
-            if (event.touchAction == TOUCH_DOWN)
+            numTap++;    // Tap counter
+
+            // Detect GESTURE_DOUBLE_TAP
+            if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (GetMagnitude(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
             {
-                if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
-                else
-                {
-                    // Set the press position
-                    initialTapPosition = event.position[0];
-                    
-                    // If too much time have passed, we reset the double tap
-                    if (GetCurrentTime() - eventTime > TAP_TIMEOUT) untap = false;
-                    
-                    // If we are in time, we detect the double tap
-                    if (untap) doubleTapping = true;
-                    
-                    // Update our event time
-                    eventTime = GetCurrentTime();
-                    
-                    // Set hold
-                    if (doubleTapping) currentGesture = GESTURE_DOUBLETAP;
-                    else currentGesture = GESTURE_TAP;
-                }
+                currentGesture = GESTURE_DOUBLETAP;
+                numTap = 0;
             }
-            else if (event.touchAction == TOUCH_UP)
+            else    // Detect GESTURE_TAP
             {
-			    currentGesture = GESTURE_NONE;
-
-                // Detect that we are tapping instead of holding
-                if (GetCurrentTime() - eventTime < TAP_TIMEOUT)
-                {
-                    if (doubleTapping) untap = false;
-                    else untap = true;
-                }
-                
-                // Tap finished
-                doubleTapping = false;
-
-                // Update our event time
-                eventTime = GetCurrentTime();
+                numTap = 1;
+                currentGesture = GESTURE_TAP;
             }
-            // Begin dragging
-            else if (event.touchAction == TOUCH_MOVE)
+            
+            touchDownPosition = event.position[0];
+            
+            touchUpPosition = touchDownPosition;
+            eventTime = GetCurrentTime();
+        }
+        else if (event.touchAction == TOUCH_UP)
+        {
+            if (currentGesture = GESTURE_DRAG) 
             {
-                if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
-                else
-                {
-                    // Set the drag starting position
-                    initialDragPosition = initialTapPosition;
-                    endDragPosition = initialDragPosition;
-                    
-                    // Initialize drag
-                    draggingTimeCounter = 0;
-                    gestureType = TYPE_DRAG;
-                    currentGesture = GESTURE_NONE;
-                }
+                touchUpPosition = event.position[0];
             }
-        } break;
-        case TYPE_DRAG: // Detect DRAG and SWIPE events 
-        {
-            // end of the drag
-            if (event.touchAction == TOUCH_UP)
+            
+            // Calculate for swipe
+            magnitude = GetMagnitude(touchDownPosition, touchUpPosition);
+            intensity = magnitude / (float)draggingTimeCounter;
+            
+            // Detect GESTURE_SWIPE
+            if ((intensity > FORCE_TO_SWIPE) && (touchId == 0))
+            {
+                angle = CalculateAngle(touchDownPosition, touchUpPosition, magnitude);
+                if ((angle < 30) || (angle > 330)) currentGesture = GESTURE_SWIPE_RIGHT;        // Right
+                else if ((angle > 30) && (angle < 120)) currentGesture = GESTURE_SWIPE_UP;      // Up
+                else if ((angle > 120) && (angle < 210)) currentGesture = GESTURE_SWIPE_LEFT;   // Left
+                else if ((angle > 210) && (angle < 300)) currentGesture = GESTURE_SWIPE_DOWN;   // Down
+                else currentGesture = GESTURE_NONE;
+            }
+            else
             {
-                // Return Swipe if we have enough sensitivity
-                if (intensity > FORCE_TO_SWIPE)
-                {
-                    if (angle < 30 || angle > 330) currentGesture = GESTURE_SWIPE_RIGHT; // Right
-                    else if (angle > 60 && angle < 120) currentGesture = GESTURE_SWIPE_UP; // Up
-                    else if (angle > 150 && angle < 210) currentGesture = GESTURE_SWIPE_LEFT; // Left
-                    else if (angle > 240 && angle < 300) currentGesture = GESTURE_SWIPE_DOWN; // Down
-                }
-                
                 magnitude = 0;
                 angle = 0;
                 intensity = 0;
                 
-                gestureType = TYPE_MOTIONLESS;
+                currentGesture = GESTURE_NONE;
             }
-            // Update while we are dragging
-            else if (event.touchAction == TOUCH_MOVE)
+            
+            draggingTimeCounter = 0;
+        }
+        else if (event.touchAction == TOUCH_MOVE)
+        {
+            if (GetMagnitude(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime();
+            moveDownPosition = event.position[0];
+            
+            if (currentGesture == GESTURE_HOLD) 
             {
-                if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
-                else
-                {
-                    lastDragPosition = endDragPosition;
-                    endDragPosition = event.position[0];
-                    
-                    //endDragPosition.x = AMotionEvent_getX(event, 0);
-                    //endDragPosition.y = AMotionEvent_getY(event, 0);
-                    
-                    // Calculate attributes
-                    dragVector = (Vector2){ endDragPosition.x - lastDragPosition.x, endDragPosition.y - lastDragPosition.y };
-                    magnitude = sqrt(pow(endDragPosition.x - initialDragPosition.x, 2) + pow(endDragPosition.y - initialDragPosition.y, 2));
-                    angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude);
-                    intensity = magnitude / (float)draggingTimeCounter;
-                    
-                    // Check if drag movement is less than minimum to keep it as hold state or switch to drag state
-                    if(magnitude > FORCE_TO_SWIPE)
-                    {
-                        currentGesture = GESTURE_DRAG;
-                        draggingTimeCounter++;
-                    }
-                    else currentGesture = GESTURE_HOLD;
-                }
+                if (numHold == 1) touchDownPosition = event.position[0];
+                
+                numHold = 2;
+
+                magnitude = GetMagnitude(touchDownPosition, moveDownPosition);
+                
+                // Detect GESTURE_DRAG
+                if (magnitude >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG;
             }
-        } break;
-        case TYPE_DUAL_INPUT:
+            
+            draggingTimeCounter++;
+        }
+    }
+    else
+    {
+        // two fingers
+        
+        if (event.touchAction == TOUCH_DOWN)
+        {
+            touchDownPosition = event.position[0];
+            touchDownPosition2 = event.position[1];
+            
+            currentGesture = GESTURE_HOLD;
+        }
+        else if (event.touchAction == TOUCH_MOVE)
         {
-            if (event.touchAction == TOUCH_UP)
+            magnitude = GetMagnitude(moveDownPosition, moveDownPosition2);
+            
+            touchDownPosition = moveDownPosition;
+            touchDownPosition2 = moveDownPosition2;
+            
+            moveDownPosition = event.position[0];
+            moveDownPosition2 = event.position[1];
+            
+            if ( (GetMagnitude(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (GetMagnitude(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH))
             {
-                if (event.pointCount == 1)
-                {
-                    // Set the drag starting position
-                    initialTapPosition = event.position[0];
-                }
-                gestureType = TYPE_MOTIONLESS;
+                if ((GetMagnitude(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN;
+                else currentGesture = GESTURE_PINCH_OUT;
             }
-            else if (event.touchAction == TOUCH_MOVE)
+            else 
             {
-                // Adapt the ending position of the inputs
-                firstEndPinchPosition = event.position[0];
-                secondEndPinchPosition = event.position[1];
-                
-                // If there is no more than two inputs
-                if (event.pointCount == 2)
-                {
-                    // Calculate distances
-                    float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition);
-                    float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition);
-
-                    // Calculate Vectors
-                    Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y };
-                    Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y };
-
-                    // Detect the pinch gesture
-                    if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance;
-                    else pinchDelta = 0;
-                    
-                    // Pinch gesture resolution
-                    if (pinchDelta != 0)
-                    {
-                        if (pinchDelta > 0) currentGesture = GESTURE_PINCH_IN;
-                        else currentGesture = GESTURE_PINCH_OUT;
-                    }
-                }
-                else
-                {
-                    // Set the drag starting position
-                    initialTapPosition = event.position[0];
-                    
-                    gestureType = TYPE_MOTIONLESS;
-                }
-                
-                // Readapt the initial position of the inputs
-                firstInitialPinchPosition = firstEndPinchPosition;
-                secondInitialPinchPosition = secondEndPinchPosition;
+               currentGesture = GESTURE_HOLD; 
             }
-        } break;
+        }
+        else if (event.touchAction == TOUCH_UP)
+        {
+            currentGesture = GESTURE_NONE;
+        }
+    }
+}
+
+// Update gestures detected (must be called every frame)
+void UpdateGestures(void)
+{
+    // NOTE: Gestures are processed through system callbacks on touch events
+
+    // Detect GESTURE_HOLD
+    if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && pointCount < 2) currentGesture = GESTURE_HOLD;
+    if ((GetCurrentTime() - eventTime) > TAP_TIMEOUT && (currentGesture == GESTURE_DRAG) && pointCount < 2)
+    {
+        currentGesture = GESTURE_HOLD;
+        numHold = 1;
     }
+   
+    // Detect GESTURE_NONE
+    if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
+    {
+        currentGesture = GESTURE_NONE;
+    }
+}
+
+// Calculate distance between two vectors
+float Vector2Distance(Vector2 v1, Vector3 v2)
+{
+    float result;
+
+    float dx = v2.x - v1.x;
+    float dy = v2.y - v1.y;
+
+    result = sqrt(dx*dx + dy*dy);
+
+    return result;
 }
 
 // Check if a gesture have been detected
 bool IsGestureDetected(void)
 {
-    if (currentGesture != GESTURE_NONE) return true;
+    if ((enabledGestures & currentGesture) != GESTURE_NONE) return true;
     else return false;
 }
 
@@ -298,7 +301,7 @@ int GetGestureType(void)
 
 void SetGesturesEnabled(unsigned int gestureFlags)
 {
-    enabledGestures = enabledGestures | gestureFlags;
+    enabledGestures = gestureFlags;
 }
 
 // Get drag intensity (pixels per frame)
@@ -440,6 +443,7 @@ static float VectorDotProduct(Vector2 v1, Vector2 v2)
     return result;
 }
 
+// Time measure returned are milliseconds
 static double GetCurrentTime()
 {
     double time = 0;

+ 11 - 12
src/raylib.h

@@ -435,17 +435,17 @@ typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
 // Gestures type
 // NOTE: It could be used as flags to enable only some gestures
 typedef enum {
-    GESTURE_NONE        = 1,
-    GESTURE_TAP         = 2,
-    GESTURE_DOUBLETAP   = 4,
-    GESTURE_HOLD        = 8,
-    GESTURE_DRAG        = 16,
-    GESTURE_SWIPE_RIGHT = 32,
-    GESTURE_SWIPE_LEFT  = 64,
-    GESTURE_SWIPE_UP    = 128,
-    GESTURE_SWIPE_DOWN  = 256,
-    GESTURE_PINCH_IN    = 512,
-    GESTURE_PINCH_OUT   = 1024
+    GESTURE_NONE        = 0,
+    GESTURE_TAP         = 1,
+    GESTURE_DOUBLETAP   = 2,
+    GESTURE_HOLD        = 4,
+    GESTURE_DRAG        = 8,
+    GESTURE_SWIPE_RIGHT = 16,
+    GESTURE_SWIPE_LEFT  = 32,
+    GESTURE_SWIPE_UP    = 64,
+    GESTURE_SWIPE_DOWN  = 128,
+    GESTURE_PINCH_IN    = 256,
+    GESTURE_PINCH_OUT   = 512
 } Gestures;
 
 typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction;
@@ -781,7 +781,6 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
 bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox);                                           // Detect collision between ray and box
 Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius);   // Detect collision of player radius with cubicmap
                                                                                                                 // NOTE: Return the normal vector of the impacted surface
-
 //------------------------------------------------------------------------------------
 // Shaders System Functions (Module: rlgl)
 // NOTE: This functions are useless when using OpenGL 1.1