aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2016-02-02 16:43:42 +0100
committerRay <raysan5@gmail.com>2016-02-02 16:43:42 +0100
commit728e1715cc52fb25081f3ce17cb5b3f72f7eb218 (patch)
tree8a9f80f4bf4c990562fdf05048e9f7d19e03f195 /src
parente484d58d9c9cc9a081675e2ceef4d55a276ce43c (diff)
downloadraylib-728e1715cc52fb25081f3ce17cb5b3f72f7eb218.tar.gz
raylib-728e1715cc52fb25081f3ce17cb5b3f72f7eb218.zip
Redesigned gestures system...
...and improved mouse gestures support Some testing still required...
Diffstat (limited to 'src')
-rw-r--r--src/core.c29
-rw-r--r--src/gestures.c300
-rw-r--r--src/raylib.h23
3 files changed, 189 insertions, 163 deletions
diff --git a/src/core.c b/src/core.c
index cf6fcf33..1c9e16ae 100644
--- a/src/core.c
+++ b/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;
diff --git a/src/gestures.c b/src/gestures.c
index ea744555..59f2c5b7 100644
--- a/src/gestures.c
+++ b/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;
diff --git a/src/raylib.h b/src/raylib.h
index 6c1a8999..a22c3f83 100644
--- a/src/raylib.h
+++ b/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