47 #define PI 3.14159265358979323846 53 #ifndef MAX_TOUCH_POINTS 54 #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported 62 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) 64 #elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) 65 typedef enum bool {
false = 0,
true = !
false } bool;
68 #if !defined(RL_VECTOR2_TYPE) 76 #if defined(RGESTURES_STANDALONE) 82 GESTURE_DOUBLETAP = 2,
85 GESTURE_SWIPE_RIGHT = 16,
86 GESTURE_SWIPE_LEFT = 32,
87 GESTURE_SWIPE_UP = 64,
88 GESTURE_SWIPE_DOWN = 128,
89 GESTURE_PINCH_IN = 256,
90 GESTURE_PINCH_OUT = 512
105 int pointId[MAX_TOUCH_POINTS];
106 Vector2 position[MAX_TOUCH_POINTS];
118 #if defined(__cplusplus) 123 void UpdateGestures(
void);
125 #if defined(RGESTURES_STANDALONE) 126 void SetGesturesEnabled(
unsigned int flags);
127 bool IsGestureDetected(
int gesture);
128 int GetGestureDetected(
void);
130 float GetGestureHoldDuration(
void);
131 Vector2 GetGestureDragVector(
void);
132 float GetGestureDragAngle(
void);
133 Vector2 GetGesturePinchVector(
void);
134 float GetGesturePinchAngle(
void);
137 #if defined(__cplusplus) 141 #endif // RGESTURES_H 149 #if defined(RGESTURES_IMPLEMENTATION) 151 #if defined(RGESTURES_STANDALONE) 153 #if defined(__cplusplus) 157 int __stdcall QueryPerformanceCounter(
unsigned long long int *lpPerformanceCount);
158 int __stdcall QueryPerformanceFrequency(
unsigned long long int *lpFrequency);
159 #if defined(__cplusplus) 162 #elif defined(__linux__) 163 #if _POSIX_C_SOURCE < 199309L 164 #undef _POSIX_C_SOURCE 165 #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. 167 #include <sys/time.h> 172 #if defined(__APPLE__) // macOS also defines __MACH__ 173 #include <mach/clock.h> 174 #include <mach/mach.h> 181 #define FORCE_TO_SWIPE 0.2f // Swipe force, measured in normalized screen units/time 182 #define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f) 183 #define DRAG_TIMEOUT 0.3f // Drag minimum time for web, measured in seconds 184 #define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) 185 #define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds 186 #define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds 187 #define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) 195 unsigned int current;
196 unsigned int enabledFlags;
234 static GesturesData GESTURES = {
236 .current = GESTURE_NONE,
237 .enabledFlags = 0b0000001111111111
243 static float rgVector2Angle(
Vector2 initialPosition,
Vector2 finalPosition);
245 static double rgGetCurrentTime(
void);
252 void SetGesturesEnabled(
unsigned int flags)
254 GESTURES.enabledFlags = flags;
258 bool IsGestureDetected(
unsigned int gesture)
260 if ((GESTURES.enabledFlags & GESTURES.current) == gesture)
return true;
268 GESTURES.Touch.pointCount =
event.pointCount;
270 if (GESTURES.Touch.pointCount == 1)
272 if (event.touchAction == TOUCH_ACTION_DOWN)
274 GESTURES.Touch.tapCounter++;
277 if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rgGetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE))
279 GESTURES.current = GESTURE_DOUBLETAP;
280 GESTURES.Touch.tapCounter = 0;
284 GESTURES.Touch.tapCounter = 1;
285 GESTURES.current = GESTURE_TAP;
288 GESTURES.Touch.downPositionA =
event.position[0];
289 GESTURES.Touch.downDragPosition =
event.position[0];
291 GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
292 GESTURES.Touch.eventTime = rgGetCurrentTime();
294 GESTURES.Swipe.startTime = rgGetCurrentTime();
296 GESTURES.Drag.vector = (
Vector2){ 0.0f, 0.0f };
298 else if (event.touchAction == TOUCH_ACTION_UP)
301 if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition =
event.position[0];
304 GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
305 GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime));
308 if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG))
311 GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
313 if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT;
314 else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP;
315 else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT;
316 else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN;
317 else GESTURES.current = GESTURE_NONE;
321 GESTURES.Drag.distance = 0.0f;
322 GESTURES.Drag.intensity = 0.0f;
323 GESTURES.Drag.angle = 0.0f;
325 GESTURES.current = GESTURE_NONE;
328 GESTURES.Touch.downDragPosition = (
Vector2){ 0.0f, 0.0f };
329 GESTURES.Touch.pointCount = 0;
331 else if (event.touchAction == TOUCH_ACTION_MOVE)
333 GESTURES.Touch.moveDownPositionA =
event.position[0];
335 if (GESTURES.current == GESTURE_HOLD)
337 if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA =
event.position[0];
339 GESTURES.Hold.resetRequired =
false;
342 if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT)
344 GESTURES.Touch.eventTime = rgGetCurrentTime();
345 GESTURES.current = GESTURE_DRAG;
349 GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x;
350 GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
353 else if (GESTURES.Touch.pointCount == 2)
355 if (event.touchAction == TOUCH_ACTION_DOWN)
357 GESTURES.Touch.downPositionA =
event.position[0];
358 GESTURES.Touch.downPositionB =
event.position[1];
360 GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA;
361 GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB;
365 GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
366 GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y;
368 GESTURES.current = GESTURE_HOLD;
369 GESTURES.Hold.timeDuration = rgGetCurrentTime();
371 else if (event.touchAction == TOUCH_ACTION_MOVE)
373 GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
375 GESTURES.Touch.moveDownPositionA =
event.position[0];
376 GESTURES.Touch.moveDownPositionB =
event.position[1];
378 GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
379 GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
381 if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
383 if ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN;
384 else GESTURES.current = GESTURE_PINCH_OUT;
388 GESTURES.current = GESTURE_HOLD;
389 GESTURES.Hold.timeDuration = rgGetCurrentTime();
393 GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
395 else if (event.touchAction == TOUCH_ACTION_UP)
397 GESTURES.Pinch.distance = 0.0f;
398 GESTURES.Pinch.angle = 0.0f;
399 GESTURES.Pinch.vector = (
Vector2){ 0.0f, 0.0f };
400 GESTURES.Touch.pointCount = 0;
402 GESTURES.current = GESTURE_NONE;
405 else if (GESTURES.Touch.pointCount > 2)
412 void UpdateGestures(
void)
417 if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2))
419 GESTURES.current = GESTURE_HOLD;
420 GESTURES.Hold.timeDuration = rgGetCurrentTime();
424 if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN))
426 GESTURES.current = GESTURE_NONE;
431 int GetGestureDetected(
void)
434 return (GESTURES.enabledFlags & GESTURES.current);
438 float GetGestureHoldDuration(
void)
444 if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration;
450 Vector2 GetGestureDragVector(
void)
454 return GESTURES.Drag.vector;
459 float GetGestureDragAngle(
void)
463 return GESTURES.Drag.angle;
467 Vector2 GetGesturePinchVector(
void)
471 return GESTURES.Pinch.vector;
476 float GetGesturePinchAngle(
void)
480 return GESTURES.Pinch.angle;
489 float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
491 if (angle < 0) angle += 360.0f;
501 float dx = v2.x - v1.x;
502 float dy = v2.y - v1.y;
504 result = (float)sqrt(dx*dx + dy*dy);
510 static double rgGetCurrentTime(
void)
514 #if !defined(RGESTURES_STANDALONE) 518 unsigned long long int clockFrequency, currentTime;
520 QueryPerformanceFrequency(&clockFrequency);
521 QueryPerformanceCounter(¤tTime);
523 time = (double)currentTime/clockFrequency;
526 #if defined(__linux__) 529 clock_gettime(CLOCK_MONOTONIC, &now);
530 unsigned long long int nowTime = (
unsigned long long int)now.tv_sec*1000000000LLU + (
unsigned long long int)now.tv_nsec;
532 time = ((double)nowTime*1e-9);
535 #if defined(__APPLE__) 541 host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
544 clock_get_time(cclock, &now);
545 mach_port_deallocate(mach_task_self(), cclock);
546 unsigned long long int nowTime = (
unsigned long long int)now.tv_sec*1000000000LLU + (
unsigned long long int)now.tv_nsec;
548 time = ((double)nowTime*1e-9);
555 #endif // RGESTURES_IMPLEMENTATION Definition: rgestures.h:102