minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

rgestures.h (22530B)


      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(&currentTime);
    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