11 #include "list/list.h"
12 #include "talloc/talloc.h"
13 #include "container_of/container_of.h"
15 #include <SDL/SDL_image.h>
22 #define MAX_X CWIID_IR_X_MAX
23 #define MAX_Y CWIID_IR_Y_MAX
26 #define RIGHT_PLAYER 2
28 static LIST_HEAD(objects);
36 /* Based loosely on http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */
37 /* Faster Line Segment Intersection */
38 /* Franklin Antonio */
39 static bool lines_intersect(const struct coord *start1,
40 const struct coord *start2,
41 const struct coord *start3,
42 const struct coord *start4,
43 struct coord *intersect)
45 double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num;
48 Ax = start2->x - start1->x;
49 Bx = start3->x - start4->x;
51 if(Ax<0) { /* X bound box test*/
52 lo.x = start2->x; hi.x = start1->x;
54 hi.x = start2->x; lo.x = start1->x;
57 if(hi.x < start4->x || start3->x < lo.x) return false;
59 if(hi.x < start3->x || start4->x < lo.x) return false;
62 Ay = start2->y - start1->y;
63 By = start3->y - start4->y;
65 if(Ay<0) { /* Y bound box test*/
66 lo.y = start2->y; hi.y = start1->y;
68 hi.y = start2->y; lo.y = start1->y;
71 if(hi.y < start4->y || start3->y < lo.y) return false;
73 if(hi.y < start3->y || start4->y < lo.y) return false;
77 Cx = start1->x - start3->x;
78 Cy = start1->y - start3->y;
79 d = By*Cx - Bx*Cy; /* alpha numerator*/
80 f = Ay*Bx - Ax*By; /* both denominator*/
81 if (f>0) { /* alpha tests*/
82 if (d < 0 || d > f) return false;
84 if (d > 0 || d < f) return false;
87 e = Ax*Cy - Ay*Cx; /* beta numerator*/
88 if (f > 0) { /* beta tests*/
89 if (e < 0 || e > f) return false;
91 if (e > 0 || e < f) return false;
94 /*compute intersection coordinates*/
95 /* Don't worry about tiny values of f (< 1/2 pixel across screen) */
96 if (fabs(f) < 1.0 / (2.0 * MAX_X * MAX_Y))
99 num = d*Ax; /* numerator */
100 intersect->x = start1->x + num / f; /* intersection x */
103 intersect->y = start1->y + num / f; /* intersection y */
108 // A set of very useful macros that you will find in most
109 // code that I write whether I use them in a program or
112 #define abs(a) (((a)<0) ? -(a) : (a))
113 #define sign(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0)
115 // The following code implements a Bresenham line drawing
116 // algorithm. There are 4 separate routines each optimized
117 // for one of the four pixel depths supported by SDL. SDL
118 // support many pixel formats, but it only support 8, 16,
119 // 24, and 32 bit pixels.
121 //----------------------------------------------------------
123 // Draw lines in 8 bit surfaces.
125 static void line8(SDL_Surface *s,
150 yOffset = sy * s->pitch;
155 lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
161 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
162 *(lineAddr + x) = (Uint8)color;
183 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
184 *(lineAddr + x) = (Uint8)color;
202 //----------------------------------------------------------
204 // Draw lines in 16 bit surfaces. Note that this code will
205 // also work on 15 bit surfaces.
207 static void line16(SDL_Surface *s,
232 yOffset = sy * s->pitch;
237 lineAddr = ((Uint8 *)s->pixels) + (y * s->pitch);
243 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
244 *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
265 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
266 *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
284 //----------------------------------------------------------
286 // Draw lines in 24 bit surfaces. 24 bit surfaces require
287 // special handling because the pixels don't fall on even
288 // address boundaries. Instead of being able to store a
289 // single byte, word, or long you have to store 3
290 // individual bytes. As a result 24 bit graphics is slower
291 // than the other pixel sizes.
293 static void line24(SDL_Surface *s,
311 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
322 yOffset = sy * s->pitch;
327 lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
333 Uint8 *p = (lineAddr + (x * 3));
334 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
335 memcpy(p, &color, 3);
356 Uint8 *p = (lineAddr + (x * 3));
357 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
358 memcpy(p, &color, 3);
376 //----------------------------------------------------------
378 // Draw lines in 32 bit surfaces. Note that this routine
379 // ignores alpha values. It writes them into the surface
380 // if they are included in the pixel, but does nothing
383 static void line32(SDL_Surface *s,
408 yOffset = sy * s->pitch;
413 lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
419 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
420 *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
441 if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
442 *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
460 //----------------------------------------------------------
462 // Examine the depth of a surface and select a line
463 // drawing routine optimized for the bytes/pixel of the
466 static void line(SDL_Surface *s,
471 switch (s->format->BytesPerPixel)
474 line8(s, x1, y1, x2, y2, color);
477 line16(s, x1, y1, x2, y2, color);
480 line24(s, x1, y1, x2, y2, color);
483 line32(s, x1, y1, x2, y2, color);
488 /* Bounding box to be updated. */
489 static bool needs_update;
490 static struct coord start_update, end_update;
494 /* List of all objects. */
495 struct list_node list;
497 struct coord start, end;
499 void (*redraw)(SDL_Surface *s, struct object *me);
504 struct object object;
513 struct object object;
515 struct coord start, end;
516 struct list_node list;
518 struct timeval expires;
519 /* Does someone score if they hit this line ? */
525 struct object object;
532 static void thick_line(SDL_Surface *s, const struct line_segment *l,
535 struct line_segment adj;
536 int x, y, minx = MAX_X, miny = MAX_Y, maxx = 0, maxy = 0;
541 for (x = -1; x < 2; x++) {
542 for (y = -1; y < 2; y++) {
543 adj.start.x = l->start.x + x;
544 adj.end.x = l->end.x + x;
545 adj.start.y = l->start.y + y;
546 adj.end.y = l->end.y + y;
548 if (adj.start.x < minx)
550 if (adj.start.x > maxx)
552 if (adj.start.y < miny)
554 if (adj.start.y > maxy)
556 if (adj.end.x < minx)
558 if (adj.end.x > maxx)
560 if (adj.end.y < miny)
562 if (adj.end.y > maxy)
565 line(s, adj.start.x, adj.start.y, adj.end.x, adj.end.y,
578 SDL_UpdateRect(s, minx, miny, maxx-minx, maxy-miny);
579 SDL_UnlockSurface(s);
582 static bool intersect(const struct coord *c1, const struct coord *c2,
583 const struct line_segment *seg, struct coord *intersect)
585 return lines_intersect(c1, c2, &seg->start, &seg->end, intersect);
588 static double dist(const struct coord *c1, const struct coord *c2)
590 double x = (c1->x - c2->x), y = (c1->y - c2->y);
591 return sqrt(x * x + y * y);
594 static unsigned rad_to_deg(double rad)
596 return ((unsigned)(rad / M_PI * 180) + 360) % 360;
599 static void bounce(struct ball *ball, const struct line_segment *line,
600 struct coord *move, double increase_speed)
602 double len, speed, lang, iang, oang;
603 struct coord isect, new;
605 new.x = ball->pos.x + move->x;
606 new.y = ball->pos.y + move->y;
608 /* How far were we supposed to move ball? */
609 len = sqrt(move->x * move->x + move->y * move->y);
611 /* How far is it to intersection? */
612 if (!intersect(&ball->pos, &new, line, &isect))
613 errx(1, "No intersection any more?\n");;
614 len -= dist(&ball->pos, &isect);
616 /* Move ball to intersection. */
618 printf("ball is now at %f,%f\n", ball->pos.x, ball->pos.y);
620 /* Outgoing angle = 2 * line angle - incident angle. */
621 lang = atan2(line->end.x - line->start.x, line->end.y - line->start.y);
622 iang = atan2(ball->move.x, ball->move.y);
623 oang = 2 * lang - iang, 2*M_PI;
624 printf("lang = %u, iang = %u, oang=%u\n",
629 /* Set new direction for ball, at slightly increased speed */
630 speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y);
631 speed += increase_speed;
632 ball->move.x = sin(oang) * speed;
633 ball->move.y = cos(oang) * speed;
636 move->x = sin(oang) * len;
637 move->y = cos(oang) * len;
638 printf("len = %f, move = %f,%f\n", len, move->x, move->y);
641 static struct line_segment border[] = {
642 { .start = { 0, 0, }, .end = { MAX_X-1, 0 } },
643 { .start = { MAX_X-1, 0, }, .end = { MAX_X-1, MAX_Y-1 } },
644 { .start = { MAX_X-1, MAX_Y-1, }, .end = { 0, MAX_Y-1 } },
645 { .start = { 0, MAX_Y-1, }, .end = { 0, 0 } },
648 static inline float deg_to_rad(float degrees)
650 return degrees * M_PI / 180;
653 static SDL_Surface *sub_surface(SDL_Surface *screen, int w, int h)
655 return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
656 screen->format->BitsPerPixel,
657 screen->format->Rmask,
658 screen->format->Gmask,
659 screen->format->Bmask,
660 screen->format->Amask);
663 static SDL_Surface *ball_surface(SDL_Surface *screen)
667 /* Just like the screen surface. */
668 ball = sub_surface(screen, 5, 5);
670 /* Lock the surface */
671 SDL_LockSurface(ball);
673 /* Black, white corners. */
674 memset(ball->pixels, 0x00, ball->pitch * 5);
675 line(ball, 0, 0, 0, 0, 0xFFFFFFFF);
676 line(ball, 4, 0, 4, 0, 0xFFFFFFFF);
677 line(ball, 0, 4, 0, 4, 0xFFFFFFFF);
678 line(ball, 4, 4, 4, 4, 0xFFFFFFFF);
679 SDL_UnlockSurface(ball);
684 static void clear_ignore(struct list_head *lines)
686 struct line_segment *i;
687 printf("Unignoring...\n");
688 list_for_each(lines, i, list)
692 static uint16_t *find_valid_point(struct cwiid_state *state)
696 for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
697 if (state->ir_src[i].valid)
698 return state->ir_src[i].pos;
703 static void calibrate(SDL_Surface *screen,
704 const char *filename,
705 cwiid_wiimote_t *wiimote,
706 struct coord *calib, unsigned x, unsigned y)
708 SDL_Surface *img = IMG_Load(filename);
710 struct cwiid_state state;
711 int last_x = MAX_X, last_y = MAX_Y, count = 0;
712 SDL_Rect rect = { .x = screen->w/2 - img->w/2,
713 .y = screen->h/2 - img->h/2 };
715 SDL_BlitSurface(img, NULL, screen, &rect);
716 SDL_UpdateRect(screen, 0, 0, 0, 0);
717 SDL_FreeSurface(img);
721 /* Must see it for a full half second. */
725 if (cwiid_get_state(wiimote, &state))
726 errx(1, "No wii state");
728 pos = find_valid_point(&state);
733 /* Allow some jitter */
734 if (abs(pos[0]-last_x) < 3 && abs(pos[1]-last_y) < 3)
741 if (SDL_PollEvent(&event)
742 && (event.type == SDL_QUIT
743 || (event.type == SDL_KEYDOWN
744 && event.key.keysym.sym == SDLK_ESCAPE))) {
753 printf("Calibration point: %u,%u\n", last_x, last_y);
756 static bool map_coord(unsigned int x, unsigned int y,
757 const struct coord calib[],
760 struct coord line_start, line_end;
761 struct coord pos = { x, y }, intersect;
764 /* Calibration layout:
770 * We figure out the distance to each side, and then map using:
772 * x = d1 / (d1 + d2) * (rawend - rawstart) + rawstart
775 line_end.x = MAX_X-1;
776 line_start.y = line_end.y = y;
778 if (!lines_intersect(&calib[0], &calib[3], &line_start, &line_end,
781 d1 = dist(&pos, &intersect);
782 if (!lines_intersect(&calib[1], &calib[2], &line_start, &line_end,
785 d2 = dist(&pos, &intersect);
786 res->x = d1 / (d1 + d2) * MAX_X;
789 line_end.y = MAX_Y-1;
790 line_start.x = line_end.x = x;
792 if (!lines_intersect(&calib[0], &calib[1], &line_start, &line_end,
795 d1 = dist(&pos, &intersect);
796 if (!lines_intersect(&calib[3], &calib[2], &line_start, &line_end,
799 d2 = dist(&pos, &intersect);
800 res->y = d1 / (d1 + d2) * MAX_Y;
805 static void add_update(const struct object *obj)
808 start_update = obj->start;
809 end_update = obj->end;
813 if (obj->start.x < start_update.x)
814 start_update.x = obj->start.x;
815 if (obj->start.y < start_update.y)
816 start_update.y = obj->start.y;
817 if (obj->end.x > end_update.x)
818 end_update.x = obj->end.x;
819 if (obj->end.y > end_update.y)
820 end_update.y = obj->end.y;
823 static void destroy_object(struct object *object)
825 list_del(&object->list);
829 static void add_object(struct list_head *list,
831 unsigned int startx, unsigned int starty,
832 unsigned int width, unsigned int height,
833 void (*redraw)(SDL_Surface *s, struct object *me))
835 list_add_tail(list, &obj->list);
836 obj->start.x = startx;
837 obj->start.y = starty;
838 obj->end.x = startx + width;
839 obj->end.y = starty + height;
840 obj->redraw = redraw;
844 static void redraw_line(SDL_Surface *s, struct object *me)
846 struct line_segment *l = container_of(me, struct line_segment, object);
851 static int destroy_line(struct line_segment *l)
854 destroy_object(&l->object);
858 static void line_object_setup(struct list_head *lines,
859 struct list_head *objects,
860 struct line_segment *l)
862 unsigned int tmp, startx, endx, starty, endy;
864 list_add_tail(lines, &l->list);
871 /* Find bounding box */
882 /* Padding for thick lines (beware underflow) */
890 add_object(objects, &l->object, startx, starty,
891 endx - startx, endy - starty, redraw_line);
894 static void add_line(struct list_head *lines,
895 unsigned int startx, unsigned int starty,
896 unsigned int endx, unsigned int endy,
897 const struct coord calib[])
899 struct line_segment *l = talloc(NULL, struct line_segment);
902 if (!map_coord(startx, starty, calib, &l->start)
903 || !map_coord(endx, endy, calib, &l->end)) {
910 gettimeofday(&now, NULL);
912 l->expires.tv_sec += EXPIRY_SECS;
914 line_object_setup(lines, &objects, l);
915 talloc_set_destructor(l, destroy_line);
918 static void redraw_ball(SDL_Surface *s, struct object *me)
920 struct ball *b = container_of(me, struct ball, object);
921 SDL_Rect rect = { .x = b->pos.x - b->image->w/2,
922 .y = b->pos.y - b->image->h/2 };
924 SDL_BlitSurface(b->image, NULL, s, &rect);
927 static void redraw_score(SDL_Surface *s, struct object *me)
929 struct score *score = container_of(me, struct score, object);
930 SDL_Rect rect = { .x = score->object.start.x,
931 .y = score->object.start.y };
933 SDL_BlitSurface(score->image, NULL, s, &rect);
936 static SDL_Surface *score(struct score *s)
941 SDL_FreeSurface(s->image);
942 sprintf(filename, "images/%u.png", s->value);
943 s->image = IMG_Load(filename);
944 /* No more images? You won! */
948 add_update(&s->object);
952 /* Due to rounding, we exaggerate bounding box by 1 here. */
953 static void do_updates(struct list_head *objects, SDL_Surface *screen)
956 unsigned int y, startx, starty, endx, endy;
959 if (start_update.x <= 0)
962 startx = start_update.x - 1;
963 if (start_update.y <= 0)
966 starty = start_update.y - 1;
968 endx = end_update.x+1;
969 endy = end_update.y+1;
971 if (endx > screen->w)
973 if (endy > screen->h)
976 SDL_LockSurface(screen);
977 /* First we clear the area to white. */
978 for (y = starty; y < endy; y++) {
979 memset(screen->pixels + y * screen->pitch
980 + screen->format->BytesPerPixel * startx,
982 (endx - startx) * screen->format->BytesPerPixel);
984 SDL_UnlockSurface(screen);
986 /* Now redraw everything which overlaps it */
987 list_for_each(objects, i, list) {
988 if (i->end.x < startx)
990 if (i->end.y < starty)
992 if (i->start.x > endx)
994 if (i->start.y > endy)
996 i->redraw(screen, i);
999 SDL_UpdateRect(screen, startx, starty, endx - startx, endy - starty);
1001 /* Reset bounding box */
1002 needs_update = false;
1005 static bool same_side(const struct ball *ball, unsigned int x)
1007 return (ball->pos.x >= MAX_X/2) == (x >= MAX_X/2);
1010 int main(int argc, char *argv[])
1013 SDL_Surface *screen;
1016 unsigned int i, time_since_last_ir = INT_MAX;
1017 cwiid_wiimote_t *wiimote;
1018 struct cwiid_state state;
1019 struct coord calib[4];
1020 bdaddr_t addr = *BDADDR_ANY;
1021 bool mouse = false, needs_calibration = true, drawing = false;
1023 struct cwiid_ir_src *ir, last_ir = { .valid = 0 };
1024 struct score left, right;
1026 videoflags = SDL_SWSURFACE;
1028 if (argv[1] && streq(argv[1], "--fullscreen")) {
1029 videoflags |= SDL_FULLSCREEN;
1034 if (argv[1] && strstarts(argv[1], "--calib=")) {
1035 needs_calibration = false;
1036 if (sscanf(argv[1], "--calib=%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
1037 &calib[0].x, &calib[0].y,
1038 &calib[1].x, &calib[1].y,
1039 &calib[2].x, &calib[2].y,
1040 &calib[3].x, &calib[3].y) != 8)
1041 errx(1, "Not enough calibration points");
1046 if (argv[1] && streq(argv[1], "--mouse")) {
1048 needs_calibration = false;
1049 calib[0].x = calib[0].y = 0;
1050 calib[1].x = MAX_X - 1;
1052 calib[2].x = MAX_X - 1;
1053 calib[2].y = MAX_Y - 1;
1055 calib[3].y = MAX_Y - 1;
1061 errx(1, "Usage: %s [--fullscreen] [--calib=x,y,x,y,x,y,x,y] [--mouse] speed\n",
1064 /* Initialize SDL */
1065 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
1066 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
1073 printf("Put Wiimote in discoverable mode (press 1+2)\n");
1074 wiimote = cwiid_open(&addr, 0);
1076 errx(1, "Can't find the Wiimote");
1078 if (cwiid_set_rpt_mode(wiimote, CWIID_RPT_IR))
1079 errx(1, "Can't set IR repeat mode");
1082 if ((screen=SDL_SetVideoMode(MAX_X,MAX_Y,video_bpp,videoflags)) == NULL) {
1083 errx(1, "Couldn't set %dx%dx%d video mode: %s",
1084 MAX_X, MAX_Y,video_bpp, SDL_GetError());
1087 /* Set the surface pixels and refresh! */
1088 if (SDL_LockSurface(screen) < 0) {
1089 errx(1, "Couldn't lock the display surface: %s",
1093 memset(screen->pixels, 0xFF, screen->pitch * screen->h);
1095 SDL_UnlockSurface(screen);
1096 SDL_UpdateRect(screen, 0, 0, 0, 0);
1098 if (needs_calibration) {
1100 calibrate(screen, "images/top-left.png",
1101 wiimote, &calib[0], 0, 0);
1102 calibrate(screen, "images/top-right.png",
1103 wiimote, &calib[1], MAX_X - 1, 0);
1104 calibrate(screen, "images/bottom-right.png",
1105 wiimote, &calib[2], MAX_X - 1, MAX_Y - 1);
1106 calibrate(screen, "images/bottom-left.png",
1107 wiimote, &calib[3], 0, MAX_Y - 1);
1110 /* Create borders, put them in list. */
1111 for (i = 0; i < ARRAY_SIZE(border); i++) {
1112 border[i].ignore = false;
1113 border[i].expires.tv_sec = LONG_MAX;
1114 border[i].expires.tv_usec = 0;
1115 line_object_setup(&lines, &objects, &border[i]);
1118 /* Set up scores. */
1119 left.value = right.value = 0;
1120 left.image = IMG_Load("images/0.png");
1121 left.won = IMG_Load("images/left-won.png");
1122 right.image = IMG_Load("images/0.png");
1123 right.won = IMG_Load("images/right-won.png");
1124 if (!left.image || !right.image || !left.won || !right.won)
1125 err(1, "Opening score images");
1127 add_object(&objects, &left.object,
1128 MAX_X/6 - left.image->w/2, 10,
1129 left.image->w, left.image->h, redraw_score);
1130 add_object(&objects, &right.object,
1131 MAX_X - MAX_X/6 - left.image->w/2, 10,
1132 left.image->w, left.image->h, redraw_score);
1134 /* Hit right border = score to left, and vice versa. */
1135 border[1].score = &left;
1136 border[3].score = &right;
1138 srandom(time(NULL));
1139 ball.pos.x = MAX_X/2;
1140 ball.pos.y = MAX_Y/2;
1141 ball.move.x = (random() % 2 ? -1 : 1) * atoi(argv[1]);
1143 ball.image = ball_surface(screen);
1144 add_object(&objects, &ball.object,
1145 ball.pos.x - ball.image->w/2,
1146 ball.pos.y - ball.image->h/2,
1147 ball.image->w, ball.image->h, redraw_ball);
1150 struct coord new, isect, move = ball.move;
1151 struct line_segment *best_l, *l, *next;
1155 bool ignored = false;
1157 gettimeofday(&now, NULL);
1160 list_for_each_safe(&lines, l, next, list) {
1161 if (timercmp(&l->expires, &now, <))
1166 best_d = MAX_X + MAX_Y;
1168 new.x = ball.pos.x + move.x;
1169 new.y = ball.pos.y + move.y;
1171 list_for_each(&lines, l, list) {
1172 if (!l->ignore && intersect(&ball.pos, &new, l, &isect)) {
1174 d = dist(&ball.pos, &isect);
1183 printf("Ball bouncing off (%f,%f %f,%f)!\n",
1184 best_l->start.x, best_l->start.y,
1185 best_l->end.x, best_l->end.y);
1186 /* Only increase speed on *first* bounce, to avoid
1187 * mega speed increases. */
1188 bounce(&ball, best_l, &move, ignored ? 0.0 : 0.1);
1190 /* If we moved, stop ignoring lines. */
1191 if (ignored && (move.x > 0.001 || move.y > 0.001))
1192 clear_ignore(&lines);
1194 /* Don't hit the same line twice. */
1195 printf("Ignoring that line\n");
1196 best_l->ignore = ignored = true;
1197 if (best_l->score) {
1198 SDL_Surface *won = score(best_l->score);
1202 rect.x = MAX_X/2 - won->w/2;
1203 rect.y = MAX_Y/2 - won->h/2;
1206 SDL_BlitSurface(won, NULL, screen,
1208 SDL_UpdateRect(screen,
1218 if (ignored && (move.x > 0.001 || move.y > 0.001)) {
1219 clear_ignore(&lines);
1220 printf("Moving by %f,%f to %f,%f\n",
1221 move.x, move.y, new.x, new.y);
1224 /* We also need to redraw under old ball. */
1225 add_update(&ball.object);
1229 ball.object.start.x = ball.pos.x - ball.image->w/2;
1230 ball.object.start.y = ball.pos.y - ball.image->h/2;
1231 ball.object.end.x = ball.pos.x + ball.image->w/2;
1232 ball.object.end.y = ball.pos.y + ball.image->h/2;
1234 /* Need to draw under new ball. */
1235 add_update(&ball.object);
1237 /* Clears, redraws and resets the updates */
1238 do_updates(&objects, screen);
1242 while (SDL_PollEvent(&event)) {
1243 if (event.type == SDL_QUIT
1244 || (event.type == SDL_KEYDOWN
1245 && event.key.keysym.sym == SDLK_ESCAPE)) {
1250 switch (event.type) {
1251 case SDL_MOUSEBUTTONDOWN:
1254 case SDL_MOUSEBUTTONUP:
1257 case SDL_MOUSEMOTION:
1259 !same_side(&ball, event.motion.x))
1262 add_line(&lines, event.motion.x,
1265 + event.motion.xrel,
1267 + event.motion.yrel,
1276 if (cwiid_get_state(wiimote, &state))
1277 errx(1, "No wii state");
1279 /* Find biggest state. */
1280 ir = &state.ir_src[0];
1281 for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
1282 if (!state.ir_src[i].valid)
1284 /* Only look at dots on same side as ball */
1285 if (!same_side(&ball, state.ir_src[i].pos[0]))
1287 if (!ir->valid || state.ir_src[i].size > ir->size)
1288 ir = &state.ir_src[i];
1292 /* Give it some slack for missing one or two... */
1293 if (time_since_last_ir <= 5
1294 && same_side(&ball, last_ir.pos[0])) {
1295 add_line(&lines, last_ir.pos[0],
1301 time_since_last_ir = 0;
1304 time_since_last_ir++;