From 9ed3b76db83e6d8ce3aee49979a7da469b65b544 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Sat, 17 Dec 2022 04:31:07 +0100
Subject: [PATCH] cmake: add interface-only SDL2_gesture::SDL2_gesture target +
test
---
CMakeLists.txt | 48 +++++
SDL_gesture.h | 93 +++++----
cmake/CommonFindSDL2.cmake | 22 +++
cmake/FindPrivateSDL2.cmake | 45 +++++
cmake/FindSDL2main.cmake | 29 +++
cmake/FindSDL2test.cmake | 22 +++
cmake/SDL_gestureConfig.cmake.in | 7 +
test/CMakeLists.txt | 53 ++++++
test/testgesture.c | 316 +++++++++++++++++++++++++++++++
9 files changed, 588 insertions(+), 47 deletions(-)
create mode 100644 CMakeLists.txt
create mode 100644 cmake/CommonFindSDL2.cmake
create mode 100644 cmake/FindPrivateSDL2.cmake
create mode 100644 cmake/FindSDL2main.cmake
create mode 100644 cmake/FindSDL2test.cmake
create mode 100644 cmake/SDL_gestureConfig.cmake.in
create mode 100644 test/CMakeLists.txt
create mode 100644 test/testgesture.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c80a46d
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 3.0)
+project(SDL_gesture VERSION 1.0.0 LANGUAGES C)
+
+include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
+
+option(SDLGESTURE_TESTS "Build SDL_gesture tests" ON)
+
+add_library(SDL_gesture INTERFACE)
+add_library(SDL_gesture::SDL_gesture ALIAS SDL_gesture)
+target_include_directories(SDL_gesture INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
+
+if(SDLGESTURE_TESTS)
+ add_subdirectory(test)
+endif()
+
+if(WINDOWS AND NOT MINGW)
+ set(SDLGESTURE_INSTALL_CMAKEDIR_ROOT_DEFAULT "cmake")
+else()
+ set(SDLGESTURE_INSTALL_CMAKEDIR_ROOT_DEFAULT "${CMAKE_INSTALL_LIBDIR}/cmake")
+endif()
+set(SDLGESTURE_INSTALL_CMAKEDIR_ROOT "${SDLGESTURE_INSTALL_CMAKEDIR_ROOT_DEFAULT}" CACHE STRING "Root folder where to install SDLConfig.cmake related files (SDL_gesture subfolder for MSVC projects)")
+
+if(WINDOWS AND NOT MINGW)
+ set(SDLGESTURE_INSTALL_CMAKEDIR "${SDLGESTURE_INSTALL_CMAKEDIR_ROOT}")
+ set(LICENSES_PREFIX "licenses/SDL_gesture")
+else()
+ set(SDLGESTURE_INSTALL_CMAKEDIR "${SDLGESTURE_INSTALL_CMAKEDIR_ROOT}/SDL_gesture")
+ set(LICENSES_PREFIX "${CMAKE_INSTALL_DATAROOTDIR}/licenses/SDL_gesture")
+endif()
+
+configure_package_config_file(cmake/SDL_gestureConfig.cmake.in SDL_gestureConfig.cmake
+ INSTALL_DESTINATION "${SDLGESTURE_INSTALL_CMAKEDIR}"
+ INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
+ PATH_VARS "CMAKE_INSTALL_FULL_INCLUDEDIR"
+ NO_SET_AND_CHECK_MACRO
+)
+write_basic_package_version_file(SDL_gestureConfigVersion.cmake
+ COMPATIBILITY AnyNewerVersion
+)
+
+install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/SDL_gesture.h"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/SDL_gestureConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/SDL_gestureConfigVersion.cmake"
+ DESTINATION "${SDLGESTURE_INSTALL_CMAKEDIR}"
+)
+install(FILES "LICENSE.txt" DESTINATION "${LICENSES_PREFIX}")
diff --git a/SDL_gesture.h b/SDL_gesture.h
index d7d8b32..d3bf44e 100644
--- a/SDL_gesture.h
+++ b/SDL_gesture.h
@@ -24,15 +24,16 @@
#ifndef INCL_SDL_GESTURE_H
#define INCL_SDL_GESTURE_H
-#if !defined(SDL_VERSION_MAJOR)
+#if !defined(SDL_MAJOR_VERSION)
#error Please include SDL.h before including this header.
-#elif SDL_VERSION_MAJOR < 2
+#elif SDL_MAJOR_VERSION < 2
#error This header requires SDL2 or later.
-#elif SDL_VERSION_MAJOR == 2
+#elif SDL_MAJOR_VERSION == 2
/* building against SDL2? Just use the built-in SDL2 implementation. */
#define Gesture_Init() (0)
#define Gesture_Quit()
#define Gesture_ID SDL_GestureID
+#define Gesture_LoadDollarTemplates SDL_LoadDollarTemplates
#define Gesture_RecordGesture SDL_RecordGesture
#define Gesture_SaveAllDollarTemplates SDL_SaveAllDollarTemplates
#define Gesture_SaveDollarTemplate SDL_SaveDollarTemplate
@@ -40,7 +41,7 @@
#define GESTURE_DOLLARRECORD SDL_DOLLARRECORD
#define GESTURE_MULTIGESTURE SDL_MULTIGESTURE
#define Gesture_MultiGestureEvent SDL_MultiGestureEvent
-#define Gesture_DollarGestureEvent SDL_MultiGestureEvent
+#define Gesture_DollarGestureEvent SDL_DollarGestureEvent
#else
/* Set up for C function definitions, even when using C++ */
@@ -77,7 +78,7 @@ typedef struct Gesture_DollarGestureEvent
Uint32 type;
Uint32 timestamp;
SDL_TouchID touchId;
- SDL_GestureID gestureId;
+ Gesture_ID gestureId;
Uint32 numFingers;
float error;
float x;
@@ -137,7 +138,7 @@ extern int SDLCALL Gesture_SaveAllDollarTemplates(SDL_RWops *dst);
* \sa SDL_LoadDollarTemplates
* \sa SDL_SaveAllDollarTemplates
*/
-extern int SDLCALL Gesture_SaveDollarTemplate(SDL_GestureID gestureId,SDL_RWops *dst);
+extern int SDLCALL Gesture_SaveDollarTemplate(Gesture_ID gestureId, SDL_RWops *dst);
/**
* Load Dollar Gesture templates from a file.
@@ -159,9 +160,6 @@ extern int SDLCALL Gesture_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *s
}
#endif
-#endif /* !defined INCL_SDL_GESTURE_H */
-
-
#if defined(SDL_GESTURE_IMPLEMENTATION)
#define GESTURE_MAX_DOLLAR_PATH_SIZE 1024
@@ -200,7 +198,7 @@ static SDL_bool GestureRecordAll = SDL_FALSE;
static void GestureProcessEvent(const SDL_Event *event);
-static int SDLCALL *GestureEventWatch(void *userdata, SDL_Event *event)
+static int SDLCALL GestureEventWatch(void *userdata, SDL_Event *event)
{
GestureProcessEvent(event);
return 1;
@@ -264,7 +262,7 @@ static GestureTouch *GestureGetTouch(const SDL_TouchID touchId)
return NULL;
}
-int SDL_RecordGesture(SDL_TouchID touchId)
+int Gesture_RecordGesture(SDL_TouchID touchId)
{
const int numtouchdevs = SDL_GetNumTouchDevices();
int i;
@@ -350,7 +348,7 @@ static int GestureSaveTemplate(GestureDollarTemplate *templ, SDL_RWops *dst)
}
DECLSPEC int SDLCALL
-SDL_SaveAllDollarTemplates(SDL_RWops *dst)
+Gesture_SaveAllDollarTemplates(SDL_RWops *dst)
{
int i, j, rtrn = 0;
for (i = 0; i < GestureNumTouches; i++) {
@@ -363,7 +361,7 @@ SDL_SaveAllDollarTemplates(SDL_RWops *dst)
}
DECLSPEC int SDLCALL
-SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *dst)
+Gesture_SaveDollarTemplate(Gesture_ID gestureId, SDL_RWops *dst)
{
int i, j;
for (i = 0; i < GestureNumTouches; i++) {
@@ -422,7 +420,7 @@ static int GestureAddDollar(GestureTouch *inTouch, SDL_FPoint *path)
}
DECLSPEC int SDLCALL
-SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
+Gesture_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
{
int i, loaded = 0;
GestureTouch *touch = NULL;
@@ -442,7 +440,7 @@ SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
while (1) {
GestureDollarTemplate templ;
- const Sint64 bytes = sizeof(templ->path[0]) * GESTURE_DOLLARNPOINTS;
+ const Sint64 bytes = sizeof(templ.path[0]) * GESTURE_DOLLARNPOINTS;
if (SDL_RWread(src, templ.path, bytes) < bytes) {
if (loaded == 0) {
@@ -653,46 +651,46 @@ static float GestureDollarRecognize(const GestureDollarPath *path, int *bestTemp
static void GestureSendMulti(GestureTouch *touch, float dTheta, float dDist)
{
- if (SDL_GetEventState(SDL_MULTIGESTURE) == SDL_ENABLE) {
- SDL_Event event;
- event.type = GESTURE_MULTIGESTURE;
- event.common.timestamp = 0;
- event.mgesture.touchId = touch->touchId;
- event.mgesture.x = touch->centroid.x;
- event.mgesture.y = touch->centroid.y;
- event.mgesture.dTheta = dTheta;
- event.mgesture.dDist = dDist;
- event.mgesture.numFingers = touch->numDownFingers;
- SDL_PushEvent(&event);
+ if (SDL_GetEventState(GESTURE_MULTIGESTURE) == SDL_ENABLE) {
+ Gesture_MultiGestureEvent mgesture;
+ mgesture.type = GESTURE_MULTIGESTURE;
+ mgesture.timestamp = 0;
+ mgesture.touchId = touch->touchId;
+ mgesture.x = touch->centroid.x;
+ mgesture.y = touch->centroid.y;
+ mgesture.dTheta = dTheta;
+ mgesture.dDist = dDist;
+ mgesture.numFingers = touch->numDownFingers;
+ SDL_PushEvent((SDL_Event*)&mgesture);
}
}
-static void GestureSendDollar(GestureTouch *touch, SDL_GestureID gestureId, float error)
+static void GestureSendDollar(GestureTouch *touch, Gesture_ID gestureId, float error)
{
- if (SDL_GetEventState(SDL_DOLLARGESTURE) == SDL_ENABLE) {
- SDL_Event event;
- event.type = GESTURE_DOLLARGESTURE;
- event.common.timestamp = 0;
- event.dgesture.touchId = touch->touchId;
- event.dgesture.x = touch->centroid.x;
- event.dgesture.y = touch->centroid.y;
- event.dgesture.gestureId = gestureId;
- event.dgesture.error = error;
+ if (SDL_GetEventState(GESTURE_DOLLARGESTURE) == SDL_ENABLE) {
+ Gesture_DollarGestureEvent dgesture;
+ dgesture.type = GESTURE_DOLLARGESTURE;
+ dgesture.timestamp = 0;
+ dgesture.touchId = touch->touchId;
+ dgesture.x = touch->centroid.x;
+ dgesture.y = touch->centroid.y;
+ dgesture.gestureId = gestureId;
+ dgesture.error = error;
/* A finger came up to trigger this event. */
- event.dgesture.numFingers = touch->numDownFingers + 1;
- SDL_PushEvent(&event);
+ dgesture.numFingers = touch->numDownFingers + 1;
+ SDL_PushEvent((SDL_Event*)&dgesture);
}
}
-static void GestureSendDollarRecord(GestureTouch *touch, SDL_GestureID gestureId)
+static void GestureSendDollarRecord(GestureTouch *touch, Gesture_ID gestureId)
{
- if (SDL_GetEventState(SDL_DOLLARRECORD) == SDL_ENABLE) {
- SDL_Event event;
- event.type = GESTURE_DOLLARRECORD;
- event.common.timestamp = 0;
- event.dgesture.touchId = touch->touchId;
- event.dgesture.gestureId = gestureId;
- SDL_PushEvent(&event);
+ if (SDL_GetEventState(GESTURE_DOLLARRECORD) == SDL_ENABLE) {
+ Gesture_DollarGestureEvent dgesture;
+ dgesture.type = GESTURE_DOLLARRECORD;
+ dgesture.timestamp = 0;
+ dgesture.touchId = touch->touchId;
+ dgesture.gestureId = gestureId;
+ SDL_PushEvent((SDL_Event*)&dgesture);
}
}
@@ -850,6 +848,7 @@ static void GestureProcessEvent(const SDL_Event *event)
}
#endif /* defined(SDL_GESTURE_IMPLEMENTATION) */
-#endif /* SDL vesion > 2 */
+#endif /* SDL version > 2 */
+#endif /* INCL_SDL_GESTURE_H */
/* vi: set sts=4 ts=4 sw=4 expandtab: */
diff --git a/cmake/CommonFindSDL2.cmake b/cmake/CommonFindSDL2.cmake
new file mode 100644
index 0000000..59939dc
--- /dev/null
+++ b/cmake/CommonFindSDL2.cmake
@@ -0,0 +1,22 @@
+# Common variables for FindSDL2*.cmake modules
+
+set(_inc_suffixes include)
+set(_lib_suffixes)
+if(MSVC)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ list(APPEND _lib_suffixes "lib/x86")
+ endif()
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND _lib_suffixes "lib/x64")
+ endif()
+endif()
+if(MINGW)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ list(APPEND _lib_suffixes "i686-w64-mingw32/lib")
+ list(APPEND _inc_suffixes "i686-w64-mingw32/include")
+ endif()
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND _lib_suffixes "x86_64-w64-mingw32/lib")
+ list(APPEND _inc_suffixes "x86_64-w64-mingw32/include")
+ endif()
+endif()
diff --git a/cmake/FindPrivateSDL2.cmake b/cmake/FindPrivateSDL2.cmake
new file mode 100644
index 0000000..ba0732b
--- /dev/null
+++ b/cmake/FindPrivateSDL2.cmake
@@ -0,0 +1,45 @@
+include(FindPackageHandleStandardArgs)
+include("${CMAKE_CURRENT_LIST_DIR}/CommonFindSDL2.cmake")
+
+find_library(SDL2_LIBRARY
+ NAMES SDL2
+ HINTS ${SDL2_DIR} ENV SDL2_DIR
+ PATH_SUFFIXES ${_lib_suffixes}
+)
+
+find_path(SDL2_INCLUDE_DIR
+ NAMES SDL_haptic.h
+ PATH_SUFFIXES SDL2
+ HINTS ${SDL2_DIR} ENV SDL2_DIR
+ PATH_SUFFIXES ${_inc_suffixes}
+)
+
+set(SDL2_VERSION)
+if(SDL2_INCLUDE_DIR)
+ file(READ "${SDL2_INCLUDE_DIR}/SDL_version.h" _sdl_version_h)
+ string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl2_major_re "${_sdl_version_h}")
+ set(_sdl2_major "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl2_minor_re "${_sdl_version_h}")
+ set(_sdl2_minor "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)" _sdl2_patch_re "${_sdl_version_h}")
+ set(_sdl2_patch "${CMAKE_MATCH_1}")
+ if(_sdl2_major_re AND _sdl2_minor_re AND _sdl2_patch_re)
+ set(SDL2_VERSION "${_sdl2_major}.${_sdl2_minor}.${_sdl2_patch}")
+ endif()
+endif()
+
+find_package_handle_standard_args(PrivateSDL2
+ REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR
+ VERSION_VAR SDL2_VERSION
+)
+
+if(PrivateSDL2_FOUND)
+ if(NOT TARGET PrivateSDL2::PrivateSDL2)
+ add_library(PrivateSDL2::PrivateSDL2 UNKNOWN IMPORTED)
+ set_target_properties(PrivateSDL2::PrivateSDL2 PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${SDL2_LIBRARY}"
+ )
+ endif()
+endif()
diff --git a/cmake/FindSDL2main.cmake b/cmake/FindSDL2main.cmake
new file mode 100644
index 0000000..7c67ba1
--- /dev/null
+++ b/cmake/FindSDL2main.cmake
@@ -0,0 +1,29 @@
+include(FindPackageHandleStandardArgs)
+include("${CMAKE_CURRENT_LIST_DIR}/CommonFindSDL2.cmake")
+
+find_library(SDL2_MAIN_LIBRARY
+ NAMES SDL2main SDL2_main
+ HINTS ${SDL2_DIR} ENV SDL2_DIR
+ PATH_SUFFIXES ${_lib_suffixes}
+)
+
+find_package_handle_standard_args(SDL2main
+ REQUIRED_VARS SDL2_MAIN_LIBRARY
+)
+
+if(SDL2main_FOUND)
+ if(NOT TARGET SDL2::SDL2main)
+ add_library(SDL2::SDL2main UNKNOWN IMPORTED)
+ set_target_properties(SDL2::SDL2main PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${SDL2_MAIN_LIBRARY}"
+ )
+ if(MINGW)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set_target_properties(SDL2::SDL2main PROPERTIES INTERFACE_LINK_LIBRARIES "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:-Wl,--undefined=_WinMain@16>")
+ else()
+ set_target_properties(SDL2::SDL2main PROPERTIES INTERFACE_LINK_LIBRARIES "$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:-Wl,--undefined=WinMain>")
+ endif()
+ endif()
+ endif()
+endif()
diff --git a/cmake/FindSDL2test.cmake b/cmake/FindSDL2test.cmake
new file mode 100644
index 0000000..56613b8
--- /dev/null
+++ b/cmake/FindSDL2test.cmake
@@ -0,0 +1,22 @@
+include(FindPackageHandleStandardArgs)
+include("${CMAKE_CURRENT_LIST_DIR}/CommonFindSDL2.cmake")
+
+find_library(SDL2_TEST_LIBRARY
+ NAMES SDL2test SDL2_test
+ HINTS ${SDL2_DIR} ENV SDL2_DIR
+ PATH_SUFFIXES ${_lib_suffixes}
+)
+
+find_package_handle_standard_args(SDL2test
+ REQUIRED_VARS SDL2_TEST_LIBRARY
+)
+
+if(SDL2test_FOUND)
+ if(NOT TARGET SDL2::SDL2test)
+ add_library(SDL2::SDL2test UNKNOWN IMPORTED)
+ set_target_properties(SDL2::SDL2test PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${SDL2_TEST_LIBRARY}"
+ )
+ endif()
+endif()
diff --git a/cmake/SDL_gestureConfig.cmake.in b/cmake/SDL_gestureConfig.cmake.in
new file mode 100644
index 0000000..c1ab70a
--- /dev/null
+++ b/cmake/SDL_gestureConfig.cmake.in
@@ -0,0 +1,7 @@
+@PACKAGE_INIT@
+
+if(NOT TARGET SDL_gesture::SDL_gesture)
+ add_library(SDL_gesture INTERFACE)
+ target_include_directories(SDL_gesture INTERFACE "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@")
+ add_library(SDL_gesture::SDL_gesture ALIAS SDL_gesture)
+endif()
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..8b5b310
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,53 @@
+cmake_minimum_required(VERSION 3.0)
+project(SDL_gesture_tests C)
+
+option(SDLGESTURE_TESTS_STATIC "Link to static SDLx library" OFF)
+
+if(SDLGESTURE_TESTS_STATIC)
+ set(SDL2_COMPONENTS "SDL2-static")
+ set(SDL2_TARGET "SDL2::SDL2-static")
+
+ set(SDL3_COMPONENTS "SDL3-static")
+ set(SDL3_TARGET "SDL3::SDL3-static")
+else()
+ set(SDL2_COMPONENTS "SDL2")
+ set(SDL2_TARGET "SDL2::SDL2")
+
+ set(SDL3_COMPONENTS "SDL3")
+ set(SDL3_TARGET "SDL3::SDL3")
+endif()
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake")
+
+find_package(SDL2 CONFIG COMPONENTS ${SDL2_COMPONENTS} SDL2main SDL2test)
+if(NOT SDL2_FOUND OR NOT TARGET SDL2::SDL2)
+ find_package(PrivateSDL2 MODULE REQUIRED)
+ set(SDL2_TARGET "PrivateSDL2::PrivateSDL2")
+endif()
+if(NOT TARGET SDL2::SDL2main)
+ find_package(SDL2main MODULE QUIET)
+ if(NOT SDL2main_FOUND)
+ add_library(SDL2::SDL2main INTERFACE)
+ endif()
+endif()
+if(NOT TARGET SDL2::SDL2test)
+ find_package(SDL2test MODULE REQUIRED)
+endif()
+
+find_package(SDL3 QUIET CONFIG COMPONENTS ${SDL3_COMPONENTS} SDL3_test)
+if(NOT SDL3_FOUND)
+ message(STATUS "SDL3 not found -> not testing SDL_gesture with SDL3")
+endif()
+
+if(NOT TARGET SDL_gesture::SDL_gesture)
+ find_package(SDL_gesture REQUIRED)
+endif()
+
+add_executable(testgesture_sdl2 testgesture.c)
+target_link_libraries(testgesture_sdl2 PRIVATE SDL2::SDL2test SDL_gesture::SDL_gesture SDL2::SDL2main ${SDL2_TARGET})
+
+if(TARGET ${SDL3_TARGET})
+ add_executable(testgesture_sdl3 testgesture.c)
+ target_compile_definitions(testgesture_sdl3 PRIVATE TESTGESTURE_SDL3)
+ target_link_libraries(testgesture_sdl3 PRIVATE SDL3::SDL3_test SDL_gesture::SDL_gesture ${SDL3_TARGET})
+endif()
diff --git a/test/testgesture.c b/test/testgesture.c
new file mode 100644
index 0000000..1584ee3
--- /dev/null
+++ b/test/testgesture.c
@@ -0,0 +1,316 @@
+/*
+ Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+ 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.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely.
+*/
+
+/* Usage:
+ * Spacebar to begin recording a gesture on all touches.
+ * s to save all touches into "./gestureSave"
+ * l to load all touches from "./gestureSave"
+ */
+
+#if defined(TESTGESTURE_SDL3)
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_test.h>
+#else
+#include "SDL.h"
+#include "SDL_test.h"
+#endif
+
+#define SDL_GESTURE_IMPLEMENTATION 1
+#include "SDL_gesture.h"
+
+#ifdef __EMSCRIPTEN__
+#include <emscripten/emscripten.h>
+#endif
+
+
+#define WIDTH 640
+#define HEIGHT 480
+#define BPP 4
+
+/* MUST BE A POWER OF 2! */
+#define EVENT_BUF_SIZE 256
+
+#define VERBOSE 0
+
+static SDLTest_CommonState *state;
+static SDL_Event events[EVENT_BUF_SIZE];
+static int eventWrite;
+static int colors[7] = { 0xFF, 0xFF00, 0xFF0000, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF };
+static int quitting = 0;
+
+typedef struct
+{
+ float x, y;
+} Point;
+
+typedef struct
+{
+ float ang, r;
+ Point p;
+} Knob;
+
+static Knob knob = { 0.0f, 0.1f, { 0.0f, 0.0f } };
+
+static void
+setpix(SDL_Surface *screen, float _x, float _y, unsigned int col)
+{
+ Uint32 *pixmem32;
+ Uint32 colour;
+ Uint8 r, g, b;
+ const int x = (int)_x;
+ const int y = (int)_y;
+ float a;
+
+ if ((x < 0) || (x >= screen->w) || (y < 0) || (y >= screen->h)) {
+ return;
+ }
+
+ pixmem32 = (Uint32 *)screen->pixels + y * screen->pitch / BPP + x;
+
+ SDL_memcpy(&colour, pixmem32, screen->format->BytesPerPixel);
+
+ SDL_GetRGB(colour, screen->format, &r, &g, &b);
+
+ /* r = 0;g = 0; b = 0; */
+ a = (float)((col >> 24) & 0xFF);
+ if (a == 0) {
+ a = 0xFF; /* Hack, to make things easier. */
+ }
+
+ a = (a == 0.0f) ? 1 : (a / 255.0f);
+ r = (Uint8)(r * (1 - a) + ((col >> 16) & 0xFF) * a);
+ g = (Uint8)(g * (1 - a) + ((col >> 8) & 0xFF) * a);
+ b = (Uint8)(b * (1 - a) + ((col >> 0) & 0xFF) * a);
+ colour = SDL_MapRGB(screen->format, r, g, b);
+
+ *pixmem32 = colour;
+}
+
+#if 0 /* unused */
+static void
+drawLine(SDL_Surface *screen, float x0, float y0, float x1, float y1, unsigned int col)
+{
+ float t;
+ for (t = 0; t < 1; t += (float) (1.0f / SDL_max(SDL_fabs(x0 - x1), SDL_fabs(y0 - y1)))) {
+ setpix(screen, x1 + t * (x0 - x1), y1 + t * (y0 - y1), col);
+ }
+}
+#endif
+
+static void
+drawCircle(SDL_Surface *screen, float x, float y, float r, unsigned int c)
+{
+ float tx, ty, xr;
+ for (ty = (float)-SDL_fabs(r); ty <= (float)SDL_fabs((int)r); ty++) {
+ xr = (float)SDL_sqrt(r * r - ty * ty);
+ if (r > 0) { /* r > 0 ==> filled circle */
+ for (tx = -xr + 0.5f; tx <= xr - 0.5f; tx++) {
+ setpix(screen, x + tx, y + ty, c);
+ }
+ } else {
+ setpix(screen, x - xr + 0.5f, y + ty, c);
+ setpix(screen, x + xr - 0.5f, y + ty, c);
+ }
+ }
+}
+
+static void
+drawKnob(SDL_Surface *screen, const Knob *k)
+{
+ drawCircle(screen, k->p.x * screen->w, k->p.y * screen->h, k->r * screen->w, 0xFFFFFF);
+ drawCircle(screen, (k->p.x + k->r / 2 * SDL_cosf(k->ang)) * screen->w,
+ (k->p.y + k->r / 2 * SDL_sinf(k->ang)) * screen->h, k->r / 4 * screen->w, 0);
+}
+
+static void
+DrawScreen(SDL_Window *window)
+{
+ SDL_Surface *screen = SDL_GetWindowSurface(window);
+ int i;
+
+ if (screen == NULL) {
+ return;
+ }
+
+ SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 75, 75, 75));
+
+ /* draw Touch History */
+ for (i = eventWrite; i < eventWrite + EVENT_BUF_SIZE; ++i) {
+ const SDL_Event *event = &events[i & (EVENT_BUF_SIZE - 1)];
+ const float age = (float)(i - eventWrite) / EVENT_BUF_SIZE;
+ float x, y;
+ unsigned int c, col;
+
+ if ((event->type == SDL_FINGERMOTION) ||
+ (event->type == SDL_FINGERDOWN) ||
+ (event->type == SDL_FINGERUP)) {
+ x = event->tfinger.x;
+ y = event->tfinger.y;
+
+ /* draw the touch: */
+ c = colors[event->tfinger.fingerId % 7];
+ col = ((unsigned int)(c * (0.1f + 0.85f))) | (unsigned int)(0xFF * age) << 24;
+
+ if (event->type == SDL_FINGERMOTION) {
+ drawCircle(screen, x * screen->w, y * screen->h, 5, col);
+ } else if (event->type == SDL_FINGERDOWN) {
+ drawCircle(screen, x * screen->w, y * screen->h, -10, col);
+ }
+ }
+ }
+
+ if (knob.p.x > 0) {
+ drawKnob(screen, &knob);
+ }
+
+ SDL_UpdateWindowSurface(window);
+}
+
+static void
+loop(void)
+{
+ union {
+ SDL_Event event;
+ Gesture_MultiGestureEvent mgesture;
+ Gesture_DollarGestureEvent dgesture;
+ } u_event;
+ SDL_RWops *stream;
+ int i;
+
+ while (SDL_PollEvent(&u_event.event)) {
+ SDLTest_CommonEvent(state, &u_event.event, &quitting);
+
+ /* Record _all_ events */
+ events[eventWrite & (EVENT_BUF_SIZE - 1)] = u_event.event;
+ eventWrite++;
+
+ switch (u_event.event.type) {
+ case SDL_KEYDOWN:
+ switch (u_event.event.key.keysym.sym) {
+ case SDLK_i:
+ {
+ for (i = 0; i < SDL_GetNumTouchDevices(); ++i) {
+ const SDL_TouchID id = SDL_GetTouchDevice(i);
+#if SDL_VERSION_ATLEAST(2, 22, 0)
+ const char *name = SDL_GetTouchName(i);
+#else
+ const char *name = "<unknown>";
+#endif
+ SDL_Log("Fingers Down on device %" SDL_PRIs64 " (%s): %d", id, name, SDL_GetNumTouchFingers(id));
+ }
+ break;
+ }
+
+ case SDLK_SPACE:
+ Gesture_RecordGesture(-1);
+ break;
+
+ case SDLK_s:
+ stream = SDL_RWFromFile("gestureSave", "w");
+ SDL_Log("Wrote %i templates", Gesture_SaveAllDollarTemplates(stream));
+ SDL_RWclose(stream);
+ break;
+
+ case SDLK_l:
+ stream = SDL_RWFromFile("gestureSave", "r");
+ SDL_Log("Loaded: %i", Gesture_LoadDollarTemplates(-1, stream));
+ SDL_RWclose(stream);
+ break;
+ }
+ break;
+
+#if VERBOSE
+ case SDL_FINGERMOTION:
+ SDL_Log("Finger: %" SDL_PRIs64 ", x: %f, y: %f", u_event.event.tfinger.fingerId,
+ u_event.event.tfinger.x, u_event.event.tfinger.y);
+ break;
+
+ case SDL_FINGERDOWN:
+ SDL_Log("Finger: %" SDL_PRIs64 " down - x: %f, y: %f",
+ u_event.event.tfinger.fingerId, u_event.event.tfinger.x, u_event.event.tfinger.y);
+ break;
+
+ case SDL_FINGERUP:
+ SDL_Log("Finger: %" SDL_PRIs64 " up - x: %f, y: %f",
+ u_event.event.tfinger.fingerId, u_event.event.tfinger.x, u_event.event.tfinger.y);
+ break;
+#endif
+
+ case GESTURE_MULTIGESTURE:
+#if VERBOSE
+ SDL_Log("Multi Gesture: x = %f, y = %f, dAng = %f, dR = %f",
+ u_event.mgesture.x, u_event.mgesture.y,
+ u_event.mgesture.dTheta, u_event.mgesture.dDist);
+ SDL_Log("MG: numDownTouch = %i", u_event.mgesture.numFingers);
+#endif
+
+ knob.p.x = u_event.mgesture.x;
+ knob.p.y = u_event.mgesture.y;
+ knob.ang += u_event.mgesture.dTheta;
+ knob.r += u_event.mgesture.dDist;
+ break;
+
+ case GESTURE_DOLLARGESTURE:
+ SDL_Log("Gesture %" SDL_PRIs64 " performed, error: %f",
+ u_event.dgesture.gestureId, u_event.dgesture.error);
+ break;
+
+ case GESTURE_DOLLARRECORD:
+ SDL_Log("Recorded gesture: %" SDL_PRIs64 "", u_event.dgesture.gestureId);
+ break;
+ }
+ }
+
+ for (i = 0; i < state->num_windows; ++i) {
+ if (state->windows[i]) {
+ DrawScreen(state->windows[i]);
+ }
+ }
+
+#ifdef __EMSCRIPTEN__
+ if (quitting) {
+ emscripten_cancel_main_loop();
+ }
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
+ if (state == NULL) {
+ return 1;
+ }
+ Gesture_Init();
+
+ state->window_title = "Gesture Test";
+ state->window_w = WIDTH;
+ state->window_h = HEIGHT;
+ state->skip_renderer = SDL_TRUE;
+
+ if (!SDLTest_CommonDefaultArgs(state, argc, argv) || !SDLTest_CommonInit(state)) {
+ Gesture_Quit();
+ SDLTest_CommonQuit(state);
+ return 1;
+ }
+
+#ifdef __EMSCRIPTEN__
+ emscripten_set_main_loop(loop, 0, 1);
+#else
+ while (!quitting) {
+ loop();
+ }
+#endif
+ Gesture_Quit();
+ SDLTest_CommonQuit(state);
+ return 0;
+}
+