From 3bd7109d8bd1c408891f7d1cfa4925983547e0cd Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 6 Oct 2015 17:21:04 +0200 Subject: Reviewed GetCurrentTime() -IN PROGRESS- Time measure on Windows platform done with: QueryPerformanceCounter() Testing required! --- src/gestures.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 27e3830a..61660571 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -35,7 +35,10 @@ #include // Defines int32_t, int64_t #if defined(_WIN32) - //#include + //#define WIN32_LEAN_AND_MEAN + //#include // ISSUE: Rectangle redeclared, CloseWindow/ShowCursor conflicting types +int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); +int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); #elif defined(__linux) #include // Used for clock functions #endif @@ -546,6 +549,29 @@ static double GetCurrentTime() time = ((double)nowTime/10000000.0); // time in seconds */ +/* + double pcFreq = 0.0; + __int64 counterStart = 0; // In C99 defined a standard 64-bit integer type named int64_t and unsigned version uint64_t in stdint.h. + + //int64_t or uint64_t is type defined as long long or unsigned long long in C99's stdint.h. + + //LARGE_INTEGER li; // Represents a 64-bit signed integer value + //li.QuadPart // A signed 64-bit integer + + unsigned long long int li; // __int64, same as long long + if(!QueryPerformanceFrequency(&li)) return 0; + + pcFreq = (double)(li)/1000.0; + + QueryPerformanceCounter(&li); + counterStart = li; + + unsigned long long int tm; + QueryPerformanceCounter(&tm); + time = (double)(tm - counterStart)/pcFreq; +*/ + unsigned long long int tm, tf; + time = (double)(QueryPerformanceCounter(&tm)/QueryPerformanceFrequency(&tf)); // time in seconds #endif #if defined(__linux) -- cgit v1.2.3 From 580c0a72966b0dbc6eae26e8b01657e732ec266a Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 30 Oct 2015 11:30:32 +0100 Subject: Moved gestures touch functionality back to core Required gestures module when compiling for Android and Web --- src/core.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/gestures.c | 63 +++++++++------------------------------- src/raylib.h | 7 +++-- 3 files changed, 107 insertions(+), 55 deletions(-) (limited to 'src/gestures.c') diff --git a/src/core.c b/src/core.c index 47bce873..b2d94506 100644 --- a/src/core.c +++ b/src/core.c @@ -95,6 +95,11 @@ #define DEFAULT_GAMEPAD_DEV "/dev/input/js0" #endif +#if defined(PLATFORM_WEB) + #include + #include +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -158,6 +163,10 @@ static int renderOffsetY = 0; // Offset Y from render area (must b static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) +static Vector2 touchPosition; // Touch position on screen +#endif + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... @@ -247,6 +256,10 @@ static void TakeScreenshot(void); static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands #endif +#if defined(PLATFORM_WEB) +static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData); +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition - Window and OpenGL Context Functions //---------------------------------------------------------------------------------- @@ -279,6 +292,12 @@ void InitWindow(int width, int height, const char *title) InitGamepad(); // Gamepad init #endif +#if defined(PLATFORM_WEB) + InitGesturesSystem(); + + emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); +#endif + mousePosition.x = screenWidth/2; mousePosition.y = screenHeight/2; @@ -335,6 +354,8 @@ void InitWindow(int width, int height, struct android_app *state) //InitGesturesSystem(app); // NOTE: Must be called by user InitAssetManager(app->activity->assetManager); + + InitGesturesSystem(app); TraceLog(INFO, "Android app initialized successfully"); @@ -499,7 +520,7 @@ void EndDrawing(void) SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events - + currentTime = GetTime(); drawTime = currentTime - previousTime; previousTime = currentTime; @@ -814,7 +835,7 @@ Vector2 GetMousePosition(void) void SetMousePosition(Vector2 position) { mousePosition = position; -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // NOTE: emscripten not implemented glfwSetCursorPos(window, position.x, position.y); #endif @@ -969,6 +990,41 @@ bool IsGamepadButtonUp(int gamepad, int button) } #endif +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) +// Returns touch position X +int GetTouchX(void) +{ + return (int)touchPosition.x; +} + +// Returns touch position Y +int GetTouchY(void) +{ + return (int)touchPosition.y; +} + +// 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)) + { + // 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; + } + else + { + position.x = position.x*((float)renderWidth/(float)displayWidth) - renderOffsetX/2; + position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2; + } + + return position; +} +#endif + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -1547,6 +1603,13 @@ static bool GetMouseButtonStatus(int button) // Poll (store) all input events static void PollInputEvents(void) { +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) + // Touch events reading (requires gestures module) + touchPosition = GetRawTouchPosition(); + + UpdateGestures(); +#endif + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling double mouseX; @@ -1940,6 +2003,31 @@ static void SetupFramebufferSize(int displayWidth, int displayHeight) } } +#if defined(PLATFORM_WEB) +static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData) +{ + //isFullscreen: int e->isFullscreen + //fullscreenEnabled: int e->fullscreenEnabled + //fs element nodeName: (char *) e->nodeName + //fs element id: (char *) e->id + //Current element size: (int) e->elementWidth, (int) e->elementHeight + //Screen size:(int) e->screenWidth, (int) e->screenHeight + + if (e->isFullscreen) + { + TraceLog(INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); + } + else + { + TraceLog(INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); + } + + // TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input + + return 0; +} +#endif + // Plays raylib logo appearing animation static void LogoAnimation(void) { diff --git a/src/gestures.c b/src/gestures.c index 61660571..f5e8c62f 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -122,7 +122,7 @@ static int currentGesture = GESTURE_NONE; static unsigned int enabledGestures = 0; // TODO: Currently not in use... -static Vector2 touchPosition; +static Vector2 rawTouchPosition; //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -147,55 +147,15 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Module Functions Definition //---------------------------------------------------------------------------------- -// Returns touch position X -int GetTouchX(void) +// Get touch position (could require further processing depending on display size) +Vector2 GetRawTouchPosition(void) { - return (int)touchPosition.x; -} - -// Returns touch position Y -int GetTouchY(void) -{ - return (int)touchPosition.y; -} - -// 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)) - { - // 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; - } - else - { - position.x = position.x*((float)renderWidth / (float)displayWidth) - renderOffsetX/2; - position.y = position.y*((float)renderHeight / (float)displayHeight) - renderOffsetY/2; - } -*/ - return position; + return rawTouchPosition; } // 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; else return false; } @@ -382,7 +342,7 @@ static void ProcessMotionEvent(GestureEvent event) { lastDragPosition = endDragPosition; - endDragPosition = touchPosition; + endDragPosition = rawTouchPosition; //endDragPosition.x = AMotionEvent_getX(event, 0); //endDragPosition.y = AMotionEvent_getY(event, 0); @@ -594,8 +554,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) if (type == AINPUT_EVENT_TYPE_MOTION) { - touchPosition.x = AMotionEvent_getX(event, 0); - touchPosition.y = AMotionEvent_getY(event, 0); + rawTouchPosition.x = AMotionEvent_getX(event, 0); + rawTouchPosition.y = AMotionEvent_getY(event, 0); } else if (type == AINPUT_EVENT_TYPE_KEY) { @@ -676,10 +636,13 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent 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 }; + //gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].canvasX, touchEvent->touches[0].canvasY }; + //gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].canvasX, touchEvent->touches[1].canvasY }; + gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; + gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; + printf("EVENT DETECTED!\n"); - touchPosition = gestureEvent.position[0]; + rawTouchPosition = gestureEvent.position[0]; ProcessMotionEvent(gestureEvent); diff --git a/src/raylib.h b/src/raylib.h index 9067c77d..d3729a91 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -458,13 +458,14 @@ bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad b #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -//------------------------------------------------------------------------------------ -// Gestures and Touch Handling Functions (Module: gestures) -//------------------------------------------------------------------------------------ int GetTouchX(void); // Returns touch position X (relative to screen size) int GetTouchY(void); // Returns touch position Y (relative to screen size) Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) +//------------------------------------------------------------------------------------ +// Gestures and Touch Handling Functions (Module: gestures) +//------------------------------------------------------------------------------------ +Vector2 GetRawTouchPosition(void); // Gewt touch position (raw) #if defined(PLATFORM_WEB) void InitGesturesSystem(void); // Init gestures system (web) #elif defined(PLATFORM_ANDROID) -- cgit v1.2.3 From b894a78385249c68344cd74d9bc456e962467381 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 30 Dec 2015 13:34:45 +0100 Subject: Reviewed function GetCurrentTime() on WIN32 --- src/gestures.c | 41 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index f5e8c62f..77ea4262 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -35,10 +35,9 @@ #include // Defines int32_t, int64_t #if defined(_WIN32) - //#define WIN32_LEAN_AND_MEAN - //#include // ISSUE: Rectangle redeclared, CloseWindow/ShowCursor conflicting types -int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); -int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); + // 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 // Used for clock functions #endif @@ -500,38 +499,14 @@ static float VectorDotProduct(Vector2 v1, Vector2 v2) static double GetCurrentTime() { 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 - - time = ((double)nowTime/10000000.0); // time in seconds -*/ -/* - double pcFreq = 0.0; - __int64 counterStart = 0; // In C99 defined a standard 64-bit integer type named int64_t and unsigned version uint64_t in stdint.h. - //int64_t or uint64_t is type defined as long long or unsigned long long in C99's stdint.h. +#if defined(_WIN32) + unsigned long long int clockFrequency, currentTime; - //LARGE_INTEGER li; // Represents a 64-bit signed integer value - //li.QuadPart // A signed 64-bit integer + QueryPerformanceFrequency(&clockFrequency); + QueryPerformanceCounter(¤tTime); - unsigned long long int li; // __int64, same as long long - if(!QueryPerformanceFrequency(&li)) return 0; - - pcFreq = (double)(li)/1000.0; - - QueryPerformanceCounter(&li); - counterStart = li; - - unsigned long long int tm; - QueryPerformanceCounter(&tm); - time = (double)(tm - counterStart)/pcFreq; -*/ - unsigned long long int tm, tf; - time = (double)(QueryPerformanceCounter(&tm)/QueryPerformanceFrequency(&tf)); // time in seconds + time = (double)currentTime/clockFrequency*1000.0f; // time in miliseconds #endif #if defined(__linux) -- cgit v1.2.3 From 802f29fb0e5ac23ed1b13f4f00ecd37555950c55 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 2 Jan 2016 10:42:43 +0100 Subject: Eat Android Back key to avoid crash --- src/gestures.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 77ea4262..adde85b9 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -534,20 +534,16 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) } 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); - + int32_t keycode = AKeyEvent_getKeyCode(event); + int32_t AKeyEvent_getMetaState(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) + if ((keycode == AKEYCODE_BACK)) // && mActiveMode) { - setActiveMode(false); - return 1; + //setActiveMode(false); + //return 1; } - */ } int32_t action = AMotionEvent_getAction(event); -- cgit v1.2.3 From d32feaa6685584e9856aa94f4d5bf80b7f5b861c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 3 Jan 2016 13:01:21 +0100 Subject: Reviewed Android inputs and gestures system Corrected Android processing for some inputs (BACK button, VOLUME buttons) Redesigned Gestures system (some work still required) SetEnabledGestures() - Only support desired gestures (requires some review) --- src/core.c | 224 +++++++++++++++++++++++++++++++------- src/gestures.c | 332 +++++++++++++++------------------------------------------ src/gestures.h | 21 ++-- src/raylib.h | 20 ++-- 4 files changed, 294 insertions(+), 303 deletions(-) (limited to 'src/gestures.c') diff --git a/src/core.c b/src/core.c index acfc63d5..14510a1b 100644 --- a/src/core.c +++ b/src/core.c @@ -66,7 +66,7 @@ #include // Java native interface #include // Android sensors functions #include // Defines AWINDOW_FLAG_FULLSCREEN and others - //#include // Defines basic app state struct and manages activity + #include // Defines basic app state struct and manages activity #include // Khronos EGL library - Native platform display device control functions #include // Khronos OpenGL ES 2.0 library @@ -103,7 +103,6 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_TOUCH_POINTS 256 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -121,7 +120,8 @@ static struct android_app *app; // Android activity static struct android_poll_source *source; // Android events polling source static int ident, events; static bool windowReady = false; // Used to detect display initialization - +static bool appEnabled = true; // Used to detec if app is active +static bool contextRebindRequired = false; // Used to know context rebind required #elif defined(PLATFORM_RPI) static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device) @@ -149,6 +149,7 @@ static int gamepadStream = -1; // Gamepad device file descripto static EGLDisplay display; // Native display device (physical screen connection) static EGLSurface surface; // Surface to draw on, framebuffers (connected to context) static EGLContext context; // Graphic context, mode in which drawing can be done +static EGLConfig config; // Graphic config static uint64_t baseTime; // Base time measure for hi-res timer static bool windowShouldClose = false; // Flag to set window for closing #endif @@ -254,10 +255,12 @@ static void TakeScreenshot(void); #if defined(PLATFORM_ANDROID) static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands +static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs #endif #if defined(PLATFORM_WEB) static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData); +static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); #endif //---------------------------------------------------------------------------------- @@ -293,9 +296,15 @@ void InitWindow(int width, int height, const char *title) #endif #if defined(PLATFORM_WEB) - InitGesturesSystem(); - emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback); + + // 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); #endif mousePosition.x = screenWidth/2; @@ -350,24 +359,23 @@ void InitWindow(int width, int height, struct android_app *state) //state->userData = &engine; app->onAppCmd = AndroidCommandCallback; - - InitAssetManager(app->activity->assetManager); + app->onInputEvent = AndroidInputCallback; - InitGesturesSystem(app); + InitAssetManager(app->activity->assetManager); TraceLog(INFO, "Android app initialized successfully"); + // Wait for window to be initialized (display and context) while (!windowReady) { - // Wait for window to be initialized (display and context) // Process events loop while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0) { // Process this event if (source != NULL) source->process(app, source); - // Check if we are exiting - if (app->destroyRequested != 0) windowShouldClose = true; + // NOTE: Never close window, native activity is controlled by the system! + //if (app->destroyRequested != 0) windowShouldClose = true; } } } @@ -1221,7 +1229,6 @@ static void InitDisplay(int width, int height) }; EGLint numConfigs; - EGLConfig config; // Get an EGL display connection display = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -1455,30 +1462,62 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) if (app->window != NULL) { - // Init device display (monitor, LCD, ...) - InitDisplay(screenWidth, screenHeight); + if (contextRebindRequired) + { + // Reset screen scaling to full display size + EGLint displayFormat; + eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &displayFormat); + ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat); - // Init OpenGL graphics - InitGraphics(); + // Recreate display surface and re-attach OpenGL context + surface = eglCreateWindowSurface(display, config, app->window, NULL); + eglMakeCurrent(display, surface, surface, context); - // Load default font for convenience - // NOTE: External function (defined in module: text) - LoadDefaultFont(); + contextRebindRequired = false; + } + else + { + // Init device display (monitor, LCD, ...) + InitDisplay(screenWidth, screenHeight); + + // Init OpenGL graphics + InitGraphics(); + + // Load default font for convenience + // NOTE: External function (defined in module: text) + LoadDefaultFont(); + + // TODO: GPU assets reload in case of lost focus (lost context) + // NOTE: This problem has been solved just unbinding and rebinding context from display + /* + if (assetsReloadRequired) + { + for (int i = 0; i < assetsCount; i++) + { + // TODO: Unload old asset if required + + // Load texture again to pointed texture + (*textureAsset + i) = LoadTexture(assetPath[i]); + } + } + */ - // Init hi-res timer - InitTimer(); + // Init hi-res timer + InitTimer(); - // raylib logo appearing animation (if enabled) - if (showLogo) - { - SetTargetFPS(60); - LogoAnimation(); + // raylib logo appearing animation (if enabled) + if (showLogo) + { + SetTargetFPS(60); // Not required on Android + LogoAnimation(); + } } } } break; case APP_CMD_GAINED_FOCUS: { TraceLog(INFO, "APP_CMD_GAINED_FOCUS"); + appEnabled = true; //ResumeMusicStream(); } break; case APP_CMD_PAUSE: @@ -1489,11 +1528,18 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) { //DrawFrame(); TraceLog(INFO, "APP_CMD_LOST_FOCUS"); + appEnabled = false; //PauseMusicStream(); } break; case APP_CMD_TERM_WINDOW: { - // TODO: Do display destruction here? -> Yes but only display, don't free buffers! + // Dettach OpenGL context and destroy display surface + // NOTE 1: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...) + // NOTE 2: In some cases (too many context loaded), OS could unload context automatically... :( + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, surface); + + contextRebindRequired = true; TraceLog(INFO, "APP_CMD_TERM_WINDOW"); } break; @@ -1524,6 +1570,61 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) default: break; } } + +// Android: Get input events +static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) +{ + //http://developer.android.com/ndk/reference/index.html + + 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 keycode = AKeyEvent_getKeyCode(event); + //int32_t AKeyEvent_getMetaState(event); + + //if (keycode == AKEYCODE_HOME) { } + //if (keycode == AKEYCODE_POWER) { } + if (keycode == AKEYCODE_BACK) + { + // Eat BACK_BUTTON, just do nothing... and don't let to be handled by OS! + return 1; + } + else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN)) + { + // Set default OS behaviour + return 0; + } + } + + int32_t action = AMotionEvent_getAction(event); + unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; + + GestureEvent gestureEvent; + + // Register touch actions + if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN; + else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP; + else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = AMotionEvent_getPointerCount(event); + + // Register touch points position + // NOTE: Only two points registered + gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; + gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); + + return 0; // return 1; +} #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) @@ -1613,9 +1714,8 @@ static bool GetMouseButtonStatus(int button) static void PollInputEvents(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - // Touch events reading (requires gestures module) - touchPosition = GetRawTouchPosition(); - + + // TODO: Remove this requirement... UpdateGestures(); #endif @@ -1645,23 +1745,18 @@ static void PollInputEvents(void) glfwPollEvents(); // Register keyboard/mouse events... and window events! #elif defined(PLATFORM_ANDROID) - // TODO: Check virtual keyboard (?) - // Poll Events (registered events) - // TODO: Enable/disable activityMinimized to block activity if minimized - //while ((ident = ALooper_pollAll(activityMinimized ? 0 : -1, NULL, &events,(void**)&source)) >= 0) - while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0) + // NOTE: Activity is paused if not enabled (appEnabled) + while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) { // Process this event if (source != NULL) source->process(app, source); - // Check if we are exiting + // NOTE: Never close window, native activity is controlled by the system! if (app->destroyRequested != 0) { - // NOTE: Never close window, native activity is controlled by the system! //TraceLog(INFO, "Closing Window..."); //windowShouldClose = true; - //ANativeActivity_finish(app->activity); } } @@ -2035,6 +2130,59 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte return 0; } + +// 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; + + // Register touch actions + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_DOWN; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_UP; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = touchEvent->numTouches; + + // Register touch points position + // NOTE: Only two points registered + // TODO: Touch data should be scaled accordingly! + //gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].canvasX, touchEvent->touches[0].canvasY }; + //gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].canvasX, touchEvent->touches[1].canvasY }; + gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; + gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; + + touchPosition = gestureEvent.position[0]; + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); // Process obtained gestures data + + return 1; +} #endif // Plays raylib logo appearing animation diff --git a/src/gestures.c b/src/gestures.c index adde85b9..88cdb528 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -42,23 +42,12 @@ #include // Used for clock functions #endif -#if defined(PLATFORM_ANDROID) - #include // Java native interface - #include // Android sensors functions - #include // Defines AWINDOW_FLAG_FULLSCREEN and others -#endif - -#if defined(PLATFORM_WEB) - #include - #include -#endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- #define FORCE_TO_SWIPE 20 #define TAP_TIMEOUT 300 -#define MAX_TOUCH_POINTS 4 +//#define MAX_TOUCH_POINTS 4 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -69,20 +58,6 @@ typedef enum { 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 //---------------------------------------------------------------------------------- @@ -119,133 +94,24 @@ static float pinchDelta = 0; // Pinch delta displacement static int previousGesture = GESTURE_NONE; static int currentGesture = GESTURE_NONE; -static unsigned int enabledGestures = 0; // TODO: Currently not in use... - -static Vector2 rawTouchPosition; +// Enabled gestures flags, all gestures enabled by default +static unsigned int enabledGestures = 0b0000011111111111; //---------------------------------------------------------------------------------- // 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 - //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- -// Get touch position (could require further processing depending on display size) -Vector2 GetRawTouchPosition(void) -{ - return rawTouchPosition; -} - -// Check if a gesture have been detected -bool IsGestureDetected(void) -{ - if (currentGesture != GESTURE_NONE) return true; - else return false; -} - -// Check gesture type -int GetGestureType(void) -{ - return currentGesture; -} - -void SetGesturesEnabled(unsigned int gestureFlags) -{ - enabledGestures = gestureFlags; -} - -// Get drag intensity (pixels per frame) -float GetGestureDragIntensity(void) -{ - return intensity; -} - -// Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGestureDragAngle(void) -{ - return angle; -} - -// Get drag vector (between initial and final position) -Vector2 GetGestureDragVector(void) -{ - return dragVector; -} - -// Hold time measured in frames -int GetGestureHoldDuration(void) -{ - return 0; -} - -// Get magnitude between two pinch points -float GetGesturePinchDelta(void) -{ - return pinchDelta; -} - -// 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; - - // 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; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -static void ProcessMotionEvent(GestureEvent event) +// Process gesture event and translate it into gestures +void ProcessGestureEvent(GestureEvent event) { // Resets dragVector = (Vector2){ 0, 0 }; @@ -257,7 +123,7 @@ static void ProcessMotionEvent(GestureEvent event) { case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events { - if (event.action == DOWN) + if (event.touchAction == TOUCH_DOWN) { if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else @@ -279,7 +145,7 @@ static void ProcessMotionEvent(GestureEvent event) else currentGesture = GESTURE_TAP; } } - else if (event.action == UP) + else if (event.touchAction == TOUCH_UP) { currentGesture = GESTURE_NONE; @@ -297,7 +163,7 @@ static void ProcessMotionEvent(GestureEvent event) eventTime = GetCurrentTime(); } // Begin dragging - else if (event.action == MOVE) + else if (event.touchAction == TOUCH_MOVE) { if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else @@ -316,7 +182,7 @@ static void ProcessMotionEvent(GestureEvent event) case TYPE_DRAG: // Detect DRAG and SWIPE events { // end of the drag - if (event.action == UP) + if (event.touchAction == TOUCH_UP) { // Return Swipe if we have enough sensitivity if (intensity > FORCE_TO_SWIPE) @@ -334,14 +200,13 @@ static void ProcessMotionEvent(GestureEvent event) gestureType = TYPE_MOTIONLESS; } // Update while we are dragging - else if (event.action == MOVE) + else if (event.touchAction == TOUCH_MOVE) { if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); else { lastDragPosition = endDragPosition; - - endDragPosition = rawTouchPosition; + endDragPosition = event.position[0]; //endDragPosition.x = AMotionEvent_getX(event, 0); //endDragPosition.y = AMotionEvent_getY(event, 0); @@ -359,7 +224,7 @@ static void ProcessMotionEvent(GestureEvent event) } break; case TYPE_DUAL_INPUT: { - if (event.action == UP) + if (event.touchAction == TOUCH_UP) { if (event.pointCount == 1) { @@ -368,7 +233,7 @@ static void ProcessMotionEvent(GestureEvent event) } gestureType = TYPE_MOTIONLESS; } - else if (event.action == MOVE) + else if (event.touchAction == TOUCH_MOVE) { // Adapt the ending position of the inputs firstEndPinchPosition = event.position[0]; @@ -410,9 +275,78 @@ static void ProcessMotionEvent(GestureEvent event) } } break; } - //-------------------------------------------------------------------- } +// Check if a gesture have been detected +bool IsGestureDetected(void) +{ + if (currentGesture != GESTURE_NONE) return true; + else return false; +} + +// Check gesture type +int GetGestureType(void) +{ + // Get current gesture only if enabled + return (enabledGestures & currentGesture); +} + +void SetGesturesEnabled(unsigned int gestureFlags) +{ + enabledGestures = enabledGestures | gestureFlags; +} + +// Get drag intensity (pixels per frame) +float GetGestureDragIntensity(void) +{ + return intensity; +} + +// Get drag angle +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGestureDragAngle(void) +{ + return angle; +} + +// Get drag vector (between initial and final position) +Vector2 GetGestureDragVector(void) +{ + return dragVector; +} + +// Hold time measured in frames +int GetGestureHoldDuration(void) +{ + return 0; +} + +// Get magnitude between two pinch points +float GetGesturePinchDelta(void) +{ + return pinchDelta; +} + +// Get angle beween two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGesturePinchAngle(void) +{ + return 0; +} + +// 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; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) { float angle; @@ -520,103 +454,3 @@ static double GetCurrentTime() 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) - { - rawTouchPosition.x = AMotionEvent_getX(event, 0); - rawTouchPosition.y = AMotionEvent_getY(event, 0); - } - else if (type == AINPUT_EVENT_TYPE_KEY) - { - int32_t keycode = AKeyEvent_getKeyCode(event); - int32_t AKeyEvent_getMetaState(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 ((keycode == 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 }; - gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; - gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; - printf("EVENT DETECTED!\n"); - - rawTouchPosition = gestureEvent.position[0]; - - ProcessMotionEvent(gestureEvent); - - return 1; -} -#endif \ No newline at end of file diff --git a/src/gestures.h b/src/gestures.h index 896f3028..b5cf2767 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -67,6 +67,17 @@ typedef enum { GESTURE_PINCH_OUT = 1024 } Gestures; +typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; + +// Gesture events +// NOTE: MAX_TOUCH_POINTS fixed to 4 +typedef struct { + int touchAction; + int pointCount; + int pointerId[4]; + Vector2 position[4]; +} GestureEvent; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -79,19 +90,11 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -int GetTouchX(void); // Returns touch position X (relative to screen size) -int GetTouchY(void); // Returns touch position Y (relative to screen size) -Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) - -#if defined(PLATFORM_WEB) -void InitGesturesSystem(void); // Init gestures system (web) -#elif defined(PLATFORM_ANDROID) -void InitGesturesSystem(struct android_app *app); // Init gestures system (android) -#endif void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures float GetGestureDragIntensity(void); // Get gesture drag intensity float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/raylib.h b/src/raylib.h index 1113958d..864a240a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -70,7 +70,7 @@ #endif #if defined(PLATFORM_ANDROID) - #include // Defines android_app struct + typedef struct android_app; // Define android_app struct (android_native_app_glue.h) #endif //---------------------------------------------------------------------------------- @@ -432,6 +432,17 @@ typedef enum { GESTURE_PINCH_OUT = 1024 } Gestures; +typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; + +// Gesture events +// NOTE: MAX_TOUCH_POINTS fixed to 4 +typedef struct { + int touchAction; + int pointCount; + int pointerId[4]; + Vector2 position[4]; +} GestureEvent; + // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; @@ -571,16 +582,11 @@ Vector2 GetTouchPosition(void); // Returns touch positio //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ -Vector2 GetRawTouchPosition(void); // Get touch position (raw) -#if defined(PLATFORM_WEB) -void InitGesturesSystem(void); // Init gestures system (web) -#elif defined(PLATFORM_ANDROID) -void InitGesturesSystem(struct android_app *app); // Init gestures system (android) -#endif void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures float GetGestureDragIntensity(void); // Get gesture drag intensity float GetGestureDragAngle(void); // Get gesture drag angle -- cgit v1.2.3 From 233f7611da96ea6bc0b7c62f6a06dacef707f9d7 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Fri, 22 Jan 2016 17:07:54 +0100 Subject: Fixed hold gesture detection - Fixed gestures hold detection. - Improved hold state detection for little touch position increments (sensitivity). --- src/gestures.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 88cdb528..ea744555 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -217,8 +217,13 @@ void ProcessGestureEvent(GestureEvent event) angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude); intensity = magnitude / (float)draggingTimeCounter; - currentGesture = GESTURE_DRAG; - draggingTimeCounter++; + // Check if drag movement is less than minimum to keep it as hold state or switch to drag state + if(magnitude > FORCE_TO_SWIPE) + { + currentGesture = GESTURE_DRAG; + draggingTimeCounter++; + } + else currentGesture = GESTURE_HOLD; } } } break; @@ -339,8 +344,13 @@ 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; + // When screen is touched, in first frame GESTURE_TAP is called but in next frame touch event callback is not called (if touch position doesn't change), + // so we need to store previous frame gesture type manually in this update function to switch to HOLD if current gesture is + // GESTURE_TAP two frames in a row. Due to current gesture is set to HOLD, current gesture doesn't need to be reset to NONE every frame. + // It will be reset when UP is called. + if(currentGesture == GESTURE_TAP) previousGesture = currentGesture; + + if(previousGesture == GESTURE_TAP && currentGesture == GESTURE_TAP) currentGesture = GESTURE_HOLD; } //---------------------------------------------------------------------------------- -- cgit v1.2.3 From 728e1715cc52fb25081f3ce17cb5b3f72f7eb218 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 2 Feb 2016 16:43:42 +0100 Subject: Redesigned gestures system... ...and improved mouse gestures support Some testing still required... --- src/core.c | 29 +++++- src/gestures.c | 300 +++++++++++++++++++++++++++++---------------------------- src/raylib.h | 23 +++-- 3 files changed, 189 insertions(+), 163 deletions(-) (limited to 'src/gestures.c') diff --git a/src/core.c b/src/core.c index cf6fcf33..1c9e16ae 100644 --- a/src/core.c +++ b/src/core.c @@ -253,6 +253,7 @@ static void InitGamepad(void); // Init raw gamepad inpu static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move static void CharCallback(GLFWwindow *window, unsigned int key); // GLFW3 Char Key Callback, runs on key pressed (get char value) static void ScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area @@ -1415,6 +1416,7 @@ static void InitDisplay(int width, int height) glfwSetCursorEnterCallback(window, CursorEnterCallback); glfwSetKeyCallback(window, KeyCallback); glfwSetMouseButtonCallback(window, MouseButtonCallback); + glfwSetCursorPosCallback(window, MouseCursorPosCallback); // Track mouse position changes glfwSetCharCallback(window, CharCallback); glfwSetScrollCallback(window, ScrollCallback); glfwSetWindowIconifyCallback(window, WindowIconifyCallback); @@ -1677,7 +1679,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // Register touch actions if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; - else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE; + //else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE; else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP; // Register touch points count @@ -1685,7 +1687,28 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // Register touch points position, only one point registered gestureEvent.position[0] = GetMousePosition(); + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Cursor Position Callback, runs on mouse move +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +{ +#define ENABLE_MOUSE_GESTURES +#if defined(ENABLE_MOUSE_GESTURES) + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent; + + gestureEvent.touchAction = TOUCH_MOVE; + + // Register touch points count + gestureEvent.pointCount = 1; + // Register touch points position, only one point registered + gestureEvent.position[0] = (Vector2){ (float)x, (float)y }; + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); #endif @@ -1934,7 +1957,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Register touch points count gestureEvent.pointCount = AMotionEvent_getPointerCount(event); - // Register touch points id DESKTOP + // Register touch points id gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0); gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1); @@ -2496,7 +2519,7 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent // Register touch points count gestureEvent.pointCount = touchEvent->numTouches; - // Register touch points id WEB + // Register touch points id gestureEvent.pointerId[0] = touchEvent->touches[0].identifier; gestureEvent.pointerId[1] = touchEvent->touches[1].identifier; diff --git a/src/gestures.c b/src/gestures.c index ea744555..59f2c5b7 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -46,7 +46,11 @@ // Defines and Macros //---------------------------------------------------------------------------------- #define FORCE_TO_SWIPE 20 -#define TAP_TIMEOUT 300 +#define FORCE_TO_DRAG 20 +#define FORCE_TO_PINCH 5 +#define TAP_TIMEOUT 300 // Time in milliseconds +#define PINCH_TIMEOUT 300 // Time in milliseconds +#define DOUBLETAP_RANGE 30 //#define MAX_TOUCH_POINTS 4 //---------------------------------------------------------------------------------- @@ -61,10 +65,6 @@ typedef enum { //---------------------------------------------------------------------------------- // 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 }; @@ -78,6 +78,21 @@ static Vector2 endDragPosition = { 0, 0 }; static Vector2 lastDragPosition = { 0, 0 }; static Vector2 dragVector = { 0, 0 }; +// Albert&Ian +static Vector2 touchDownPosition = { 0, 0 }; +static Vector2 touchDownPosition2 = { 0, 0 }; +static Vector2 touchUpPosition = { 0, 0 }; +static Vector2 moveDownPosition = { 0, 0 }; +static Vector2 moveDownPosition2 = { 0, 0 }; + +static int numTap = 0; +static int numHold = 0; +static int numPinch = 0; +static int pointCount = 0; +static int touchId = -1; + +static double eventTime = 0; + 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) @@ -95,7 +110,7 @@ static int previousGesture = GESTURE_NONE; static int currentGesture = GESTURE_NONE; // Enabled gestures flags, all gestures enabled by default -static unsigned int enabledGestures = 0b0000011111111111; +static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -105,6 +120,7 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, flo static float VectorDistance(Vector2 v1, Vector2 v2); static float VectorDotProduct(Vector2 v1, Vector2 v2); static double GetCurrentTime(); +static float Vector2Distance(); //---------------------------------------------------------------------------------- // Module Functions Definition @@ -119,173 +135,160 @@ void ProcessGestureEvent(GestureEvent event) previousGesture = currentGesture; - switch (gestureType) - { - case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events + pointCount = event.pointCount; + + // Albert&Ian + if (pointCount < 2) + { + touchId = event.pointerId[0]; + if (event.touchAction == TOUCH_DOWN) { - if (event.touchAction == TOUCH_DOWN) + numTap++; // Tap counter + + // Detect GESTURE_DOUBLE_TAP + if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (GetMagnitude(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) { - 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; - } + currentGesture = GESTURE_DOUBLETAP; + numTap = 0; } - else if (event.touchAction == TOUCH_UP) + else // Detect GESTURE_TAP { - 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(); + numTap = 1; + currentGesture = GESTURE_TAP; } - // Begin dragging - else if (event.touchAction == TOUCH_MOVE) + + touchDownPosition = event.position[0]; + + touchUpPosition = touchDownPosition; + eventTime = GetCurrentTime(); + } + else if (event.touchAction == TOUCH_UP) + { + if (currentGesture = GESTURE_DRAG) { - 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; - } + touchUpPosition = event.position[0]; } - } break; - case TYPE_DRAG: // Detect DRAG and SWIPE events - { - // end of the drag - if (event.touchAction == TOUCH_UP) + + // Calculate for swipe + magnitude = GetMagnitude(touchDownPosition, touchUpPosition); + intensity = magnitude / (float)draggingTimeCounter; + + // Detect GESTURE_SWIPE + if ((intensity > FORCE_TO_SWIPE) && (touchId == 0)) + { + angle = CalculateAngle(touchDownPosition, touchUpPosition, magnitude); + if ((angle < 30) || (angle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right + else if ((angle > 30) && (angle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up + else if ((angle > 120) && (angle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left + else if ((angle > 210) && (angle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down + else currentGesture = GESTURE_NONE; + } + else { - // 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; + currentGesture = GESTURE_NONE; } - // Update while we are dragging - else if (event.touchAction == TOUCH_MOVE) + + draggingTimeCounter = 0; + } + else if (event.touchAction == TOUCH_MOVE) + { + if (GetMagnitude(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); + moveDownPosition = event.position[0]; + + if (currentGesture == GESTURE_HOLD) { - if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); - else - { - lastDragPosition = endDragPosition; - endDragPosition = event.position[0]; - - //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; - - // Check if drag movement is less than minimum to keep it as hold state or switch to drag state - if(magnitude > FORCE_TO_SWIPE) - { - currentGesture = GESTURE_DRAG; - draggingTimeCounter++; - } - else currentGesture = GESTURE_HOLD; - } + if (numHold == 1) touchDownPosition = event.position[0]; + + numHold = 2; + + magnitude = GetMagnitude(touchDownPosition, moveDownPosition); + + // Detect GESTURE_DRAG + if (magnitude >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; } - } break; - case TYPE_DUAL_INPUT: + + draggingTimeCounter++; + } + } + else + { + // two fingers + + if (event.touchAction == TOUCH_DOWN) + { + touchDownPosition = event.position[0]; + touchDownPosition2 = event.position[1]; + + currentGesture = GESTURE_HOLD; + } + else if (event.touchAction == TOUCH_MOVE) { - if (event.touchAction == TOUCH_UP) + magnitude = GetMagnitude(moveDownPosition, moveDownPosition2); + + touchDownPosition = moveDownPosition; + touchDownPosition2 = moveDownPosition2; + + moveDownPosition = event.position[0]; + moveDownPosition2 = event.position[1]; + + if ( (GetMagnitude(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (GetMagnitude(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) { - if (event.pointCount == 1) - { - // Set the drag starting position - initialTapPosition = event.position[0]; - } - gestureType = TYPE_MOTIONLESS; + if ((GetMagnitude(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN; + else currentGesture = GESTURE_PINCH_OUT; } - else if (event.touchAction == TOUCH_MOVE) + else { - // 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; + currentGesture = GESTURE_HOLD; } - } break; + } + else if (event.touchAction == TOUCH_UP) + { + currentGesture = GESTURE_NONE; + } + } +} + +// Update gestures detected (must be called every frame) +void UpdateGestures(void) +{ + // NOTE: Gestures are processed through system callbacks on touch events + + // Detect GESTURE_HOLD + if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && pointCount < 2) currentGesture = GESTURE_HOLD; + if ((GetCurrentTime() - eventTime) > TAP_TIMEOUT && (currentGesture == GESTURE_DRAG) && pointCount < 2) + { + currentGesture = GESTURE_HOLD; + numHold = 1; } + + // Detect GESTURE_NONE + if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) + { + currentGesture = GESTURE_NONE; + } +} + +// Calculate distance between two vectors +float Vector2Distance(Vector2 v1, Vector3 v2) +{ + float result; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + + result = sqrt(dx*dx + dy*dy); + + return result; } // Check if a gesture have been detected bool IsGestureDetected(void) { - if (currentGesture != GESTURE_NONE) return true; + if ((enabledGestures & currentGesture) != GESTURE_NONE) return true; else return false; } @@ -298,7 +301,7 @@ int GetGestureType(void) void SetGesturesEnabled(unsigned int gestureFlags) { - enabledGestures = enabledGestures | gestureFlags; + enabledGestures = gestureFlags; } // Get drag intensity (pixels per frame) @@ -440,6 +443,7 @@ static float VectorDotProduct(Vector2 v1, Vector2 v2) return result; } +// Time measure returned are milliseconds static double GetCurrentTime() { double time = 0; diff --git a/src/raylib.h b/src/raylib.h index 6c1a8999..a22c3f83 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -435,17 +435,17 @@ typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; // Gestures type // NOTE: It could be used as flags to enable only some gestures typedef enum { - GESTURE_NONE = 1, - GESTURE_TAP = 2, - GESTURE_DOUBLETAP = 4, - GESTURE_HOLD = 8, - GESTURE_DRAG = 16, - GESTURE_SWIPE_RIGHT = 32, - GESTURE_SWIPE_LEFT = 64, - GESTURE_SWIPE_UP = 128, - GESTURE_SWIPE_DOWN = 256, - GESTURE_PINCH_IN = 512, - GESTURE_PINCH_OUT = 1024 + GESTURE_NONE = 0, + GESTURE_TAP = 1, + GESTURE_DOUBLETAP = 2, + GESTURE_HOLD = 4, + GESTURE_DRAG = 8, + GESTURE_SWIPE_RIGHT = 16, + GESTURE_SWIPE_LEFT = 32, + GESTURE_SWIPE_UP = 64, + GESTURE_SWIPE_DOWN = 128, + GESTURE_PINCH_IN = 256, + GESTURE_PINCH_OUT = 512 } Gestures; typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; @@ -781,7 +781,6 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap // NOTE: Return the normal vector of the impacted surface - //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 -- cgit v1.2.3 From 65ecde1e75bd9e2738c8640e966328abeaa5658e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 2 Feb 2016 17:59:13 +0100 Subject: Cleaned code a little bit --- src/gestures.c | 118 +++++++++------------------------------------------------ 1 file changed, 18 insertions(+), 100 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 59f2c5b7..8c690066 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -65,20 +65,11 @@ typedef enum { //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -// Tap gesture variables -static Vector2 initialTapPosition = { 0, 0 }; - -// Double Tap gesture variables -static bool doubleTapping = false; -static bool untap = false; // Check if recently done a tap // Drag gesture variables -static Vector2 initialDragPosition = { 0, 0 }; -static Vector2 endDragPosition = { 0, 0 }; -static Vector2 lastDragPosition = { 0, 0 }; static Vector2 dragVector = { 0, 0 }; -// Albert&Ian +// Touch gesture variables static Vector2 touchDownPosition = { 0, 0 }; static Vector2 touchDownPosition2 = { 0, 0 }; static Vector2 touchUpPosition = { 0, 0 }; @@ -87,7 +78,6 @@ static Vector2 moveDownPosition2 = { 0, 0 }; static int numTap = 0; static int numHold = 0; -static int numPinch = 0; static int pointCount = 0; static int touchId = -1; @@ -99,10 +89,6 @@ static float intensity = 0; // How fast we did the drag (pixels per static int draggingTimeCounter = 0; // Time that have passed while dragging // 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 // Detected gestures @@ -115,12 +101,9 @@ static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -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 float Vector2Distance(Vector2 v1, Vector2 v2); static double GetCurrentTime(); -static float Vector2Distance(); //---------------------------------------------------------------------------------- // Module Functions Definition @@ -135,18 +118,18 @@ void ProcessGestureEvent(GestureEvent event) previousGesture = currentGesture; - pointCount = event.pointCount; + pointCount = event.pointCount; // Required on UpdateGestures() - // Albert&Ian 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) && (GetMagnitude(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) + if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) { currentGesture = GESTURE_DOUBLETAP; numTap = 0; @@ -164,19 +147,17 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_UP) { - if (currentGesture = GESTURE_DRAG) - { - touchUpPosition = event.position[0]; - } - + if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; + // Calculate for swipe - magnitude = GetMagnitude(touchDownPosition, touchUpPosition); + magnitude = Vector2Distance(touchDownPosition, touchUpPosition); intensity = magnitude / (float)draggingTimeCounter; // Detect GESTURE_SWIPE if ((intensity > FORCE_TO_SWIPE) && (touchId == 0)) { angle = CalculateAngle(touchDownPosition, touchUpPosition, magnitude); + if ((angle < 30) || (angle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right else if ((angle > 30) && (angle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up else if ((angle > 120) && (angle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left @@ -196,7 +177,8 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_MOVE) { - if (GetMagnitude(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); + if (Vector2Distance(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); + moveDownPosition = event.position[0]; if (currentGesture == GESTURE_HOLD) @@ -205,7 +187,7 @@ void ProcessGestureEvent(GestureEvent event) numHold = 2; - magnitude = GetMagnitude(touchDownPosition, moveDownPosition); + magnitude = Vector2Distance(touchDownPosition, moveDownPosition); // Detect GESTURE_DRAG if (magnitude >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; @@ -214,10 +196,8 @@ void ProcessGestureEvent(GestureEvent event) draggingTimeCounter++; } } - else + else // Two touch points { - // two fingers - if (event.touchAction == TOUCH_DOWN) { touchDownPosition = event.position[0]; @@ -227,7 +207,7 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_MOVE) { - magnitude = GetMagnitude(moveDownPosition, moveDownPosition2); + magnitude = Vector2Distance(moveDownPosition, moveDownPosition2); touchDownPosition = moveDownPosition; touchDownPosition2 = moveDownPosition2; @@ -235,9 +215,9 @@ void ProcessGestureEvent(GestureEvent event) moveDownPosition = event.position[0]; moveDownPosition2 = event.position[1]; - if ( (GetMagnitude(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (GetMagnitude(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) + if ((Vector2Distance(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) { - if ((GetMagnitude(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN; + if ((Vector2Distance(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN; else currentGesture = GESTURE_PINCH_OUT; } else @@ -259,6 +239,7 @@ void UpdateGestures(void) // Detect GESTURE_HOLD if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && pointCount < 2) currentGesture = GESTURE_HOLD; + if ((GetCurrentTime() - eventTime) > TAP_TIMEOUT && (currentGesture == GESTURE_DRAG) && pointCount < 2) { currentGesture = GESTURE_HOLD; @@ -272,19 +253,6 @@ void UpdateGestures(void) } } -// Calculate distance between two vectors -float Vector2Distance(Vector2 v1, Vector3 v2) -{ - float result; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - - result = sqrt(dx*dx + dy*dy); - - return result; -} - // Check if a gesture have been detected bool IsGestureDetected(void) { @@ -342,20 +310,6 @@ float GetGesturePinchAngle(void) return 0; } -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events - - // When screen is touched, in first frame GESTURE_TAP is called but in next frame touch event callback is not called (if touch position doesn't change), - // so we need to store previous frame gesture type manually in this update function to switch to HOLD if current gesture is - // GESTURE_TAP two frames in a row. Due to current gesture is set to HOLD, current gesture doesn't need to be reset to NONE every frame. - // It will be reset when UP is called. - if(currentGesture == GESTURE_TAP) previousGesture = currentGesture; - - if(previousGesture == GESTURE_TAP && currentGesture == GESTURE_TAP) currentGesture = GESTURE_HOLD; -} - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -395,28 +349,7 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, floa 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; - - // Resets - magnitude = 0; - angle = 0; - intensity = 0; - - gestureType = TYPE_DUAL_INPUT; -} - -static float VectorDistance(Vector2 v1, Vector2 v2) +static float Vector2Distance(Vector2 v1, Vector2 v2) { float result; @@ -428,21 +361,6 @@ 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; -} - // Time measure returned are milliseconds static double GetCurrentTime() { -- cgit v1.2.3 From e98ea900cfc3b20bc4c09424a58893524f90534d Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 3 Feb 2016 19:29:59 +0100 Subject: Reviewing gestures module (IN PROGRESS) --- src/gestures.c | 99 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 41 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 8c690066..13c7845a 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 +* Reviewed by Ramon Santamaria +* Redesigned by Albert Martos and Ian Eito +* Initial design by Marc Palau * * 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. @@ -56,18 +58,14 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -typedef enum { - TYPE_MOTIONLESS, - TYPE_DRAG, - TYPE_DUAL_INPUT -} GestureType; +// ... //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- // Drag gesture variables -static Vector2 dragVector = { 0, 0 }; +static Vector2 dragVector = { 0.0f , 0.0f }; // Touch gesture variables static Vector2 touchDownPosition = { 0, 0 }; @@ -81,15 +79,15 @@ static int numHold = 0; static int pointCount = 0; static int touchId = -1; -static double eventTime = 0; +static double eventTime = 0.0; -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 +static float dragDistance = 0.0f; // DRAG distance (from initial touch point to current) +static float dragAngle = 0; // DRAG angle direction +static float dragIntensity = 0; // DRAG intensity, how far why did the DRAG (pixels per frame) +static int draggingTimeCounter = 0; // DRAG time // RAY: WTF!!! Counting... frames??? // Pinch gesture variables -static float pinchDelta = 0; // Pinch delta displacement +static float pinchDistance = 0.0f; // Pinch displacement distance // RAY: Not used! o__O // Detected gestures static int previousGesture = GESTURE_NONE; @@ -112,9 +110,9 @@ static double GetCurrentTime(); // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event) { - // Resets - dragVector = (Vector2){ 0, 0 }; - pinchDelta = 0; + // Reset required variables + dragVector = (Vector2){ 0.0f, 0.0f }; // RAY: Not used??? + pinchDistance = 0.0f; previousGesture = currentGesture; @@ -150,25 +148,25 @@ void ProcessGestureEvent(GestureEvent event) if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; // Calculate for swipe - magnitude = Vector2Distance(touchDownPosition, touchUpPosition); - intensity = magnitude / (float)draggingTimeCounter; + dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); + dragIntensity = dragDistance/(float)draggingTimeCounter; // RAY: WTF!!! Counting frames??? // Detect GESTURE_SWIPE - if ((intensity > FORCE_TO_SWIPE) && (touchId == 0)) + if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? { - angle = CalculateAngle(touchDownPosition, touchUpPosition, magnitude); + dragAngle = CalculateAngle(touchDownPosition, touchUpPosition, dragDistance); - if ((angle < 30) || (angle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right - else if ((angle > 30) && (angle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up - else if ((angle > 120) && (angle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left - else if ((angle > 210) && (angle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down + 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 { - magnitude = 0; - angle = 0; - intensity = 0; + dragDistance = 0.0f; + dragIntensity = 0.0f; + dragAngle = 0.0f; currentGesture = GESTURE_NONE; } @@ -187,13 +185,13 @@ void ProcessGestureEvent(GestureEvent event) numHold = 2; - magnitude = Vector2Distance(touchDownPosition, moveDownPosition); + dragDistance = Vector2Distance(touchDownPosition, moveDownPosition); // Detect GESTURE_DRAG - if (magnitude >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; + if (dragDistance >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; } - draggingTimeCounter++; + draggingTimeCounter++; // RAY: What do you count??? Move event actions? } } else // Two touch points @@ -207,7 +205,7 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_MOVE) { - magnitude = Vector2Distance(moveDownPosition, moveDownPosition2); + pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); touchDownPosition = moveDownPosition; touchDownPosition2 = moveDownPosition2; @@ -217,7 +215,7 @@ void ProcessGestureEvent(GestureEvent event) if ((Vector2Distance(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) { - if ((Vector2Distance(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN; + if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; else currentGesture = GESTURE_PINCH_OUT; } else @@ -227,6 +225,8 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_UP) { + pinchDistance = 0.0f; + currentGesture = GESTURE_NONE; } } @@ -272,41 +272,47 @@ void SetGesturesEnabled(unsigned int gestureFlags) enabledGestures = gestureFlags; } -// Get drag intensity (pixels per frame) -float GetGestureDragIntensity(void) +// Get drag dragIntensity (pixels per frame) +float GetGestureDragdragIntensity(void) { - return intensity; + return dragIntensity; } // Get drag angle // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGestureDragAngle(void) { - return angle; + return dragAngle; } // Get drag vector (between initial and final position) Vector2 GetGestureDragVector(void) { + // TODO: Calculate DRAG vector + return dragVector; } -// Hold time measured in frames +// Hold time measured in ms int GetGestureHoldDuration(void) { + // TODO: Return last hold time in ms + return 0; } -// Get magnitude between two pinch points +// Get distance between two pinch points float GetGesturePinchDelta(void) { - return pinchDelta; + return pinchDistance; } // Get angle beween two pinch points // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGesturePinchAngle(void) { + // TODO: Calculate pinch angle + return 0; } @@ -314,13 +320,23 @@ float GetGesturePinchAngle(void) // Module specific Functions Definition //---------------------------------------------------------------------------------- +// RAY: Do we really need magnitude??? why??? +// TODO: Remove magnitude dependency... static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) { float angle; - // Calculate arcsinus of the movement + // Calculate arcsinus of the movement // RAY: o__O angle = asin((finalPosition.y - initialPosition.y)/magnitude); angle *= RAD2DEG; + + // RAY: review this (better) solution + //angle = atan2(p1.y - p2.y, p1.x - p2.x); + //angle *= RAD2DEG; + + // http://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors + + // TODO: Remove sector dependency (self-note: check moving eyes exercise) // Calculate angle depending on the sector if ((finalPosition.x - initialPosition.x) >= 0) @@ -349,6 +365,7 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, floa return angle; } +// Calculate distance between two Vector2 static float Vector2Distance(Vector2 v1, Vector2 v2) { float result; -- cgit v1.2.3 From 687fe2c3c79bac68e6eab3ae393fefed0a7a4b07 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 8 Feb 2016 09:04:33 +0100 Subject: Updated --- src/gestures.c | 54 +++++++++++++----------------------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index 13c7845a..09c18fc4 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -99,7 +99,7 @@ static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude); +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); static float Vector2Distance(Vector2 v1, Vector2 v2); static double GetCurrentTime(); @@ -152,9 +152,9 @@ void ProcessGestureEvent(GestureEvent event) dragIntensity = dragDistance/(float)draggingTimeCounter; // RAY: WTF!!! Counting frames??? // Detect GESTURE_SWIPE - if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? + if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? { - dragAngle = CalculateAngle(touchDownPosition, touchUpPosition, dragDistance); + dragAngle = Vector2Angle(touchDownPosition, touchUpPosition); if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up @@ -322,46 +322,18 @@ float GetGesturePinchAngle(void) // RAY: Do we really need magnitude??? why??? // TODO: Remove magnitude dependency... -static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude) +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) { float angle; - - // Calculate arcsinus of the movement // RAY: o__O - angle = asin((finalPosition.y - initialPosition.y)/magnitude); - angle *= RAD2DEG; - + // RAY: review this (better) solution - //angle = atan2(p1.y - p2.y, p1.x - p2.x); - //angle *= RAD2DEG; - - // http://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors - - // TODO: Remove sector dependency (self-note: check moving eyes exercise) + angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x); + 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; - } - } + if (angle < 0) angle += 360; + // http://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors + return angle; } @@ -389,16 +361,16 @@ static double GetCurrentTime() QueryPerformanceFrequency(&clockFrequency); QueryPerformanceCounter(¤tTime); - time = (double)currentTime/clockFrequency*1000.0f; // time in miliseconds + 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; -- cgit v1.2.3 From a847df921f94a7fd118fcb608b23f11d8255c236 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Feb 2016 10:31:06 +0100 Subject: Reviewed gestures module --- src/core.c | 30 ++++++++++------ src/gestures.c | 110 +++++++++++++++++++++++++++++++++++---------------------- src/gestures.h | 1 + src/raylib.h | 9 ++--- 4 files changed, 94 insertions(+), 56 deletions(-) (limited to 'src/gestures.c') diff --git a/src/core.c b/src/core.c index 699cc2b7..05ec0c0a 100644 --- a/src/core.c +++ b/src/core.c @@ -117,7 +117,8 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define STORAGE_FILENAME "storage.data" +#define STORAGE_FILENAME "storage.data" +#define MAX_TOUCH_POINTS 2 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -182,7 +183,7 @@ static bool fullscreen = false; // Fullscreen mode (useful only for static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) -static Vector2 touchPosition; // Touch position on screen +static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) @@ -1228,7 +1229,7 @@ bool IsGamepadButtonUp(int gamepad, int button) int GetTouchX(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - return (int)touchPosition.x; + return (int)touchPosition[0].x; #else // PLATFORM_DESKTOP, PLATFORM_RPI return GetMouseX(); #endif @@ -1238,7 +1239,7 @@ int GetTouchX(void) int GetTouchY(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - return (int)touchPosition.y; + return (int)touchPosition[0].y; #else // PLATFORM_DESKTOP, PLATFORM_RPI return GetMouseY(); #endif @@ -1246,10 +1247,13 @@ int GetTouchY(void) // Returns touch position XY // TODO: touch position should be scaled depending on display size and render size -Vector2 GetTouchPosition(void) +Vector2 GetTouchPosition(int index) { + Vector2 position = { -1.0f, -1.0f }; + #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) - Vector2 position = touchPosition; + if (index < MAX_TOUCH_POINTS) position = touchPosition[index]; + else TraceLog(WARNING, "Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { @@ -1263,7 +1267,7 @@ Vector2 GetTouchPosition(void) position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2; } #else // PLATFORM_DESKTOP, PLATFORM_RPI - Vector2 position = GetMousePosition(); + if (index == 0) position = GetMousePosition(); #endif return position; @@ -1916,8 +1920,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) if (type == AINPUT_EVENT_TYPE_MOTION) { - touchPosition.x = AMotionEvent_getX(event, 0); - touchPosition.y = AMotionEvent_getY(event, 0); + // Get first touch position + touchPosition[0].x = AMotionEvent_getX(event, 0); + touchPosition[0].y = AMotionEvent_getY(event, 0); + + // Get second touch position + touchPosition[1].x = AMotionEvent_getX(event, 1); + touchPosition[1].y = AMotionEvent_getY(event, 1); } else if (type == AINPUT_EVENT_TYPE_KEY) { @@ -2535,7 +2544,8 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY }; gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY }; - touchPosition = gestureEvent.position[0]; + touchPosition[0] = gestureEvent.position[0]; + touchPosition[1] = gestureEvent.position[1]; // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); // Process obtained gestures data diff --git a/src/gestures.c b/src/gestures.c index 09c18fc4..e5a8eb9e 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -31,9 +31,7 @@ #include "raylib.h" // Required for typedef(s): Vector2, Gestures #endif -#include // malloc(), free() -#include // printf(), fprintf() -#include // Used for ... +#include // Used for: atan2(), sqrt() #include // Defines int32_t, int64_t #if defined(_WIN32) @@ -47,13 +45,12 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 20 +#define FORCE_TO_SWIPE 1 #define FORCE_TO_DRAG 20 #define FORCE_TO_PINCH 5 #define TAP_TIMEOUT 300 // Time in milliseconds #define PINCH_TIMEOUT 300 // Time in milliseconds #define DOUBLETAP_RANGE 30 -//#define MAX_TOUCH_POINTS 4 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -64,30 +61,33 @@ // Global Variables Definition //---------------------------------------------------------------------------------- -// Drag gesture variables -static Vector2 dragVector = { 0.0f , 0.0f }; - // Touch gesture variables -static Vector2 touchDownPosition = { 0, 0 }; -static Vector2 touchDownPosition2 = { 0, 0 }; -static Vector2 touchUpPosition = { 0, 0 }; -static Vector2 moveDownPosition = { 0, 0 }; -static Vector2 moveDownPosition2 = { 0, 0 }; +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; static int numHold = 0; +static bool isMoving = false; +static float timeHold = 0.0f; static int pointCount = 0; static int touchId = -1; static double eventTime = 0.0; +static double swipeTime = 0.0; +// Drag gesture variables +static Vector2 dragVector = { 0.0f , 0.0f }; static float dragDistance = 0.0f; // DRAG distance (from initial touch point to current) -static float dragAngle = 0; // DRAG angle direction -static float dragIntensity = 0; // DRAG intensity, how far why did the DRAG (pixels per frame) -static int draggingTimeCounter = 0; // DRAG time // RAY: WTF!!! Counting... frames??? +static float dragAngle = 0.0f; // DRAG angle direction +static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) // Pinch gesture variables static float pinchDistance = 0.0f; // Pinch displacement distance // RAY: Not used! o__O +static float pinchAngle = 0.0f; // Pinch displacement distance // RAY: Not used! o__O // Detected gestures static int previousGesture = GESTURE_NONE; @@ -111,9 +111,6 @@ static double GetCurrentTime(); void ProcessGestureEvent(GestureEvent event) { // Reset required variables - dragVector = (Vector2){ 0.0f, 0.0f }; // RAY: Not used??? - pinchDistance = 0.0f; - previousGesture = currentGesture; pointCount = event.pointCount; // Required on UpdateGestures() @@ -139,9 +136,12 @@ void ProcessGestureEvent(GestureEvent event) } touchDownPosition = event.position[0]; + touchDownDragPosition = event.position[0]; touchUpPosition = touchDownPosition; eventTime = GetCurrentTime(); + + dragVector = (Vector2){ 0.0f, 0.0f }; } else if (event.touchAction == TOUCH_UP) { @@ -149,12 +149,15 @@ void ProcessGestureEvent(GestureEvent event) // Calculate for swipe dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); - dragIntensity = dragDistance/(float)draggingTimeCounter; // RAY: WTF!!! Counting frames??? + dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); + + isMoving = false; // Detect GESTURE_SWIPE if ((dragIntensity > FORCE_TO_SWIPE) && (touchId == 0)) // RAY: why check (touchId == 0)??? { - dragAngle = Vector2Angle(touchDownPosition, touchUpPosition); + // 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 @@ -171,12 +174,18 @@ void ProcessGestureEvent(GestureEvent event) currentGesture = GESTURE_NONE; } - draggingTimeCounter = 0; + touchDownPosition = (Vector2){ 0.0f, 0.0f }; } else if (event.touchAction == TOUCH_MOVE) { if (Vector2Distance(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); + if (!isMoving) + { + swipeTime = GetCurrentTime(); + isMoving = true; + } + moveDownPosition = event.position[0]; if (currentGesture == GESTURE_HOLD) @@ -190,8 +199,9 @@ void ProcessGestureEvent(GestureEvent event) // Detect GESTURE_DRAG if (dragDistance >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; } - - draggingTimeCounter++; // RAY: What do you count??? Move event actions? + + dragVector.x = moveDownPosition.x - touchDownDragPosition.x; + dragVector.y = moveDownPosition.y - touchDownDragPosition.y; } } else // Two touch points @@ -200,13 +210,15 @@ void ProcessGestureEvent(GestureEvent event) { touchDownPosition = event.position[0]; touchDownPosition2 = event.position[1]; + pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); } else if (event.touchAction == TOUCH_MOVE) { pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); - + touchDownPosition = moveDownPosition; touchDownPosition2 = moveDownPosition2; @@ -220,12 +232,17 @@ void ProcessGestureEvent(GestureEvent event) } else { - currentGesture = GESTURE_HOLD; + 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; currentGesture = GESTURE_NONE; } @@ -238,11 +255,16 @@ void UpdateGestures(void) // NOTE: Gestures are processed through system callbacks on touch events // Detect GESTURE_HOLD - if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && pointCount < 2) currentGesture = 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) + if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) { currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); numHold = 1; } @@ -288,17 +310,19 @@ float GetGestureDragAngle(void) // Get drag vector (between initial and final position) Vector2 GetGestureDragVector(void) { - // TODO: Calculate DRAG vector - + // NOTE: Calculated in... return dragVector; } // Hold time measured in ms -int GetGestureHoldDuration(void) +float GetGestureHoldDuration(void) { - // TODO: Return last hold time in ms + float time = 0.0f; + + // DONE: Return last hold time in ms + if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; - return 0; + return time; } // Get distance between two pinch points @@ -307,32 +331,34 @@ float GetGesturePinchDelta(void) return pinchDistance; } +// Get number of touch points +int GetTouchPointsCount(void) +{ + return pointCount; +} + // Get angle beween two pinch points // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGesturePinchAngle(void) { - // TODO: Calculate pinch angle + // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE - return 0; + return pinchAngle; } //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- -// RAY: Do we really need magnitude??? why??? -// TODO: Remove magnitude dependency... +// Returns angle from two-points vector with X-axis static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) { float angle; - - // RAY: review this (better) solution + angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x); angle *= RAD2DEG; - if (angle < 0) angle += 360; - - // http://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors + if (angle < 0) angle += 360.0f; return angle; } diff --git a/src/gestures.h b/src/gestures.h index b5cf2767..52f778be 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -102,6 +102,7 @@ Vector2 GetGestureDragVector(void); // Get gesture drag vect int GetGestureHoldDuration(void); // Get gesture hold time in frames float GetGesturePinchDelta(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle +int GetTouchPointsCount(void); // Get touch points count #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index 3d8100b3..55a68ad1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -600,9 +600,9 @@ bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad b bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed #endif -int GetTouchX(void); // Returns touch position X (relative to screen size) -int GetTouchY(void); // Returns touch position Y (relative to screen size) -Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size) +int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) +int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +Vector2 GetTouchPosition(int index) // Returns touch position XY for a touch point index (relative to screen size) #if defined(PLATFORM_ANDROID) bool IsButtonPressed(int button); // Detect if an android physic button has been pressed @@ -622,9 +622,10 @@ void ProcessGestureEvent(GestureEvent event); // Process gesture event float GetGestureDragIntensity(void); // Get gesture drag intensity float GetGestureDragAngle(void); // Get gesture drag angle Vector2 GetGestureDragVector(void); // Get gesture drag vector -int GetGestureHoldDuration(void); // Get gesture hold time in frames +float GetGestureHoldDuration(void); // Get gesture hold time in ms float GetGesturePinchDelta(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle +int GetTouchPointsCount(void); // Get touch points count //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) -- cgit v1.2.3 From c69ce1d7504b94108721403c867bddbf50d7b890 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Feb 2016 13:54:32 +0100 Subject: Updated comments --- src/gestures.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index e5a8eb9e..a2744460 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -45,7 +45,7 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 1 +#define FORCE_TO_SWIPE 1 // Time in milliseconds #define FORCE_TO_DRAG 20 #define FORCE_TO_PINCH 5 #define TAP_TIMEOUT 300 // Time in milliseconds @@ -80,14 +80,14 @@ static double eventTime = 0.0; static double swipeTime = 0.0; // Drag gesture variables -static Vector2 dragVector = { 0.0f , 0.0f }; -static float dragDistance = 0.0f; // DRAG distance (from initial touch point to current) -static float dragAngle = 0.0f; // DRAG angle direction -static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) +static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) +static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) for SWIPE GESTURE +static float dragAngle = 0.0f; // DRAG angle direction for SWIPE GESTURE +static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) for SWIPE GESTURE // Pinch gesture variables -static float pinchDistance = 0.0f; // Pinch displacement distance // RAY: Not used! o__O -static float pinchAngle = 0.0f; // Pinch displacement distance // RAY: Not used! o__O +static float pinchDistance = 0.0f; // Pinch displacement distance +static float pinchAngle = 0.0f; // Pinch displacement distance // Detected gestures static int previousGesture = GESTURE_NONE; @@ -122,7 +122,7 @@ void ProcessGestureEvent(GestureEvent event) 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)) { @@ -174,7 +174,7 @@ void ProcessGestureEvent(GestureEvent event) currentGesture = GESTURE_NONE; } - touchDownPosition = (Vector2){ 0.0f, 0.0f }; + touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; } else if (event.touchAction == TOUCH_MOVE) { @@ -297,6 +297,8 @@ void SetGesturesEnabled(unsigned int gestureFlags) // Get drag dragIntensity (pixels per frame) float GetGestureDragdragIntensity(void) { + // NOTE: drag intensity is calculated on one touch points TOUCH_UP + return dragIntensity; } @@ -304,22 +306,26 @@ float GetGestureDragdragIntensity(void) // NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise float GetGestureDragAngle(void) { + // NOTE: drag angle is calculated on one touch points TOUCH_UP + return dragAngle; } -// Get drag vector (between initial and final position) +// Get drag vector (between initial touch point to current) Vector2 GetGestureDragVector(void) { - // NOTE: Calculated in... + // NOTE: drag vector is calculated on one touch points TOUCH_MOVE + return dragVector; } // Hold time measured in ms float GetGestureHoldDuration(void) { + // NOTE: time is calculated on current gesture HOLD + float time = 0.0f; - // DONE: Return last hold time in ms if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; return time; @@ -328,12 +334,17 @@ float GetGestureHoldDuration(void) // Get distance between two pinch points float GetGesturePinchDelta(void) { + // 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 pinchDistance; } // Get number of touch points int GetTouchPointsCount(void) { + // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called + return pointCount; } -- cgit v1.2.3 From 94c92a58a1a8131c4d71ba32f18e836f6178231c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 13 Feb 2016 17:08:09 +0100 Subject: Some tweaks --- src/gestures.c | 4 ++-- src/raygui.c | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src/gestures.c') diff --git a/src/gestures.c b/src/gestures.c index a2744460..16442e45 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -2,9 +2,9 @@ * * raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * -* Reviewed by Ramon Santamaria -* Redesigned by Albert Martos and Ian Eito * 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. diff --git a/src/raygui.c b/src/raygui.c index 2c68c96f..60df2121 100644 --- a/src/raygui.c +++ b/src/raygui.c @@ -2,7 +2,8 @@ * * raygui - raylib IMGUI system (Immedite Mode GUI) * -* Copyright (c) 2015 Kevin Gato, Daniel Nicolás, Sergio Martinez and Ramon Santamaria +* Initial design by Kevin Gato and Daniel Nicolás +* Reviewed by Albert Martos, Ian Eito, Sergio Martinez and 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. @@ -856,10 +857,6 @@ char *GuiTextBox(Rectangle bounds, char *text) return text; } -// TODO: GuiBox? -// TODO: GuiWindow? -// TODO: GuiPanel? - // Save current GUI style into a text file void SaveGuiStyle(const char *fileName) { @@ -873,12 +870,14 @@ void SaveGuiStyle(const char *fileName) // Load GUI style from a text file void LoadGuiStyle(const char *fileName) { + #define MAX_STYLE_PROPERTIES 128 + typedef struct { char id[64]; int value; } StyleProperty; - StyleProperty *styleProp = (StyleProperty *)malloc(128*sizeof(StyleProperty));; + StyleProperty *styleProp = (StyleProperty *)malloc(MAX_STYLE_PROPERTIES*sizeof(StyleProperty));; int counter = 0; FILE *styleFile = fopen(fileName, "rt"); -- cgit v1.2.3 From afd2ffb74a84bf48b9129c613e1673ceae0bd46b Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 17 Feb 2016 13:00:48 +0100 Subject: Updated gestures module Using normalized [0..1] input points --- src/core.c | 28 +++++++++++- src/gestures.c | 134 ++++++++++++++++++++++++++++++--------------------------- src/gestures.h | 12 +++--- src/raylib.h | 11 +++-- 4 files changed, 109 insertions(+), 76 deletions(-) (limited to 'src/gestures.c') diff --git a/src/core.c b/src/core.c index 0c85ab26..7b981097 100644 --- a/src/core.c +++ b/src/core.c @@ -1700,14 +1700,22 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // Register touch actions if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; - //else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_MOVE; else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP; + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointerId[0] = 0; + // Register touch points count gestureEvent.pointCount = 1; // Register touch points position, only one point registered gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); @@ -1729,6 +1737,10 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) // Register touch points position, only one point registered gestureEvent.position[0] = (Vector2){ (float)x, (float)y }; + + // Normalize gestureEvent.position[0] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); @@ -1992,6 +2004,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); + gestureEvent.position[1].y /= (float)GetScreenHeight(); + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); @@ -2564,6 +2583,13 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent touchPosition[0] = gestureEvent.position[0]; touchPosition[1] = gestureEvent.position[1]; + // Normalize gestureEvent.position[x] for screenWidth and screenHeight + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); + gestureEvent.position[1].y /= (float)GetScreenHeight(); + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); // Process obtained gestures data diff --git a/src/gestures.c b/src/gestures.c index 16442e45..af92ba3d 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -45,12 +45,12 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 1 // Time in milliseconds -#define FORCE_TO_DRAG 20 -#define FORCE_TO_PINCH 5 -#define TAP_TIMEOUT 300 // Time in milliseconds -#define PINCH_TIMEOUT 300 // Time in milliseconds -#define DOUBLETAP_RANGE 30 +#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 @@ -68,26 +68,29 @@ 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; -static int numHold = 0; -static bool isMoving = false; -static float timeHold = 0.0f; + static int pointCount = 0; static int touchId = -1; static double eventTime = 0.0; static double swipeTime = 0.0; +// Hold gesture variables +static int numHold = 0; +static float timeHold = 0.0f; + // Drag gesture variables static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) -static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) for SWIPE GESTURE -static float dragAngle = 0.0f; // DRAG angle direction for SWIPE GESTURE -static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) for SWIPE GESTURE +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 float pinchDistance = 0.0f; // Pinch displacement distance -static float pinchAngle = 0.0f; // Pinch displacement distance +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; @@ -101,7 +104,7 @@ static unsigned int enabledGestures = 0b0000001111111111; //---------------------------------------------------------------------------------- static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); static float Vector2Distance(Vector2 v1, Vector2 v2); -static double GetCurrentTime(); +static double GetCurrentTime(void); //---------------------------------------------------------------------------------- // Module Functions Definition @@ -147,17 +150,19 @@ void ProcessGestureEvent(GestureEvent event) { if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; - // Calculate for swipe + // NOTE: dragIntensity dependend on the resolution of the screen dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); + + // TODO: Make getures detection resolution independant - isMoving = false; + 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);; + 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 @@ -178,26 +183,28 @@ void ProcessGestureEvent(GestureEvent event) } else if (event.touchAction == TOUCH_MOVE) { - if (Vector2Distance(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); + if ((currentGesture == GESTURE_DRAG)) eventTime = GetCurrentTime(); - if (!isMoving) + if (!startMoving) { swipeTime = GetCurrentTime(); - isMoving = true; + startMoving = true; } moveDownPosition = event.position[0]; - if (currentGesture == GESTURE_HOLD) + if (currentGesture == GESTURE_HOLD) { if (numHold == 1) touchDownPosition = event.position[0]; numHold = 2; - - dragDistance = Vector2Distance(touchDownPosition, moveDownPosition); // Detect GESTURE_DRAG - if (dragDistance >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; + if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) + { + eventTime = GetCurrentTime(); + currentGesture = GESTURE_DRAG; + } } dragVector.x = moveDownPosition.x - touchDownDragPosition.x; @@ -210,7 +217,11 @@ void ProcessGestureEvent(GestureEvent event) { touchDownPosition = event.position[0]; touchDownPosition2 = event.position[1]; - pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); + + //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); + + pinchVector.x = touchDownPosition2.x - touchDownPosition.x; + pinchVector.y = touchDownPosition2.y - touchDownPosition.y; currentGesture = GESTURE_HOLD; timeHold = GetCurrentTime(); @@ -218,22 +229,25 @@ void ProcessGestureEvent(GestureEvent event) else if (event.touchAction == TOUCH_MOVE) { pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); - + touchDownPosition = moveDownPosition; touchDownPosition2 = moveDownPosition2; moveDownPosition = event.position[0]; moveDownPosition2 = event.position[1]; - if ((Vector2Distance(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) + 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 + else { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); } // NOTE: Angle should be inverted in Y @@ -243,6 +257,7 @@ void ProcessGestureEvent(GestureEvent event) { pinchDistance = 0.0f; pinchAngle = 0.0f; + pinchVector = (Vector2){ 0.0f, 0.0f }; currentGesture = GESTURE_NONE; } @@ -289,26 +304,30 @@ int GetGestureType(void) 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 dragIntensity (pixels per frame) -float GetGestureDragdragIntensity(void) +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) { - // NOTE: drag intensity is calculated on one touch points TOUCH_UP - - return dragIntensity; + 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) { - // NOTE: drag angle is calculated on one touch points TOUCH_UP + // NOTE: time is calculated on current gesture HOLD - return dragAngle; + float time = 0.0f; + + if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; + + return time; } // Get drag vector (between initial touch point to current) @@ -319,33 +338,22 @@ Vector2 GetGestureDragVector(void) return dragVector; } -// Hold time measured in ms -float GetGestureHoldDuration(void) +// Get drag angle +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGestureDragAngle(void) { - // NOTE: time is calculated on current gesture HOLD - - float time = 0.0f; - - if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; + // NOTE: drag angle is calculated on one touch points TOUCH_UP - return time; + return dragAngle; } // Get distance between two pinch points -float GetGesturePinchDelta(void) +Vector2 GetGesturePinchVector(void) { // 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 pinchDistance; -} - -// Get number of touch points -int GetTouchPointsCount(void) -{ - // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called - - return pointCount; + return pinchVector; } // Get angle beween two pinch points @@ -388,7 +396,7 @@ static float Vector2Distance(Vector2 v1, Vector2 v2) } // Time measure returned are milliseconds -static double GetCurrentTime() +static double GetCurrentTime(void) { double time = 0; diff --git a/src/gestures.h b/src/gestures.h index 52f778be..5468eb54 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -90,19 +90,19 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures +int GetTouchPointsCount(void); // Get touch points count -float GetGestureDragIntensity(void); // Get gesture drag intensity -float GetGestureDragAngle(void); // Get gesture drag angle +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector -int GetGestureHoldDuration(void); // Get gesture hold time in frames -float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle -int GetTouchPointsCount(void); // Get touch points count + #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index f5a3cc31..def56ee2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -607,19 +607,18 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ +void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures +int GetTouchPointsCount(void); // Get touch points count -float GetGestureDragIntensity(void); // Get gesture drag intensity -float GetGestureDragAngle(void); // Get gesture drag angle +float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector -float GetGestureHoldDuration(void); // Get gesture hold time in ms -float GetGesturePinchDelta(void); // Get gesture pinch delta +float GetGestureDragAngle(void); // Get gesture drag angle +Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle -int GetTouchPointsCount(void); // Get touch points count //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) -- cgit v1.2.3