From: Rusty Russell Date: Thu, 17 Jan 2008 12:43:46 +0000 (+1100) Subject: Wiimote integration! X-Git-Url: https://git.ozlabs.org/?p=ponghero.git;a=commitdiff_plain;h=ca2ca6fb976f96fb9a752d80bd2b6538e8571ed9;ds=sidebyside Wiimote integration! --- diff --git a/prpong.c b/prpong.c index 09d5113..cd5a5a6 100644 --- a/prpong.c +++ b/prpong.c @@ -11,83 +11,85 @@ #include "list/list.h" #include #include +#include #define MAX_X CWIID_IR_X_MAX #define MAX_Y CWIID_IR_Y_MAX +struct coord +{ + double x; + double y; +}; + /* Obtained from http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */ /* Faster Line Segment Intersection */ /* Franklin Antonio */ - -/* The use of some short working variables allows this code to run */ -/* faster on 16-bit computers, but is not essential. It should not */ -/* affect operation on 32-bit computers. The short working variables*/ -/* to not restrict the range of valid input values, as these were */ -/* constrained in any case, due to algorithm restrictions. */ -static bool lines_intersect(double x1, double y1, - double x2, double y2, - double x3, double y3, - double x4, double y4, - double *x, double *y) +static bool lines_intersect(const struct coord *start1, + const struct coord *start2, + const struct coord *start3, + const struct coord *start4, + struct coord *intersect) { - double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num; - double x1lo,x1hi,y1lo,y1hi; + struct coord lo, hi; - Ax = x2-x1; - Bx = x3-x4; + Ax = start2->x - start1->x; + Bx = start3->x - start4->x; - if(Ax<0) { /* X bound box test*/ - x1lo=x2; x1hi=x1; + if(Ax<0) { /* X bound box test*/ + lo.x = start2->x; hi.x = start1->x; } else { - x1hi=x2; x1lo=x1; + hi.x = start2->x; lo.x = start1->x; } if(Bx>0) { - if(x1hi < x4 || x3 < x1lo) return false; + if(hi.x < start4->x || start3->x < lo.x) return false; } else { - if(x1hi < x3 || x4 < x1lo) return false; + if(hi.x < start3->x || start4->x < lo.x) return false; } - Ay = y2-y1; - By = y3-y4; + Ay = start2->y - start1->y; + By = start3->y - start4->y; - if(Ay<0) { /* Y bound box test*/ - y1lo=y2; y1hi=y1; + if(Ay<0) { /* Y bound box test*/ + lo.y = start2->y; hi.y = start1->y; } else { - y1hi=y2; y1lo=y1; + hi.y = start2->y; lo.y = start1->y; } if(By>0) { - if(y1hi < y4 || y3 < y1lo) return false; + if(hi.y < start4->y || start3->y < lo.y) return false; } else { - if(y1hi < y3 || y4 < y1lo) return false; + if(hi.y < start3->y || start4->y < lo.y) return false; } - Cx = x1-x3; - Cy = y1-y3; - d = By*Cx - Bx*Cy; /* alpha numerator*/ - f = Ay*Bx - Ax*By; /* both denominator*/ - if(f>0) { /* alpha tests*/ - if(d<0 || d>f) return false; + Cx = start1->x - start3->x; + Cy = start1->y - start3->y; + d = By*Cx - Bx*Cy; /* alpha numerator*/ + f = Ay*Bx - Ax*By; /* both denominator*/ + if (f>0) { /* alpha tests*/ + if (d < 0 || d > f) return false; } else { - if(d>0 || d 0 || d < f) return false; } - e = Ax*Cy - Ay*Cx; /* beta numerator*/ - if(f>0) { /* beta tests*/ - if(e<0 || e>f) return false; + e = Ax*Cy - Ay*Cx; /* beta numerator*/ + if (f > 0) { /* beta tests*/ + if (e < 0 || e > f) return false; } else { - if(e>0 || e 0 || e < f) return false; } /*compute intersection coordinates*/ + /* Don't worry about tiny values of f (< 1/2 pixel across screen) */ + if (fabs(f) < 1.0 / (2.0 * MAX_X * MAX_Y)) + return false; - if(f==0) return false; - num = d*Ax; /* numerator */ - *x = x1 + num / f; /* intersection x */ + num = d*Ax; /* numerator */ + intersect->x = start1->x + num / f; /* intersection x */ num = d*Ay; - *y = y1 + num / f; /* intersection y */ + intersect->y = start1->y + num / f; /* intersection y */ return true; } @@ -472,13 +474,6 @@ static void line(SDL_Surface *s, } } -#if 1 -struct coord -{ - double x; - double y; -}; - struct ball { struct coord pos; @@ -546,15 +541,12 @@ static void thick_line(SDL_Surface *s, const struct line_segment *l, static bool intersect(const struct coord *c1, const struct coord *c2, const struct line_segment *seg, struct coord *intersect) { - return lines_intersect(c1->x, c1->y, c2->x, c2->y, - seg->start.x, seg->start.y, - seg->end.x, seg->end.y, - &intersect->x, &intersect->y); + return lines_intersect(c1, c2, &seg->start, &seg->end, intersect); } static double dist(const struct coord *c1, const struct coord *c2) { - float x = (c1->x - c2->x), y = (c1->y - c2->y); + double x = (c1->x - c2->x), y = (c1->y - c2->y); return sqrt(x * x + y * y); } @@ -564,19 +556,20 @@ static unsigned rad_to_deg(double rad) } static void bounce(struct ball *ball, const struct line_segment *line, - struct coord *remainder) + struct coord *move, double increase_speed) { double len, speed, lang, iang, oang; struct coord isect, new; - new.x = ball->pos.x + ball->move.x; - new.y = ball->pos.y + ball->move.y; + new.x = ball->pos.x + move->x; + new.y = ball->pos.y + move->y; /* How far were we supposed to move ball? */ - len = sqrt(remainder->x * remainder->x + remainder->y * remainder->y); + len = sqrt(move->x * move->x + move->y * move->y); /* How far is it to intersection? */ - intersect(&ball->pos, &new, line, &isect); + if (!intersect(&ball->pos, &new, line, &isect)) + errx(1, "No intersection any more?\n");; len -= dist(&ball->pos, &isect); /* Move ball to intersection. */ @@ -592,16 +585,16 @@ static void bounce(struct ball *ball, const struct line_segment *line, rad_to_deg(iang), rad_to_deg(oang)); - /* Set new direction for ball, at same speed */ + /* Set new direction for ball, at slightly increased speed */ speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y); - speed *= 1.01; + speed += increase_speed; ball->move.x = sin(oang) * speed; ball->move.y = cos(oang) * speed; - /* Set remainder. */ - remainder->x = sin(oang) * len; - remainder->y = cos(oang) * len; - printf("len = %f, remainder = %f,%f\n", len, remainder->x, remainder->y); + /* Set move. */ + move->x = sin(oang) * len; + move->y = cos(oang) * len; + printf("len = %f, move = %f,%f\n", len, move->x, move->y); } static struct line_segment border[] = { @@ -661,14 +654,25 @@ int main(int argc, char *argv[]) SDL_Surface *screen, *ballsur, *savesur = NULL; Uint8 video_bpp; Uint32 videoflags; - unsigned int i; + unsigned int i, time_since_last_ir = INT_MAX; SDL_Rect rect; - bool creating_lines = false; - struct timeval line_life = { 5, 0 }; + struct timeval line_life = { 3, 0 }; + cwiid_wiimote_t *wiimote; + struct cwiid_state state; + bdaddr_t addr = *BDADDR_ANY; LIST_HEAD(lines); + struct cwiid_ir_src *ir, last_ir = { .valid = 0 }; + + videoflags = SDL_SWSURFACE; + + if (argv[1] && streq(argv[1], "--fullscreen")) { + videoflags = SDL_SWSURFACE; + argc--; + argv++; + } if (argc != 5) - errx(1, "Usage: %s ballx bally ballangle ballspeed\n" + errx(1, "Usage: %s [--fullscreen] ballx bally ballangle ballspeed\n" " Where ballangle is 0 for north, 90 for east, etc\n", argv[0]); @@ -685,9 +689,15 @@ int main(int argc, char *argv[]) } video_bpp = 0; - videoflags = SDL_SWSURFACE; - /* Set 640x480 video mode */ + 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 ( (screen=SDL_SetVideoMode(MAX_X,MAX_Y,video_bpp,videoflags)) == NULL ) { errx(1, "Couldn't set %dx%dx%d video mode: %s", MAX_X, MAX_Y,video_bpp, SDL_GetError()); @@ -721,12 +731,14 @@ int main(int argc, char *argv[]) double best_d; SDL_Event event; struct timeval now; + bool ignored = false; gettimeofday(&now, NULL); /* Expire lines */ list_for_each_safe(&lines, l, next, list) { if (timercmp(&l->expires, &now, <)) { + printf("Deleting line %p\n", l); list_del(&l->list); /* FIXME: Undraw properly. */ thick_line(screen, l, 0xFFFFFFFF); @@ -755,21 +767,24 @@ int main(int argc, char *argv[]) printf("Ball bouncing off (%f,%f %f,%f)!\n", best_l->start.x, best_l->start.y, best_l->end.x, best_l->end.y); - bounce(&ball, best_l, &move); + /* Only increase speed on *first* bounce, to avoid + * mega speed increases. */ + bounce(&ball, best_l, &move, ignored ? 0.0 : 0.1); /* If we moved, stop ignoring lines. */ - if (move.x > 0.001 || move.y > 0.001) + if (ignored && (move.x > 0.001 || move.y > 0.001)) clear_ignore(&lines); /* Don't hit the same line twice. */ printf("Ignoring that line\n"); - best_l->ignore = true; + best_l->ignore = ignored = true; goto again; } - if (move.x > 0.001 || move.y > 0.001) { + if (ignored && (move.x > 0.001 || move.y > 0.001)) { clear_ignore(&lines); - printf("Moving by %f,%f to %f,%f\n", move.x, move.y, new.x, new.y); + printf("Moving by %f,%f to %f,%f\n", + move.x, move.y, new.x, new.y); } /* Restore what was there before ball. */ @@ -796,28 +811,43 @@ int main(int argc, char *argv[]) ball.pos = new; SDL_Delay(25); - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - SDL_Quit(); - return 0; - } - if (event.type == SDL_MOUSEBUTTONDOWN) - creating_lines = true; - else if (event.type == SDL_MOUSEBUTTONUP) - creating_lines = false; + if (SDL_PollEvent(&event) + && (event.type == SDL_QUIT + || (event.type == SDL_KEYDOWN + && event.key.keysym.sym == SDLK_ESCAPE))) { + SDL_Quit(); + return 0; + } + + if (cwiid_get_state(wiimote, &state)) + errx(1, "No wii state"); - if (creating_lines && event.type == SDL_MOUSEMOTION) { + /* Find biggest state. */ + ir = &state.ir_src[0]; + for (i = 0; i < CWIID_IR_SRC_COUNT; i++) { + if (!state.ir_src[i].valid) + continue; + if (!ir->valid || state.ir_src[i].size > ir->size) + ir = &state.ir_src[0]; + } + + if (ir->valid) { + /* Give it some slack for missing one or two... */ + if (time_since_last_ir <= 3) { struct line_segment *n = malloc(sizeof(*n)); - n->start.x = event.motion.x - event.motion.xrel; - n->start.y = event.motion.y - event.motion.yrel; - n->end.x = event.motion.x; - n->end.y = event.motion.y; + /* Wiimote coordinates are backwards for us. */ + n->start.x = MAX_X - last_ir.pos[0]; + n->start.y = MAX_Y - last_ir.pos[1]; + n->end.x = MAX_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); } + time_since_last_ir = 0; + last_ir = *ir; } + time_since_last_ir++; } } -#endif