X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=prpong.c;h=7799f63fdccf90d068ab2f90d34f858163cfdc26;hb=d1dd6d7b08f5ac95e6e0806abe93e51701044e23;hp=36b297e600d02c3c8c774b922d28a64e8d01e079;hpb=b2d2e0a475b2831604b11986ef342ba749eb4222;p=ponghero.git diff --git a/prpong.c b/prpong.c index 36b297e..7799f63 100644 --- a/prpong.c +++ b/prpong.c @@ -12,6 +12,7 @@ #include #include #include +#include #define MAX_X CWIID_IR_X_MAX #define MAX_Y CWIID_IR_Y_MAX @@ -648,6 +649,122 @@ static void clear_ignore(struct list_head *lines) i->ignore = false; } +static uint16_t *find_valid_point(struct cwiid_state *state) +{ + unsigned int i; + + for (i = 0; i < CWIID_IR_SRC_COUNT; i++) { + if (state->ir_src[i].valid) + return state->ir_src[i].pos; + } + return NULL; +} + +static void calibrate(SDL_Surface *screen, + cwiid_wiimote_t *wiimote, + struct coord *calib, unsigned x, unsigned y) +{ + uint16_t *pos; + struct cwiid_state state; + unsigned int last_x = MAX_X, last_y = MAX_Y, count = 0; + + /* Must see it for a full half second. */ + while (count < 20) { + SDL_Event event; + + if (cwiid_get_state(wiimote, &state)) + errx(1, "No wii state"); + + pos = find_valid_point(&state); + if (!pos || pos[0] != last_x || pos[1] != last_y) + count = 0; + + if (pos) { + last_x = pos[0]; + last_y = pos[1]; + count++; + } + + SDL_Delay(25); + if (SDL_PollEvent(&event) + && (event.type == SDL_QUIT + || (event.type == SDL_KEYDOWN + && event.key.keysym.sym == SDLK_ESCAPE))) { + SDL_Quit(); + exit(0); + } + } + + calib->x = last_x; + calib->y = last_y; + printf("Calibration point: %u,%u\n", last_x, last_y); +} + +static bool map_coord(unsigned int x, unsigned int y, + const struct coord calib[], + struct coord *res) +{ + struct coord line_start, line_end; + struct coord pos = { x, y }, intersect; + double d1, d2; + + /* Calibration layout: + * + * 0 1 + * + * 3 2 + * + * We figure out the distance to each side, and then map using: + * + * x = d1 / (d1 + d2) * (rawend - rawstart) + rawstart + */ + line_start.x = 0; + line_end.x = MAX_X-1; + line_start.y = line_end.y = y; + + if (!lines_intersect(&calib[0], &calib[3], &line_start, &line_end, + &intersect)) + return false; + d1 = dist(&pos, &intersect); + if (!lines_intersect(&calib[1], &calib[2], &line_start, &line_end, + &intersect)) + return false; + d2 = dist(&pos, &intersect); + res->x = d1 / (d1 + d2) * MAX_X; + + line_start.y = 0; + line_end.y = MAX_Y-1; + line_start.x = line_end.x = x; + + if (!lines_intersect(&calib[0], &calib[1], &line_start, &line_end, + &intersect)) + return false; + d1 = dist(&pos, &intersect); + if (!lines_intersect(&calib[3], &calib[2], &line_start, &line_end, + &intersect)) + return false; + d2 = dist(&pos, &intersect); + res->y = d1 / (d1 + d2) * MAX_Y; + + return true; +} + +static struct line_segment *new_line(unsigned int startx, unsigned int starty, + unsigned int endx, unsigned int endy, + const struct coord calib[]) +{ + struct line_segment *l = malloc(sizeof(*l)); + + l->ignore = false; + if (!map_coord(startx, starty, calib, &l->start) + || !map_coord(endx, endy, calib, &l->end)) { + free(l); + return NULL; + } + return l; +} + + int main(int argc, char *argv[]) { struct ball ball; @@ -659,20 +776,49 @@ int main(int argc, char *argv[]) struct timeval line_life = { 3, 0 }; cwiid_wiimote_t *wiimote; struct cwiid_state state; + struct coord calib[4]; bdaddr_t addr = *BDADDR_ANY; + bool mouse = false, needs_calibration = true, drawing = false; LIST_HEAD(lines); struct cwiid_ir_src *ir, last_ir = { .valid = 0 }; + struct line_segment *n; videoflags = SDL_SWSURFACE; if (argv[1] && streq(argv[1], "--fullscreen")) { - videoflags = SDL_SWSURFACE; + videoflags |= SDL_FULLSCREEN; + argc--; + argv++; + } + + if (argv[1] && strstarts(argv[1], "--calib=")) { + needs_calibration = false; + if (sscanf(argv[1], "--calib=%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", + &calib[0].x, &calib[0].y, + &calib[1].x, &calib[1].y, + &calib[2].x, &calib[2].y, + &calib[3].x, &calib[3].y) != 8) + errx(1, "Not enough calibration points"); + argc--; + argv++; + } + + if (argv[1] && streq(argv[1], "--mouse")) { + mouse = true; + needs_calibration = false; + calib[0].x = calib[0].y = 0; + calib[1].x = MAX_X - 1; + calib[1].y = 0; + calib[2].x = MAX_X - 1; + calib[2].y = MAX_Y - 1; + calib[3].x = 0; + calib[3].y = MAX_Y - 1; argc--; argv++; } if (argc != 5) - errx(1, "Usage: %s [--fullscreen] ballx bally ballangle ballspeed\n" + errx(1, "Usage: %s [--fullscreen] [--calib=x,y,x,y,x,y,x,y] [--mouse] ballx bally ballangle ballspeed\n" " Where ballangle is 0 for north, 90 for east, etc\n", argv[0]); @@ -683,20 +829,22 @@ int main(int argc, char *argv[]) printf("ball move = %f,%f\n", ball.move.x, ball.move.y); /* Initialize SDL */ - if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); return(1); } video_bpp = 0; - printf("Put Wiimote in discoverable mode (press 1+2)\n"); - wiimote = cwiid_open(&addr, 0); - if (!wiimote) - errx(1, "Can't find the Wiimote"); + if (!mouse) { + printf("Put Wiimote in discoverable mode (press 1+2)\n"); + wiimote = cwiid_open(&addr, 0); + if (!wiimote) + errx(1, "Can't find the Wiimote"); - if (cwiid_set_rpt_mode(wiimote, CWIID_RPT_IR)) - errx(1, "Can't set IR repeat mode"); + if (cwiid_set_rpt_mode(wiimote, CWIID_RPT_IR)) + errx(1, "Can't set IR repeat mode"); + } if ( (screen=SDL_SetVideoMode(MAX_X,MAX_Y,video_bpp,videoflags)) == NULL ) { errx(1, "Couldn't set %dx%dx%d video mode: %s", @@ -714,6 +862,14 @@ int main(int argc, char *argv[]) SDL_UnlockSurface(screen); SDL_UpdateRect(screen, 0, 0, 0, 0); + if (needs_calibration) { + /* Calibration */ + calibrate(screen, wiimote, &calib[0], 0, 0); + calibrate(screen, wiimote, &calib[1], MAX_X - 1, 0); + calibrate(screen, wiimote, &calib[2], MAX_X - 1, MAX_Y - 1); + calibrate(screen, wiimote, &calib[3], 0, MAX_Y - 1); + } + /* Draw borders, put them in list. */ for (i = 0; i < ARRAY_SIZE(border); i++) { border[i].ignore = false; @@ -811,14 +967,46 @@ int main(int argc, char *argv[]) ball.pos = new; SDL_Delay(25); - if (SDL_PollEvent(&event) - && (event.type == SDL_QUIT - || (event.type == SDL_KEYDOWN - && event.key.keysym.sym == SDLK_ESCAPE))) { - SDL_Quit(); - return 0; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT + || (event.type == SDL_KEYDOWN + && event.key.keysym.sym == SDLK_ESCAPE)) { + SDL_Quit(); + return 0; + } + if (mouse) { + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + drawing = true; + break; + case SDL_MOUSEBUTTONUP: + drawing = false; + break; + case SDL_MOUSEMOTION: + if (!drawing) + break; + + n = new_line(event.motion.x, + event.motion.y, + event.motion.x + + event.motion.xrel, + event.motion.y + + event.motion.yrel, + calib); + + if (n) { + timeradd(&now, &line_life, + &n->expires); + list_add_tail(&lines, &n->list); + thick_line(screen, n, 0); + } + } + } } + if (mouse) + continue; + if (cwiid_get_state(wiimote, &state)) errx(1, "No wii state"); @@ -834,16 +1022,16 @@ int main(int argc, char *argv[]) if (ir->valid) { /* Give it some slack for missing one or two... */ if (time_since_last_ir <= 5) { - struct line_segment *n = malloc(sizeof(*n)); - /* Wiimote coordinates are backwards for us. */ - n->start.x = last_ir.pos[0]; - n->start.y = MAX_Y - last_ir.pos[1]; - n->end.x = ir->pos[0]; - n->end.y = MAX_Y - ir->pos[1]; - n->ignore = false; - timeradd(&now, &line_life, &n->expires); - list_add_tail(&lines, &n->list); - thick_line(screen, n, 0); + n = new_line(last_ir.pos[0], + last_ir.pos[1], + ir->pos[0], + ir->pos[1], + calib); + if (n) { + timeradd(&now, &line_life, &n->expires); + list_add_tail(&lines, &n->list); + thick_line(screen, n, 0); + } } time_since_last_ir = 0; last_ir = *ir;