Commit 311a3e94 authored by Ryan C. Gordon's avatar Ryan C. Gordon

Merge from https://bitbucket.org/keestux/sdl ... SDL_gesture code cleanup.

parents a61775dd 8d5ba0eb
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
freely, subject to the following restrictions: freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not 1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be in a product, an acknowledgment in the product documentation would be
appreciated but is not required. appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#define MAXPATHSIZE 1024 #define MAXPATHSIZE 1024
#define DOLLARNPOINTS 64 #define DOLLARNPOINTS 64
...@@ -44,35 +44,35 @@ ...@@ -44,35 +44,35 @@
#define ENABLE_DOLLAR #define ENABLE_DOLLAR
#define PHI 0.618033989 #define PHI 0.618033989
typedef struct { typedef struct {
float x,y; float x,y;
} SDL_FloatPoint; } SDL_FloatPoint;
typedef struct { typedef struct {
float length; float length;
int numPoints; int numPoints;
SDL_FloatPoint p[MAXPATHSIZE]; SDL_FloatPoint p[MAXPATHSIZE];
} SDL_DollarPath; } SDL_DollarPath;
typedef struct { typedef struct {
SDL_FloatPoint path[DOLLARNPOINTS]; SDL_FloatPoint path[DOLLARNPOINTS];
unsigned long hash; unsigned long hash;
} SDL_DollarTemplate; } SDL_DollarTemplate;
typedef struct { typedef struct {
SDL_GestureID id; SDL_TouchID id;
SDL_FloatPoint res; SDL_FloatPoint res;
SDL_FloatPoint centroid; SDL_FloatPoint centroid;
SDL_DollarPath dollarPath; SDL_DollarPath dollarPath;
Uint16 numDownFingers; Uint16 numDownFingers;
int numDollarTemplates; int numDollarTemplates;
SDL_DollarTemplate *dollarTemplate; SDL_DollarTemplate *dollarTemplate;
SDL_bool recording; SDL_bool recording;
} SDL_GestureTouch; } SDL_GestureTouch;
SDL_GestureTouch *SDL_gestureTouch; SDL_GestureTouch *SDL_gestureTouch;
...@@ -80,573 +80,584 @@ int SDL_numGestureTouches = 0; ...@@ -80,573 +80,584 @@ int SDL_numGestureTouches = 0;
SDL_bool recordAll; SDL_bool recordAll;
#if 0 #if 0
static void PrintPath(SDL_FloatPoint *path) { static void PrintPath(SDL_FloatPoint *path)
int i; {
printf("Path:"); int i;
for(i=0;i<DOLLARNPOINTS;i++) { printf("Path:");
printf(" (%f,%f)",path[i].x,path[i].y); for (i=0; i<DOLLARNPOINTS; i++) {
} printf(" (%f,%f)",path[i].x,path[i].y);
printf("\n"); }
printf("\n");
} }
#endif #endif
int SDL_RecordGesture(SDL_TouchID touchId) { int SDL_RecordGesture(SDL_TouchID touchId)
int i; {
if(touchId < 0) recordAll = SDL_TRUE; int i;
for(i = 0;i < SDL_numGestureTouches; i++) { if (touchId < 0) recordAll = SDL_TRUE;
if((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) { for (i = 0; i < SDL_numGestureTouches; i++) {
SDL_gestureTouch[i].recording = SDL_TRUE; if ((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
if(touchId >= 0) SDL_gestureTouch[i].recording = SDL_TRUE;
return 1; if (touchId >= 0)
} return 1;
} }
return (touchId < 0); }
return (touchId < 0);
} }
static unsigned long SDL_HashDollar(SDL_FloatPoint* points) { static unsigned long SDL_HashDollar(SDL_FloatPoint* points)
unsigned long hash = 5381; {
int i; unsigned long hash = 5381;
for(i = 0;i < DOLLARNPOINTS; i++) { int i;
hash = ((hash<<5) + hash) + (unsigned long)points[i].x; for (i = 0; i < DOLLARNPOINTS; i++) {
hash = ((hash<<5) + hash) + (unsigned long)points[i].y; hash = ((hash<<5) + hash) + (unsigned long)points[i].x;
} hash = ((hash<<5) + hash) + (unsigned long)points[i].y;
return hash; }
return hash;
} }
static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops * src) { static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops * src)
if(src == NULL) return 0; {
if (src == NULL) return 0;
//No Longer storing the Hash, rehash on load
//if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
if(SDL_RWwrite(src,templ->path,
sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS)
return 0;
return 1; //No Longer storing the Hash, rehash on load
//if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
if (SDL_RWwrite(src,templ->path,
sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS)
return 0;
return 1;
} }
int SDL_SaveAllDollarTemplates(SDL_RWops *src) { int SDL_SaveAllDollarTemplates(SDL_RWops *src)
int i,j,rtrn = 0; {
for(i = 0; i < SDL_numGestureTouches; i++) { int i,j,rtrn = 0;
SDL_GestureTouch* touch = &SDL_gestureTouch[i]; for (i = 0; i < SDL_numGestureTouches; i++) {
for(j = 0;j < touch->numDollarTemplates; j++) { SDL_GestureTouch* touch = &SDL_gestureTouch[i];
rtrn += SaveTemplate(&touch->dollarTemplate[i],src); for (j = 0; j < touch->numDollarTemplates; j++) {
rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
}
} }
} return rtrn;
return rtrn;
} }
int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src) { int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src)
int i,j; {
for(i = 0; i < SDL_numGestureTouches; i++) { int i,j;
SDL_GestureTouch* touch = &SDL_gestureTouch[i]; for (i = 0; i < SDL_numGestureTouches; i++) {
for(j = 0;j < touch->numDollarTemplates; j++) { SDL_GestureTouch* touch = &SDL_gestureTouch[i];
if(touch->dollarTemplate[i].hash == gestureId) { for (j = 0; j < touch->numDollarTemplates; j++) {
return SaveTemplate(&touch->dollarTemplate[i],src); if (touch->dollarTemplate[i].hash == gestureId) {
} return SaveTemplate(&touch->dollarTemplate[i],src);
}
}
} }
} SDL_SetError("Unknown gestureId");
SDL_SetError("Unknown gestureId"); return -1;
return -1;
} }
//path is an already sampled set of points //path is an already sampled set of points
//Returns the index of the gesture on success, or -1 //Returns the index of the gesture on success, or -1
static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch,SDL_FloatPoint* path) { static int SDL_AddDollarGesture_one(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
SDL_DollarTemplate* dollarTemplate; {
SDL_DollarTemplate *templ; SDL_DollarTemplate* dollarTemplate;
int i = 0; SDL_DollarTemplate *templ;
if(inTouch == NULL) { int index;
if(SDL_numGestureTouches == 0) return -1;
for(i = 0;i < SDL_numGestureTouches; i++) { index = inTouch->numDollarTemplates;
inTouch = &SDL_gestureTouch[i]; dollarTemplate =
dollarTemplate =
(SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate, (SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
(inTouch->numDollarTemplates + 1) * (index + 1) *
sizeof(SDL_DollarTemplate)); sizeof(SDL_DollarTemplate));
if(!dollarTemplate) { if (!dollarTemplate) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return -1; return -1;
}
inTouch->dollarTemplate = dollarTemplate;
templ =
&inTouch->dollarTemplate[inTouch->numDollarTemplates];
SDL_memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
templ->hash = SDL_HashDollar(templ->path);
inTouch->numDollarTemplates++;
} }
return inTouch->numDollarTemplates - 1;
} else {
SDL_DollarTemplate* dollarTemplate =
( SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
(inTouch->numDollarTemplates + 1) *
sizeof(SDL_DollarTemplate));
if(!dollarTemplate) {
SDL_OutOfMemory();
return -1;
}
inTouch->dollarTemplate = dollarTemplate; inTouch->dollarTemplate = dollarTemplate;
templ = templ = &inTouch->dollarTemplate[index];
&inTouch->dollarTemplate[inTouch->numDollarTemplates]; SDL_memcpy(templ->path, path, DOLLARNPOINTS*sizeof(SDL_FloatPoint));
SDL_memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
templ->hash = SDL_HashDollar(templ->path); templ->hash = SDL_HashDollar(templ->path);
inTouch->numDollarTemplates++; inTouch->numDollarTemplates++;
return inTouch->numDollarTemplates - 1;
} return index;
return -1;
} }
int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) { static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path)
int i,loaded = 0; {
SDL_GestureTouch *touch = NULL; int index;
if(src == NULL) return 0; int i = 0;
if(touchId >= 0) { if (inTouch == NULL) {
for(i = 0;i < SDL_numGestureTouches; i++) if (SDL_numGestureTouches == 0) return -1;
if(SDL_gestureTouch[i].id == touchId) for (i = 0; i < SDL_numGestureTouches; i++) {
touch = &SDL_gestureTouch[i]; inTouch = &SDL_gestureTouch[i];
if(touch == NULL) return -1; index = SDL_AddDollarGesture_one(inTouch, path);
} if (index < 0)
return -1;
while(1) { }
SDL_DollarTemplate templ; // Use the index of the last one added.
return index;
if(SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < } else {
DOLLARNPOINTS) break; return SDL_AddDollarGesture_one(inTouch, path);
if(touchId >= 0) {
//printf("Adding loaded gesture to 1 touch\n");
if(SDL_AddDollarGesture(touch,templ.path)) loaded++;
} }
else { return -1;
//printf("Adding to: %i touches\n",SDL_numGestureTouches); }
for(i = 0;i < SDL_numGestureTouches; i++) {
touch = &SDL_gestureTouch[i]; int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src)
//printf("Adding loaded gesture to + touches\n"); {
//TODO: What if this fails? int i,loaded = 0;
SDL_AddDollarGesture(touch,templ.path); SDL_GestureTouch *touch = NULL;
} if (src == NULL) return 0;
loaded++; if (touchId >= 0) {
for (i = 0; i < SDL_numGestureTouches; i++)
if (SDL_gestureTouch[i].id == touchId)
touch = &SDL_gestureTouch[i];
if (touch == NULL) return -1;
} }
}
return loaded; while (1) {
} SDL_DollarTemplate templ;
if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) <
DOLLARNPOINTS) break;
if (touchId >= 0) {
//printf("Adding loaded gesture to 1 touch\n");
if (SDL_AddDollarGesture(touch, templ.path) >= 0)
loaded++;
}
else {
//printf("Adding to: %i touches\n",SDL_numGestureTouches);
for (i = 0; i < SDL_numGestureTouches; i++) {
touch = &SDL_gestureTouch[i];
//printf("Adding loaded gesture to + touches\n");
//TODO: What if this fails?
SDL_AddDollarGesture(touch,templ.path);
}
loaded++;
}
}
static float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang) { return loaded;
// SDL_FloatPoint p[DOLLARNPOINTS];
float dist = 0;
SDL_FloatPoint p;
int i;
for(i = 0; i < DOLLARNPOINTS; i++) {
p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
(p.y-templ[i].y)*(p.y-templ[i].y)));
}
return dist/DOLLARNPOINTS;
} }
static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ) {
//------------BEGIN DOLLAR BLACKBOX----------------// static float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang)
//-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-// {
//-"http://depts.washington.edu/aimgroup/proj/dollar/"-// // SDL_FloatPoint p[DOLLARNPOINTS];
double ta = -M_PI/4; float dist = 0;
double tb = M_PI/4; SDL_FloatPoint p;
double dt = M_PI/90; int i;
float x1 = (float)(PHI*ta + (1-PHI)*tb); for (i = 0; i < DOLLARNPOINTS; i++) {
float f1 = dollarDifference(points,templ,x1); p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
float x2 = (float)((1-PHI)*ta + PHI*tb); p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
float f2 = dollarDifference(points,templ,x2); dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
while(SDL_fabs(ta-tb) > dt) { (p.y-templ[i].y)*(p.y-templ[i].y)));
if(f1 < f2) {
tb = x2;
x2 = x1;
f2 = f1;
x1 = (float)(PHI*ta + (1-PHI)*tb);
f1 = dollarDifference(points,templ,x1);
} }
else { return dist/DOLLARNPOINTS;
ta = x1;
x1 = x2; }
f1 = f2;
x2 = (float)((1-PHI)*ta + PHI*tb); static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ)
f2 = dollarDifference(points,templ,x2); {
//------------BEGIN DOLLAR BLACKBOX----------------//
//-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
//-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
double ta = -M_PI/4;
double tb = M_PI/4;
double dt = M_PI/90;
float x1 = (float)(PHI*ta + (1-PHI)*tb);
float f1 = dollarDifference(points,templ,x1);
float x2 = (float)((1-PHI)*ta + PHI*tb);
float f2 = dollarDifference(points,templ,x2);
while (SDL_fabs(ta-tb) > dt) {
if (f1 < f2) {
tb = x2;
x2 = x1;
f2 = f1;
x1 = (float)(PHI*ta + (1-PHI)*tb);
f1 = dollarDifference(points,templ,x1);
}
else {
ta = x1;
x1 = x2;
f1 = f2;
x2 = (float)((1-PHI)*ta + PHI*tb);
f2 = dollarDifference(points,templ,x2);
}
} }
} /*
/* if (f1 <= f2)
if(f1 <= f2) printf("Min angle (x1): %f\n",x1);
printf("Min angle (x1): %f\n",x1); else if (f1 > f2)
else if(f1 > f2) printf("Min angle (x2): %f\n",x2);
printf("Min angle (x2): %f\n",x2); */
*/ return SDL_min(f1,f2);
return SDL_min(f1,f2);
} }
//DollarPath contains raw points, plus (possibly) the calculated length //DollarPath contains raw points, plus (possibly) the calculated length
static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points) { static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
int i; {
float interval; int i;
float dist; float interval;
int numPoints = 0; float dist;
SDL_FloatPoint centroid; int numPoints = 0;
float xmin,xmax,ymin,ymax; SDL_FloatPoint centroid;
float ang; float xmin,xmax,ymin,ymax;
float w,h; float ang;
float length = path->length; float w,h;
float length = path->length;
//Calculate length if it hasn't already been done
if(length <= 0) { //Calculate length if it hasn't already been done
for(i=1;i<path->numPoints;i++) { if (length <= 0) {
float dx = path->p[i ].x - for (i=1;i < path->numPoints; i++) {
path->p[i-1].x; float dx = path->p[i ].x - path->p[i-1].x;
float dy = path->p[i ].y - float dy = path->p[i ].y - path->p[i-1].y;
path->p[i-1].y; length += (float)(SDL_sqrt(dx*dx+dy*dy));
length += (float)(SDL_sqrt(dx*dx+dy*dy)); }
}
//Resample
interval = length/(DOLLARNPOINTS - 1);
dist = interval;
centroid.x = 0;centroid.y = 0;
//printf("(%f,%f)\n",path->p[path->numPoints-1].x,path->p[path->numPoints-1].y);
for (i = 1; i < path->numPoints; i++) {
float d = (float)(SDL_sqrt((path->p[i-1].x-path->p[i].x)*(path->p[i-1].x-path->p[i].x)+
(path->p[i-1].y-path->p[i].y)*(path->p[i-1].y-path->p[i].y)));
//printf("d = %f dist = %f/%f\n",d,dist,interval);
while (dist + d > interval) {
points[numPoints].x = path->p[i-1].x +
((interval-dist)/d)*(path->p[i].x-path->p[i-1].x);
points[numPoints].y = path->p[i-1].y +
((interval-dist)/d)*(path->p[i].y-path->p[i-1].y);
centroid.x += points[numPoints].x;
centroid.y += points[numPoints].y;
numPoints++;
dist -= interval;
}
dist += d;
} }
} if (numPoints < DOLLARNPOINTS-1) {
SDL_SetError("ERROR: NumPoints = %i\n",numPoints);
//Resample return 0;
interval = length/(DOLLARNPOINTS - 1);
dist = interval;
centroid.x = 0;centroid.y = 0;
//printf("(%f,%f)\n",path->p[path->numPoints-1].x,path->p[path->numPoints-1].y);
for(i = 1;i < path->numPoints;i++) {
float d = (float)(SDL_sqrt((path->p[i-1].x-path->p[i].x)*(path->p[i-1].x-path->p[i].x)+
(path->p[i-1].y-path->p[i].y)*(path->p[i-1].y-path->p[i].y)));
//printf("d = %f dist = %f/%f\n",d,dist,interval);
while(dist + d > interval) {
points[numPoints].x = path->p[i-1].x +
((interval-dist)/d)*(path->p[i].x-path->p[i-1].x);
points[numPoints].y = path->p[i-1].y +
((interval-dist)/d)*(path->p[i].y-path->p[i-1].y);
centroid.x += points[numPoints].x;
centroid.y += points[numPoints].y;
numPoints++;
dist -= interval;
} }
dist += d; //copy the last point
} points[DOLLARNPOINTS-1] = path->p[path->numPoints-1];
if(numPoints < DOLLARNPOINTS-1) { numPoints = DOLLARNPOINTS;
SDL_SetError("ERROR: NumPoints = %i\n",numPoints);
return 0; centroid.x /= numPoints;
} centroid.y /= numPoints;
//copy the last point
points[DOLLARNPOINTS-1] = path->p[path->numPoints-1]; //printf("Centroid (%f,%f)",centroid.x,centroid.y);
numPoints = DOLLARNPOINTS; //Rotate Points so point 0 is left of centroid and solve for the bounding box
xmin = centroid.x;
centroid.x /= numPoints; xmax = centroid.x;
centroid.y /= numPoints; ymin = centroid.y;
ymax = centroid.y;
//printf("Centroid (%f,%f)",centroid.x,centroid.y);
//Rotate Points so point 0 is left of centroid and solve for the bounding box ang = (float)(SDL_atan2(centroid.y - points[0].y,
xmin = centroid.x; centroid.x - points[0].x));
xmax = centroid.x;
ymin = centroid.y; for (i = 0; i<numPoints; i++) {
ymax = centroid.y; float px = points[i].x;
float py = points[i].y;
ang = (float)(SDL_atan2(centroid.y - points[0].y, points[i].x = (float)((px - centroid.x)*SDL_cos(ang) -
centroid.x - points[0].x)); (py - centroid.y)*SDL_sin(ang) + centroid.x);
points[i].y = (float)((px - centroid.x)*SDL_sin(ang) +
for(i = 0;i<numPoints;i++) { (py - centroid.y)*SDL_cos(ang) + centroid.y);
float px = points[i].x;
float py = points[i].y;
points[i].x = (float)((px - centroid.x)*SDL_cos(ang) - if (points[i].x < xmin) xmin = points[i].x;
(py - centroid.y)*SDL_sin(ang) + centroid.x); if (points[i].x > xmax) xmax = points[i].x;
points[i].y = (float)((px - centroid.x)*SDL_sin(ang) + if (points[i].y < ymin) ymin = points[i].y;
(py - centroid.y)*SDL_cos(ang) + centroid.y); if (points[i].y > ymax) ymax = points[i].y;
}
if(points[i].x < xmin) xmin = points[i].x; //Scale points to DOLLARSIZE, and translate to the origin
if(points[i].x > xmax) xmax = points[i].x; w = xmax-xmin;
if(points[i].y < ymin) ymin = points[i].y; h = ymax-ymin;
if(points[i].y > ymax) ymax = points[i].y;
} for (i=0; i<numPoints; i++) {
points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
//Scale points to DOLLARSIZE, and translate to the origin points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
w = xmax-xmin; }
h = ymax-ymin; return numPoints;
for(i=0;i<numPoints;i++) {
points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
}
return numPoints;
} }
static float dollarRecognize(const SDL_DollarPath *path,int *bestTempl,SDL_GestureTouch* touch) { static float dollarRecognize(const SDL_DollarPath *path,int *bestTempl,SDL_GestureTouch* touch)
{
SDL_FloatPoint points[DOLLARNPOINTS];
int i;
float bestDiff = 10000;
dollarNormalize(path,points); SDL_FloatPoint points[DOLLARNPOINTS];
int i;
float bestDiff = 10000;
//PrintPath(points); dollarNormalize(path,points);
*bestTempl = -1;
for(i = 0;i < touch->numDollarTemplates;i++) { //PrintPath(points);
float diff = bestDollarDifference(points,touch->dollarTemplate[i].path); *bestTempl = -1;
if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;} for (i = 0; i < touch->numDollarTemplates; i++) {
} float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
return bestDiff; if (diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
}
return bestDiff;
} }
int SDL_GestureAddTouch(SDL_Touch* touch) { int SDL_GestureAddTouch(SDL_Touch* touch)
SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch, {
(SDL_numGestureTouches + 1) * SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
sizeof(SDL_GestureTouch)); (SDL_numGestureTouches + 1) *
sizeof(SDL_GestureTouch));
if(!gestureTouch) { if (!gestureTouch) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return -1; return -1;
} }
SDL_gestureTouch = gestureTouch; SDL_gestureTouch = gestureTouch;
SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres; SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
SDL_gestureTouch[SDL_numGestureTouches].res.y = touch->yres; SDL_gestureTouch[SDL_numGestureTouches].res.y = touch->yres;
SDL_gestureTouch[SDL_numGestureTouches].numDownFingers = 0; SDL_gestureTouch[SDL_numGestureTouches].numDownFingers = 0;
SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres; SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
SDL_gestureTouch[SDL_numGestureTouches].id = touch->id; SDL_gestureTouch[SDL_numGestureTouches].id = touch->id;
SDL_gestureTouch[SDL_numGestureTouches].numDollarTemplates = 0; SDL_gestureTouch[SDL_numGestureTouches].numDollarTemplates = 0;
SDL_gestureTouch[SDL_numGestureTouches].recording = SDL_FALSE; SDL_gestureTouch[SDL_numGestureTouches].recording = SDL_FALSE;
SDL_numGestureTouches++; SDL_numGestureTouches++;
return 0; return 0;
} }
static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) { static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
int i; {
for(i = 0;i < SDL_numGestureTouches; i++) { int i;
//printf("%i ?= %i\n",SDL_gestureTouch[i].id,id); for (i = 0; i < SDL_numGestureTouches; i++) {
if(SDL_gestureTouch[i].id == id) return &SDL_gestureTouch[i]; //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
} if (SDL_gestureTouch[i].id == id)
return NULL; return &SDL_gestureTouch[i];
}
return NULL;
} }
static int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) { int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
SDL_Event event; {
event.mgesture.type = SDL_MULTIGESTURE; SDL_Event event;
event.mgesture.touchId = touch->id; event.mgesture.type = SDL_MULTIGESTURE;
event.mgesture.x = touch->centroid.x; event.mgesture.touchId = touch->id;
event.mgesture.y = touch->centroid.y; event.mgesture.x = touch->centroid.x;
event.mgesture.dTheta = dTheta; event.mgesture.y = touch->centroid.y;
event.mgesture.dDist = dDist; event.mgesture.dTheta = dTheta;
event.mgesture.numFingers = touch->numDownFingers; event.mgesture.dDist = dDist;
return SDL_PushEvent(&event) > 0; event.mgesture.numFingers = touch->numDownFingers;
return SDL_PushEvent(&event) > 0;
} }
static int SDL_SendGestureDollar(SDL_GestureTouch* touch, static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
SDL_GestureID gestureId,float error) { SDL_GestureID gestureId,float error)
SDL_Event event; {
event.dgesture.type = SDL_DOLLARGESTURE; SDL_Event event;
event.dgesture.touchId = touch->id; event.dgesture.type = SDL_DOLLARGESTURE;
/* event.dgesture.touchId = touch->id;
/*
//TODO: Add this to give location of gesture? //TODO: Add this to give location of gesture?
event.mgesture.x = touch->centroid.x; event.mgesture.x = touch->centroid.x;
event.mgesture.y = touch->centroid.y; event.mgesture.y = touch->centroid.y;
*/ */
event.dgesture.gestureId = gestureId; event.dgesture.gestureId = gestureId;
event.dgesture.error = error; event.dgesture.error = error;
//A finger came up to trigger this event. //A finger came up to trigger this event.
event.dgesture.numFingers = touch->numDownFingers + 1; event.dgesture.numFingers = touch->numDownFingers + 1;
return SDL_PushEvent(&event) > 0; return SDL_PushEvent(&event) > 0;
} }
static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId) { static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
SDL_Event event; {
event.dgesture.type = SDL_DOLLARRECORD; SDL_Event event;
event.dgesture.touchId = touch->id; event.dgesture.type = SDL_DOLLARRECORD;
event.dgesture.gestureId = gestureId; event.dgesture.touchId = touch->id;
return SDL_PushEvent(&event) > 0; event.dgesture.gestureId = gestureId;
return SDL_PushEvent(&event) > 0;
} }
void SDL_GestureProcessEvent(SDL_Event* event) void SDL_GestureProcessEvent(SDL_Event* event)
{ {
float x,y; float x,y;
SDL_FloatPoint path[DOLLARNPOINTS]; SDL_FloatPoint path[DOLLARNPOINTS];
int index; int index;
int i; int i;
float pathDx, pathDy; float pathDx, pathDy;
SDL_FloatPoint lastP; SDL_FloatPoint lastP;
SDL_FloatPoint lastCentroid; SDL_FloatPoint lastCentroid;
float lDist; float lDist;
float Dist; float Dist;
float dtheta; float dtheta;
float dDist; float dDist;
if(event->type == SDL_FINGERMOTION || if (event->type == SDL_FINGERMOTION ||
event->type == SDL_FINGERDOWN || event->type == SDL_FINGERDOWN ||
event->type == SDL_FINGERUP) { event->type == SDL_FINGERUP) {
SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId); SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
//Shouldn't be possible //Shouldn't be possible
if(inTouch == NULL) return; if (inTouch == NULL) return;
//printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x, //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
// (int)event->tfinger.y, // (int)event->tfinger.y,
// (int)inTouch->res.x,(int)inTouch->res.y); // (int)inTouch->res.x,(int)inTouch->res.y);
x = ((float)event->tfinger.x)/(float)inTouch->res.x; x = ((float)event->tfinger.x)/(float)inTouch->res.x;
y = ((float)event->tfinger.y)/(float)inTouch->res.y; y = ((float)event->tfinger.y)/(float)inTouch->res.y;
//Finger Up //Finger Up
if(event->type == SDL_FINGERUP) { if (event->type == SDL_FINGERUP) {
inTouch->numDownFingers--; inTouch->numDownFingers--;
#ifdef ENABLE_DOLLAR #ifdef ENABLE_DOLLAR
if(inTouch->recording) { if (inTouch->recording) {
inTouch->recording = SDL_FALSE; inTouch->recording = SDL_FALSE;
dollarNormalize(&inTouch->dollarPath,path); dollarNormalize(&inTouch->dollarPath,path);
//PrintPath(path); //PrintPath(path);
if(recordAll) { if (recordAll) {
index = SDL_AddDollarGesture(NULL,path); index = SDL_AddDollarGesture(NULL,path);
for(i = 0;i < SDL_numGestureTouches; i++) for (i = 0; i < SDL_numGestureTouches; i++)
SDL_gestureTouch[i].recording = SDL_FALSE; SDL_gestureTouch[i].recording = SDL_FALSE;
} }
else { else {
index = SDL_AddDollarGesture(inTouch,path); index = SDL_AddDollarGesture(inTouch,path);
} }
if(index >= 0) { if (index >= 0) {
SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash); SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
} }
else { else {
SDL_SendDollarRecord(inTouch,-1); SDL_SendDollarRecord(inTouch,-1);
} }
} }
else { else {
int bestTempl; int bestTempl;
float error; float error;
error = dollarRecognize(&inTouch->dollarPath, error = dollarRecognize(&inTouch->dollarPath,
&bestTempl,inTouch); &bestTempl,inTouch);
if(bestTempl >= 0){ if (bestTempl >= 0){
//Send Event //Send Event
unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash; unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
SDL_SendGestureDollar(inTouch,gestureId,error); SDL_SendGestureDollar(inTouch,gestureId,error);
//printf ("%s\n",);("Dollar error: %f\n",error); //printf ("%s\n",);("Dollar error: %f\n",error);
}
}
#endif
//inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
if (inTouch->numDownFingers > 0) {
inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
x)/inTouch->numDownFingers;
inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
y)/inTouch->numDownFingers;
}
} }
} else if (event->type == SDL_FINGERMOTION) {
#endif float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
//inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers]; float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
if(inTouch->numDownFingers > 0) { //printf("dx,dy: (%f,%f)\n",dx,dy);
inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
x)/inTouch->numDownFingers;
inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
y)/inTouch->numDownFingers;
}
}
else if(event->type == SDL_FINGERMOTION) {
float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
//printf("dx,dy: (%f,%f)\n",dx,dy);
#ifdef ENABLE_DOLLAR #ifdef ENABLE_DOLLAR
SDL_DollarPath* path = &inTouch->dollarPath; SDL_DollarPath* path = &inTouch->dollarPath;
if(path->numPoints < MAXPATHSIZE) { if (path->numPoints < MAXPATHSIZE) {
path->p[path->numPoints].x = inTouch->centroid.x; path->p[path->numPoints].x = inTouch->centroid.x;
path->p[path->numPoints].y = inTouch->centroid.y; path->p[path->numPoints].y = inTouch->centroid.y;
pathDx = pathDx =
(path->p[path->numPoints].x-path->p[path->numPoints-1].x); (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
pathDy = pathDy =
(path->p[path->numPoints].y-path->p[path->numPoints-1].y); (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy); path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
path->numPoints++; path->numPoints++;
} }
#endif #endif
lastP.x = x - dx; lastP.x = x - dx;
lastP.y = y - dy; lastP.y = y - dy;
lastCentroid = inTouch->centroid; lastCentroid = inTouch->centroid;
inTouch->centroid.x += dx/inTouch->numDownFingers; inTouch->centroid.x += dx/inTouch->numDownFingers;
inTouch->centroid.y += dy/inTouch->numDownFingers; inTouch->centroid.y += dy/inTouch->numDownFingers;
//printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y); //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
if(inTouch->numDownFingers > 1) { if (inTouch->numDownFingers > 1) {
SDL_FloatPoint lv; //Vector from centroid to last x,y position SDL_FloatPoint lv; //Vector from centroid to last x,y position
SDL_FloatPoint v; //Vector from centroid to current x,y position SDL_FloatPoint v; //Vector from centroid to current x,y position
//lv = inTouch->gestureLast[j].cv; //lv = inTouch->gestureLast[j].cv;
lv.x = lastP.x - lastCentroid.x; lv.x = lastP.x - lastCentroid.x;
lv.y = lastP.y - lastCentroid.y; lv.y = lastP.y - lastCentroid.y;
lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y); lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
//printf("lDist = %f\n",lDist); //printf("lDist = %f\n",lDist);
v.x = x - inTouch->centroid.x; v.x = x - inTouch->centroid.x;
v.y = y - inTouch->centroid.y; v.y = y - inTouch->centroid.y;
//inTouch->gestureLast[j].cv = v; //inTouch->gestureLast[j].cv = v;
Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y); Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
// SDL_cos(dTheta) = (v . lv)/(|v| * |lv|) // SDL_cos(dTheta) = (v . lv)/(|v| * |lv|)
//Normalize Vectors to simplify angle calculation //Normalize Vectors to simplify angle calculation
lv.x/=lDist; lv.x/=lDist;
lv.y/=lDist; lv.y/=lDist;
v.x/=Dist; v.x/=Dist;
v.y/=Dist; v.y/=Dist;
dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y); dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
dDist = (Dist - lDist); dDist = (Dist - lDist);
if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values if (lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
//inTouch->gestureLast[j].dDist = dDist; //inTouch->gestureLast[j].dDist = dDist;
//inTouch->gestureLast[j].dtheta = dtheta; //inTouch->gestureLast[j].dtheta = dtheta;
//printf("dDist = %f, dTheta = %f\n",dDist,dtheta); //printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
//gdtheta = gdtheta*.9 + dtheta*.1; //gdtheta = gdtheta*.9 + dtheta*.1;
//gdDist = gdDist*.9 + dDist*.1 //gdDist = gdDist*.9 + dDist*.1
//knob.r += dDist/numDownFingers; //knob.r += dDist/numDownFingers;
//knob.ang += dtheta; //knob.ang += dtheta;
//printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist); //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
//printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist); //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
SDL_SendGestureMulti(inTouch,dtheta,dDist); SDL_SendGestureMulti(inTouch,dtheta,dDist);
} }
else { else {
//inTouch->gestureLast[j].dDist = 0; //inTouch->gestureLast[j].dDist = 0;
//inTouch->gestureLast[j].dtheta = 0; //inTouch->gestureLast[j].dtheta = 0;
//inTouch->gestureLast[j].cv.x = 0; //inTouch->gestureLast[j].cv.x = 0;
//inTouch->gestureLast[j].cv.y = 0; //inTouch->gestureLast[j].cv.y = 0;
} }
//inTouch->gestureLast[j].f.p.x = x; //inTouch->gestureLast[j].f.p.x = x;
//inTouch->gestureLast[j].f.p.y = y; //inTouch->gestureLast[j].f.p.y = y;
//break; //break;
//pressure? //pressure?
} }
if(event->type == SDL_FINGERDOWN) {
inTouch->numDownFingers++; if (event->type == SDL_FINGERDOWN) {
inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
x)/inTouch->numDownFingers; inTouch->numDownFingers++;
inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+ inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+
y)/inTouch->numDownFingers; x)/inTouch->numDownFingers;
//printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y, inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
// inTouch->centroid.x,inTouch->centroid.y); y)/inTouch->numDownFingers;
//printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
// inTouch->centroid.x,inTouch->centroid.y);
#ifdef ENABLE_DOLLAR #ifdef ENABLE_DOLLAR
inTouch->dollarPath.length = 0; inTouch->dollarPath.length = 0;
inTouch->dollarPath.p[0].x = x; inTouch->dollarPath.p[0].x = x;
inTouch->dollarPath.p[0].y = y; inTouch->dollarPath.p[0].y = y;
inTouch->dollarPath.numPoints = 1; inTouch->dollarPath.numPoints = 1;
#endif #endif
}
} }
}
} }
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment