Wiimote integration!
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 17 Jan 2008 12:43:46 +0000 (23:43 +1100)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 17 Jan 2008 12:43:46 +0000 (23:43 +1100)
prpong.c

index 09d5113cf191efce46edfae000300ebe14a708ca..cd5a5a66826eae3092d4adeef82dcc5ed9243c7b 100644 (file)
--- a/prpong.c
+++ b/prpong.c
 #include "list/list.h"
 #include <SDL/SDL.h>
 #include <cwiid.h>
+#include <assert.h>
 
 #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<f) return false;
+               if (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<f) return false;
+               if (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