sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_gesture.c (22792B)


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