github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/rgestures.h (about)

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