src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Jun 2015 23:36:06 -0700
changeset 9776 952ff8a5076f
parent 9619 b94b6d0bff0f
child 9791 bf1504455f2a
permissions -rw-r--r--
Fixed bug 3030 - SDL_RecreateWindow fails to restore title, icon, etc.

Adam M.

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