Kaynağa Gözat

Redesigned gestures system...

...and improved mouse gestures support
Some testing still required...
pull/83/head
Ray 9 yıl önce
ebeveyn
işleme
728e1715cc
3 değiştirilmiş dosya ile 189 ekleme ve 163 silme
  1. +26
    -3
      src/core.c
  2. +152
    -148
      src/gestures.c
  3. +11
    -12
      src/raylib.h

+ 26
- 3
src/core.c Dosyayı Görüntüle

@ -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;
k">else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE;
o">//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 Dosyayı Görüntüle

@ -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 (p">(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 Dosyayı Görüntüle

@ -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

Yükleniyor…
İptal
Kaydet