diff options
| author | erdgeist <> | 2008-09-16 15:40:46 +0000 |
|---|---|---|
| committer | erdgeist <> | 2008-09-16 15:40:46 +0000 |
| commit | 8d957f068792b4ee55f807930c975699c29922a2 (patch) | |
| tree | 4a960cbe6c05797175a7c8b518f93e4459bafd1d | |
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | display.c | 63 | ||||
| -rw-r--r-- | display.h | 6 | ||||
| -rw-r--r-- | gm.h | 5 | ||||
| -rw-r--r-- | heuristics.c | 111 | ||||
| -rw-r--r-- | heuristics.h | 13 | ||||
| -rw-r--r-- | locate.c | 91 | ||||
| -rw-r--r-- | locate.h | 9 | ||||
| -rw-r--r-- | main.c | 172 | ||||
| -rw-r--r-- | vubars.c | 148 | ||||
| -rw-r--r-- | vubars.h | 6 |
11 files changed, 629 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bf43616 --- /dev/null +++ b/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | main: main.c locate.c display.c vubars.c locate.h gm.h display.h vubars.h heuristics.c | ||
| 2 | gcc -O2 -o main main.c locate.c display.c vubars.c heuristics.c -l cwiid -lm -lSDL -lSDL_gfx | ||
| 3 | |||
| 4 | clean: | ||
| 5 | rm main | ||
diff --git a/display.c b/display.c new file mode 100644 index 0000000..a4ac62b --- /dev/null +++ b/display.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | #include <SDL/SDL.h> | ||
| 2 | #include <SDL/SDL_gfxPrimitives.h> | ||
| 3 | |||
| 4 | #include "display.h" | ||
| 5 | |||
| 6 | static SDL_Surface *screen; | ||
| 7 | static int g_width, g_height; | ||
| 8 | |||
| 9 | void display_init( int width, int height) { | ||
| 10 | g_width = width; | ||
| 11 | g_height = height; | ||
| 12 | |||
| 13 | if (SDL_Init (SDL_INIT_EVERYTHING) == -1) { | ||
| 14 | fprintf( stderr, "Can't initialize SDL.\n" ); | ||
| 15 | exit (1); | ||
| 16 | } | ||
| 17 | |||
| 18 | screen = SDL_SetVideoMode ( width, height, 24, SDL_SWSURFACE | SDL_DOUBLEBUF ); | ||
| 19 | if( !screen ) { | ||
| 20 | fprintf( stderr, "Can't set video mode.\n" ); | ||
| 21 | exit( 1 ); | ||
| 22 | } | ||
| 23 | |||
| 24 | memset( screen->pixels, 0, width * height * 3 ); | ||
| 25 | SDL_WM_SetCaption ( "GodMachine", "GodMachine" ); | ||
| 26 | |||
| 27 | } | ||
| 28 | |||
| 29 | void display_clear( ) { | ||
| 30 | // rectangleColor( screen, 0, 0, g_width, g_height, 0 ); | ||
| 31 | |||
| 32 | memset( screen->pixels, 0, g_width * g_height * 3 ); | ||
| 33 | vlineColor( screen, g_width / 2, 0, g_height, 0xffffffff ); | ||
| 34 | hlineColor( screen, 0, g_width, g_height / 2, 0xffffffff ); | ||
| 35 | } | ||
| 36 | |||
| 37 | void display_circle( int wii_id, int x, int y, int w ) { | ||
| 38 | int xoff = ( wii_id & 1 ) * g_width / 2; | ||
| 39 | int yoff = ( wii_id >> 1 ) * g_height / 2; | ||
| 40 | |||
| 41 | filledCircleColor(screen, x + xoff, y + yoff, w, 0xffffffff ); | ||
| 42 | |||
| 43 | } | ||
| 44 | |||
| 45 | void display_line( int wii_id, int x0, int y0, int x1, int y1 ) { | ||
| 46 | int xoff = ( wii_id & 1 ) * g_width / 2; | ||
| 47 | int yoff = ( wii_id >> 1 ) * g_height / 2; | ||
| 48 | |||
| 49 | aalineColor( screen, x0 + xoff, y0 + yoff, x1 + xoff, y1 + yoff, 0xffffffff ); | ||
| 50 | |||
| 51 | } | ||
| 52 | |||
| 53 | void display_rectangle( int wii_id, int x, int y, int w, int h ) { | ||
| 54 | int xoff = ( wii_id & 1 ) * g_width / 2; | ||
| 55 | int yoff = ( wii_id >> 1 ) * g_height / 2; | ||
| 56 | |||
| 57 | boxColor( screen, x + xoff, y + yoff, x + xoff + w, y + yoff + h, 0xffffffff ); | ||
| 58 | |||
| 59 | } | ||
| 60 | |||
| 61 | void display_redraw() { | ||
| 62 | SDL_Flip( screen ); | ||
| 63 | } | ||
diff --git a/display.h b/display.h new file mode 100644 index 0000000..2b2464f --- /dev/null +++ b/display.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | void display_init( int width, int height); | ||
| 2 | void display_redraw( ); | ||
| 3 | |||
| 4 | void display_clear( ); | ||
| 5 | void display_line( int wii_id, int x0, int y0, int x1, int y1 ); | ||
| 6 | void display_circle( int wii_id, int x, int y, int w ); | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | typedef struct { | ||
| 2 | double x; double y; | ||
| 3 | } wii_pt; | ||
| 4 | |||
| 5 | #define WII_COUNT 4 | ||
diff --git a/heuristics.c b/heuristics.c new file mode 100644 index 0000000..429a612 --- /dev/null +++ b/heuristics.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | |||
| 3 | #include "vubars.h" | ||
| 4 | |||
| 5 | static void heuristics_getGesture( int const amount, int const off, int const * const values, | ||
| 6 | int *dxl, int *dyl, int *dxr, int *dyr ); | ||
| 7 | |||
| 8 | int heuristics_getEnergy( int const amount, int const * const values ) { | ||
| 9 | int energy = 0; | ||
| 10 | int i; | ||
| 11 | |||
| 12 | for( i = 0; i < amount-1; ++i ) | ||
| 13 | energy += values[i]*values[i+1]; | ||
| 14 | |||
| 15 | return energy; | ||
| 16 | } | ||
| 17 | |||
| 18 | // Gets the two longest consecutive gestures found | ||
| 19 | // in frames. -1 in off[ab] means no gesture found | ||
| 20 | |||
| 21 | // Here what counts: the bigger abs(dx[ab]), the longer the gesture | ||
| 22 | // the bigger dy[ab]/dx[ab], the slower the gesture | ||
| 23 | void heuristics_getGestures( int const amount, int const * const values, | ||
| 24 | int *offa, int *dxa, int *dya, int *dda, | ||
| 25 | int *offb, int *dxb, int *dyb, int *ddb ) | ||
| 26 | { | ||
| 27 | int i, l = 0; | ||
| 28 | int dxl [ amount ], dyl [ amount ], dxr [ amount ], dyr [ amount ]; | ||
| 29 | |||
| 30 | // Get the longest gestures for each point - both into left and rite | ||
| 31 | for( i=0; i<amount; ++i ) | ||
| 32 | heuristics_getGesture( amount, i, values, dxl + i, dyl + i, dxr + i, dyr + i ); | ||
| 33 | |||
| 34 | // "Sort" gesture by length | ||
| 35 | *offa = *dxa = *dya = 0; | ||
| 36 | for( i=0; i<amount; ++i ) { | ||
| 37 | if( dxr[ i ] > *dxa ) { *offa = i; *dxa = dxr[ i ]; *dya = dyr[ i ]; *dda = 1; } | ||
| 38 | if( dxl[ i ] > *dxa ) { *offa = i; *dxa = dxl[ i ]; *dya = dyl[ i ]; *dda =-1; } | ||
| 39 | } | ||
| 40 | |||
| 41 | // If no gesture found at all, invalidate off | ||
| 42 | // and return... second run wouldnt suddenly find a gesture | ||
| 43 | if( *dxa == 0 ) { *offa = *offb = -1; return; } | ||
| 44 | |||
| 45 | // Now clear the best result - this will find us the second best result | ||
| 46 | i = *offa; | ||
| 47 | if( *dda == 1 ) { | ||
| 48 | for( i=*offa; i < *offa + dxr[ *offa ]; ++i ) | ||
| 49 | dxr[ i ] = 0; | ||
| 50 | } else { | ||
| 51 | for( i=*offa; i > *offa - dxl[ *offa ]; --i ) | ||
| 52 | dxl[ i ] = 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | // "Sort" remaining gestures by length | ||
| 56 | *offb = *dxb = *dyb = 0; | ||
| 57 | for( i=0; i<amount; ++i ) { | ||
| 58 | if( dxr[ i ] > *dxb ) { *offb = i; *dxb = dxr[ i ]; *dyb = dyr[ i ]; *ddb = 1;} | ||
| 59 | if( dxl[ i ] > *dxb ) { *offb = i; *dxb = -dxl[ i ]; *dyb = dyl[ i ]; *ddb =-1;} | ||
| 60 | } | ||
| 61 | |||
| 62 | // If no secondary gesture found, invalidate off | ||
| 63 | if( *dxb == 0 ) *offb = -1; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void heuristics_getGesture( int const amount, int const off, int const * const values, | ||
| 67 | int * const dxl, int * const dyl, int * const dxr, int * const dyr ) | ||
| 68 | { | ||
| 69 | int i; | ||
| 70 | |||
| 71 | // Initialize as "nothing happened" | ||
| 72 | *dxl = *dxr = *dyl = *dyr = 0; | ||
| 73 | |||
| 74 | // if this didn't peak in last frame, we're not starting | ||
| 75 | // a gesture here. | ||
| 76 | if( values[off] != VU_PEAK ) return; | ||
| 77 | |||
| 78 | if( off > 0 ) *dyl = values[off]-values[off-1]; | ||
| 79 | if( off < amount-1 ) *dyr = values[off]-values[off+1]; | ||
| 80 | |||
| 81 | if( !*dyl && !*dyr ) return; | ||
| 82 | |||
| 83 | // Depending on where this peaks seems to have come from, | ||
| 84 | // chose direction where to follow it | ||
| 85 | // try to collect enough monotonic samples and calculate a | ||
| 86 | // slope. Since our sample peaks, all others cant be larger | ||
| 87 | if( (*dyl) && (*dyl < *dyr) ) { | ||
| 88 | (*dxl)++; | ||
| 89 | for( i=off-1; i>=0; --i ) { | ||
| 90 | int dy = values[i+1] - values[i]; | ||
| 91 | |||
| 92 | // If it scrolled out of scope, ignore it | ||
| 93 | if( !values[i] || dy < 0 ) break; | ||
| 94 | |||
| 95 | (*dxl)++; | ||
| 96 | (*dyl) += dy; | ||
| 97 | } | ||
| 98 | } else { | ||
| 99 | (*dxr)++; | ||
| 100 | // Do the same when going right | ||
| 101 | for( i=off+1; i<amount; ++i ) { | ||
| 102 | int dy = values[i-1] - values[i]; | ||
| 103 | |||
| 104 | // If it scrolled out of scope, ignore it | ||
| 105 | if( !values[i] || dy < 0 ) break; | ||
| 106 | |||
| 107 | (*dxr)++; | ||
| 108 | (*dyr) += dy; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
diff --git a/heuristics.h b/heuristics.h new file mode 100644 index 0000000..a01d1f7 --- /dev/null +++ b/heuristics.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Gets the two longest consecutive gestures found | ||
| 2 | // in frames. -1 in off[ab] means no gesture found | ||
| 3 | |||
| 4 | // Here what counts: the bigger abs(dx[ab]), the longer the gesture | ||
| 5 | // the bigger dy[ab]/dx[ab], the slower the gesture | ||
| 6 | void heuristics_getGestures( int const amount, int const * const values, | ||
| 7 | int *offa, int *dxa, int *dya, int *dda, | ||
| 8 | int *offb, int *dxb, int *dyb, int *ddb ); | ||
| 9 | |||
| 10 | // Calculate an "energy" level contained in vu bars. | ||
| 11 | // to soften spikes, we correlate neighbouring bars | ||
| 12 | int heuristics_getEnergy( int const amount, int const * const values ); | ||
| 13 | |||
diff --git a/locate.c b/locate.c new file mode 100644 index 0000000..1d3ec72 --- /dev/null +++ b/locate.c | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | #include <math.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | |||
| 4 | #include "gm.h" | ||
| 5 | |||
| 6 | static wii_pt bounds[2][4]; | ||
| 7 | static int g_calibrated[4]; | ||
| 8 | |||
| 9 | double get_dist( wii_pt *p1, wii_pt *p2 ) { | ||
| 10 | double d = (p1->x - p2->x)*(p1->x - p2->x) + | ||
| 11 | (p1->y - p2->y)*(p1->y - p2->y); | ||
| 12 | return sqrt(d); | ||
| 13 | } | ||
| 14 | |||
| 15 | /* This call stores information about the expected | ||
| 16 | rectangle for each wii | ||
| 17 | */ | ||
| 18 | void wii_calibrate( int wii_id, wii_pt *coords ) { | ||
| 19 | double max_dist = 0.0; | ||
| 20 | int pt1 = 0, pt2 = 0, i, j; | ||
| 21 | |||
| 22 | /* Points with maximal distance span a rectangle */ | ||
| 23 | for( i=0; i<4; ++i ) | ||
| 24 | for( j=1; j<4; ++j ) { | ||
| 25 | double dist = get_dist( coords+i, coords+j ); | ||
| 26 | if( dist > max_dist ) { | ||
| 27 | pt1 = i; pt2 = j; | ||
| 28 | max_dist = dist; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | if( coords[pt1].x > coords[pt2].x ) { | ||
| 33 | bounds[0][wii_id] = coords[pt1]; | ||
| 34 | bounds[1][wii_id] = coords[pt2]; | ||
| 35 | } else { | ||
| 36 | bounds[1][wii_id] = coords[pt1]; | ||
| 37 | bounds[0][wii_id] = coords[pt2]; | ||
| 38 | } | ||
| 39 | |||
| 40 | g_calibrated[wii_id] = 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | int wii_point_to_led( int wii_id, wii_pt *coords ) { | ||
| 44 | // Ick nenn die immer so. | ||
| 45 | const double x0 = bounds[0][wii_id].x; | ||
| 46 | const double y0 = bounds[0][wii_id].y; | ||
| 47 | const double x1 = bounds[1][wii_id].x; | ||
| 48 | const double y1 = bounds[1][wii_id].y; | ||
| 49 | const double xp = coords->x; | ||
| 50 | const double yp = coords->y; | ||
| 51 | |||
| 52 | //printf( "%lf:%lf ", xp, yp ); | ||
| 53 | |||
| 54 | // Where m is slope of orthogonal line | ||
| 55 | // And n is square of diagonal of bounding box | ||
| 56 | double m = (x1-x0)*(xp-x0)+(y1-y0)*(yp-y0); | ||
| 57 | double n = (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0); | ||
| 58 | |||
| 59 | // To find out distance of coord to our base line | ||
| 60 | double q = (xp-x0)*(y1-y0)-(yp-y0)*(x1-x0); | ||
| 61 | |||
| 62 | //printf( "%lf %lf %lf\n", m, n, q ); | ||
| 63 | |||
| 64 | double offs_on_line = m/n; | ||
| 65 | double dist_to_line = q/n; | ||
| 66 | |||
| 67 | // If wii is not calibrated, we cannot detect point | ||
| 68 | if( !g_calibrated[wii_id] ) | ||
| 69 | return -1; | ||
| 70 | |||
| 71 | // Point is too far away to be considered a match | ||
| 72 | if( ( dist_to_line > 0.1 ) || ( dist_to_line < -0.1 ) ) { | ||
| 73 | // puts( "too far " ); | ||
| 74 | return -1; | ||
| 75 | } | ||
| 76 | |||
| 77 | // printf( "%1.3lf\n", offs_on_line ); | ||
| 78 | |||
| 79 | // Check, which segment our line hits | ||
| 80 | if( ( offs_on_line > (-1.0/6.0) ) && ( offs_on_line <= (1.0/6.0) ) ) | ||
| 81 | return 0; | ||
| 82 | if( ( offs_on_line > ( 1.0/6.0) ) && ( offs_on_line <= (3.0/6.0) ) ) | ||
| 83 | return 1; | ||
| 84 | if( ( offs_on_line > ( 3.0/6.0) ) && ( offs_on_line <= (5.0/6.0) ) ) | ||
| 85 | return 2; | ||
| 86 | if( ( offs_on_line > ( 5.0/6.0) ) && ( offs_on_line <= (7.0/6.0) ) ) | ||
| 87 | return 3; | ||
| 88 | |||
| 89 | // No match! | ||
| 90 | return -1; | ||
| 91 | } | ||
diff --git a/locate.h b/locate.h new file mode 100644 index 0000000..0b72f72 --- /dev/null +++ b/locate.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #ifndef _WII_LOCATE_H_ | ||
| 2 | #define _WII_LOCATE_H_ | ||
| 3 | |||
| 4 | #include "gm.h" | ||
| 5 | |||
| 6 | void wii_calibrate( int wii_id, wii_pt *coords ); | ||
| 7 | int wii_point_to_led( int wii_id, wii_pt *coords ); | ||
| 8 | |||
| 9 | #endif | ||
| @@ -0,0 +1,172 @@ | |||
| 1 | #include <stdarg.h> | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <stdlib.h> | ||
| 4 | #include <signal.h> | ||
| 5 | #include <time.h> | ||
| 6 | |||
| 7 | #include <cwiid.h> | ||
| 8 | #include "gm.h" | ||
| 9 | #include "display.h" | ||
| 10 | |||
| 11 | /* Our wii's bluetooth and wii handles */ | ||
| 12 | static bdaddr_t g_bdaddr[4]; | ||
| 13 | static cwiid_wiimote_t *g_wiimotes[4]; | ||
| 14 | static int g_num_controls = 0; | ||
| 15 | static int g_samples_received = 0; | ||
| 16 | static uint32_t g_starttime; | ||
| 17 | |||
| 18 | static volatile int g_redraw_lock = 0; | ||
| 19 | |||
| 20 | static const int g_width = 400, g_height = 300; | ||
| 21 | |||
| 22 | cwiid_mesg_callback_t cwiid_callback; | ||
| 23 | cwiid_err_t err; | ||
| 24 | void err(cwiid_wiimote_t *wiimote, const char *s, va_list ap) | ||
| 25 | { | ||
| 26 | if (wiimote) printf("%d:", cwiid_get_id(wiimote)); else printf("-1:"); | ||
| 27 | vprintf(s, ap); | ||
| 28 | printf("\n"); | ||
| 29 | } | ||
| 30 | |||
| 31 | int main( int argc, char **argv ) { | ||
| 32 | int LEDs[4] = { CWIID_LED1_ON, CWIID_LED1_ON | CWIID_LED2_ON, | ||
| 33 | CWIID_LED1_ON | CWIID_LED2_ON | CWIID_LED3_ON, | ||
| 34 | CWIID_LED1_ON | CWIID_LED2_ON | CWIID_LED3_ON | CWIID_LED4_ON }; | ||
| 35 | int i; | ||
| 36 | struct timeval now; | ||
| 37 | |||
| 38 | signal( SIGINT, exit ); | ||
| 39 | display_init( g_width, g_height); | ||
| 40 | |||
| 41 | cwiid_set_err(err); | ||
| 42 | |||
| 43 | /* If no bdaddrs given on command line, just connect to | ||
| 44 | first visible wii */ | ||
| 45 | if( argc <= 1 ) { | ||
| 46 | char bt_out[64]; | ||
| 47 | g_bdaddr[0] = *BDADDR_ANY; | ||
| 48 | |||
| 49 | while( !(g_wiimotes[g_num_controls] = cwiid_open( &g_bdaddr[0], 0 ))) | ||
| 50 | fprintf( stderr, "Unable to connect to wiimote\n" ); | ||
| 51 | |||
| 52 | ba2str( &g_bdaddr[0], bt_out ); | ||
| 53 | fprintf( stderr, "Connected to wiimote %i (BT-Addr: %s)\n", i, bt_out ); | ||
| 54 | g_num_controls++; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* ... else try to reach every single wii */ | ||
| 58 | for( i=0; i<argc-1; ++i ) { | ||
| 59 | str2ba(argv[i+1], &g_bdaddr[i]); | ||
| 60 | |||
| 61 | while( !(g_wiimotes[g_num_controls] = cwiid_open( &g_bdaddr[i], 0 ))) | ||
| 62 | fprintf( stderr, "Unable to connect to wiimote %i (BT-Addr: %s)\n", i, argv[i+1] ); | ||
| 63 | |||
| 64 | g_num_controls++; | ||
| 65 | fprintf( stderr, "Connected to wiimote %i (BT-Addr: %s)\n", i, argv[i+1] ); | ||
| 66 | } | ||
| 67 | |||
| 68 | for( i=0; i<g_num_controls; ++i ) { | ||
| 69 | if (cwiid_set_mesg_callback(g_wiimotes[i], cwiid_callback)) { | ||
| 70 | fprintf(stderr, "Unable to set message callback\n"); | ||
| 71 | return -1; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* Set report mode to IR */ | ||
| 75 | cwiid_set_rpt_mode(g_wiimotes[i], CWIID_RPT_IR); | ||
| 76 | |||
| 77 | /* Enable call back */ | ||
| 78 | cwiid_enable(g_wiimotes[i], CWIID_FLAG_MESG_IFC); | ||
| 79 | |||
| 80 | /* Reflect number in leds */ | ||
| 81 | cwiid_set_led(g_wiimotes[i], LEDs[i]); | ||
| 82 | } | ||
| 83 | |||
| 84 | gettimeofday(&now, (struct timezone *)NULL); | ||
| 85 | g_starttime = now.tv_sec * 1000 + now.tv_usec / 1000; /* in ms */ | ||
| 86 | |||
| 87 | /* Spin and let call back do all the work */ | ||
| 88 | while( 1 ) { | ||
| 89 | if( ! (++i & 0xffff ) ) { | ||
| 90 | int wii_id, led; | ||
| 91 | while( g_redraw_lock ); | ||
| 92 | |||
| 93 | for( wii_id=0; wii_id<4; ++wii_id ) | ||
| 94 | for( led = 0; led<4; ++led ) | ||
| 95 | display_rectangle( wii_id, led * g_width / 16, 0, g_width / 16, vubars_getinfo(wii_id, led)/2 ); | ||
| 96 | |||
| 97 | display_redraw(); | ||
| 98 | usleep( 1000 ); | ||
| 99 | vubars_reduce(); | ||
| 100 | display_rectangle( 2, g_width/2-10, 0, 20, -vubars_getweather()/2 ); | ||
| 101 | display_rectangle( 2, g_width/2-15, -128, 30, 1 ); | ||
| 102 | display_rectangle( 2, g_width/2-15, -64, 30, 1 ); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | void cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, | ||
| 110 | union cwiid_mesg mesg[], struct timespec *timestamp) | ||
| 111 | { | ||
| 112 | int i, j, k, wii_id, ledmask; | ||
| 113 | int valid_sources; | ||
| 114 | struct timeval now; | ||
| 115 | uint32_t runtime; | ||
| 116 | wii_pt coords[4]; | ||
| 117 | |||
| 118 | gettimeofday(&now, (struct timezone *)NULL); | ||
| 119 | runtime = now.tv_sec * 1000 + now.tv_usec / 1000 - g_starttime; /* in ms */ | ||
| 120 | |||
| 121 | for( i=0; i<g_num_controls; ++i ) { | ||
| 122 | if( wiimote == g_wiimotes[i] ) | ||
| 123 | wii_id = i; | ||
| 124 | } | ||
| 125 | g_redraw_lock = 1; | ||
| 126 | display_clear(); | ||
| 127 | g_samples_received++; | ||
| 128 | for (i=0; i < mesg_count; i++) { | ||
| 129 | switch (mesg[i].type) { | ||
| 130 | |||
| 131 | case CWIID_MESG_IR: | ||
| 132 | // printf("IR Report (%i): ", wii_id ); | ||
| 133 | // printf("(%ld Hz) ", ( g_samples_received * 1000 ) / runtime ); | ||
| 134 | |||
| 135 | valid_sources = 0; | ||
| 136 | for (j = 0; j < CWIID_IR_SRC_COUNT; j++) { | ||
| 137 | if (mesg[i].ir_mesg.src[j].valid) { | ||
| 138 | coords[valid_sources].x = (double)mesg[i].ir_mesg.src[j].pos[CWIID_X]; | ||
| 139 | coords[valid_sources].y = (double)mesg[i].ir_mesg.src[j].pos[CWIID_Y]; | ||
| 140 | |||
| 141 | display_circle( wii_id, coords[valid_sources].x / 5.0, coords[valid_sources].y / 5.0, 6 ); | ||
| 142 | valid_sources++; | ||
| 143 | // printf("(%d,%d) ", mesg[i].ir_mesg.src[j].pos[CWIID_X], | ||
| 144 | // mesg[i].ir_mesg.src[j].pos[CWIID_Y]); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | if (!valid_sources) { | ||
| 149 | // printf("no sources detected"); | ||
| 150 | } | ||
| 151 | |||
| 152 | if( valid_sources == 4 ) { | ||
| 153 | wii_calibrate( wii_id, coords ); | ||
| 154 | } | ||
| 155 | |||
| 156 | ledmask = 0; | ||
| 157 | for( j=0; j<valid_sources; ++j ) { | ||
| 158 | int led = wii_point_to_led( wii_id, coords+j ); | ||
| 159 | ledmask |= 1<<led; | ||
| 160 | } | ||
| 161 | for( j=0; j<4; ++j ) { | ||
| 162 | vubars_peak( wii_id, j, ( ledmask >> j ) & 1 ); | ||
| 163 | } | ||
| 164 | |||
| 165 | break; | ||
| 166 | default: | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | g_redraw_lock = 0; | ||
| 171 | } | ||
| 172 | |||
diff --git a/vubars.c b/vubars.c new file mode 100644 index 0000000..8fcf081 --- /dev/null +++ b/vubars.c | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <math.h> | ||
| 3 | |||
| 4 | #include "gm.h" | ||
| 5 | #include "vubars.h" | ||
| 6 | #include "heuristics.h" | ||
| 7 | |||
| 8 | // This is our current idea of how we want to influence the weather | ||
| 9 | // 128 means: do nothing at all | ||
| 10 | // | ||
| 11 | // We want to default to softening the weather, so our value always | ||
| 12 | // flows back towards 100 | ||
| 13 | static double vu_value_main = 100.0; | ||
| 14 | static double vu_value_softening = 0.0; | ||
| 15 | static double vu_value_activating = 0.0; | ||
| 16 | |||
| 17 | static int wii_last[WII_COUNT * 4]; | ||
| 18 | static int wii_bars[WII_COUNT * 4]; | ||
| 19 | |||
| 20 | int vubars_peak( int wii_id, int led, int is_on ) { | ||
| 21 | if( is_on ) { | ||
| 22 | wii_last[wii_id*4+led] = 0; | ||
| 23 | } else { | ||
| 24 | if( ++wii_last[wii_id*4+led] == 1 ) | ||
| 25 | wii_bars[wii_id*4+led] = VU_PEAK; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | int vubars_getinfo( int wii_id, int led ) { | ||
| 30 | return wii_bars[wii_id*4+led]; | ||
| 31 | } | ||
| 32 | |||
| 33 | int vubars_getweather( ) { | ||
| 34 | return (int)vu_value_main; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int GESTURE_A_dd = 0; | ||
| 38 | static int GESTURE_A_dx = 0; | ||
| 39 | static int GESTURE_A_dy = 0; | ||
| 40 | |||
| 41 | static int GESTURE_A_off = 0; | ||
| 42 | static int GESTURE_A_ttl = 0; | ||
| 43 | |||
| 44 | static int GESTURE_B_dd = 0; | ||
| 45 | static int GESTURE_B_dx = 0; | ||
| 46 | static int GESTURE_B_dy = 0; | ||
| 47 | |||
| 48 | static int GESTURE_B_off = 0; | ||
| 49 | static int GESTURE_B_ttl = 0; | ||
| 50 | |||
| 51 | static void match_gesture( int off, int dx, int dy, int dd ) { | ||
| 52 | if( ( GESTURE_A_dd == dd ) && ( GESTURE_A_off == off + dd ) ) { | ||
| 53 | printf( "...continued A\n" ); | ||
| 54 | |||
| 55 | GESTURE_A_off = off; | ||
| 56 | GESTURE_A_dx = dx; | ||
| 57 | GESTURE_A_dy = dy; | ||
| 58 | GESTURE_A_ttl = VU_PEAK; | ||
| 59 | |||
| 60 | } else if ( ( GESTURE_B_dd == dd ) && ( GESTURE_B_off == off + dd ) ) { | ||
| 61 | printf( "...continued B\n" ); | ||
| 62 | |||
| 63 | GESTURE_B_off = off; | ||
| 64 | GESTURE_B_dx = dx; | ||
| 65 | GESTURE_B_dy = dy; | ||
| 66 | GESTURE_B_ttl = VU_PEAK; | ||
| 67 | |||
| 68 | } else { | ||
| 69 | printf( "\n" ); | ||
| 70 | |||
| 71 | if( GESTURE_B_ttl >= GESTURE_A_ttl ) { | ||
| 72 | GESTURE_A_off = off; | ||
| 73 | GESTURE_A_dd = dd; | ||
| 74 | GESTURE_A_dx = dx; | ||
| 75 | GESTURE_A_dy = dy; | ||
| 76 | GESTURE_A_ttl = VU_PEAK; | ||
| 77 | } else { | ||
| 78 | GESTURE_B_off = off; | ||
| 79 | GESTURE_B_dd = dd; | ||
| 80 | GESTURE_B_dx = dx; | ||
| 81 | GESTURE_B_dy = dy; | ||
| 82 | GESTURE_B_ttl = VU_PEAK; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void vubars_reduce() { | ||
| 88 | int i; | ||
| 89 | double diff; | ||
| 90 | |||
| 91 | // First do some heuristics voodoo | ||
| 92 | int offa, offb, dxa, dxb, dya, dyb, dda, ddb; | ||
| 93 | |||
| 94 | heuristics_getGestures( 16, wii_bars, &offa, &dxa, &dya, &dda, &offb, &dxb, &dyb, &ddb ); | ||
| 95 | |||
| 96 | if( ( offa != -1 ) && ( dxa > 2 ) ) { | ||
| 97 | printf( "1mary gesture detected: offset: % 2d direction: %s len: % 2d speed: %lf", | ||
| 98 | offa, dda < 0 ? "left" : "rite", dxa, (double)dya / (double)dxa ); | ||
| 99 | match_gesture( offa, dxa, dya, dda ); | ||
| 100 | } | ||
| 101 | |||
| 102 | |||
| 103 | if( ( offb != -1 ) && ( dxb > 2 ) ) { | ||
| 104 | printf( "2ndry gesture detected: offset: % 2d direction: %s len: % 2d speed: %lf\n", | ||
| 105 | offb, ddb < 0 ? "left" : "rite", dxb, (double)dyb / (double)dxb ); | ||
| 106 | match_gesture( offb, dxb, dyb, ddb ); | ||
| 107 | } | ||
| 108 | |||
| 109 | // Have two gestures living at one | ||
| 110 | if( GESTURE_A_ttl && GESTURE_B_ttl ) { | ||
| 111 | if( GESTURE_A_dd == GESTURE_B_dd ) { | ||
| 112 | // printf( "Two gestures pointing into the same direction.\n" ); | ||
| 113 | } else { | ||
| 114 | // The more interesting case: hands move into opposite directions | ||
| 115 | if( GESTURE_A_dd == -1 ) { | ||
| 116 | if ( GESTURE_A_off < GESTURE_B_off ) | ||
| 117 | printf( "Slower! (Case 1)\n" ); | ||
| 118 | else | ||
| 119 | printf( "Faster! (Case 2)\n" ); | ||
| 120 | } else { | ||
| 121 | if ( GESTURE_A_off < GESTURE_B_off ) | ||
| 122 | printf( "Faster! (Case 3)\n" ); | ||
| 123 | else | ||
| 124 | printf( "Slower! (Case 4)\n" ); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | // Now try to modify the weather by using values from our vu-bars | ||
| 130 | diff = (double)heuristics_getEnergy( 16, wii_bars ); | ||
| 131 | vu_value_main += diff / 40000.0; | ||
| 132 | |||
| 133 | diff = vu_value_main - 100.0; | ||
| 134 | if( diff<0 ) diff = -diff; | ||
| 135 | diff = sqrt( diff ); | ||
| 136 | |||
| 137 | if( vu_value_main > 100.0 ) diff = -diff; | ||
| 138 | |||
| 139 | vu_value_main += diff; | ||
| 140 | |||
| 141 | for( i=0; i<WII_COUNT*4; ++i ) | ||
| 142 | if( wii_bars[i] ) | ||
| 143 | wii_bars[i]-=VU_STEP; | ||
| 144 | |||
| 145 | if( GESTURE_A_ttl ) GESTURE_A_ttl -= VU_STEP; | ||
| 146 | if( GESTURE_B_ttl ) GESTURE_B_ttl -= VU_STEP; | ||
| 147 | |||
| 148 | } | ||
diff --git a/vubars.h b/vubars.h new file mode 100644 index 0000000..8cca6b8 --- /dev/null +++ b/vubars.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | static unsigned long const VU_STEP = 10; | ||
| 2 | static unsigned long const VU_PEAK = 400; | ||
| 3 | |||
| 4 | int vubars_peak( int wii_id, int led, int is_on ); | ||
| 5 | void vubars_reduce(); | ||
| 6 | int vubars_getweather(); | ||
