src/events/SDL_gesture.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 18 Feb 2019 07:50:33 -0800
changeset 12612 07c39cbbeacf
parent 12503 806492103856
child 13028 1e4d6b83f946
permissions -rw-r--r--
Fixed bug 4500 - Heap-Buffer Overflow in Map1toN pertaining to SDL_pixels.c

Petr Pisar

The reproducer has these data in BITMAPINFOHEADER:

biSize = 40
biBitCount = 8
biClrUsed = 131075

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