aboutsummaryrefslogtreecommitdiff
path: root/src/gestures.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gestures.c')
-rw-r--r--src/gestures.c778
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(&currentTime);
+
+ 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