rgestures.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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-2025 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. #ifndef RGESTURES_H
  43. #define RGESTURES_H
  44. #ifndef PI
  45. #define PI 3.14159265358979323846
  46. #endif
  47. //----------------------------------------------------------------------------------
  48. // Defines and Macros
  49. //----------------------------------------------------------------------------------
  50. #ifndef MAX_TOUCH_POINTS
  51. #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
  52. #endif
  53. //----------------------------------------------------------------------------------
  54. // Types and Structures Definition
  55. // NOTE: Below types are required for standalone usage
  56. //----------------------------------------------------------------------------------
  57. // Boolean type
  58. #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
  59. #include <stdbool.h>
  60. #elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
  61. typedef enum bool { false = 0, true = !false } bool;
  62. #endif
  63. #if !defined(RL_VECTOR2_TYPE)
  64. // Vector2 type
  65. typedef struct Vector2 {
  66. float x;
  67. float y;
  68. } Vector2;
  69. #endif
  70. #if defined(RGESTURES_STANDALONE)
  71. // Gestures type
  72. // NOTE: It could be used as flags to enable only some gestures
  73. typedef enum {
  74. GESTURE_NONE = 0,
  75. GESTURE_TAP = 1,
  76. GESTURE_DOUBLETAP = 2,
  77. GESTURE_HOLD = 4,
  78. GESTURE_DRAG = 8,
  79. GESTURE_SWIPE_RIGHT = 16,
  80. GESTURE_SWIPE_LEFT = 32,
  81. GESTURE_SWIPE_UP = 64,
  82. GESTURE_SWIPE_DOWN = 128,
  83. GESTURE_PINCH_IN = 256,
  84. GESTURE_PINCH_OUT = 512
  85. } Gesture;
  86. #endif
  87. typedef enum {
  88. TOUCH_ACTION_UP = 0,
  89. TOUCH_ACTION_DOWN,
  90. TOUCH_ACTION_MOVE,
  91. TOUCH_ACTION_CANCEL
  92. } TouchAction;
  93. // Gesture event
  94. typedef struct {
  95. int touchAction;
  96. int pointCount;
  97. int pointId[MAX_TOUCH_POINTS];
  98. Vector2 position[MAX_TOUCH_POINTS];
  99. } GestureEvent;
  100. //----------------------------------------------------------------------------------
  101. // Global Variables Definition
  102. //----------------------------------------------------------------------------------
  103. //...
  104. //----------------------------------------------------------------------------------
  105. // Module Functions Declaration
  106. //----------------------------------------------------------------------------------
  107. #if defined(__cplusplus)
  108. extern "C" { // Prevents name mangling of functions
  109. #endif
  110. void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
  111. void UpdateGestures(void); // Update gestures detected (must be called every frame)
  112. #if defined(RGESTURES_STANDALONE)
  113. void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
  114. bool IsGestureDetected(int gesture); // Check if a gesture have been detected
  115. int GetGestureDetected(void); // Get latest detected gesture
  116. float GetGestureHoldDuration(void); // Get gesture hold time in seconds
  117. Vector2 GetGestureDragVector(void); // Get gesture drag vector
  118. float GetGestureDragAngle(void); // Get gesture drag angle
  119. Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
  120. float GetGesturePinchAngle(void); // Get gesture pinch angle
  121. #endif
  122. #if defined(__cplusplus)
  123. }
  124. #endif
  125. #endif // RGESTURES_H
  126. /***********************************************************************************
  127. *
  128. * RGESTURES IMPLEMENTATION
  129. *
  130. ************************************************************************************/
  131. #if defined(RGESTURES_IMPLEMENTATION)
  132. #if defined(RGESTURES_STANDALONE)
  133. #if defined(_WIN32)
  134. #if defined(__cplusplus)
  135. extern "C" { // Prevents name mangling of functions
  136. #endif
  137. // Functions required to query time on Windows
  138. int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
  139. int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
  140. #if defined(__cplusplus)
  141. }
  142. #endif
  143. #elif defined(__linux__)
  144. #if _POSIX_C_SOURCE < 199309L
  145. #undef _POSIX_C_SOURCE
  146. #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
  147. #endif
  148. #include <sys/time.h> // Required for: timespec
  149. #include <time.h> // Required for: clock_gettime()
  150. #include <math.h> // Required for: sqrtf(), atan2f()
  151. #endif
  152. #if defined(__APPLE__) // macOS also defines __MACH__
  153. #include <mach/clock.h> // Required for: clock_get_time()
  154. #include <mach/mach.h> // Required for: mach_timespec_t
  155. #endif
  156. #endif
  157. //----------------------------------------------------------------------------------
  158. // Defines and Macros
  159. //----------------------------------------------------------------------------------
  160. #define FORCE_TO_SWIPE 0.2f // Swipe force, measured in normalized screen units/time
  161. #define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
  162. #define DRAG_TIMEOUT 0.3f // Drag minimum time for web, measured in seconds
  163. #define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
  164. #define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds
  165. #define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds
  166. #define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
  167. //----------------------------------------------------------------------------------
  168. // Types and Structures Definition
  169. //----------------------------------------------------------------------------------
  170. // Gestures module state context [136 bytes]
  171. typedef struct {
  172. unsigned int current; // Current detected gesture
  173. unsigned int enabledFlags; // Enabled gestures flags
  174. struct {
  175. int firstId; // Touch id for first touch point
  176. int pointCount; // Touch points counter
  177. double eventTime; // Time stamp when an event happened
  178. Vector2 upPosition; // Touch up position
  179. Vector2 downPositionA; // First touch down position
  180. Vector2 downPositionB; // Second touch down position
  181. Vector2 downDragPosition; // Touch drag position
  182. Vector2 moveDownPositionA; // First touch down position on move
  183. Vector2 moveDownPositionB; // Second touch down position on move
  184. Vector2 previousPositionA; // Previous position A to compare for pinch gestures
  185. Vector2 previousPositionB; // Previous position B to compare for pinch gestures
  186. int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions)
  187. } Touch;
  188. struct {
  189. bool resetRequired; // HOLD reset to get first touch point again
  190. double timeDuration; // HOLD duration in seconds
  191. } Hold;
  192. struct {
  193. Vector2 vector; // DRAG vector (between initial and current position)
  194. float angle; // DRAG angle (relative to x-axis)
  195. float distance; // DRAG distance (from initial touch point to final) (normalized [0..1])
  196. float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame)
  197. } Drag;
  198. struct {
  199. double startTime; // SWIPE start time to calculate drag intensity
  200. } Swipe;
  201. struct {
  202. Vector2 vector; // PINCH vector (between first and second touch points)
  203. float angle; // PINCH angle (relative to x-axis)
  204. float distance; // PINCH displacement distance (normalized [0..1])
  205. } Pinch;
  206. } GesturesData;
  207. //----------------------------------------------------------------------------------
  208. // Global Variables Definition
  209. //----------------------------------------------------------------------------------
  210. static GesturesData GESTURES = {
  211. .Touch.firstId = -1,
  212. .current = GESTURE_NONE, // No current gesture detected
  213. .enabledFlags = 0b0000001111111111 // All gestures supported by default
  214. };
  215. //----------------------------------------------------------------------------------
  216. // Module Internal Functions Declaration
  217. //----------------------------------------------------------------------------------
  218. static float rgVector2Angle(Vector2 initialPosition, Vector2 finalPosition);
  219. static float rgVector2Distance(Vector2 v1, Vector2 v2);
  220. static double rgGetCurrentTime(void);
  221. //----------------------------------------------------------------------------------
  222. // Module Functions Definition
  223. //----------------------------------------------------------------------------------
  224. // Enable only desired gestures to be detected
  225. void SetGesturesEnabled(unsigned int flags)
  226. {
  227. GESTURES.enabledFlags = flags;
  228. }
  229. // Check if a gesture have been detected
  230. bool IsGestureDetected(unsigned int gesture)
  231. {
  232. if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true;
  233. else return false;
  234. }
  235. // Process gesture event and translate it into gestures
  236. void ProcessGestureEvent(GestureEvent event)
  237. {
  238. // Reset required variables
  239. GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures()
  240. if (GESTURES.Touch.pointCount == 1) // One touch point
  241. {
  242. if (event.touchAction == TOUCH_ACTION_DOWN)
  243. {
  244. GESTURES.Touch.tapCounter++; // Tap counter
  245. // Detect GESTURE_DOUBLE_TAP
  246. if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rgGetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE))
  247. {
  248. GESTURES.current = GESTURE_DOUBLETAP;
  249. GESTURES.Touch.tapCounter = 0;
  250. }
  251. else // Detect GESTURE_TAP
  252. {
  253. GESTURES.Touch.tapCounter = 1;
  254. GESTURES.current = GESTURE_TAP;
  255. }
  256. GESTURES.Touch.downPositionA = event.position[0];
  257. GESTURES.Touch.downDragPosition = event.position[0];
  258. GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
  259. GESTURES.Touch.eventTime = rgGetCurrentTime();
  260. GESTURES.Swipe.startTime = rgGetCurrentTime();
  261. GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f };
  262. }
  263. else if (event.touchAction == TOUCH_ACTION_UP)
  264. {
  265. // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
  266. if (GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD) GESTURES.Touch.upPosition = event.position[0];
  267. // NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
  268. GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
  269. GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.startTime));
  270. // Detect GESTURE_SWIPE
  271. if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.current != GESTURE_DRAG))
  272. {
  273. // NOTE: Angle should be inverted in Y
  274. GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
  275. if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right
  276. else if ((GESTURES.Drag.angle >= 30) && (GESTURES.Drag.angle <= 150)) GESTURES.current = GESTURE_SWIPE_UP; // Up
  277. else if ((GESTURES.Drag.angle > 150) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left
  278. else if ((GESTURES.Drag.angle >= 210) && (GESTURES.Drag.angle <= 330)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down
  279. else GESTURES.current = GESTURE_NONE;
  280. }
  281. else
  282. {
  283. GESTURES.Drag.distance = 0.0f;
  284. GESTURES.Drag.intensity = 0.0f;
  285. GESTURES.Drag.angle = 0.0f;
  286. GESTURES.current = GESTURE_NONE;
  287. }
  288. GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f };
  289. GESTURES.Touch.pointCount = 0;
  290. }
  291. else if (event.touchAction == TOUCH_ACTION_MOVE)
  292. {
  293. GESTURES.Touch.moveDownPositionA = event.position[0];
  294. if (GESTURES.current == GESTURE_HOLD)
  295. {
  296. if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0];
  297. GESTURES.Hold.resetRequired = false;
  298. // Detect GESTURE_DRAG
  299. if ((rgGetCurrentTime() - GESTURES.Touch.eventTime) > DRAG_TIMEOUT)
  300. {
  301. GESTURES.Touch.eventTime = rgGetCurrentTime();
  302. GESTURES.current = GESTURE_DRAG;
  303. }
  304. }
  305. GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x;
  306. GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
  307. }
  308. }
  309. else if (GESTURES.Touch.pointCount == 2) // Two touch points
  310. {
  311. if (event.touchAction == TOUCH_ACTION_DOWN)
  312. {
  313. GESTURES.Touch.downPositionA = event.position[0];
  314. GESTURES.Touch.downPositionB = event.position[1];
  315. GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA;
  316. GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB;
  317. //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
  318. GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
  319. GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y;
  320. GESTURES.current = GESTURE_HOLD;
  321. GESTURES.Hold.timeDuration = rgGetCurrentTime();
  322. }
  323. else if (event.touchAction == TOUCH_ACTION_MOVE)
  324. {
  325. GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
  326. GESTURES.Touch.moveDownPositionA = event.position[0];
  327. GESTURES.Touch.moveDownPositionB = event.position[1];
  328. GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
  329. GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
  330. if ((rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH))
  331. {
  332. if ( rgVector2Distance(GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB) > rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) ) GESTURES.current = GESTURE_PINCH_IN;
  333. else GESTURES.current = GESTURE_PINCH_OUT;
  334. }
  335. else
  336. {
  337. GESTURES.current = GESTURE_HOLD;
  338. GESTURES.Hold.timeDuration = rgGetCurrentTime();
  339. }
  340. // NOTE: Angle should be inverted in Y
  341. GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB);
  342. }
  343. else if (event.touchAction == TOUCH_ACTION_UP)
  344. {
  345. GESTURES.Pinch.distance = 0.0f;
  346. GESTURES.Pinch.angle = 0.0f;
  347. GESTURES.Pinch.vector = (Vector2){ 0.0f, 0.0f };
  348. GESTURES.Touch.pointCount = 0;
  349. GESTURES.current = GESTURE_NONE;
  350. }
  351. }
  352. else if (GESTURES.Touch.pointCount > 2) // More than two touch points
  353. {
  354. // TODO: Process gesture events for more than two points
  355. }
  356. }
  357. // Update gestures detected (must be called every frame)
  358. void UpdateGestures(void)
  359. {
  360. // NOTE: Gestures are processed through system callbacks on touch events
  361. // Detect GESTURE_HOLD
  362. if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2))
  363. {
  364. GESTURES.current = GESTURE_HOLD;
  365. GESTURES.Hold.timeDuration = rgGetCurrentTime();
  366. }
  367. // Detect GESTURE_NONE
  368. if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN))
  369. {
  370. GESTURES.current = GESTURE_NONE;
  371. }
  372. }
  373. // Get latest detected gesture
  374. int GetGestureDetected(void)
  375. {
  376. // Get current gesture only if enabled
  377. return (GESTURES.enabledFlags & GESTURES.current);
  378. }
  379. // Hold time measured in seconds
  380. float GetGestureHoldDuration(void)
  381. {
  382. // NOTE: time is calculated on current gesture HOLD
  383. double time = 0.0;
  384. if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration;
  385. return (float)time;
  386. }
  387. // Get drag vector (between initial touch point to current)
  388. Vector2 GetGestureDragVector(void)
  389. {
  390. // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE
  391. return GESTURES.Drag.vector;
  392. }
  393. // Get drag angle
  394. // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
  395. float GetGestureDragAngle(void)
  396. {
  397. // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP
  398. return GESTURES.Drag.angle;
  399. }
  400. // Get distance between two pinch points
  401. Vector2 GetGesturePinchVector(void)
  402. {
  403. // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE
  404. return GESTURES.Pinch.vector;
  405. }
  406. // Get angle between two pinch points
  407. // NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
  408. float GetGesturePinchAngle(void)
  409. {
  410. // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE
  411. return GESTURES.Pinch.angle;
  412. }
  413. //----------------------------------------------------------------------------------
  414. // Module Internal Functions Definition
  415. //----------------------------------------------------------------------------------
  416. // Get angle from two-points vector with X-axis
  417. static float rgVector2Angle(Vector2 v1, Vector2 v2)
  418. {
  419. float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
  420. if (angle < 0) angle += 360.0f;
  421. return angle;
  422. }
  423. // Calculate distance between two Vector2
  424. static float rgVector2Distance(Vector2 v1, Vector2 v2)
  425. {
  426. float result;
  427. float dx = v2.x - v1.x;
  428. float dy = v2.y - v1.y;
  429. result = (float)sqrt(dx*dx + dy*dy);
  430. return result;
  431. }
  432. // Time measure returned are seconds
  433. static double rgGetCurrentTime(void)
  434. {
  435. double time = 0;
  436. #if !defined(RGESTURES_STANDALONE)
  437. time = GetTime();
  438. #else
  439. #if defined(_WIN32)
  440. unsigned long long int clockFrequency, currentTime;
  441. QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
  442. QueryPerformanceCounter(&currentTime);
  443. time = (double)currentTime/clockFrequency; // Time in seconds
  444. #endif
  445. #if defined(__linux__)
  446. // NOTE: Only for Linux-based systems
  447. struct timespec now;
  448. clock_gettime(CLOCK_MONOTONIC, &now);
  449. unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
  450. time = ((double)nowTime*1e-9); // Time in seconds
  451. #endif
  452. #if defined(__APPLE__)
  453. //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
  454. //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
  455. clock_serv_t cclock;
  456. mach_timespec_t now;
  457. host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
  458. // NOTE: OS X does not have clock_gettime(), using clock_get_time()
  459. clock_get_time(cclock, &now);
  460. mach_port_deallocate(mach_task_self(), cclock);
  461. unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds
  462. time = ((double)nowTime*1e-9); // Time in seconds
  463. #endif
  464. #endif
  465. return time;
  466. }
  467. #endif // RGESTURES_IMPLEMENTATION