diff options
Diffstat (limited to 'src/gestures.c')
| -rw-r--r-- | src/gestures.c | 778 |
1 files changed, 269 insertions, 509 deletions
diff --git a/src/gestures.c b/src/gestures.c index 4cb61222..9028f43b 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -1,8 +1,10 @@ /********************************************************************************************** * -* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5) +* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * -* Copyright (c) 2015 Marc Palau and Ramon Santamaria +* Initial design by Marc Palau +* Redesigned by Albert Martos and Ian Eito +* Reviewed by Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -29,486 +31,360 @@ #include "raylib.h" // Required for typedef(s): Vector2, Gestures #endif -#include <stdlib.h> // malloc(), free() -#include <stdio.h> // printf(), fprintf() -#include <math.h> // Used for ... +#include <math.h> // Used for: atan2(), sqrt() #include <stdint.h> // Defines int32_t, int64_t #if defined(_WIN32) - //#include <Windows.h> + // Functions required to query time on Windows + int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); + int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); #elif defined(__linux) #include <sys/time.h> // Declares storage size of ‘now’ #include <time.h> // Used for clock functions #endif -#if defined(PLATFORM_ANDROID) - #include <jni.h> // Java native interface - #include <android/sensor.h> // Android sensors functions - #include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others -#endif - -#if defined(PLATFORM_WEB) - #include <emscripten/emscripten.h> - #include <emscripten/html5.h> -#endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 20 -#define TAP_TIMEOUT 300 -#define MAX_TOUCH_POINTS 4 +#define FORCE_TO_SWIPE 0.0005f // Measured in normalized pixels / time +#define MINIMUM_DRAG 0.015f // Measured in normalized pixels [0..1] +#define MINIMUM_PINCH 0.005f // Measured in normalized pixels [0..1] +#define TAP_TIMEOUT 300 // Time in milliseconds +#define PINCH_TIMEOUT 300 // Time in milliseconds +#define DOUBLETAP_RANGE 0.03f //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { - TYPE_MOTIONLESS, - TYPE_DRAG, - TYPE_DUAL_INPUT -} GestureType; - -typedef enum { - UP, - DOWN, - MOVE -} ActionType; - -typedef struct { - ActionType action; - int pointCount; - int pointerId[MAX_TOUCH_POINTS]; - Vector2 position[MAX_TOUCH_POINTS]; -} GestureEvent; - +// ... //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static GestureType gestureType = TYPE_MOTIONLESS; -static double eventTime = 0; -//static int32_t touchId; // Not used... -// Tap gesture variables -static Vector2 initialTapPosition = { 0, 0 }; +// Touch gesture variables +static Vector2 touchDownPosition = { 0.0f, 0.0f }; +static Vector2 touchDownPosition2 = { 0.0f, 0.0f }; +static Vector2 touchDownDragPosition = { 0.0f, 0.0f }; +static Vector2 touchUpPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition2 = { 0.0f, 0.0f }; +static int numTap = 0; -// Double Tap gesture variables -static bool doubleTapping = false; -static bool untap = false; // Check if recently done a tap +static int pointCount = 0; +static int touchId = -1; -// Drag gesture variables -static Vector2 initialDragPosition = { 0, 0 }; -static Vector2 endDragPosition = { 0, 0 }; -static Vector2 lastDragPosition = { 0, 0 }; -static Vector2 dragVector = { 0, 0 }; +static double eventTime = 0.0; +static double swipeTime = 0.0; + +// Hold gesture variables +static int numHold = 0; +static float timeHold = 0.0f; -static float magnitude = 0; // Distance traveled dragging -static float angle = 0; // Angle direction of the drag -static float intensity = 0; // How fast we did the drag (pixels per frame) -static int draggingTimeCounter = 0; // Time that have passed while dragging +// Drag gesture variables +static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) +static float dragAngle = 0.0f; // DRAG angle (relative to x-axis) +static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1]) +static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) +static bool startMoving = false; // SWIPE used to define when start measuring swipeTime // Pinch gesture variables -static Vector2 firstInitialPinchPosition = { 0, 0 }; -static Vector2 secondInitialPinchPosition = { 0, 0 }; -static Vector2 firstEndPinchPosition = { 0, 0 }; -static Vector2 secondEndPinchPosition = { 0, 0 }; -static float pinchDelta = 0; // Pinch delta displacement +static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points) +static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis) +static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1]) // Detected gestures static int previousGesture = GESTURE_NONE; static int currentGesture = GESTURE_NONE; -static unsigned int enabledGestures = 0; // TODO: Currently not in use... - -static Vector2 touchPosition; +// Enabled gestures flags, all gestures enabled by default +static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static void ProcessMotionEvent(GestureEvent event); - -static void InitPinchGesture(Vector2 posA, Vector2 posB); -static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude); -static float VectorDistance(Vector2 v1, Vector2 v2); -static float VectorDotProduct(Vector2 v1, Vector2 v2); -static double GetCurrentTime(); - -#if defined(PLATFORM_WEB) -static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); -#endif - -#if defined(PLATFORM_ANDROID) -static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); -#endif +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); +static float Vector2Distance(Vector2 v1, Vector2 v2); +static double GetCurrentTime(void); //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -// Returns touch position X -int GetTouchX(void) +// Process gesture event and translate it into gestures +void ProcessGestureEvent(GestureEvent event) { - return (int)touchPosition.x; + // Reset required variables + previousGesture = currentGesture; + + pointCount = event.pointCount; // Required on UpdateGestures() + + if (pointCount < 2) + { + touchId = event.pointerId[0]; + + if (event.touchAction == TOUCH_DOWN) + { + numTap++; // Tap counter + + // Detect GESTURE_DOUBLE_TAP + if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) + { + currentGesture = GESTURE_DOUBLETAP; + numTap = 0; + } + else // Detect GESTURE_TAP + { + numTap = 1; + currentGesture = GESTURE_TAP; + } + + touchDownPosition = event.position[0]; + touchDownDragPosition = event.position[0]; + + touchUpPosition = touchDownPosition; + eventTime = GetCurrentTime(); + + dragVector = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_UP) + { + if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; + + // NOTE: dragIntensity dependend on the resolution of the screen + dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); + dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); + + // TODO: Make getures detection resolution independant + + startMoving = false; + + // Detect GESTURE_SWIPE + if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? + { + // NOTE: Angle should be inverted in Y + dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition); + + if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right + else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up + else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left + else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down + else currentGesture = GESTURE_NONE; + } + else + { + dragDistance = 0.0f; + dragIntensity = 0.0f; + dragAngle = 0.0f; + + currentGesture = GESTURE_NONE; + } + + touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_MOVE) + { + if ((currentGesture == GESTURE_DRAG)) eventTime = GetCurrentTime(); + + if (!startMoving) + { + swipeTime = GetCurrentTime(); + startMoving = true; + } + + moveDownPosition = event.position[0]; + + if (currentGesture == GESTURE_HOLD) + { + if (numHold == 1) touchDownPosition = event.position[0]; + + numHold = 2; + + // Detect GESTURE_DRAG + if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) + { + eventTime = GetCurrentTime(); + currentGesture = GESTURE_DRAG; + } + } + + dragVector.x = moveDownPosition.x - touchDownDragPosition.x; + dragVector.y = moveDownPosition.y - touchDownDragPosition.y; + } + } + else // Two touch points + { + if (event.touchAction == TOUCH_DOWN) + { + touchDownPosition = event.position[0]; + touchDownPosition2 = event.position[1]; + + //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); + + pinchVector.x = touchDownPosition2.x - touchDownPosition.x; + pinchVector.y = touchDownPosition2.y - touchDownPosition.y; + + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + else if (event.touchAction == TOUCH_MOVE) + { + pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); + + touchDownPosition = moveDownPosition; + touchDownPosition2 = moveDownPosition2; + + moveDownPosition = event.position[0]; + moveDownPosition2 = event.position[1]; + + pinchVector.x = moveDownPosition2.x - moveDownPosition.x; + pinchVector.y = moveDownPosition2.y - moveDownPosition.y; + + if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH)) + { + if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; + else currentGesture = GESTURE_PINCH_OUT; + } + else + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + + // NOTE: Angle should be inverted in Y + pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2); + } + else if (event.touchAction == TOUCH_UP) + { + pinchDistance = 0.0f; + pinchAngle = 0.0f; + pinchVector = (Vector2){ 0.0f, 0.0f }; + + currentGesture = GESTURE_NONE; + } + } } -// Returns touch position Y -int GetTouchY(void) +// Update gestures detected (must be called every frame) +void UpdateGestures(void) { - return (int)touchPosition.y; -} + // NOTE: Gestures are processed through system callbacks on touch events -// Returns touch position XY -// TODO: touch position should be scaled depending on display size and render size -Vector2 GetTouchPosition(void) -{ - Vector2 position = touchPosition; -/* - if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) + // Detect GESTURE_HOLD + if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2)) + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + + if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) { - // TODO: Seems to work ok but... review! - position.x = position.x*((float)screenWidth / (float)(displayWidth - renderOffsetX)) - renderOffsetX/2; - position.y = position.y*((float)screenHeight / (float)(displayHeight - renderOffsetY)) - renderOffsetY/2; + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + numHold = 1; } - else + + // Detect GESTURE_NONE + if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) { - position.x = position.x*((float)renderWidth / (float)displayWidth) - renderOffsetX/2; - position.y = position.y*((float)renderHeight / (float)displayHeight) - renderOffsetY/2; + currentGesture = GESTURE_NONE; } -*/ - return position; } // Check if a gesture have been detected bool IsGestureDetected(void) { -/* - if (currentGesture == GESTURE_DRAG) TraceLog(INFO, "DRAG"); - else if (currentGesture == GESTURE_TAP) TraceLog(INFO, "TAP"); - else if (currentGesture == GESTURE_DOUBLETAP) TraceLog(INFO, "DOUBLE"); - else if (currentGesture == GESTURE_HOLD) TraceLog(INFO, "HOLD"); - else if (currentGesture == GESTURE_SWIPE_RIGHT) TraceLog(INFO, "RIGHT"); - else if (currentGesture == GESTURE_SWIPE_UP) TraceLog(INFO, "UP"); - else if (currentGesture == GESTURE_SWIPE_LEFT) TraceLog(INFO, "LEFT"); - else if (currentGesture == GESTURE_SWIPE_DOWN) TraceLog(INFO, "DOWN"); - else if (currentGesture == GESTURE_PINCH_IN) TraceLog(INFO, "PINCH IN"); - else if (currentGesture == GESTURE_PINCH_OUT) TraceLog(INFO, "PINCH OUT"); -*/ - - if (currentGesture != GESTURE_NONE) return true; + if ((enabledGestures & currentGesture) != GESTURE_NONE) return true; else return false; } // Check gesture type int GetGestureType(void) { - return currentGesture; + // Get current gesture only if enabled + return (enabledGestures & currentGesture); } -void SetGesturesEnabled(unsigned int gestureFlags) +// Get number of touch points +int GetTouchPointsCount(void) { - enabledGestures = gestureFlags; + // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called + + return pointCount; } -// Get drag intensity (pixels per frame) -float GetGestureDragIntensity(void) +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) { - return intensity; + enabledGestures = gestureFlags; } -// Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGestureDragAngle(void) +// Hold time measured in ms +float GetGestureHoldDuration(void) { - return angle; + // NOTE: time is calculated on current gesture HOLD + + float time = 0.0f; + + if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; + + return time; } -// Get drag vector (between initial and final position) +// Get drag vector (between initial touch point to current) Vector2 GetGestureDragVector(void) { + // NOTE: drag vector is calculated on one touch points TOUCH_MOVE + return dragVector; } -// Hold time measured in frames -int GetGestureHoldDuration(void) +// Get drag angle +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGestureDragAngle(void) { - return 0; + // NOTE: drag angle is calculated on one touch points TOUCH_UP + + return dragAngle; } -// Get magnitude between two pinch points -float GetGesturePinchDelta(void) +// Get distance between two pinch points +Vector2 GetGesturePinchVector(void) { - return pinchDelta; + // NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index) + // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE + + return pinchVector; } // Get angle beween two pinch points // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGesturePinchAngle(void) { - return 0; -} - -#if defined(PLATFORM_WEB) -// Init gestures system (web) -void InitGesturesSystem(void) -{ - // Init gestures system web (emscripten) - - // NOTE: Some code examples - //emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch); - //emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); - - emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenInputCallback); - emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback); - emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback); - emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback); -} -#elif defined(PLATFORM_ANDROID) -// Init gestures system (android) -void InitGesturesSystem(struct android_app *app) -{ - app->onInputEvent = AndroidInputCallback; + // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE - // TODO: Receive frameBuffer data: displayWidth/displayHeight, renderWidth/renderHeight, screenWidth/screenHeight -} -#endif - -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events - - if ((previousGesture == GESTURE_TAP) && (currentGesture == GESTURE_TAP)) currentGesture = GESTURE_HOLD; - else if (currentGesture != GESTURE_HOLD) currentGesture = GESTURE_NONE; + return pinchAngle; } //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- -static void ProcessMotionEvent(GestureEvent event) -{ - // Resets - dragVector = (Vector2){ 0, 0 }; - pinchDelta = 0; - - previousGesture = currentGesture; - - switch (gestureType) - { - case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events - { - if (event.action == DOWN) - { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - // Set the press position - initialTapPosition = event.position[0]; - - // If too much time have passed, we reset the double tap - if (GetCurrentTime() - eventTime > TAP_TIMEOUT) untap = false; - - // If we are in time, we detect the double tap - if (untap) doubleTapping = true; - - // Update our event time - eventTime = GetCurrentTime(); - - // Set hold - if (doubleTapping) currentGesture = GESTURE_DOUBLETAP; - else currentGesture = GESTURE_TAP; - } - } - else if (event.action == UP) - { - currentGesture = GESTURE_NONE; - - // Detect that we are tapping instead of holding - if (GetCurrentTime() - eventTime < TAP_TIMEOUT) - { - if (doubleTapping) untap = false; - else untap = true; - } - - // Tap finished - doubleTapping = false; - // Update our event time - eventTime = GetCurrentTime(); - } - // Begin dragging - else if (event.action == MOVE) - { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - // Set the drag starting position - initialDragPosition = initialTapPosition; - endDragPosition = initialDragPosition; - - // Initialize drag - draggingTimeCounter = 0; - gestureType = TYPE_DRAG; - currentGesture = GESTURE_NONE; - } - } - } break; - case TYPE_DRAG: // Detect DRAG and SWIPE events - { - // end of the drag - if (event.action == UP) - { - // Return Swipe if we have enough sensitivity - if (intensity > FORCE_TO_SWIPE) - { - if (angle < 30 || angle > 330) currentGesture = GESTURE_SWIPE_RIGHT; // Right - else if (angle > 60 && angle < 120) currentGesture = GESTURE_SWIPE_UP; // Up - else if (angle > 150 && angle < 210) currentGesture = GESTURE_SWIPE_LEFT; // Left - else if (angle > 240 && angle < 300) currentGesture = GESTURE_SWIPE_DOWN; // Down - } - - magnitude = 0; - angle = 0; - intensity = 0; - - gestureType = TYPE_MOTIONLESS; - } - // Update while we are dragging - else if (event.action == MOVE) - { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - lastDragPosition = endDragPosition; - - endDragPosition = touchPosition; - - //endDragPosition.x = AMotionEvent_getX(event, 0); - //endDragPosition.y = AMotionEvent_getY(event, 0); - - // Calculate attributes - dragVector = (Vector2){ endDragPosition.x - lastDragPosition.x, endDragPosition.y - lastDragPosition.y }; - magnitude = sqrt(pow(endDragPosition.x - initialDragPosition.x, 2) + pow(endDragPosition.y - initialDragPosition.y, 2)); - angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude); - intensity = magnitude / (float)draggingTimeCounter; - - currentGesture = GESTURE_DRAG; - draggingTimeCounter++; - } - } - } break; - case TYPE_DUAL_INPUT: - { - if (event.action == UP) - { - if (event.pointCount == 1) - { - // Set the drag starting position - initialTapPosition = event.position[0]; - } - gestureType = TYPE_MOTIONLESS; - } - else if (event.action == MOVE) - { - // Adapt the ending position of the inputs - firstEndPinchPosition = event.position[0]; - secondEndPinchPosition = event.position[1]; - - // If there is no more than two inputs - if (event.pointCount == 2) - { - // Calculate distances - float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition); - float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition); - - // Calculate Vectors - Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y }; - Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y }; - - // Detect the pinch gesture - if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance; - else pinchDelta = 0; - - // Pinch gesture resolution - if (pinchDelta != 0) - { - if (pinchDelta > 0) currentGesture = GESTURE_PINCH_IN; - else currentGesture = GESTURE_PINCH_OUT; - } - } - else - { - // Set the drag starting position - initialTapPosition = event.position[0]; - - gestureType = TYPE_MOTIONLESS; - } - - // Readapt the initial position of the inputs - firstInitialPinchPosition = firstEndPinchPosition; - secondInitialPinchPosition = secondEndPinchPosition; - } - } break; - } - //-------------------------------------------------------------------- -} - -static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) +// Returns angle from two-points vector with X-axis +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) { float angle; - - // Calculate arcsinus of the movement - angle = asin((finalPosition.y - initialPosition.y)/magnitude); - angle *= RAD2DEG; - - // Calculate angle depending on the sector - if ((finalPosition.x - initialPosition.x) >= 0) - { - // Sector 4 - if ((finalPosition.y - initialPosition.y) >= 0) - { - angle *= -1; - angle += 360; - } - // Sector 1 - else angle *= -1; - } - else - { - // Sector 3 - if ((finalPosition.y - initialPosition.y) >= 0) angle += 180; - // Sector 2 - else - { - angle *= -1; - angle = 180 - angle; - } - } - - return angle; -} -static void InitPinchGesture(Vector2 posA, Vector2 posB) -{ - initialDragPosition = (Vector2){ 0, 0 }; - endDragPosition = (Vector2){ 0, 0 }; - lastDragPosition = (Vector2){ 0, 0 }; - - // Initialize positions - firstInitialPinchPosition = posA; - secondInitialPinchPosition = posB; - - firstEndPinchPosition = firstInitialPinchPosition; - secondEndPinchPosition = secondInitialPinchPosition; + angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x); + angle *= RAD2DEG; - // Resets - magnitude = 0; - angle = 0; - intensity = 0; + if (angle < 0) angle += 360.0f; - gestureType = TYPE_DUAL_INPUT; + return angle; } -static float VectorDistance(Vector2 v1, Vector2 v2) +// Calculate distance between two Vector2 +static float Vector2Distance(Vector2 v1, Vector2 v2) { float result; @@ -520,144 +396,28 @@ static float VectorDistance(Vector2 v1, Vector2 v2) return result; } -static float VectorDotProduct(Vector2 v1, Vector2 v2) -{ - float result; - - float v1Module = sqrt(v1.x*v1.x + v1.y*v1.y); - float v2Module = sqrt(v2.x*v2.x + v2.y*v2.y); - - Vector2 v1Normalized = { v1.x / v1Module, v1.y / v1Module }; - Vector2 v2Normalized = { v2.x / v2Module, v2.y / v2Module }; - - result = v1Normalized.x*v2Normalized.x + v1Normalized.y*v2Normalized.y; - - return result; -} - -static double GetCurrentTime() +// Time measure returned are milliseconds +static double GetCurrentTime(void) { double time = 0; + #if defined(_WIN32) -/* - // NOTE: Requires Windows.h - FILETIME tm; - GetSystemTimePreciseAsFileTime(&tm); - ULONGLONG nowTime = ((ULONGLONG)tm.dwHighDateTime << 32) | (ULONGLONG)tm.dwLowDateTime; // Time provided in 100-nanosecond intervals + unsigned long long int clockFrequency, currentTime; - time = ((double)nowTime/10000000.0); // time in seconds -*/ + QueryPerformanceFrequency(&clockFrequency); + QueryPerformanceCounter(¤tTime); + + time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds #endif #if defined(__linux) // NOTE: Only for Linux-based systems struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time provided in nanoseconds + uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds - time = ((double)nowTime/1000000.0); // time in miliseconds + time = ((double)nowTime/1000000.0); // Time in miliseconds #endif return time; } - -#if defined(PLATFORM_ANDROID) -// Android: Get input events -static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) -{ - int type = AInputEvent_getType(event); - - if (type == AINPUT_EVENT_TYPE_MOTION) - { - touchPosition.x = AMotionEvent_getX(event, 0); - touchPosition.y = AMotionEvent_getY(event, 0); - } - else if (type == AINPUT_EVENT_TYPE_KEY) - { - //int32_t key = AKeyEvent_getKeyCode(event); - //int32_t AKeyEvent_getMetaState(event); - - //int32_t code = AKeyEvent_getKeyCode((const AInputEvent *)event); - - // If we are in active mode, we eat the back button and move into pause mode. - // If we are already in pause mode, we allow the back button to be handled by the OS, which means we'll be shut down. - /* - if ((code == AKEYCODE_BACK) && mActiveMode) - { - setActiveMode(false); - return 1; - } - */ - } - - int32_t action = AMotionEvent_getAction(event); - unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; - - GestureEvent gestureEvent; - - // Action - if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.action = DOWN; - else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.action = UP; - else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.action = MOVE; - - // Points - gestureEvent.pointCount = AMotionEvent_getPointerCount(event); - - // Position - gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; - gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; - - ProcessMotionEvent(gestureEvent); - - return 0; // return 1; -} -#endif - -#if defined(PLATFORM_WEB) -// Web: Get input events -static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) -{ - /* - for (int i = 0; i < touchEvent->numTouches; i++) - { - long x, y, id; - - if (!touchEvent->touches[i].isChanged) continue; - - id = touchEvent->touches[i].identifier; - x = touchEvent->touches[i].canvasX; - y = touchEvent->touches[i].canvasY; - } - - printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, - event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : ""); - - for(int i = 0; i < event->numTouches; ++i) - { - const EmscriptenTouchPoint *t = &event->touches[i]; - - printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", - t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); - } - */ - GestureEvent gestureEvent; - - // Action - if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.action = DOWN; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.action = UP; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.action = MOVE; - - // Points - gestureEvent.pointCount = touchEvent->numTouches; - - // Position - gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].canvasX, touchEvent->touches[0].canvasY }; - gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].canvasX, touchEvent->touches[1].canvasY }; - - touchPosition = gestureEvent.position[0]; - - ProcessMotionEvent(gestureEvent); - - return 1; -} -#endif |
