src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 22 Jun 2014 11:02:56 -0700
changeset 8910 c23ffe72934c
parent 8775 047537a5a114
child 9456 2d6ec08030a0
permissions -rw-r--r--
Partial fix for bug 2556 - add compilation flag -Wshadow

I added -Wshadow and then turned it off again because of massive variable shadowing in the blit macros.

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