1/* 2 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely. 11*/ 12/* Usage: 13 * Spacebar to begin recording a gesture on all touches. 14 * s to save all touches into "./gestureSave" 15 * l to load all touches from "./gestureSave" 16 */ 17 18#include <stdio.h> 19#include <math.h> 20 21#include "SDL.h" 22#include "SDL_touch.h" 23#include "SDL_gesture.h" 24 25/* Make sure we have good macros for printing 32 and 64 bit values */ 26#ifndef PRIs32 27#define PRIs32 "d" 28#endif 29#ifndef PRIu32 30#define PRIu32 "u" 31#endif 32#ifndef PRIs64 33#ifdef __WIN32__ 34#define PRIs64 "I64" 35#else 36#define PRIs64 "lld" 37#endif 38#endif 39#ifndef PRIu64 40#ifdef __WIN32__ 41#define PRIu64 "I64u" 42#else 43#define PRIu64 "llu" 44#endif 45#endif 46 47#define WIDTH 640 48#define HEIGHT 480 49#define BPP 4 50#define DEPTH 32 51 52/* MUST BE A POWER OF 2! */ 53#define EVENT_BUF_SIZE 256 54 55 56#define VERBOSE 0 57 58static SDL_Window *window; 59static SDL_Event events[EVENT_BUF_SIZE]; 60static int eventWrite; 61 62 63static int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF}; 64 65typedef struct { 66 float x,y; 67} Point; 68 69typedef struct { 70 float ang,r; 71 Point p; 72} Knob; 73 74static Knob knob; 75 76void handler (int sig) 77{ 78 SDL_Log ("exiting...(%d)", sig); 79 exit (0); 80} 81 82void perror_exit (char *error) 83{ 84 perror (error); 85 handler (9); 86} 87 88void setpix(SDL_Surface *screen, float _x, float _y, unsigned int col) 89{ 90 Uint32 *pixmem32; 91 Uint32 colour; 92 Uint8 r,g,b; 93 int x = (int)_x; 94 int y = (int)_y; 95 float a; 96 97 if(x < 0 || x >= screen->w) return; 98 if(y < 0 || y >= screen->h) return; 99 100 pixmem32 = (Uint32*) screen->pixels + y*screen->pitch/BPP + x; 101 102 SDL_memcpy(&colour,pixmem32,screen->format->BytesPerPixel); 103 104 SDL_GetRGB(colour,screen->format,&r,&g,&b); 105 /* r = 0;g = 0; b = 0; */ 106 a = (float)((col>>24)&0xFF); 107 if(a == 0) a = 0xFF; /* Hack, to make things easier. */ 108 a /= 0xFF; 109 r = (Uint8)(r*(1-a) + ((col>>16)&0xFF)*(a)); 110 g = (Uint8)(g*(1-a) + ((col>> 8)&0xFF)*(a)); 111 b = (Uint8)(b*(1-a) + ((col>> 0)&0xFF)*(a)); 112 colour = SDL_MapRGB( screen->format,r, g, b); 113 114 115 *pixmem32 = colour; 116} 117 118void drawLine(SDL_Surface *screen,float x0,float y0,float x1,float y1,unsigned int col) { 119 float t; 120 for(t=0;t<1;t+=(float)(1.f/SDL_max(SDL_fabs(x0-x1),SDL_fabs(y0-y1)))) 121 setpix(screen,x1+t*(x0-x1),y1+t*(y0-y1),col); 122} 123 124void drawCircle(SDL_Surface* screen,float x,float y,float r,unsigned int c) 125{ 126 float tx,ty; 127 float xr; 128 for(ty = (float)-SDL_fabs(r);ty <= (float)SDL_fabs((int)r);ty++) { 129 xr = (float)sqrt(r*r - ty*ty); 130 if(r > 0) { /* r > 0 ==> filled circle */ 131 for(tx=-xr+.5f;tx<=xr-.5;tx++) { 132 setpix(screen,x+tx,y+ty,c); 133 } 134 } 135 else { 136 setpix(screen,x-xr+.5f,y+ty,c); 137 setpix(screen,x+xr-.5f,y+ty,c); 138 } 139 } 140} 141 142void drawKnob(SDL_Surface* screen,Knob k) { 143 drawCircle(screen,k.p.x*screen->w,k.p.y*screen->h,k.r*screen->w,0xFFFFFF); 144 drawCircle(screen,(k.p.x+k.r/2*SDL_cosf(k.ang))*screen->w, 145 (k.p.y+k.r/2*SDL_sinf(k.ang))*screen->h,k.r/4*screen->w,0); 146} 147 148void DrawScreen(SDL_Surface* screen) 149{ 150 int i; 151#if 1 152 SDL_FillRect(screen, NULL, 0); 153#else 154 int x, y; 155 for(y = 0;y < screen->h;y++) 156 for(x = 0;x < screen->w;x++) 157 setpix(screen,(float)x,(float)y,((x%255)<<16) + ((y%255)<<8) + (x+y)%255); 158#endif 159 160 /* draw Touch History */ 161 for(i = eventWrite; i < eventWrite+EVENT_BUF_SIZE; ++i) { 162 const SDL_Event *event = &events[i&(EVENT_BUF_SIZE-1)]; 163 float age = (float)(i - eventWrite) / EVENT_BUF_SIZE; 164 float x, y; 165 unsigned int c, col; 166 167 if(event->type == SDL_FINGERMOTION || 168 event->type == SDL_FINGERDOWN || 169 event->type == SDL_FINGERUP) { 170 x = event->tfinger.x; 171 y = event->tfinger.y; 172 173 /* draw the touch: */ 174 c = colors[event->tfinger.fingerId%7]; 175 col = ((unsigned int)(c*(.1+.85))) | (unsigned int)(0xFF*age)<<24; 176 177 if(event->type == SDL_FINGERMOTION) 178 drawCircle(screen,x*screen->w,y*screen->h,5,col); 179 else if(event->type == SDL_FINGERDOWN) 180 drawCircle(screen,x*screen->w,y*screen->h,-10,col); 181 } 182 } 183 184 if(knob.p.x > 0) 185 drawKnob(screen,knob); 186 187 SDL_UpdateWindowSurface(window); 188} 189 190SDL_Surface* initScreen(int width,int height) 191{ 192 if (!window) { 193 window = SDL_CreateWindow("Gesture Test", 194 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 195 width, height, SDL_WINDOW_RESIZABLE); 196 } 197 if (!window) { 198 return NULL; 199 } 200 return SDL_GetWindowSurface(window); 201} 202 203int main(int argc, char* argv[]) 204{ 205 SDL_Surface *screen; 206 SDL_Event event; 207 SDL_bool quitting = SDL_FALSE; 208 SDL_RWops *stream; 209 210 /* Enable standard application logging */ 211 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); 212 213 /* gesture variables */ 214 knob.r = .1f; 215 knob.ang = 0; 216 217 if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1; 218 219 if (!(screen = initScreen(WIDTH,HEIGHT))) 220 { 221 SDL_Quit(); 222 return 1; 223 } 224 225 while(!quitting) { 226 while(SDL_PollEvent(&event)) 227 { 228 /* Record _all_ events */ 229 events[eventWrite & (EVENT_BUF_SIZE-1)] = event; 230 eventWrite++; 231 232 switch (event.type) 233 { 234 case SDL_QUIT: 235 quitting = SDL_TRUE; 236 break; 237 case SDL_KEYDOWN: 238 switch (event.key.keysym.sym) 239 { 240 case SDLK_SPACE: 241 SDL_RecordGesture(-1); 242 break; 243 case SDLK_s: 244 stream = SDL_RWFromFile("gestureSave", "w"); 245 SDL_Log("Wrote %i templates", SDL_SaveAllDollarTemplates(stream)); 246 SDL_RWclose(stream); 247 break; 248 case SDLK_l: 249 stream = SDL_RWFromFile("gestureSave", "r"); 250 SDL_Log("Loaded: %i", SDL_LoadDollarTemplates(-1, stream)); 251 SDL_RWclose(stream); 252 break; 253 case SDLK_ESCAPE: 254 quitting = SDL_TRUE; 255 break; 256 } 257 break; 258 case SDL_WINDOWEVENT: 259 if (event.window.event == SDL_WINDOWEVENT_RESIZED) { 260 if (!(screen = initScreen(event.window.data1, event.window.data2))) 261 { 262 SDL_Quit(); 263 return 1; 264 } 265 } 266 break; 267 case SDL_FINGERMOTION: 268#if VERBOSE 269 SDL_Log("Finger: %i,x: %i, y: %i",event.tfinger.fingerId, 270 event.tfinger.x,event.tfinger.y); 271#endif 272 break; 273 case SDL_FINGERDOWN: 274#if VERBOSE 275 SDL_Log("Finger: %"PRIs64" down - x: %i, y: %i", 276 event.tfinger.fingerId,event.tfinger.x,event.tfinger.y); 277#endif 278 break; 279 case SDL_FINGERUP: 280#if VERBOSE 281 SDL_Log("Finger: %"PRIs64" up - x: %i, y: %i", 282 event.tfinger.fingerId,event.tfinger.x,event.tfinger.y); 283#endif 284 break; 285 case SDL_MULTIGESTURE: 286#if VERBOSE 287 SDL_Log("Multi Gesture: x = %f, y = %f, dAng = %f, dR = %f", 288 event.mgesture.x, 289 event.mgesture.y, 290 event.mgesture.dTheta, 291 event.mgesture.dDist); 292 SDL_Log("MG: numDownTouch = %i",event.mgesture.numFingers); 293#endif 294 knob.p.x = event.mgesture.x; 295 knob.p.y = event.mgesture.y; 296 knob.ang += event.mgesture.dTheta; 297 knob.r += event.mgesture.dDist; 298 break; 299 case SDL_DOLLARGESTURE: 300 SDL_Log("Gesture %"PRIs64" performed, error: %f", 301 event.dgesture.gestureId, 302 event.dgesture.error); 303 break; 304 case SDL_DOLLARRECORD: 305 SDL_Log("Recorded gesture: %"PRIs64"",event.dgesture.gestureId); 306 break; 307 } 308 } 309 DrawScreen(screen); 310 } 311 SDL_Quit(); 312 return 0; 313} 314 315