Moved Multi finger gesture recognition into the library.
authorJim Grandpre <jim.tla@gmail.com>
Wed, 07 Jul 2010 04:13:08 -0700
changeset 4657eed063a0bf5b
parent 4656 b5007b7995c6
child 4658 454385d76845
Moved Multi finger gesture recognition into the library.
include/SDL_events.h
src/events/SDL_events.c
src/events/SDL_events_c.h
src/events/SDL_gesture.c
src/events/SDL_gesture_c.h
src/events/SDL_touch.c
touchTest/gestureSDLTest.c
touchTest/makefile
touchTest/touchPong
touchTest/touchSimp
     1.1 --- a/include/SDL_events.h	Tue Jul 06 02:05:27 2010 -0700
     1.2 +++ b/include/SDL_events.h	Wed Jul 07 04:13:08 2010 -0700
     1.3 @@ -86,13 +86,17 @@
     1.4      SDL_JOYBUTTONDOWN,          /**< Joystick button pressed */
     1.5      SDL_JOYBUTTONUP,            /**< Joystick button released */
     1.6  
     1.7 -    /*Touch events - is 0x700 the correct place?*/
     1.8 +    /*Touch events*/
     1.9      SDL_FINGERDOWN     = 0x700,
    1.10      SDL_FINGERUP,
    1.11      SDL_FINGERMOTION,
    1.12      SDL_TOUCHBUTTONDOWN,
    1.13      SDL_TOUCHBUTTONUP,    
    1.14  
    1.15 +    /*Gesture events*/
    1.16 +    SDL_DOLLARGESTURE     = 0x800,
    1.17 +    SDL_MULTIGESTURE,
    1.18 +
    1.19      /* Obsolete events */
    1.20      SDL_EVENT_COMPAT1 = 0x7000, /**< SDL 1.2 events for compatibility */
    1.21      SDL_EVENT_COMPAT2,
    1.22 @@ -331,6 +335,28 @@
    1.23  } SDL_TouchButtonEvent;
    1.24  
    1.25  
    1.26 +
    1.27 +/**
    1.28 + *  \brief Multiple Finger Gesture Event
    1.29 + */
    1.30 +typedef struct SDL_MultiGestureEvent
    1.31 +{
    1.32 +    Uint32 type;        /**< ::SDL_MULTIGESTURE */
    1.33 +    Uint32 windowID;    /**< The window with mouse focus, if any */
    1.34 +    Uint8 touchId;        /**< The touch device index */
    1.35 +    Uint8 padding1;
    1.36 +    Uint8 padding2;
    1.37 +    Uint8 padding3;
    1.38 +    float dTheta;
    1.39 +    float dDist;
    1.40 +    float x;  //currently 0...1. Change to screen coords?
    1.41 +    float y;  
    1.42 +
    1.43 +} SDL_MultiGestureEvent;
    1.44 +
    1.45 +
    1.46 +
    1.47 +
    1.48  /**
    1.49   *  \brief The "quit requested" event
    1.50   */
    1.51 @@ -416,6 +442,7 @@
    1.52      SDL_ProximityEvent proximity;   /**< Proximity In or Out event */
    1.53      SDL_TouchFingerEvent tfinger;   /**< Touch finger event data */
    1.54      SDL_TouchButtonEvent tbutton;   /**< Touch button event data */
    1.55 +    SDL_MultiGestureEvent mgesture; /**< Multi Finger Gesture data*/
    1.56  
    1.57      /** Temporarily here for backwards compatibility */
    1.58      /*@{*/
     2.1 --- a/src/events/SDL_events.c	Tue Jul 06 02:05:27 2010 -0700
     2.2 +++ b/src/events/SDL_events.c	Wed Jul 07 04:13:08 2010 -0700
     2.3 @@ -493,6 +493,10 @@
     2.4      if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
     2.5          return -1;
     2.6      }
     2.7 +
     2.8 +    SDL_GestureProcessEvent(event);
     2.9 +    
    2.10 +
    2.11      return 1;
    2.12  }
    2.13  
     3.1 --- a/src/events/SDL_events_c.h	Tue Jul 06 02:05:27 2010 -0700
     3.2 +++ b/src/events/SDL_events_c.h	Wed Jul 07 04:13:08 2010 -0700
     3.3 @@ -28,7 +28,7 @@
     3.4  #include "SDL_keyboard_c.h"
     3.5  #include "SDL_touch_c.h"
     3.6  #include "SDL_windowevents_c.h"
     3.7 -
     3.8 +#include "SDL_gesture_c.h"
     3.9  /* Start and stop the event processing loop */
    3.10  extern int SDL_StartEventLoop(Uint32 flags);
    3.11  extern void SDL_StopEventLoop(void);
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/events/SDL_gesture.c	Wed Jul 07 04:13:08 2010 -0700
     4.3 @@ -0,0 +1,189 @@
     4.4 +/*
     4.5 +    SDL - Simple DirectMedia Layer
     4.6 +    Copyright (C) 1997-2010 Sam Lantinga
     4.7 +
     4.8 +    This library is free software; you can redistribute it and/or
     4.9 +    modify it under the terms of the GNU Lesser General Public
    4.10 +    License as published by the Free Software Foundation; either
    4.11 +    version 2.1 of the License, or (at your option) any later version.
    4.12 +
    4.13 +    This library is distributed in the hope that it will be useful,
    4.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    4.16 +    Lesser General Public License for more details.
    4.17 +
    4.18 +    You should have received a copy of the GNU Lesser General Public
    4.19 +    License along with this library; if not, write to the Free Software
    4.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    4.21 +
    4.22 +    Sam Lantinga
    4.23 +    slouken@libsdl.org
    4.24 +*/
    4.25 +#include "SDL_config.h"
    4.26 +
    4.27 +/* General mouse handling code for SDL */
    4.28 +
    4.29 +#include "SDL_events.h"
    4.30 +#include "SDL_events_c.h"
    4.31 +#include "SDL_gesture_c.h"
    4.32 +
    4.33 +//TODO: Replace with malloc
    4.34 +#define MAXFINGERS 3
    4.35 +#define MAXTOUCHES 2
    4.36 +
    4.37 +typedef struct {
    4.38 +  float x,y;
    4.39 +} Point;
    4.40 +
    4.41 +
    4.42 +typedef struct {
    4.43 +  Point p;
    4.44 +  float pressure;
    4.45 +  int id;
    4.46 +} Finger;
    4.47 +
    4.48 +typedef struct {
    4.49 +  Finger f;
    4.50 +  Point cv;
    4.51 +  float dtheta,dDist;
    4.52 +} TouchPoint;
    4.53 +
    4.54 +
    4.55 +typedef struct {
    4.56 +  int id;
    4.57 +  Point res;
    4.58 +  Point centroid;
    4.59 +  TouchPoint gestureLast[MAXFINGERS];
    4.60 +  int numDownFingers;
    4.61 +} GestureTouch;
    4.62 +
    4.63 +GestureTouch gestureTouch[MAXTOUCHES];
    4.64 +int numGestureTouches = 0;
    4.65 +int SDL_GestureAddTouch(SDL_Touch* touch) { 
    4.66 +  if(numGestureTouches >= MAXTOUCHES) return -1;
    4.67 +  
    4.68 +  gestureTouch[numGestureTouches].res.x = touch->xres;
    4.69 +  gestureTouch[numGestureTouches].res.y = touch->yres;
    4.70 +  gestureTouch[numGestureTouches].numDownFingers = 0;
    4.71 +
    4.72 +  gestureTouch[numGestureTouches].res.x = touch->xres;
    4.73 +  gestureTouch[numGestureTouches].id = touch->id;
    4.74 +
    4.75 +  numGestureTouches++;
    4.76 +  return 0;
    4.77 +}
    4.78 +
    4.79 +GestureTouch * SDL_GetGestureTouch(int id) {
    4.80 +  int i;
    4.81 +  for(i = 0;i < numGestureTouches; i++) {
    4.82 +    //printf("%i ?= %i\n",gestureTouch[i].id,id);
    4.83 +    if(gestureTouch[i].id == id) return &gestureTouch[i];
    4.84 +  }
    4.85 +  return NULL;
    4.86 +}
    4.87 +
    4.88 +int SDL_SendGestureMulti(GestureTouch* touch,float dTheta,float dDist) {
    4.89 +  SDL_Event event;
    4.90 +  event.mgesture.type = SDL_MULTIGESTURE;
    4.91 +  event.mgesture.touchId = touch->id;
    4.92 +  event.mgesture.x = touch->centroid.x;
    4.93 +  event.mgesture.y = touch->centroid.y;
    4.94 +  event.mgesture.dTheta = dTheta;
    4.95 +  event.mgesture.dDist = dDist;  
    4.96 +  return SDL_PushEvent(&event) > 0;
    4.97 +}
    4.98 +
    4.99 +void SDL_GestureProcessEvent(SDL_Event* event)
   4.100 +{
   4.101 +  if(event->type == SDL_FINGERMOTION || 
   4.102 +     event->type == SDL_FINGERDOWN ||
   4.103 +     event->type == SDL_FINGERUP) {
   4.104 +    GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
   4.105 +
   4.106 +
   4.107 +    //Shouldn't be possible
   4.108 +    if(inTouch == NULL) return;
   4.109 +    
   4.110 +    
   4.111 +    float x = ((float)event->tfinger.x)/inTouch->res.x;
   4.112 +    float y = ((float)event->tfinger.y)/inTouch->res.y;
   4.113 +    int j,empty = -1;
   4.114 +    
   4.115 +    for(j = 0;j<inTouch->numDownFingers;j++) {
   4.116 +      if(inTouch->gestureLast[j].f.id != event->tfinger.fingerId) continue;
   4.117 +
   4.118 +      if(event->type == SDL_FINGERUP) {
   4.119 +	inTouch->numDownFingers--;
   4.120 +	inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
   4.121 +	break;
   4.122 +      }
   4.123 +      else {
   4.124 +	float dx = x - inTouch->gestureLast[j].f.p.x;
   4.125 +	float dy = y - inTouch->gestureLast[j].f.p.y;
   4.126 +	inTouch->centroid.x += dx/inTouch->numDownFingers;
   4.127 +	inTouch->centroid.y += dy/inTouch->numDownFingers;    
   4.128 +	if(inTouch->numDownFingers > 1) {
   4.129 +	  Point lv; //Vector from centroid to last x,y position
   4.130 +	  Point v; //Vector from centroid to current x,y position
   4.131 +	  lv = inTouch->gestureLast[j].cv;
   4.132 +	  float lDist = sqrt(lv.x*lv.x + lv.y*lv.y);
   4.133 +	  //printf("lDist = %f\n",lDist);
   4.134 +	  v.x = x - inTouch->centroid.x;
   4.135 +	  v.y = y - inTouch->centroid.y;
   4.136 +	  inTouch->gestureLast[j].cv = v;
   4.137 +	  float Dist = sqrt(v.x*v.x+v.y*v.y);
   4.138 +	  // cos(dTheta) = (v . lv)/(|v| * |lv|)
   4.139 +	  
   4.140 +	  //Normalize Vectors to simplify angle calculation
   4.141 +	  lv.x/=lDist;
   4.142 +	  lv.y/=lDist;
   4.143 +	  v.x/=Dist;
   4.144 +	  v.y/=Dist;
   4.145 +	  float dtheta = atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   4.146 +	  
   4.147 +	  float dDist = (Dist - lDist);
   4.148 +	  if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
   4.149 +	  inTouch->gestureLast[j].dDist = dDist;
   4.150 +	  inTouch->gestureLast[j].dtheta = dtheta;
   4.151 +	  
   4.152 +	  //printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
   4.153 +	  //gdtheta = gdtheta*.9 + dtheta*.1;
   4.154 +	  //gdDist  =  gdDist*.9 +  dDist*.1
   4.155 +	  //knob.r += dDist/numDownFingers;
   4.156 +	  //knob.ang += dtheta;
   4.157 +	  //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   4.158 +	  //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   4.159 +	  SDL_SendGestureMulti(inTouch,dtheta,dDist);
   4.160 +	}
   4.161 +	else {
   4.162 +	  inTouch->gestureLast[j].dDist = 0;
   4.163 +	  inTouch->gestureLast[j].dtheta = 0;
   4.164 +	  inTouch->gestureLast[j].cv.x = 0;
   4.165 +	  inTouch->gestureLast[j].cv.y = 0;
   4.166 +	}
   4.167 +	inTouch->gestureLast[j].f.p.x = x;
   4.168 +	inTouch->gestureLast[j].f.p.y = y;
   4.169 +	break;
   4.170 +	//pressure?
   4.171 +      }      
   4.172 +    }
   4.173 +    
   4.174 +    if(j == inTouch->numDownFingers) {
   4.175 +      //printf("Finger Down!!!\n");
   4.176 +      inTouch->numDownFingers++;
   4.177 +      inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
   4.178 +			     x)/inTouch->numDownFingers;
   4.179 +      inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
   4.180 +			     y)/inTouch->numDownFingers;
   4.181 +      
   4.182 +      inTouch->gestureLast[j].f.id = event->tfinger.fingerId;
   4.183 +      inTouch->gestureLast[j].f.p.x  = x;
   4.184 +      inTouch->gestureLast[j].f.p.y  = y;	
   4.185 +      inTouch->gestureLast[j].cv.x = 0;
   4.186 +      inTouch->gestureLast[j].cv.y = 0;
   4.187 +    }
   4.188 +  }
   4.189 +}  
   4.190 +  
   4.191 +  /* vi: set ts=4 sw=4 expandtab: */
   4.192 +  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/events/SDL_gesture_c.h	Wed Jul 07 04:13:08 2010 -0700
     5.3 @@ -0,0 +1,32 @@
     5.4 +/*
     5.5 +    SDL - Simple DirectMedia Layer
     5.6 +    Copyright (C) 1997-2010 Sam Lantinga
     5.7 +
     5.8 +    This library is free software; you can redistribute it and/or
     5.9 +    modify it under the terms of the GNU Lesser General Public
    5.10 +    License as published by the Free Software Foundation; either
    5.11 +    version 2.1 of the License, or (at your option) any later version.
    5.12 +
    5.13 +    This library is distributed in the hope that it will be useful,
    5.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5.16 +    Lesser General Public License for more details.
    5.17 +
    5.18 +    You should have received a copy of the GNU Lesser General Public
    5.19 +    License along with this library; if not, write to the Free Software
    5.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    5.21 +
    5.22 +    Sam Lantinga
    5.23 +    slouken@libsdl.org
    5.24 +*/
    5.25 +#include "SDL_config.h"
    5.26 +
    5.27 +#ifndef _SDL_gesture_c_h
    5.28 +#define _SDL_gesture_c_h
    5.29 +
    5.30 +extern void SDL_GestureProcessEvent(SDL_Event* event);
    5.31 +
    5.32 +
    5.33 +#endif /* _SDL_gesture_c_h */
    5.34 +
    5.35 +/* vi: set ts=4 sw=4 expandtab: */
     6.1 --- a/src/events/SDL_touch.c	Tue Jul 06 02:05:27 2010 -0700
     6.2 +++ b/src/events/SDL_touch.c	Wed Jul 07 04:13:08 2010 -0700
     6.3 @@ -140,6 +140,9 @@
     6.4      SDL_touchPads[index]->relative_mode = SDL_FALSE;
     6.5      SDL_touchPads[index]->flush_motion = SDL_FALSE;
     6.6      
     6.7 +    //Do I want this here? Probably
     6.8 +    SDL_GestureAddTouch(SDL_touchPads[index]);
     6.9 +
    6.10      return index;
    6.11  }
    6.12  
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/touchTest/gestureSDLTest.c	Wed Jul 07 04:13:08 2010 -0700
     7.3 @@ -0,0 +1,687 @@
     7.4 +#include <stdio.h>
     7.5 +#include <SDL.h>
     7.6 +#include <math.h>
     7.7 +#include <SDL_touch.h>
     7.8 +
     7.9 +#define PI 3.1415926535897
    7.10 +#define PHI ((sqrt(5)-1)/2)
    7.11 +#define WIDTH 640
    7.12 +#define HEIGHT 480
    7.13 +#define BPP 4
    7.14 +#define DEPTH 32
    7.15 +
    7.16 +#define MAXFINGERS 3
    7.17 +
    7.18 +#define DOLLARNPOINTS 64
    7.19 +#define DOLLARSIZE 256
    7.20 +
    7.21 +//MUST BE A POWER OF 2!
    7.22 +#define EVENT_BUF_SIZE 256
    7.23 +
    7.24 +SDL_Event events[EVENT_BUF_SIZE];
    7.25 +int eventWrite;
    7.26 +
    7.27 +int mousx,mousy;
    7.28 +int keystat[512];
    7.29 +int bstatus;
    7.30 +
    7.31 +int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF};
    7.32 +
    7.33 +int index2fingerid[MAXFINGERS];
    7.34 +int fingersDown;
    7.35 +
    7.36 +typedef struct {
    7.37 +  float x,y;
    7.38 +} Point;
    7.39 +
    7.40 +typedef struct {
    7.41 +  Point p;
    7.42 +  float pressure;
    7.43 +  int id;
    7.44 +} Finger;
    7.45 +
    7.46 +typedef struct {
    7.47 +  Finger f;
    7.48 +  Point cv;
    7.49 +  float dtheta,dDist;
    7.50 +} TouchPoint;
    7.51 +
    7.52 + 
    7.53 +typedef struct { //dt + s
    7.54 +  Point d,s; //direction, start
    7.55 +  int points;
    7.56 +} Line;
    7.57 +
    7.58 +
    7.59 +typedef struct {
    7.60 +  float length;
    7.61 +  
    7.62 +  int numPoints;
    7.63 +  Point p[EVENT_BUF_SIZE]; //To be safe
    7.64 +} DollarPath;
    7.65 +
    7.66 +typedef struct {
    7.67 +  float ang,r;
    7.68 +  Point p;
    7.69 +} Knob;
    7.70 +
    7.71 +Knob knob;
    7.72 +
    7.73 +Finger finger[MAXFINGERS];
    7.74 +
    7.75 +
    7.76 +DollarPath dollarPath[MAXFINGERS];
    7.77 +
    7.78 +#define MAXTEMPLATES 4
    7.79 +
    7.80 +Point dollarTemplate[MAXTEMPLATES][DOLLARNPOINTS];
    7.81 +int numDollarTemplates = 0;
    7.82 +#ifdef DRAW_VECTOR_EST
    7.83 +Line gestureLine[MAXFINGERS];
    7.84 +#endif
    7.85 +
    7.86 +void handler (int sig)
    7.87 +{
    7.88 +  printf ("\exiting...(%d)\n", sig);
    7.89 +  exit (0);
    7.90 +}
    7.91 +
    7.92 +void perror_exit (char *error)
    7.93 +{
    7.94 +  perror (error);
    7.95 +  handler (9);
    7.96 +}
    7.97 +
    7.98 +
    7.99 +void setpix(SDL_Surface *screen, int x, int y, unsigned int col)
   7.100 +{
   7.101 +  Uint32 *pixmem32;
   7.102 +  Uint32 colour;
   7.103 +  
   7.104 +  if((unsigned)x > screen->w) return;
   7.105 +  if((unsigned)y > screen->h) return;
   7.106 +
   7.107 +  pixmem32 = (Uint32*) screen->pixels  + y*screen->pitch/BPP + x;
   7.108 +  
   7.109 +  Uint8 r,g,b;
   7.110 +  float a;
   7.111 +  
   7.112 +  memcpy(&colour,pixmem32,screen->format->BytesPerPixel);
   7.113 +
   7.114 +  SDL_GetRGB(colour,screen->format,&r,&g,&b); //Always returns 0xFFFFFF?
   7.115 +  //r = 0;g = 0; b = 0;
   7.116 +  a = (col>>24)&0xFF;
   7.117 +  if(a == 0) a = 0xFF; //Hack, to make things easier.
   7.118 +  a /= 0xFF;
   7.119 +  r = r*(1-a) + ((col>>16)&0xFF)*(a);
   7.120 +  g = g*(1-a) + ((col>> 8)&0xFF)*(a);
   7.121 +  b = b*(1-a) + ((col>> 0)&0xFF)*(a);
   7.122 +  colour = SDL_MapRGB( screen->format,r, g, b);
   7.123 +  
   7.124 +
   7.125 +  *pixmem32 = colour;
   7.126 +}
   7.127 +
   7.128 +void drawLine(SDL_Surface *screen,int x0,int y0,int x1,int y1,unsigned int col) {
   7.129 +  float t;
   7.130 +  for(t=0;t<1;t+=1.f/SDL_max(abs(x0-x1),abs(y0-y1)))
   7.131 +    setpix(screen,x1+t*(x0-x1),y1+t*(y0-y1),col);
   7.132 +}
   7.133 +void drawCircle(SDL_Surface* screen,int x,int y,int r,unsigned int c)
   7.134 +{
   7.135 +
   7.136 +  float a;
   7.137 +  int tx;
   7.138 +  
   7.139 +  int ty;
   7.140 +  float xr;
   7.141 +  for(ty = -abs(r);ty <= abs(r);ty++) {
   7.142 +    xr = sqrt(r*r - ty*ty);
   7.143 +    if(r > 0) { //r > 0 ==> filled circle
   7.144 +      for(tx=-xr+.5;tx<=xr-.5;tx++) {
   7.145 +	setpix(screen,x+tx,y+ty,c);
   7.146 +      }
   7.147 +    }
   7.148 +    else {
   7.149 +      setpix(screen,x-xr+.5,y+ty,c);
   7.150 +      setpix(screen,x+xr-.5,y+ty,c);
   7.151 +    }
   7.152 +  }
   7.153 +}
   7.154 +
   7.155 +void drawKnob(SDL_Surface* screen,Knob k) {
   7.156 +  //printf("Knob: x = %f, y = %f, r = %f, a = %f\n",k.p.x,k.p.y,k.r,k.ang);
   7.157 + 
   7.158 +  drawCircle(screen,k.p.x*screen->w,k.p.y*screen->h,k.r*screen->w,0xFFFFFF);
   7.159 +  
   7.160 +  drawCircle(screen,(k.p.x+k.r/2*cos(k.ang))*screen->w,
   7.161 +  	            (k.p.y+k.r/2*sin(k.ang))*screen->h,k.r/4*screen->w,0);
   7.162 +  
   7.163 +}
   7.164 +
   7.165 +void drawDollarPath(SDL_Surface* screen,Point* points,int numPoints,
   7.166 +		    int rad,unsigned int col){
   7.167 +  int i;
   7.168 +  for(i=0;i<numPoints;i++) {
   7.169 +    drawCircle(screen,points[i].x+screen->w/2,
   7.170 +	       points[i].y+screen->h/2,
   7.171 +	       rad,col);
   7.172 +  }
   7.173 +}
   7.174 +
   7.175 +float dollarDifference(Point* points,Point* templ,float ang) {
   7.176 +  //  Point p[DOLLARNPOINTS];
   7.177 +  float dist = 0;
   7.178 +  Point p;
   7.179 +  int i;
   7.180 +  for(i = 0; i < DOLLARNPOINTS; i++) {
   7.181 +    p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
   7.182 +    p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
   7.183 +    dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
   7.184 +		 (p.y-templ[i].y)*(p.y-templ[i].y));
   7.185 +  }
   7.186 +  return dist/DOLLARNPOINTS;
   7.187 +  
   7.188 +}
   7.189 +
   7.190 +float bestDollarDifference(Point* points,Point* templ) {
   7.191 +  //------------BEGIN DOLLAR BLACKBOX----------------//
   7.192 +  //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
   7.193 +  //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
   7.194 +  float ta = -PI/4;
   7.195 +  float tb = PI/4;
   7.196 +  float dt = PI/90;
   7.197 +  float x1 = PHI*ta + (1-PHI)*tb;
   7.198 +  float f1 = dollarDifference(points,templ,x1);
   7.199 +  float x2 = (1-PHI)*ta + PHI*tb;
   7.200 +  float f2 = dollarDifference(points,templ,x2);
   7.201 +  while(abs(ta-tb) > dt) {
   7.202 +    if(f1 < f2) {
   7.203 +      tb = x2;
   7.204 +      x2 = x1;
   7.205 +      f2 = f1;
   7.206 +      x1 = PHI*ta + (1-PHI)*tb;
   7.207 +      f1 = dollarDifference(points,templ,x1);
   7.208 +    }
   7.209 +    else {
   7.210 +      ta = x1;
   7.211 +      x1 = x2;
   7.212 +      f1 = f2;
   7.213 +      x2 = (1-PHI)*ta + PHI*tb;
   7.214 +      f2 = dollarDifference(points,templ,x2);
   7.215 +    }
   7.216 +  }
   7.217 +  /*
   7.218 +  if(f1 <= f2)
   7.219 +    printf("Min angle (x1): %f\n",x1);
   7.220 +  else if(f1 >  f2)
   7.221 +    printf("Min angle (x2): %f\n",x2);
   7.222 +  */
   7.223 +  return SDL_min(f1,f2);  
   7.224 +}
   7.225 +
   7.226 +float dollarRecognize(SDL_Surface* screen, DollarPath path,int *bestTempl) {
   7.227 +
   7.228 +  Point points[DOLLARNPOINTS];
   7.229 +  int numPoints = dollarNormalize(path,points);
   7.230 +  int i;
   7.231 +  
   7.232 +  int k;
   7.233 +  /*
   7.234 +  for(k = 0;k<DOLLARNPOINTS;k++) {
   7.235 +    printf("(%f,%f)\n",points[k].x,
   7.236 +	   points[k].y);
   7.237 +  }
   7.238 +  */
   7.239 +  drawDollarPath(screen,points,numPoints,-15,0xFF6600);
   7.240 +
   7.241 +  int bestDiff = 10000;
   7.242 +  *bestTempl = -1;
   7.243 +  for(i = 0;i < numDollarTemplates;i++) {
   7.244 +    int diff = bestDollarDifference(points,dollarTemplate[i]);
   7.245 +    if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
   7.246 +  }
   7.247 +  return bestDiff;
   7.248 +}
   7.249 +
   7.250 +//DollarPath contains raw points, plus (possibly) the calculated length
   7.251 +int dollarNormalize(DollarPath path,Point *points) {
   7.252 +  int i;
   7.253 +  //Calculate length if it hasn't already been done
   7.254 +  if(path.length <= 0) {
   7.255 +    for(i=1;i<path.numPoints;i++) {
   7.256 +      float dx = path.p[i  ].x - 
   7.257 +	         path.p[i-1].x;
   7.258 +      float dy = path.p[i  ].y - 
   7.259 +	         path.p[i-1].y;
   7.260 +      path.length += sqrt(dx*dx+dy*dy);
   7.261 +    }
   7.262 +  }
   7.263 +
   7.264 +
   7.265 +  //Resample
   7.266 +  float interval = path.length/(DOLLARNPOINTS - 1);
   7.267 +  float dist = 0;
   7.268 +
   7.269 +  int numPoints = 0;
   7.270 +  Point centroid; centroid.x = 0;centroid.y = 0;
   7.271 +  //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
   7.272 +  for(i = 1;i < path.numPoints;i++) {
   7.273 +    float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
   7.274 +		   (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
   7.275 +    //printf("d = %f dist = %f/%f\n",d,dist,interval);
   7.276 +    while(dist + d > interval) {
   7.277 +      points[numPoints].x = path.p[i-1].x + 
   7.278 +	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
   7.279 +      points[numPoints].y = path.p[i-1].y + 
   7.280 +	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
   7.281 +      centroid.x += points[numPoints].x;
   7.282 +      centroid.y += points[numPoints].y;
   7.283 +      numPoints++;
   7.284 +
   7.285 +      dist -= interval;
   7.286 +    }
   7.287 +    dist += d;
   7.288 +  }
   7.289 +  if(numPoints < 1) return 0;
   7.290 +  centroid.x /= numPoints;
   7.291 +  centroid.y /= numPoints;
   7.292 + 
   7.293 +  //printf("Centroid (%f,%f)",centroid.x,centroid.y);
   7.294 +  //Rotate Points so point 0 is left of centroid and solve for the bounding box
   7.295 +  float xmin,xmax,ymin,ymax;
   7.296 +  xmin = centroid.x;
   7.297 +  xmax = centroid.x;
   7.298 +  ymin = centroid.y;
   7.299 +  ymax = centroid.y;
   7.300 +  
   7.301 +  float ang = atan2(centroid.y - points[0].y,
   7.302 +		    centroid.x - points[0].x);
   7.303 +
   7.304 +  for(i = 0;i<numPoints;i++) {					       
   7.305 +    float px = points[i].x;
   7.306 +    float py = points[i].y;
   7.307 +    points[i].x = (px - centroid.x)*cos(ang) - 
   7.308 +                  (py - centroid.y)*sin(ang) + centroid.x;
   7.309 +    points[i].y = (px - centroid.x)*sin(ang) + 
   7.310 +                  (py - centroid.y)*cos(ang) + centroid.y;
   7.311 +
   7.312 +
   7.313 +    if(points[i].x < xmin) xmin = points[i].x;
   7.314 +    if(points[i].x > xmax) xmax = points[i].x; 
   7.315 +    if(points[i].y < ymin) ymin = points[i].y;
   7.316 +    if(points[i].y > ymax) ymax = points[i].y;
   7.317 +  }
   7.318 +
   7.319 +  //Scale points to DOLLARSIZE, and translate to the origin
   7.320 +  float w = xmax-xmin;
   7.321 +  float h = ymax-ymin;
   7.322 +
   7.323 +  for(i=0;i<numPoints;i++) {
   7.324 +    points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
   7.325 +    points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
   7.326 +  }  
   7.327 +  return numPoints;
   7.328 +}
   7.329 +
   7.330 +void DrawScreen(SDL_Surface* screen, int h)
   7.331 +{
   7.332 +  int x, y, xm,ym,c;
   7.333 +  if(SDL_MUSTLOCK(screen))
   7.334 +    {                                              
   7.335 +      if(SDL_LockSurface(screen) < 0) return;
   7.336 +    }
   7.337 +  for(y = 0; y < screen->h; y++ )
   7.338 +    {
   7.339 +      for( x = 0; x < screen->w; x++ )
   7.340 +        {
   7.341 +	  //setpixel(screen, x, y, (x*x)/256+3*y+h, (y*y)/256+x+h, h);
   7.342 +	  //xm = (x+h)%screen->w;
   7.343 +	  //ym = (y+h)%screen->w;
   7.344 +	  //c = sin(h/256*2*PI)*x*y/screen->w/screen->h;
   7.345 +	  //setpix(screen,x,y,255*sin(xm/screen->w*2*PI),sin(h/255*2*PI)*255*y/screen->h,c);
   7.346 +	  setpix(screen,x,y,((x%255)<<16) + ((y%255)<<8) + (x+y)%255);
   7.347 +	  //setpix(screen,x,y,0); //Inefficient, but that's okay...
   7.348 +        }
   7.349 +    }
   7.350 +  drawCircle(screen,mousx,mousy,-30,0xFFFFFF);
   7.351 +  drawLine(screen,0,0,screen->w,screen->h,0xFFFFFF);
   7.352 +
   7.353 +  int i;
   7.354 +//draw Touch History
   7.355 +  TouchPoint gestureLast[MAXFINGERS];
   7.356 +  //printf("------------------Start History------------------\n");
   7.357 +  for(i = 0;i < MAXFINGERS;i++) {
   7.358 +    gestureLast[i].f.id = -1;
   7.359 +  }
   7.360 +  int numDownFingers = 0;
   7.361 +  Point centroid;
   7.362 +  float gdtheta,gdDist;
   7.363 +
   7.364 +
   7.365 +  for(i = SDL_max(0,eventWrite - EVENT_BUF_SIZE);i < eventWrite;i++) {
   7.366 +    SDL_Event event = events[i&(EVENT_BUF_SIZE-1)];
   7.367 +    int age = eventWrite - i - 1;
   7.368 +    if(event.type == SDL_FINGERMOTION || 
   7.369 +       event.type == SDL_FINGERDOWN ||
   7.370 +       event.type == SDL_FINGERUP) {
   7.371 +      SDL_Touch* inTouch = SDL_GetTouch(event.tfinger.touchId);
   7.372 +      //SDL_Finger* inFinger = SDL_GetFinger(inTouch,event.tfinger.fingerId);
   7.373 +	    
   7.374 +      float x = ((float)event.tfinger.x)/inTouch->xres;
   7.375 +      float y = ((float)event.tfinger.y)/inTouch->yres;
   7.376 +      int j,empty = -1;
   7.377 +      
   7.378 +      for(j = 0;j<MAXFINGERS;j++) {
   7.379 +	if(gestureLast[j].f.id == event.tfinger.fingerId) {
   7.380 +	  if(event.type == SDL_FINGERUP) {
   7.381 +	    numDownFingers--;
   7.382 +	    if(numDownFingers <= 1) {
   7.383 +	      gdtheta = 0;
   7.384 +	      gdDist = 0;
   7.385 +	    }
   7.386 +	    if(!keystat[32]){ //spacebar
   7.387 +	      int bestTempl;
   7.388 +	      float error = dollarRecognize(screen,dollarPath[j],&bestTempl);
   7.389 +	      if(bestTempl >= 0){
   7.390 +		drawDollarPath(screen,dollarTemplate[bestTempl]
   7.391 +			       ,DOLLARNPOINTS,-15,0x0066FF);		
   7.392 +		printf("Dollar error: %f\n",error);
   7.393 +	      }
   7.394 +	      
   7.395 +	    }
   7.396 +	    else if(numDollarTemplates < MAXTEMPLATES) {
   7.397 +	      
   7.398 +	      dollarNormalize(dollarPath[j],
   7.399 +			      dollarTemplate[numDollarTemplates]);
   7.400 +	      /*
   7.401 +	      int k;	      
   7.402 +	      for(k = 0;k<DOLLARNPOINTS;k++) {
   7.403 +		printf("(%f,%f)\n",dollarTemplate[numDollarTemplates][i].x,
   7.404 +		       dollarTemplate[numDollarTemplates][i].y);
   7.405 +		       }*/
   7.406 +	      numDollarTemplates++;	      
   7.407 +	    }
   7.408 +
   7.409 +	    gestureLast[j].f.id = -1;
   7.410 +	    break;
   7.411 +	  }
   7.412 +	  else {
   7.413 +	    dollarPath[j].p[dollarPath[j].numPoints].x = x;
   7.414 +	    dollarPath[j].p[dollarPath[j].numPoints].y = y;
   7.415 +	    float dx = (dollarPath[j].p[dollarPath[j].numPoints  ].x-
   7.416 +			dollarPath[j].p[dollarPath[j].numPoints-1].x);
   7.417 +	    float dy = (dollarPath[j].p[dollarPath[j].numPoints  ].y-
   7.418 +			dollarPath[j].p[dollarPath[j].numPoints-1].y);
   7.419 +	    dollarPath[j].length += sqrt(dx*dx + dy*dy);
   7.420 +
   7.421 +	    dollarPath[j].numPoints++;
   7.422 +
   7.423 +	    centroid.x = centroid.x + dx/numDownFingers;
   7.424 +	    centroid.y = centroid.y + dy/numDownFingers;    
   7.425 +	    if(numDownFingers > 1) {
   7.426 +	      Point lv; //Vector from centroid to last x,y position
   7.427 +	      Point v; //Vector from centroid to current x,y position
   7.428 +	      lv.x = gestureLast[j].cv.x;
   7.429 +	      lv.y = gestureLast[j].cv.y;
   7.430 +	      float lDist = sqrt(lv.x*lv.x + lv.y*lv.y);
   7.431 +	      
   7.432 +	      v.x = x - centroid.x;
   7.433 +	      v.y = y - centroid.y;
   7.434 +	      gestureLast[j].cv = v;
   7.435 +	      float Dist = sqrt(v.x*v.x+v.y*v.y);
   7.436 +	      // cos(dTheta) = (v . lv)/(|v| * |lv|)
   7.437 +	      
   7.438 +	      lv.x/=lDist;
   7.439 +	      lv.y/=lDist;
   7.440 +	      v.x/=Dist;
   7.441 +	      v.y/=Dist;
   7.442 +	      float dtheta = atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
   7.443 +	      
   7.444 +	      float dDist = (lDist - Dist);	      
   7.445 +	      
   7.446 +	      gestureLast[j].dDist = dDist;
   7.447 +	      gestureLast[j].dtheta = dtheta;
   7.448 +
   7.449 +	      //gdtheta = gdtheta*.9 + dtheta*.1;
   7.450 +	      //gdDist  =  gdDist*.9 +  dDist*.1
   7.451 +	      gdtheta += dtheta;
   7.452 +	      gdDist += dDist;
   7.453 +
   7.454 +	      //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
   7.455 +	      //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
   7.456 +	    }
   7.457 +	    else {
   7.458 +	      gestureLast[j].dDist = 0;
   7.459 +	      gestureLast[j].dtheta = 0;
   7.460 +	      gestureLast[j].cv.x = 0;
   7.461 +	      gestureLast[j].cv.y = 0;
   7.462 +	    }
   7.463 +	    gestureLast[j].f.p.x = x;
   7.464 +	    gestureLast[j].f.p.y = y;
   7.465 +	    break;
   7.466 +	    //pressure?
   7.467 +	  }	  
   7.468 +	}
   7.469 +	else if(gestureLast[j].f.id == -1 && empty == -1) {
   7.470 +	  empty = j;
   7.471 +	}
   7.472 +      }
   7.473 +      
   7.474 +      if(j >= MAXFINGERS && empty >= 0) {
   7.475 +	//	printf("Finger Down!!!\n");
   7.476 +	numDownFingers++;
   7.477 +	centroid.x = (centroid.x*(numDownFingers - 1) + x)/numDownFingers;
   7.478 +	centroid.y = (centroid.y*(numDownFingers - 1) + y)/numDownFingers;
   7.479 +	
   7.480 +	j = empty;
   7.481 +	gestureLast[j].f.id = event.tfinger.fingerId;
   7.482 +	gestureLast[j].f.p.x  = x;
   7.483 +	gestureLast[j].f.p.y  = y;
   7.484 +	
   7.485 +	
   7.486 +	dollarPath[j].length = 0;
   7.487 +	dollarPath[j].p[0].x = x;
   7.488 +	dollarPath[j].p[0].y = y;
   7.489 +	dollarPath[j].numPoints = 1;
   7.490 +      }
   7.491 +      
   7.492 +      //draw the touch:
   7.493 +      
   7.494 +      if(gestureLast[j].f.id < 0) continue; //Finger up. Or some error...
   7.495 +      
   7.496 +      unsigned int c = colors[gestureLast[j].f.id%7]; 
   7.497 +      unsigned int col = 
   7.498 +	((unsigned int)(c*(.1+.85))) |
   7.499 +	((unsigned int)((0xFF*(1-((float)age)/EVENT_BUF_SIZE))) & 0xFF)<<24;
   7.500 +      x = gestureLast[j].f.p.x;
   7.501 +      y = gestureLast[j].f.p.y;
   7.502 +      if(event.type == SDL_FINGERMOTION)
   7.503 +	drawCircle(screen,x*screen->w,y*screen->h,5,col);
   7.504 +      else if(event.type == SDL_FINGERDOWN)
   7.505 +	drawCircle(screen,x*screen->w,y*screen->h,-10,col);     
   7.506 +      
   7.507 +      //if there is a centroid, draw it
   7.508 +      if(numDownFingers > 1) {
   7.509 +	unsigned int col = 
   7.510 +	  ((unsigned int)(0xFFFFFF)) |
   7.511 +	  ((unsigned int)((0xFF*(1-((float)age)/EVENT_BUF_SIZE))) & 0xFF)<<24;
   7.512 +	drawCircle(screen,centroid.x*screen->w,centroid.y*screen->h,5,col);
   7.513 +      }
   7.514 +    }
   7.515 +  }
   7.516 +  
   7.517 +
   7.518 +  for(i=0;i<MAXFINGERS;i++)
   7.519 +    if(finger[i].p.x >= 0 && finger[i].p.y >= 0)
   7.520 +      if(finger[i].pressure > 0)
   7.521 +	drawCircle(screen,finger[i].p.x*screen->w,finger[i].p.y*screen->h
   7.522 +		   ,20,0xFF*finger[i].pressure);
   7.523 +      else
   7.524 +	drawCircle(screen,finger[i].p.x*screen->w,finger[i].p.y*screen->h
   7.525 +		   ,20,0xFF);
   7.526 +
   7.527 +
   7.528 +  
   7.529 +  keystat[32] = 0;
   7.530 +  
   7.531 +  if(knob.p.x > 0)
   7.532 +    drawKnob(screen,knob);
   7.533 +  
   7.534 +  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
   7.535 +  
   7.536 +  SDL_Flip(screen);
   7.537 +}
   7.538 +
   7.539 +SDL_Surface* initScreen(int width,int height)
   7.540 +{
   7.541 +  return SDL_SetVideoMode(width, height, DEPTH,
   7.542 +			  SDL_HWSURFACE | SDL_RESIZABLE);
   7.543 +}
   7.544 +
   7.545 +int main(int argc, char* argv[])
   7.546 +{  
   7.547 +  SDL_Surface *screen;
   7.548 +  SDL_Event event;
   7.549 +  
   7.550 +  int keypress = 0;
   7.551 +  int h=0,s=1,i,j;
   7.552 +
   7.553 +  //gesture variables
   7.554 +  int numDownFingers = 0;
   7.555 +  float gdtheta = 0,gdDist = 0;
   7.556 +  Point centroid;
   7.557 +  knob.r = .1;
   7.558 +  knob.ang = 0;
   7.559 +  TouchPoint gestureLast[MAXFINGERS];
   7.560 +  
   7.561 +
   7.562 +
   7.563 +  memset(keystat,0,512*sizeof(keystat[0]));
   7.564 +  if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1;
   7.565 +  
   7.566 +  if (!(screen = initScreen(WIDTH,HEIGHT)))
   7.567 +    {
   7.568 +      SDL_Quit();
   7.569 +      return 1;
   7.570 +    }
   7.571 +
   7.572 +  while(!keystat[27]) {
   7.573 +    //Poll SDL
   7.574 +    while(SDL_PollEvent(&event)) 
   7.575 +      {
   7.576 +	//Record _all_ events
   7.577 +	events[eventWrite & (EVENT_BUF_SIZE-1)] = event;
   7.578 +	eventWrite++;
   7.579 +	
   7.580 +	switch (event.type) 
   7.581 +	  {
   7.582 +	  case SDL_QUIT:
   7.583 +	    keystat[27] = 1;
   7.584 +	    break;
   7.585 +	  case SDL_KEYDOWN:
   7.586 +	    //printf("%i\n",event.key.keysym.sym);
   7.587 +	    keystat[event.key.keysym.sym] = 1;
   7.588 +	    //keypress = 1;
   7.589 +	    break;
   7.590 +	  case SDL_KEYUP:
   7.591 +	      //printf("%i\n",event.key.keysym.sym);
   7.592 +	    keystat[event.key.keysym.sym] = 0;
   7.593 +	    //keypress = 1;
   7.594 +	    break;
   7.595 +	  case SDL_VIDEORESIZE:
   7.596 +	    if (!(screen = initScreen(event.resize.w,
   7.597 +				      event.resize.h)))
   7.598 +	      {
   7.599 +		SDL_Quit();
   7.600 +		return 1;
   7.601 +	      }
   7.602 +	    break;
   7.603 +	  case SDL_MOUSEMOTION:
   7.604 +	    mousx = event.motion.x;
   7.605 +	    mousy = event.motion.y; 
   7.606 +	    break;
   7.607 +	  case SDL_MOUSEBUTTONDOWN:
   7.608 +	    bstatus |=  (1<<(event.button.button-1));
   7.609 +	    break;
   7.610 +	  case SDL_MOUSEBUTTONUP:
   7.611 +	    bstatus &= ~(1<<(event.button.button-1));
   7.612 +	    break;
   7.613 +	  case SDL_FINGERMOTION:    
   7.614 +	    ;
   7.615 +	    //printf("Finger: %i,x: %i, y: %i\n",event.tfinger.fingerId,
   7.616 +	    //	   event.tfinger.x,event.tfinger.y);
   7.617 +	    SDL_Touch* inTouch = SDL_GetTouch(event.tfinger.touchId);
   7.618 +	    SDL_Finger* inFinger = SDL_GetFinger(inTouch,event.tfinger.fingerId);
   7.619 +
   7.620 +	    for(i = 0;i<MAXFINGERS;i++) 
   7.621 +	      if(index2fingerid[i] == event.tfinger.fingerId) 	      
   7.622 +		break;
   7.623 +	    if(i == MAXFINGERS) break;  
   7.624 +	    if(inTouch > 0) {
   7.625 +	      finger[i].p.x = ((float)event.tfinger.x)/
   7.626 +		inTouch->xres;
   7.627 +	      finger[i].p.y = ((float)event.tfinger.y)/
   7.628 +		inTouch->yres;
   7.629 +	      
   7.630 +	      finger[i].pressure = 
   7.631 +		((float)event.tfinger.pressure)/inTouch->pressureres;
   7.632 +	      /*
   7.633 +	      printf("Finger: %i, Pressure: %f Pressureres: %i\n",
   7.634 +		     event.tfinger.fingerId,
   7.635 +		     finger[i].pressure,
   7.636 +		     inTouch->pressureres);
   7.637 +	      */
   7.638 +	      //printf("Finger: %i, pressure: %f\n",event.tfinger.fingerId,
   7.639 +	      //   finger[event.tfinger.fingerId].pressure);
   7.640 +	    }
   7.641 +	    
   7.642 +	    break;	    
   7.643 +	  case SDL_FINGERDOWN:
   7.644 +	    printf("Finger: %i down - x: %i, y: %i\n",event.tfinger.fingerId,
   7.645 +		   event.tfinger.x,event.tfinger.y);
   7.646 +
   7.647 +	    for(i = 0;i<MAXFINGERS;i++) 
   7.648 +	      if(index2fingerid[i] == -1) {
   7.649 +		index2fingerid[i] = event.tfinger.fingerId;
   7.650 +		break;
   7.651 +	      }
   7.652 +	    finger[i].p.x = event.tfinger.x;
   7.653 +	    finger[i].p.y = event.tfinger.y;
   7.654 +	    break;
   7.655 +	  case SDL_FINGERUP:
   7.656 +	    printf("Figner: %i up - x: %i, y: %i\n",event.tfinger.fingerId,
   7.657 +	           event.tfinger.x,event.tfinger.y);
   7.658 +	    for(i = 0;i<MAXFINGERS;i++) 
   7.659 +	      if(index2fingerid[i] == event.tfinger.fingerId) {
   7.660 +		index2fingerid[i] = -1;
   7.661 +		break;
   7.662 +	      }
   7.663 +	    finger[i].p.x = -1;
   7.664 +	    finger[i].p.y = -1;
   7.665 +	    break;
   7.666 +	  case SDL_MULTIGESTURE:
   7.667 +	    knob.p.x = event.mgesture.x;
   7.668 +	    knob.p.y = event.mgesture.y;
   7.669 +	    knob.ang += event.mgesture.dTheta;
   7.670 +	    knob.r += event.mgesture.dDist;
   7.671 +	  }
   7.672 +      
   7.673 +    
   7.674 +	
   7.675 +	//And draw
   7.676 +	
   7.677 +      }
   7.678 +    DrawScreen(screen,h);
   7.679 +    //printf("c: (%f,%f)\n",centroid.x,centroid.y);
   7.680 +    //printf("numDownFingers: %i\n",numDownFingers);
   7.681 +    //for(i=0;i<512;i++) 
   7.682 +    // if(keystat[i]) printf("%i\n",i);
   7.683 +      
   7.684 +    
   7.685 +  }  
   7.686 +  SDL_Quit();
   7.687 +  
   7.688 +  return 0;
   7.689 +}
   7.690 +
     8.1 --- a/touchTest/makefile	Tue Jul 06 02:05:27 2010 -0700
     8.2 +++ b/touchTest/makefile	Wed Jul 07 04:13:08 2010 -0700
     8.3 @@ -1,4 +1,5 @@
     8.4  SDLTest : touchSimp.c touchPong.c
     8.5 +	gcc gestureSDLTest.c -o gestureSDLTest `sdl-config --cflags --libs` -g
     8.6  	gcc gestureTest.c -o gestureTest `sdl-config --cflags --libs` -g
     8.7  	gcc touchTest.c -o touchTest `sdl-config --cflags --libs` -g		
     8.8  	gcc touchSimp.c -o touchSimp `sdl-config --cflags --libs` -g
     9.1 Binary file touchTest/touchPong has changed
    10.1 Binary file touchTest/touchSimp has changed