diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2025-04-21 11:09:56 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2025-04-21 11:09:56 +0200 |
| commit | 123144c93bfc77883c8fb517828b47bbe13b8671 (patch) | |
| tree | 762739afedb5f3f168051367515cb9b9a06ec68d /raylib/src/rgestures.h | |
| download | minesweeper-master.tar.gz minesweeper-master.zip | |
Diffstat (limited to '')
| -rw-r--r-- | raylib/src/rgestures.h | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/raylib/src/rgestures.h b/raylib/src/rgestures.h new file mode 100644 index 0000000..b5624be --- /dev/null +++ b/raylib/src/rgestures.h | |||
| @@ -0,0 +1,555 @@ | |||
| 1 | /********************************************************************************************** | ||
| 2 | * | ||
| 3 | * rgestures - Gestures system, gestures processing based on input events (touch/mouse) | ||
| 4 | * | ||
| 5 | * CONFIGURATION: | ||
| 6 | * #define RGESTURES_IMPLEMENTATION | ||
| 7 | * Generates the implementation of the library into the included file. | ||
| 8 | * If not defined, the library is in header only mode and can be included in other headers | ||
| 9 | * or source files without problems. But only ONE file should hold the implementation. | ||
| 10 | * | ||
| 11 | * #define RGESTURES_STANDALONE | ||
| 12 | * If defined, the library can be used as standalone to process gesture events with | ||
| 13 | * no external dependencies. | ||
| 14 | * | ||
| 15 | * CONTRIBUTORS: | ||
| 16 | * Marc Palau: Initial implementation (2014) | ||
| 17 | * Albert Martos: Complete redesign and testing (2015) | ||
| 18 | * Ian Eito: Complete redesign and testing (2015) | ||
| 19 | * Ramon Santamaria: Supervision, review, update and maintenance | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * LICENSE: zlib/libpng | ||
| 23 | * | ||
| 24 | * Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) | ||
| 25 | * | ||
| 26 | * This software is provided "as-is", without any express or implied warranty. In no event | ||
| 27 | * will the authors be held liable for any damages arising from the use of this software. | ||
| 28 | * | ||
| 29 | * Permission is granted to anyone to use this software for any purpose, including commercial | ||
| 30 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||
| 31 | * | ||
| 32 | * 1. The origin of this software must not be misrepresented; you must not claim that you | ||
| 33 | * wrote the original software. If you use this software in a product, an acknowledgment | ||
| 34 | * in the product documentation would be appreciated but is not required. | ||
| 35 | * | ||
| 36 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||
| 37 | * as being the original software. | ||
| 38 | * | ||
| 39 | * 3. This notice may not be removed or altered from any source distribution. | ||
| 40 | * | ||
| 41 | **********************************************************************************************/ | ||
| 42 | |||
| 43 | #ifndef RGESTURES_H | ||
| 44 | #define RGESTURES_H | ||
| 45 | |||
| 46 | #ifndef PI | ||
| 47 | #define PI 3.14159265358979323846 | ||
| 48 | #endif | ||
| 49 | |||
| 50 | //---------------------------------------------------------------------------------- | ||
| 51 | // Defines and Macros | ||
| 52 | //---------------------------------------------------------------------------------- | ||
| 53 | #ifndef MAX_TOUCH_POINTS | ||
| 54 | #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported | ||
| 55 | #endif | ||
| 56 | |||
| 57 | //---------------------------------------------------------------------------------- | ||
| 58 | // Types and Structures Definition | ||
| 59 | // NOTE: Below types are required for standalone usage | ||
| 60 | //---------------------------------------------------------------------------------- | ||
| 61 | // Boolean type | ||
| 62 | #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) | ||
| 63 | #include <stdbool.h> | ||
| 64 | #elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) | ||
| 65 | typedef enum bool { false = 0, true = !false } bool; | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #if !defined(RL_VECTOR2_TYPE) | ||
| 69 | // Vector2 type | ||
| 70 | typedef struct Vector2 { | ||
| 71 | float x; | ||
| 72 | float y; | ||
| 73 | } Vector2; | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #if defined(RGESTURES_STANDALONE) | ||
| 77 | // Gestures type | ||
| 78 | // NOTE: It could be used as flags to enable only some gestures | ||
| 79 | typedef enum { | ||
| 80 | GESTURE_NONE = 0, | ||
| 81 | GESTURE_TAP = 1, | ||
| 82 | GESTURE_DOUBLETAP = 2, | ||
| 83 | GESTURE_HOLD = 4, | ||
| 84 | GESTURE_DRAG = 8, | ||
| 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 | ||
| 91 | } Gesture; | ||
| 92 | #endif | ||
| 93 | |||
| 94 | typedef enum { | ||
| 95 | TOUCH_ACTION_UP = 0, | ||
| 96 | TOUCH_ACTION_DOWN, | ||
| 97 | TOUCH_ACTION_MOVE, | ||
| 98 | TOUCH_ACTION_CANCEL | ||
| 99 | } TouchAction; | ||
| 100 | |||
| 101 | // Gesture event | ||
| 102 | typedef struct { | ||
| 103 | int touchAction; | ||
| 104 | int pointCount; | ||
| 105 | int pointId[MAX_TOUCH_POINTS]; | ||
| 106 | Vector2 position[MAX_TOUCH_POINTS]; | ||
| 107 | } GestureEvent; | ||
| 108 | |||
| 109 | //---------------------------------------------------------------------------------- | ||
| 110 | // Global Variables Definition | ||
| 111 | //---------------------------------------------------------------------------------- | ||
| 112 | //... | ||
| 113 | |||
| 114 | //---------------------------------------------------------------------------------- | ||
| 115 | // Module Functions Declaration | ||
| 116 | //---------------------------------------------------------------------------------- | ||
| 117 | |||
| 118 | #if defined(__cplusplus) | ||
| 119 | extern "C" { // Prevents name mangling of functions | ||
| 120 | #endif | ||
| 121 | |||
| 122 | void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures | ||
| 123 | void UpdateGestures(void); // Update gestures detected (must be called every frame) | ||
| 124 | |||
| 125 | #if defined(RGESTURES_STANDALONE) | ||
| 126 | void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags | ||
| 127 | bool IsGestureDetected(int gesture); // Check if a gesture have been detected | ||
| 128 | int GetGestureDetected(void); // Get latest detected gesture | ||
| 129 | |||
| 130 | float GetGestureHoldDuration(void); // Get gesture hold time in seconds | ||
| 131 | Vector2 GetGestureDragVector(void); // Get gesture drag vector | ||
| 132 | float GetGestureDragAngle(void); // Get gesture drag angle | ||
| 133 | Vector2 GetGesturePinchVector(void); // Get gesture pinch delta | ||
| 134 | float GetGesturePinchAngle(void); // Get gesture pinch angle | ||
| 135 | #endif | ||
| 136 | |||
| 137 | #if defined(__cplusplus) | ||
| 138 | } | ||
| 139 | #endif | ||
| 140 | |||
| 141 | #endif // RGESTURES_H | ||
| 142 | |||
| 143 | /*********************************************************************************** | ||
| 144 | * | ||
| 145 | * RGESTURES IMPLEMENTATION | ||
| 146 | * | ||
| 147 | ************************************************************************************/ | ||
| 148 | |||
| 149 | #if defined(RGESTURES_IMPLEMENTATION) | ||
| 150 | |||
| 151 | #if defined(RGESTURES_STANDALONE) | ||
| 152 | #if defined(_WIN32) | ||
| 153 | #if defined(__cplusplus) | ||
| 154 | extern "C" { // Prevents name mangling of functions | ||
| 155 | #endif | ||
| 156 | // Functions required to query time on Windows | ||
| 157 | int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); | ||
| 158 | int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); | ||
| 159 | #if defined(__cplusplus) | ||
| 160 | } | ||
| 161 | #endif | ||
| 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. | ||
| 166 | #endif | ||
| 167 | #include <sys/time.h> // Required for: timespec | ||
| 168 | #include <time.h> // Required for: clock_gettime() | ||
| 169 | |||
| 170 | #include <math.h> // Required for: sqrtf(), atan2f() | ||
| 171 | #endif | ||
| 172 | #if defined(__APPLE__) // macOS also defines __MACH__ | ||
| 173 | #include <mach/clock.h> // Required for: clock_get_time() | ||
| 174 | #include <mach/mach.h> // Required for: mach_timespec_t | ||
| 175 | #endif | ||
| 176 | #endif | ||
| 177 | |||
| 178 | //---------------------------------------------------------------------------------- | ||
| 179 | // Defines and Macros | ||
| 180 | //---------------------------------------------------------------------------------- | ||
| 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) | ||
| 188 | |||
| 189 | //---------------------------------------------------------------------------------- | ||
| 190 | // Types and Structures Definition | ||
| 191 | //---------------------------------------------------------------------------------- | ||
| 192 | |||
| 193 | // Gestures module state context [136 bytes] | ||
| 194 | typedef struct { | ||
| 195 | unsigned int current; // Current detected gesture | ||
| 196 | unsigned int enabledFlags; // Enabled gestures flags | ||
| 197 | struct { | ||
| 198 | int firstId; // Touch id for first touch point | ||
| 199 | int pointCount; // Touch points counter | ||
| 200 | double eventTime; // Time stamp when an event happened | ||
| 201 | Vector2 upPosition; // Touch up position | ||
| 202 | Vector2 downPositionA; // First touch down position | ||
| 203 | Vector2 downPositionB; // Second touch down position | ||
| 204 | Vector2 downDragPosition; // Touch drag position | ||
| 205 | Vector2 moveDownPositionA; // First touch down position on move | ||
| 206 | Vector2 moveDownPositionB; // Second touch down position on move | ||
| 207 | Vector2 previousPositionA; // Previous position A to compare for pinch gestures | ||
| 208 | Vector2 previousPositionB; // Previous position B to compare for pinch gestures | ||
| 209 | int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions) | ||
| 210 | } Touch; | ||
| 211 | struct { | ||
| 212 | bool resetRequired; // HOLD reset to get first touch point again | ||
| 213 | double timeDuration; // HOLD duration in seconds | ||
| 214 | } Hold; | ||
| 215 | struct { | ||
| 216 | Vector2 vector; // DRAG vector (between initial and current position) | ||
| 217 | float angle; // DRAG angle (relative to x-axis) | ||
| 218 | float distance; // DRAG distance (from initial touch point to final) (normalized [0..1]) | ||
| 219 | float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame) | ||
| 220 | } Drag; | ||
| 221 | struct { | ||
| 222 | double startTime; // SWIPE start time to calculate drag intensity | ||
| 223 | } Swipe; | ||
| 224 | struct { | ||
| 225 | Vector2 vector; // PINCH vector (between first and second touch points) | ||
| 226 | float angle; // PINCH angle (relative to x-axis) | ||
| 227 | float distance; // PINCH displacement distance (normalized [0..1]) | ||
| 228 | } Pinch; | ||
| 229 | } GesturesData; | ||
| 230 | |||
| 231 | //---------------------------------------------------------------------------------- | ||
| 232 | // Global Variables Definition | ||
| 233 | //---------------------------------------------------------------------------------- | ||
| 234 | static GesturesData GESTURES = { | ||
| 235 | .Touch.firstId = -1, | ||
| 236 | .current = GESTURE_NONE, // No current gesture detected | ||
| 237 | .enabledFlags = 0b0000001111111111 // All gestures supported by default | ||
| 238 | }; | ||
| 239 | |||
| 240 | //---------------------------------------------------------------------------------- | ||
| 241 | // Module specific Functions Declaration | ||
| 242 | //---------------------------------------------------------------------------------- | ||
| 243 | static float rgVector2Angle(Vector2 initialPosition, Vector2 finalPosition); | ||
| 244 | static float rgVector2Distance(Vector2 v1, Vector2 v2); | ||
| 245 | static double rgGetCurrentTime(void); | ||
| 246 | |||
| 247 | //---------------------------------------------------------------------------------- | ||
| 248 | // Module Functions Definition | ||
| 249 | //---------------------------------------------------------------------------------- | ||
| 250 | |||
| 251 | // Enable only desired gestures to be detected | ||
| 252 | void SetGesturesEnabled(unsigned int flags) | ||
| 253 | { | ||
| 254 | GESTURES.enabledFlags = flags; | ||
| 255 | } | ||
| 256 | |||
| 257 | // Check if a gesture have been detected | ||
| 258 | bool IsGestureDetected(unsigned int gesture) | ||
| 259 | { | ||
| 260 | if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true; | ||
| 261 | else return false; | ||
| 262 | } | ||
| 263 | |||
| 264 | // Process gesture event and translate it into gestures | ||
| 265 | void ProcessGestureEvent(GestureEvent event) | ||
| 266 | { | ||
| 267 | // Reset required variables | ||
| 268 | GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures() | ||
| 269 | |||
| 270 | if (GESTURES.Touch.pointCount == 1) // One touch point | ||
| 271 | { | ||
| 272 | if (event.touchAction == TOUCH_ACTION_DOWN) | ||
| 273 | { | ||
| 274 | GESTURES.Touch.tapCounter++; // Tap counter | ||
| 275 | |||
| 276 | // Detect GESTURE_DOUBLE_TAP | ||
| 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)) | ||
| 278 | { | ||
| 279 | GESTURES.current = GESTURE_DOUBLETAP; | ||
| 280 | GESTURES.Touch.tapCounter = 0; | ||
| 281 | } | ||
| 282 | else // Detect GESTURE_TAP | ||
| 283 | { | ||
| 284 | GESTURES.Touch.tapCounter = 1; | ||
| 285 | GESTURES.current = GESTURE_TAP; | ||
| 286 | } | ||
| 287 | |||
| 288 | GESTURES.Touch.downPositionA = event.position[0]; | ||
| 289 | GESTURES.Touch.downDragPosition = event.position[0]; | ||
| 290 | |||
| 291 | GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; | ||
| 292 | GESTURES.Touch.eventTime = rgGetCurrentTime(); | ||
| 293 | |||
| 294 | GESTURES.Swipe.startTime = rgGetCurrentTime(); | ||
| 295 | |||
| 296 | GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; | ||
| 297 | } | ||
| 298 | else if (event.touchAction == TOUCH_ACTION_UP) | ||
| 299 | { | ||
| 300 | // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases | ||
| 301 | if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0]; | ||
| 302 | |||
| 303 | // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen | ||
| 304 | GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); | ||
| 305 | GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime)); | ||
| 306 | |||
| 307 | // Detect GESTURE_SWIPE | ||
| 308 | if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG)) | ||
| 309 | { | ||
| 310 | // NOTE: Angle should be inverted in Y | ||
| 311 | GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); | ||
| 312 | |||
| 313 | if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right | ||
| 314 | else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP; // Up | ||
| 315 | else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left | ||
| 316 | else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down | ||
| 317 | else GESTURES.current = GESTURE_NONE; | ||
| 318 | } | ||
| 319 | else | ||
| 320 | { | ||
| 321 | GESTURES.Drag.distance = 0.0f; | ||
| 322 | GESTURES.Drag.intensity = 0.0f; | ||
| 323 | GESTURES.Drag.angle = 0.0f; | ||
| 324 | |||
| 325 | GESTURES.current = GESTURE_NONE; | ||
| 326 | } | ||
| 327 | |||
| 328 | GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; | ||
| 329 | GESTURES.Touch.pointCount = 0; | ||
| 330 | } | ||
| 331 | else if (event.touchAction == TOUCH_ACTION_MOVE) | ||
| 332 | { | ||
| 333 | GESTURES.Touch.moveDownPositionA = event.position[0]; | ||
| 334 | |||
| 335 | if (GESTURES.current == GESTURE_HOLD) | ||
| 336 | { | ||
| 337 | if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0]; | ||
| 338 | |||
| 339 | GESTURES.Hold.resetRequired = false; | ||
| 340 | |||
| 341 | // Detect GESTURE_DRAG | ||
| 342 | if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT) | ||
| 343 | { | ||
| 344 | GESTURES.Touch.eventTime = rgGetCurrentTime(); | ||
| 345 | GESTURES.current = GESTURE_DRAG; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 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; | ||
| 351 | } | ||
| 352 | } | ||
| 353 | else if (GESTURES.Touch.pointCount == 2) // Two touch points | ||
| 354 | { | ||
| 355 | if (event.touchAction == TOUCH_ACTION_DOWN) | ||
| 356 | { | ||
| 357 | GESTURES.Touch.downPositionA = event.position[0]; | ||
| 358 | GESTURES.Touch.downPositionB = event.position[1]; | ||
| 359 | |||
| 360 | GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA; | ||
| 361 | GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB; | ||
| 362 | |||
| 363 | //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); | ||
| 364 | |||
| 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; | ||
| 367 | |||
| 368 | GESTURES.current = GESTURE_HOLD; | ||
| 369 | GESTURES.Hold.timeDuration = rgGetCurrentTime(); | ||
| 370 | } | ||
| 371 | else if (event.touchAction == TOUCH_ACTION_MOVE) | ||
| 372 | { | ||
| 373 | GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); | ||
| 374 | |||
| 375 | GESTURES.Touch.moveDownPositionA = event.position[0]; | ||
| 376 | GESTURES.Touch.moveDownPositionB = event.position[1]; | ||
| 377 | |||
| 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; | ||
| 380 | |||
| 381 | if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) | ||
| 382 | { | ||
| 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; | ||
| 385 | } | ||
| 386 | else | ||
| 387 | { | ||
| 388 | GESTURES.current = GESTURE_HOLD; | ||
| 389 | GESTURES.Hold.timeDuration = rgGetCurrentTime(); | ||
| 390 | } | ||
| 391 | |||
| 392 | // NOTE: Angle should be inverted in Y | ||
| 393 | GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); | ||
| 394 | } | ||
| 395 | else if (event.touchAction == TOUCH_ACTION_UP) | ||
| 396 | { | ||
| 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; | ||
| 401 | |||
| 402 | GESTURES.current = GESTURE_NONE; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | else if (GESTURES.Touch.pointCount > 2) // More than two touch points | ||
| 406 | { | ||
| 407 | // TODO: Process gesture events for more than two points | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | // Update gestures detected (must be called every frame) | ||
| 412 | void UpdateGestures(void) | ||
| 413 | { | ||
| 414 | // NOTE: Gestures are processed through system callbacks on touch events | ||
| 415 | |||
| 416 | // Detect GESTURE_HOLD | ||
| 417 | if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) | ||
| 418 | { | ||
| 419 | GESTURES.current = GESTURE_HOLD; | ||
| 420 | GESTURES.Hold.timeDuration = rgGetCurrentTime(); | ||
| 421 | } | ||
| 422 | |||
| 423 | // Detect GESTURE_NONE | ||
| 424 | if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN)) | ||
| 425 | { | ||
| 426 | GESTURES.current = GESTURE_NONE; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | // Get latest detected gesture | ||
| 431 | int GetGestureDetected(void) | ||
| 432 | { | ||
| 433 | // Get current gesture only if enabled | ||
| 434 | return (GESTURES.enabledFlags & GESTURES.current); | ||
| 435 | } | ||
| 436 | |||
| 437 | // Hold time measured in seconds | ||
| 438 | float GetGestureHoldDuration(void) | ||
| 439 | { | ||
| 440 | // NOTE: time is calculated on current gesture HOLD | ||
| 441 | |||
| 442 | double time = 0.0; | ||
| 443 | |||
| 444 | if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration; | ||
| 445 | |||
| 446 | return (float)time; | ||
| 447 | } | ||
| 448 | |||
| 449 | // Get drag vector (between initial touch point to current) | ||
| 450 | Vector2 GetGestureDragVector(void) | ||
| 451 | { | ||
| 452 | // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE | ||
| 453 | |||
| 454 | return GESTURES.Drag.vector; | ||
| 455 | } | ||
| 456 | |||
| 457 | // Get drag angle | ||
| 458 | // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise | ||
| 459 | float GetGestureDragAngle(void) | ||
| 460 | { | ||
| 461 | // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP | ||
| 462 | |||
| 463 | return GESTURES.Drag.angle; | ||
| 464 | } | ||
| 465 | |||
| 466 | // Get distance between two pinch points | ||
| 467 | Vector2 GetGesturePinchVector(void) | ||
| 468 | { | ||
| 469 | // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE | ||
| 470 | |||
| 471 | return GESTURES.Pinch.vector; | ||
| 472 | } | ||
| 473 | |||
| 474 | // Get angle between two pinch points | ||
| 475 | // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise | ||
| 476 | float GetGesturePinchAngle(void) | ||
| 477 | { | ||
| 478 | // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE | ||
| 479 | |||
| 480 | return GESTURES.Pinch.angle; | ||
| 481 | } | ||
| 482 | |||
| 483 | //---------------------------------------------------------------------------------- | ||
| 484 | // Module specific Functions Definition | ||
| 485 | //---------------------------------------------------------------------------------- | ||
| 486 | // Get angle from two-points vector with X-axis | ||
| 487 | static float rgVector2Angle(Vector2 v1, Vector2 v2) | ||
| 488 | { | ||
| 489 | float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); | ||
| 490 | |||
| 491 | if (angle < 0) angle += 360.0f; | ||
| 492 | |||
| 493 | return angle; | ||
| 494 | } | ||
| 495 | |||
| 496 | // Calculate distance between two Vector2 | ||
| 497 | static float rgVector2Distance(Vector2 v1, Vector2 v2) | ||
| 498 | { | ||
| 499 | float result; | ||
| 500 | |||
| 501 | float dx = v2.x - v1.x; | ||
| 502 | float dy = v2.y - v1.y; | ||
| 503 | |||
| 504 | result = (float)sqrt(dx*dx + dy*dy); | ||
| 505 | |||
| 506 | return result; | ||
| 507 | } | ||
| 508 | |||
| 509 | // Time measure returned are seconds | ||
| 510 | static double rgGetCurrentTime(void) | ||
| 511 | { | ||
| 512 | double time = 0; | ||
| 513 | |||
| 514 | #if !defined(RGESTURES_STANDALONE) | ||
| 515 | time = GetTime(); | ||
| 516 | #else | ||
| 517 | #if defined(_WIN32) | ||
| 518 | unsigned long long int clockFrequency, currentTime; | ||
| 519 | |||
| 520 | QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! | ||
| 521 | QueryPerformanceCounter(¤tTime); | ||
| 522 | |||
| 523 | time = (double)currentTime/clockFrequency; // Time in seconds | ||
| 524 | #endif | ||
| 525 | |||
| 526 | #if defined(__linux__) | ||
| 527 | // NOTE: Only for Linux-based systems | ||
| 528 | struct timespec now; | ||
| 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; // Time in nanoseconds | ||
| 531 | |||
| 532 | time = ((double)nowTime*1e-9); // Time in seconds | ||
| 533 | #endif | ||
| 534 | |||
| 535 | #if defined(__APPLE__) | ||
| 536 | //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 | ||
| 537 | //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time | ||
| 538 | |||
| 539 | clock_serv_t cclock; | ||
| 540 | mach_timespec_t now; | ||
| 541 | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); | ||
| 542 | |||
| 543 | // NOTE: OS X does not have clock_gettime(), using clock_get_time() | ||
| 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; // Time in nanoseconds | ||
| 547 | |||
| 548 | time = ((double)nowTime*1e-9); // Time in seconds | ||
| 549 | #endif | ||
| 550 | #endif | ||
| 551 | |||
| 552 | return time; | ||
| 553 | } | ||
| 554 | |||
| 555 | #endif // RGESTURES_IMPLEMENTATION | ||
