src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 17 Apr 2014 19:52:15 -0700
changeset 8705 fee2f7e242a1
parent 8296 cb13016bf07b
child 8726 9a5a5808aa14
permissions -rw-r--r--
Fixed bug 2503 - Loop indexing and event union errors in SDL_gesture.c

Lasse Öörni

While enabling $1 gesture support in the Urho3D engine which uses SDL2 I detected some errors in the gesture code in SDL_gesture.c:

- In the function SDL_SaveAllDollarTemplates() the following line should use index variable j instead of i:

rtrn += SaveTemplate(&touch->dollarTemplate[i], dst);

- In the function SDL_SaveDollarTemplate() the following code should use index variable j instead of i:

if (touch->dollarTemplate[i].hash == gestureId) {
return SaveTemplate(&touch->dollarTemplate[i], dst);

- In the function SDL_SendGestureDollar() the x & y coordinates are being written to the mgesture structure, which results in garbage due to dgesture and mgesture being different data structures inside the union. The coordinates should be written to dgesture.x & dgesture.y respectively
jim@4657
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
jim@4657
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
jim@4657
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
jim@4657
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
philipp@7252
    14
     claim that you wrote the original software. If you use this software
philipp@7252
    15
     in a product, an acknowledgment in the product documentation would be
philipp@7252
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
philipp@7252
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
jim@4657
    20
*/
aschiffler@4865
    21
icculus@8093
    22
#include "../SDL_internal.h"
jim@4657
    23
jim@4657
    24
/* General mouse handling code for SDL */
jim@4657
    25
jim@4657
    26
#include "SDL_events.h"
jim@4657
    27
#include "SDL_events_c.h"
jim@4657
    28
#include "SDL_gesture_c.h"
jim@4657
    29
kimonline@7009
    30
#if !defined(__PSP__)
aschiffler@4865
    31
#include <memory.h>
kimonline@7009
    32
#endif
kimonline@7009
    33
aschiffler@4865
    34
#include <string.h>
aschiffler@4865
    35
#include <stdio.h>
aschiffler@4865
    36
#include <math.h>
aschiffler@4865
    37
slouken@7191
    38
/* TODO: Replace with malloc */
jim@4688
    39
jim@4658
    40
#define MAXPATHSIZE 1024
jim@4658
    41
jim@4658
    42
#define DOLLARNPOINTS 64
jim@4658
    43
#define DOLLARSIZE 256
jim@4658
    44
jim@4684
    45
#define ENABLE_DOLLAR
jim@4684
    46
kees@6065
    47
#define PHI 0.618033989
jim@4657
    48
jim@4657
    49
typedef struct {
kees@6065
    50
    float x,y;
jim@4688
    51
} SDL_FloatPoint;
jim@4658
    52
jim@4658
    53
typedef struct {
kees@6065
    54
    float length;
kees@6065
    55
kees@6065
    56
    int numPoints;
kees@6065
    57
    SDL_FloatPoint p[MAXPATHSIZE];
jim@4688
    58
} SDL_DollarPath;
jim@4658
    59
jim@4657
    60
typedef struct {
kees@6065
    61
    SDL_FloatPoint path[DOLLARNPOINTS];
kees@6065
    62
    unsigned long hash;
jim@4688
    63
} SDL_DollarTemplate;
jim@4657
    64
jim@4657
    65
typedef struct {
kees@6069
    66
    SDL_TouchID id;
kees@6065
    67
    SDL_FloatPoint centroid;
kees@6065
    68
    SDL_DollarPath dollarPath;
kees@6065
    69
    Uint16 numDownFingers;
jim@4658
    70
kees@6065
    71
    int numDollarTemplates;
kees@6065
    72
    SDL_DollarTemplate *dollarTemplate;
jim@4659
    73
kees@6065
    74
    SDL_bool recording;
jim@4688
    75
} SDL_GestureTouch;
jim@4657
    76
jim@4688
    77
SDL_GestureTouch *SDL_gestureTouch;
jim@4688
    78
int SDL_numGestureTouches = 0;
jim@4659
    79
SDL_bool recordAll;
jim@4659
    80
slouken@4868
    81
#if 0
kees@6065
    82
static void PrintPath(SDL_FloatPoint *path)
kees@6065
    83
{
kees@6065
    84
    int i;
kees@6065
    85
    printf("Path:");
kees@6066
    86
    for (i=0; i<DOLLARNPOINTS; i++) {
kees@6065
    87
        printf(" (%f,%f)",path[i].x,path[i].y);
kees@6065
    88
    }
kees@6065
    89
    printf("\n");
jim@4685
    90
}
slouken@4868
    91
#endif
jim@4685
    92
kees@6065
    93
int SDL_RecordGesture(SDL_TouchID touchId)
kees@6065
    94
{
kees@6065
    95
    int i;
kees@6066
    96
    if (touchId < 0) recordAll = SDL_TRUE;
kees@6066
    97
    for (i = 0; i < SDL_numGestureTouches; i++) {
kees@6066
    98
        if ((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
kees@6065
    99
            SDL_gestureTouch[i].recording = SDL_TRUE;
kees@6066
   100
            if (touchId >= 0)
kees@6065
   101
                return 1;
kees@6065
   102
        }
kees@6065
   103
    }
kees@6065
   104
    return (touchId < 0);
jim@4659
   105
}
jim@4659
   106
icculus@6070
   107
static unsigned long SDL_HashDollar(SDL_FloatPoint* points)
kees@6065
   108
{
kees@6065
   109
    unsigned long hash = 5381;
kees@6065
   110
    int i;
kees@6066
   111
    for (i = 0; i < DOLLARNPOINTS; i++) {
kees@6065
   112
        hash = ((hash<<5) + hash) + (unsigned long)points[i].x;
kees@6065
   113
        hash = ((hash<<5) + hash) + (unsigned long)points[i].y;
kees@6065
   114
    }
kees@6065
   115
    return hash;
jim@4659
   116
}
jim@4659
   117
jim@4665
   118
philipp@7900
   119
static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops *dst)
kees@6065
   120
{
philipp@7900
   121
    if (dst == NULL) return 0;
jim@4682
   122
gabomdq@7678
   123
    /* No Longer storing the Hash, rehash on load */
philipp@7900
   124
    /* if (SDL_RWops.write(dst, &(templ->hash), sizeof(templ->hash), 1) != 1) return 0; */
kees@6065
   125
philipp@7900
   126
    if (SDL_RWwrite(dst, templ->path,
kees@6066
   127
                    sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS)
kees@6065
   128
        return 0;
kees@6065
   129
kees@6065
   130
    return 1;
jim@4659
   131
}
jim@4659
   132
jim@4659
   133
philipp@7900
   134
int SDL_SaveAllDollarTemplates(SDL_RWops *dst)
kees@6065
   135
{
kees@6065
   136
    int i,j,rtrn = 0;
kees@6066
   137
    for (i = 0; i < SDL_numGestureTouches; i++) {
kees@6065
   138
        SDL_GestureTouch* touch = &SDL_gestureTouch[i];
kees@6066
   139
        for (j = 0; j < touch->numDollarTemplates; j++) {
slouken@8705
   140
            rtrn += SaveTemplate(&touch->dollarTemplate[j], dst);
kees@6065
   141
        }
jim@4659
   142
    }
kees@6065
   143
    return rtrn;
jim@4659
   144
}
jim@4659
   145
philipp@7900
   146
int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *dst)
kees@6065
   147
{
kees@6065
   148
    int i,j;
kees@6066
   149
    for (i = 0; i < SDL_numGestureTouches; i++) {
kees@6065
   150
        SDL_GestureTouch* touch = &SDL_gestureTouch[i];
kees@6066
   151
        for (j = 0; j < touch->numDollarTemplates; j++) {
kees@6066
   152
            if (touch->dollarTemplate[i].hash == gestureId) {
slouken@8705
   153
                return SaveTemplate(&touch->dollarTemplate[j], dst);
kees@6065
   154
            }
kees@6065
   155
        }
jim@4659
   156
    }
icculus@7037
   157
    return SDL_SetError("Unknown gestureId");
slouken@4663
   158
}
slouken@4663
   159
gabomdq@7678
   160
/* path is an already sampled set of points
gabomdq@7677
   161
Returns the index of the gesture on success, or -1 */
kees@6067
   162
static int SDL_AddDollarGesture_one(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
kees@6065
   163
{
kees@6065
   164
    SDL_DollarTemplate* dollarTemplate;
kees@6065
   165
    SDL_DollarTemplate *templ;
kees@6067
   166
    int index;
kees@6067
   167
kees@6067
   168
    index = inTouch->numDollarTemplates;
kees@6067
   169
    dollarTemplate =
kees@6067
   170
        (SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
kees@6067
   171
                                          (index + 1) *
kees@6067
   172
                                          sizeof(SDL_DollarTemplate));
kees@6067
   173
    if (!dollarTemplate) {
icculus@7037
   174
        return SDL_OutOfMemory();
kees@6067
   175
    }
kees@6067
   176
    inTouch->dollarTemplate = dollarTemplate;
kees@6067
   177
kees@6067
   178
    templ = &inTouch->dollarTemplate[index];
kees@6067
   179
    SDL_memcpy(templ->path, path, DOLLARNPOINTS*sizeof(SDL_FloatPoint));
kees@6067
   180
    templ->hash = SDL_HashDollar(templ->path);
kees@6067
   181
    inTouch->numDollarTemplates++;
kees@6067
   182
kees@6067
   183
    return index;
kees@6067
   184
}
kees@6067
   185
kees@6067
   186
static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
kees@6067
   187
{
icculus@6071
   188
    int index = -1;
kees@6065
   189
    int i = 0;
kees@6066
   190
    if (inTouch == NULL) {
kees@6066
   191
        if (SDL_numGestureTouches == 0) return -1;
kees@6066
   192
        for (i = 0; i < SDL_numGestureTouches; i++) {
kees@6065
   193
            inTouch = &SDL_gestureTouch[i];
kees@6067
   194
            index = SDL_AddDollarGesture_one(inTouch, path);
kees@6067
   195
            if (index < 0)
kees@6065
   196
                return -1;
kees@6065
   197
        }
gabomdq@7677
   198
        /* Use the index of the last one added. */
kees@6067
   199
        return index;
slouken@4663
   200
    }
philipp@7899
   201
    return SDL_AddDollarGesture_one(inTouch, path);
jim@4659
   202
}
jim@4659
   203
kees@6065
   204
int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
kees@6065
   205
{
kees@6065
   206
    int i,loaded = 0;
kees@6065
   207
    SDL_GestureTouch *touch = NULL;
kees@6066
   208
    if (src == NULL) return 0;
kees@6066
   209
    if (touchId >= 0) {
kees@6066
   210
        for (i = 0; i < SDL_numGestureTouches; i++)
kees@6066
   211
            if (SDL_gestureTouch[i].id == touchId)
kees@6065
   212
                touch = &SDL_gestureTouch[i];
kees@6066
   213
        if (touch == NULL) return -1;
kees@6065
   214
    }
jim@4659
   215
kees@6066
   216
    while (1) {
kees@6065
   217
        SDL_DollarTemplate templ;
jim@4688
   218
kees@6066
   219
        if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) <
kees@6065
   220
           DOLLARNPOINTS) break;
jim@4659
   221
kees@6066
   222
        if (touchId >= 0) {
gabomdq@7678
   223
            /* printf("Adding loaded gesture to 1 touch\n"); */
kees@6068
   224
            if (SDL_AddDollarGesture(touch, templ.path) >= 0)
kees@6068
   225
                loaded++;
kees@6065
   226
        }
kees@6065
   227
        else {
gabomdq@7678
   228
            /* printf("Adding to: %i touches\n",SDL_numGestureTouches); */
kees@6066
   229
            for (i = 0; i < SDL_numGestureTouches; i++) {
kees@6065
   230
                touch = &SDL_gestureTouch[i];
gabomdq@7678
   231
                /* printf("Adding loaded gesture to + touches\n"); */
gabomdq@7678
   232
                /* TODO: What if this fails? */
kees@6065
   233
                SDL_AddDollarGesture(touch,templ.path);
kees@6065
   234
            }
kees@6065
   235
            loaded++;
kees@6065
   236
        }
jim@4659
   237
    }
jim@4659
   238
kees@6065
   239
    return loaded;
jim@4659
   240
}
jim@4659
   241
jim@4659
   242
icculus@6070
   243
static float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang)
kees@6065
   244
{
gabomdq@7677
   245
    /*  SDL_FloatPoint p[DOLLARNPOINTS]; */
kees@6065
   246
    float dist = 0;
kees@6065
   247
    SDL_FloatPoint p;
kees@6065
   248
    int i;
kees@6066
   249
    for (i = 0; i < DOLLARNPOINTS; i++) {
kees@6065
   250
        p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
kees@6065
   251
        p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
kees@6065
   252
        dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
kees@6065
   253
                                 (p.y-templ[i].y)*(p.y-templ[i].y)));
kees@6065
   254
    }
kees@6065
   255
    return dist/DOLLARNPOINTS;
kees@6065
   256
jim@4658
   257
}
jim@4658
   258
icculus@6070
   259
static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ)
kees@6065
   260
{
gabomdq@7662
   261
    /*------------BEGIN DOLLAR BLACKBOX------------------
gabomdq@7662
   262
      -TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-
gabomdq@7662
   263
      -"http://depts.washington.edu/aimgroup/proj/dollar/"
gabomdq@7662
   264
    */
kees@6065
   265
    double ta = -M_PI/4;
kees@6065
   266
    double tb = M_PI/4;
kees@6065
   267
    double dt = M_PI/90;
kees@6065
   268
    float x1 = (float)(PHI*ta + (1-PHI)*tb);
kees@6065
   269
    float f1 = dollarDifference(points,templ,x1);
kees@6065
   270
    float x2 = (float)((1-PHI)*ta + PHI*tb);
kees@6065
   271
    float f2 = dollarDifference(points,templ,x2);
kees@6066
   272
    while (SDL_fabs(ta-tb) > dt) {
kees@6066
   273
        if (f1 < f2) {
kees@6065
   274
            tb = x2;
kees@6065
   275
            x2 = x1;
kees@6065
   276
            f2 = f1;
kees@6065
   277
            x1 = (float)(PHI*ta + (1-PHI)*tb);
kees@6065
   278
            f1 = dollarDifference(points,templ,x1);
kees@6065
   279
        }
kees@6065
   280
        else {
kees@6065
   281
            ta = x1;
kees@6065
   282
            x1 = x2;
kees@6065
   283
            f1 = f2;
kees@6065
   284
            x2 = (float)((1-PHI)*ta + PHI*tb);
kees@6065
   285
            f2 = dollarDifference(points,templ,x2);
kees@6065
   286
        }
jim@4658
   287
    }
kees@6065
   288
    /*
kees@6066
   289
      if (f1 <= f2)
kees@6066
   290
          printf("Min angle (x1): %f\n",x1);
kees@6066
   291
      else if (f1 >  f2)
kees@6066
   292
          printf("Min angle (x2): %f\n",x2);
kees@6065
   293
    */
kees@6065
   294
    return SDL_min(f1,f2);
jim@4658
   295
}
jim@4658
   296
gabomdq@7678
   297
/* DollarPath contains raw points, plus (possibly) the calculated length */
icculus@6070
   298
static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
kees@6065
   299
{
kees@6065
   300
    int i;
kees@6065
   301
    float interval;
kees@6065
   302
    float dist;
kees@6065
   303
    int numPoints = 0;
kees@6065
   304
    SDL_FloatPoint centroid;
kees@6065
   305
    float xmin,xmax,ymin,ymax;
kees@6065
   306
    float ang;
kees@6065
   307
    float w,h;
kees@6065
   308
    float length = path->length;
aschiffler@4865
   309
gabomdq@7678
   310
    /* Calculate length if it hasn't already been done */
kees@6066
   311
    if (length <= 0) {
kees@6066
   312
        for (i=1;i < path->numPoints; i++) {
kees@6066
   313
            float dx = path->p[i  ].x - path->p[i-1].x;
kees@6066
   314
            float dy = path->p[i  ].y - path->p[i-1].y;
kees@6065
   315
            length += (float)(SDL_sqrt(dx*dx+dy*dy));
kees@6065
   316
        }
jim@4658
   317
    }
jim@4658
   318
gabomdq@7678
   319
    /* Resample */
kees@6065
   320
    interval = length/(DOLLARNPOINTS - 1);
kees@6065
   321
    dist = interval;
jim@4658
   322
kees@6065
   323
    centroid.x = 0;centroid.y = 0;
jim@4658
   324
gabomdq@7678
   325
    /* printf("(%f,%f)\n",path->p[path->numPoints-1].x,path->p[path->numPoints-1].y); */
kees@6066
   326
    for (i = 1; i < path->numPoints; i++) {
kees@6065
   327
        float d = (float)(SDL_sqrt((path->p[i-1].x-path->p[i].x)*(path->p[i-1].x-path->p[i].x)+
kees@6065
   328
                                   (path->p[i-1].y-path->p[i].y)*(path->p[i-1].y-path->p[i].y)));
gabomdq@7678
   329
        /* printf("d = %f dist = %f/%f\n",d,dist,interval); */
kees@6066
   330
        while (dist + d > interval) {
kees@6065
   331
            points[numPoints].x = path->p[i-1].x +
kees@6065
   332
                ((interval-dist)/d)*(path->p[i].x-path->p[i-1].x);
kees@6065
   333
            points[numPoints].y = path->p[i-1].y +
kees@6065
   334
                ((interval-dist)/d)*(path->p[i].y-path->p[i-1].y);
kees@6065
   335
            centroid.x += points[numPoints].x;
kees@6065
   336
            centroid.y += points[numPoints].y;
kees@6065
   337
            numPoints++;
kees@6065
   338
kees@6065
   339
            dist -= interval;
kees@6065
   340
        }
kees@6065
   341
        dist += d;
jim@4658
   342
    }
kees@6066
   343
    if (numPoints < DOLLARNPOINTS-1) {
kees@6065
   344
        SDL_SetError("ERROR: NumPoints = %i\n",numPoints);
kees@6065
   345
        return 0;
kees@6065
   346
    }
gabomdq@7678
   347
    /* copy the last point */
kees@6065
   348
    points[DOLLARNPOINTS-1] = path->p[path->numPoints-1];
kees@6065
   349
    numPoints = DOLLARNPOINTS;
jim@4685
   350
kees@6065
   351
    centroid.x /= numPoints;
kees@6065
   352
    centroid.y /= numPoints;
jim@4658
   353
gabomdq@7678
   354
    /* printf("Centroid (%f,%f)",centroid.x,centroid.y); */
gabomdq@7678
   355
    /* Rotate Points so point 0 is left of centroid and solve for the bounding box */
kees@6065
   356
    xmin = centroid.x;
kees@6065
   357
    xmax = centroid.x;
kees@6065
   358
    ymin = centroid.y;
kees@6065
   359
    ymax = centroid.y;
jim@4658
   360
kees@6065
   361
    ang = (float)(SDL_atan2(centroid.y - points[0].y,
kees@6065
   362
                            centroid.x - points[0].x));
jim@4658
   363
kees@6066
   364
    for (i = 0; i<numPoints; i++) {
kees@6065
   365
        float px = points[i].x;
kees@6065
   366
        float py = points[i].y;
kees@6065
   367
        points[i].x = (float)((px - centroid.x)*SDL_cos(ang) -
kees@6065
   368
                              (py - centroid.y)*SDL_sin(ang) + centroid.x);
kees@6065
   369
        points[i].y = (float)((px - centroid.x)*SDL_sin(ang) +
kees@6065
   370
                              (py - centroid.y)*SDL_cos(ang) + centroid.y);
jim@4658
   371
jim@4658
   372
kees@6066
   373
        if (points[i].x < xmin) xmin = points[i].x;
kees@6066
   374
        if (points[i].x > xmax) xmax = points[i].x;
kees@6066
   375
        if (points[i].y < ymin) ymin = points[i].y;
kees@6066
   376
        if (points[i].y > ymax) ymax = points[i].y;
kees@6065
   377
    }
kees@6065
   378
gabomdq@7678
   379
    /* Scale points to DOLLARSIZE, and translate to the origin */
kees@6065
   380
    w = xmax-xmin;
kees@6065
   381
    h = ymax-ymin;
kees@6065
   382
kees@6066
   383
    for (i=0; i<numPoints; i++) {
kees@6065
   384
        points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
kees@6065
   385
        points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
kees@6065
   386
    }
kees@6065
   387
    return numPoints;
jim@4658
   388
}
jim@4658
   389
icculus@6070
   390
static float dollarRecognize(const SDL_DollarPath *path,int *bestTempl,SDL_GestureTouch* touch)
kees@6065
   391
{
jorgen@7510
   392
    SDL_FloatPoint points[DOLLARNPOINTS];
kees@6065
   393
    int i;
kees@6065
   394
    float bestDiff = 10000;
icculus@5981
   395
jorgen@7510
   396
    SDL_memset(points, 0, sizeof(points));
jorgen@7510
   397
kees@6065
   398
    dollarNormalize(path,points);
kees@6065
   399
gabomdq@7678
   400
    /* PrintPath(points); */
kees@6065
   401
    *bestTempl = -1;
kees@6066
   402
    for (i = 0; i < touch->numDollarTemplates; i++) {
kees@6065
   403
        float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
kees@6066
   404
        if (diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
kees@6065
   405
    }
kees@6065
   406
    return bestDiff;
slouken@4663
   407
}
slouken@4663
   408
slouken@6951
   409
int SDL_GestureAddTouch(SDL_TouchID touchId)
kees@6065
   410
{
kees@6065
   411
    SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
kees@6065
   412
                                                                     (SDL_numGestureTouches + 1) *
kees@6065
   413
                                                                     sizeof(SDL_GestureTouch));
jim@4657
   414
kees@6066
   415
    if (!gestureTouch) {
icculus@7037
   416
        return SDL_OutOfMemory();
kees@6065
   417
    }
jim@4657
   418
kees@6065
   419
    SDL_gestureTouch = gestureTouch;
jim@4658
   420
slouken@8296
   421
    SDL_zero(SDL_gestureTouch[SDL_numGestureTouches]);
slouken@6951
   422
    SDL_gestureTouch[SDL_numGestureTouches].id = touchId;
kees@6065
   423
    SDL_numGestureTouches++;
kees@6065
   424
    return 0;
jim@4657
   425
}
jim@4657
   426
icculus@6070
   427
static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
kees@6065
   428
{
kees@6065
   429
    int i;
kees@6066
   430
    for (i = 0; i < SDL_numGestureTouches; i++) {
gabomdq@7678
   431
        /* printf("%i ?= %i\n",SDL_gestureTouch[i].id,id); */
kees@6066
   432
        if (SDL_gestureTouch[i].id == id)
kees@6066
   433
            return &SDL_gestureTouch[i];
kees@6065
   434
    }
kees@6065
   435
    return NULL;
jim@4657
   436
}
jim@4657
   437
kees@6065
   438
int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
kees@6065
   439
{
kees@6065
   440
    SDL_Event event;
kees@6065
   441
    event.mgesture.type = SDL_MULTIGESTURE;
kees@6065
   442
    event.mgesture.touchId = touch->id;
kees@6065
   443
    event.mgesture.x = touch->centroid.x;
kees@6065
   444
    event.mgesture.y = touch->centroid.y;
kees@6065
   445
    event.mgesture.dTheta = dTheta;
kees@6065
   446
    event.mgesture.dDist = dDist;
kees@6065
   447
    event.mgesture.numFingers = touch->numDownFingers;
kees@6065
   448
    return SDL_PushEvent(&event) > 0;
jim@4657
   449
}
jim@4657
   450
slouken@6044
   451
static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
kees@6065
   452
                          SDL_GestureID gestureId,float error)
kees@6065
   453
{
kees@6065
   454
    SDL_Event event;
kees@6065
   455
    event.dgesture.type = SDL_DOLLARGESTURE;
kees@6065
   456
    event.dgesture.touchId = touch->id;
slouken@8705
   457
    event.dgesture.x = touch->centroid.x;
slouken@8705
   458
    event.dgesture.y = touch->centroid.y;
kees@6065
   459
    event.dgesture.gestureId = gestureId;
kees@6065
   460
    event.dgesture.error = error;
gabomdq@7678
   461
    /* A finger came up to trigger this event. */
kees@6065
   462
    event.dgesture.numFingers = touch->numDownFingers + 1;
kees@6065
   463
    return SDL_PushEvent(&event) > 0;
jim@4658
   464
}
jim@4658
   465
jim@4659
   466
icculus@6070
   467
static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
kees@6065
   468
{
kees@6065
   469
    SDL_Event event;
kees@6065
   470
    event.dgesture.type = SDL_DOLLARRECORD;
kees@6065
   471
    event.dgesture.touchId = touch->id;
kees@6065
   472
    event.dgesture.gestureId = gestureId;
kees@6065
   473
    return SDL_PushEvent(&event) > 0;
jim@4659
   474
}
jim@4659
   475
jim@4659
   476
jim@4657
   477
void SDL_GestureProcessEvent(SDL_Event* event)
jim@4657
   478
{
kees@6065
   479
    float x,y;
kees@6065
   480
    SDL_FloatPoint path[DOLLARNPOINTS];
kees@6065
   481
    int index;
kees@6065
   482
    int i;
kees@6065
   483
    float pathDx, pathDy;
kees@6065
   484
    SDL_FloatPoint lastP;
kees@6065
   485
    SDL_FloatPoint lastCentroid;
kees@6065
   486
    float lDist;
kees@6065
   487
    float Dist;
kees@6065
   488
    float dtheta;
kees@6065
   489
    float dDist;
aschiffler@4865
   490
kees@6066
   491
    if (event->type == SDL_FINGERMOTION ||
kees@6066
   492
        event->type == SDL_FINGERDOWN ||
kees@6066
   493
        event->type == SDL_FINGERUP) {
kees@6065
   494
        SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
jim@4683
   495
gabomdq@7678
   496
        /* Shouldn't be possible */
kees@6066
   497
        if (inTouch == NULL) return;
jim@4658
   498
slouken@6951
   499
        x = event->tfinger.x;
slouken@6951
   500
        y = event->tfinger.y;
kees@6065
   501
gabomdq@7678
   502
        /* Finger Up */
kees@6066
   503
        if (event->type == SDL_FINGERUP) {
kees@6065
   504
            inTouch->numDownFingers--;
jim@4688
   505
jim@4684
   506
#ifdef ENABLE_DOLLAR
kees@6066
   507
            if (inTouch->recording) {
kees@6065
   508
                inTouch->recording = SDL_FALSE;
kees@6065
   509
                dollarNormalize(&inTouch->dollarPath,path);
gabomdq@7678
   510
                /* PrintPath(path); */
kees@6066
   511
                if (recordAll) {
kees@6065
   512
                    index = SDL_AddDollarGesture(NULL,path);
kees@6066
   513
                    for (i = 0; i < SDL_numGestureTouches; i++)
kees@6065
   514
                        SDL_gestureTouch[i].recording = SDL_FALSE;
kees@6065
   515
                }
kees@6065
   516
                else {
kees@6065
   517
                    index = SDL_AddDollarGesture(inTouch,path);
kees@6065
   518
                }
kees@6065
   519
kees@6066
   520
                if (index >= 0) {
kees@6065
   521
                    SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
kees@6065
   522
                }
kees@6065
   523
                else {
kees@6065
   524
                    SDL_SendDollarRecord(inTouch,-1);
kees@6065
   525
                }
kees@6065
   526
            }
kees@6065
   527
            else {
kees@6065
   528
                int bestTempl;
kees@6065
   529
                float error;
kees@6065
   530
                error = dollarRecognize(&inTouch->dollarPath,
kees@6065
   531
                                        &bestTempl,inTouch);
kees@6066
   532
                if (bestTempl >= 0){
gabomdq@7678
   533
                    /* Send Event */
kees@6065
   534
                    unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
kees@6065
   535
                    SDL_SendGestureDollar(inTouch,gestureId,error);
gabomdq@7678
   536
                    /* printf ("%s\n",);("Dollar error: %f\n",error); */
kees@6065
   537
                }
kees@6065
   538
            }
jim@4683
   539
#endif
gabomdq@7678
   540
            /* inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; */
kees@6066
   541
            if (inTouch->numDownFingers > 0) {
kees@6065
   542
                inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
kees@6065
   543
                                       x)/inTouch->numDownFingers;
kees@6065
   544
                inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
kees@6065
   545
                                       y)/inTouch->numDownFingers;
kees@6065
   546
            }
kees@6065
   547
        }
kees@6066
   548
        else if (event->type == SDL_FINGERMOTION) {
slouken@6951
   549
            float dx = event->tfinger.dx;
slouken@6951
   550
            float dy = event->tfinger.dy;
kees@6065
   551
#ifdef ENABLE_DOLLAR
kees@6065
   552
            SDL_DollarPath* path = &inTouch->dollarPath;
kees@6066
   553
            if (path->numPoints < MAXPATHSIZE) {
kees@6065
   554
                path->p[path->numPoints].x = inTouch->centroid.x;
kees@6065
   555
                path->p[path->numPoints].y = inTouch->centroid.y;
kees@6065
   556
                pathDx =
kees@6065
   557
                    (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
kees@6065
   558
                pathDy =
kees@6065
   559
                    (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
kees@6065
   560
                path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
kees@6065
   561
                path->numPoints++;
kees@6065
   562
            }
kees@6065
   563
#endif
kees@6065
   564
            lastP.x = x - dx;
kees@6065
   565
            lastP.y = y - dy;
kees@6065
   566
            lastCentroid = inTouch->centroid;
kees@6065
   567
kees@6065
   568
            inTouch->centroid.x += dx/inTouch->numDownFingers;
kees@6065
   569
            inTouch->centroid.y += dy/inTouch->numDownFingers;
gabomdq@7678
   570
            /* printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y); */
kees@6066
   571
            if (inTouch->numDownFingers > 1) {
gabomdq@7678
   572
                SDL_FloatPoint lv; /* Vector from centroid to last x,y position */
gabomdq@7678
   573
                SDL_FloatPoint v; /* Vector from centroid to current x,y position */
gabomdq@7678
   574
                /* lv = inTouch->gestureLast[j].cv; */
kees@6065
   575
                lv.x = lastP.x - lastCentroid.x;
kees@6065
   576
                lv.y = lastP.y - lastCentroid.y;
kees@6065
   577
                lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
gabomdq@7678
   578
                /* printf("lDist = %f\n",lDist); */
kees@6065
   579
                v.x = x - inTouch->centroid.x;
kees@6065
   580
                v.y = y - inTouch->centroid.y;
gabomdq@7678
   581
                /* inTouch->gestureLast[j].cv = v; */
kees@6065
   582
                Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
gabomdq@7677
   583
                /* SDL_cos(dTheta) = (v . lv)/(|v| * |lv|) */
kees@6065
   584
gabomdq@7678
   585
                /* Normalize Vectors to simplify angle calculation */
kees@6065
   586
                lv.x/=lDist;
kees@6065
   587
                lv.y/=lDist;
kees@6065
   588
                v.x/=Dist;
kees@6065
   589
                v.y/=Dist;
kees@6065
   590
                dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
kees@6065
   591
kees@6065
   592
                dDist = (Dist - lDist);
gabomdq@7678
   593
                if (lDist == 0) {dDist = 0;dtheta = 0;} /* To avoid impossible values */
kees@6065
   594
gabomdq@7678
   595
                /* inTouch->gestureLast[j].dDist = dDist;
gabomdq@7662
   596
                inTouch->gestureLast[j].dtheta = dtheta;
kees@6065
   597
gabomdq@7662
   598
                printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
gabomdq@7662
   599
                gdtheta = gdtheta*.9 + dtheta*.1;
gabomdq@7662
   600
                gdDist  =  gdDist*.9 +  dDist*.1
gabomdq@7662
   601
                knob.r += dDist/numDownFingers;
gabomdq@7662
   602
                knob.ang += dtheta;
gabomdq@7662
   603
                printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
gabomdq@7677
   604
                printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist); */
kees@6065
   605
                SDL_SendGestureMulti(inTouch,dtheta,dDist);
kees@6065
   606
            }
kees@6065
   607
            else {
gabomdq@7678
   608
                /* inTouch->gestureLast[j].dDist = 0;
gabomdq@7662
   609
                inTouch->gestureLast[j].dtheta = 0;
gabomdq@7662
   610
                inTouch->gestureLast[j].cv.x = 0;
gabomdq@7677
   611
                inTouch->gestureLast[j].cv.y = 0; */
kees@6065
   612
            }
gabomdq@7678
   613
            /* inTouch->gestureLast[j].f.p.x = x;
gabomdq@7662
   614
            inTouch->gestureLast[j].f.p.y = y;
gabomdq@7662
   615
            break;
gabomdq@7677
   616
            pressure? */
kees@6065
   617
        }
kees@6065
   618
kees@6066
   619
        if (event->type == SDL_FINGERDOWN) {
kees@6065
   620
kees@6065
   621
            inTouch->numDownFingers++;
kees@6065
   622
            inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
kees@6065
   623
                                   x)/inTouch->numDownFingers;
kees@6065
   624
            inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
kees@6065
   625
                                   y)/inTouch->numDownFingers;
gabomdq@7678
   626
            /* printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
gabomdq@7677
   627
                 inTouch->centroid.x,inTouch->centroid.y); */
kees@6065
   628
kees@6065
   629
#ifdef ENABLE_DOLLAR
kees@6065
   630
            inTouch->dollarPath.length = 0;
kees@6065
   631
            inTouch->dollarPath.p[0].x = x;
kees@6065
   632
            inTouch->dollarPath.p[0].y = y;
kees@6065
   633
            inTouch->dollarPath.numPoints = 1;
kees@6065
   634
#endif
kees@6065
   635
        }
jim@4657
   636
    }
jim@4683
   637
}
jim@4683
   638
kees@6065
   639
/* vi: set ts=4 sw=4 expandtab: */