diff options
-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(); | ||