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