]> git.ozlabs.org Git - ponghero.git/blob - prpong.c
36b297e600d02c3c8c774b922d28a64e8d01e079
[ponghero.git] / prpong.c
1 #define _GNU_SOURCE
2 #include <math.h>
3 #include <err.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <sys/time.h>
8 #include <time.h>
9 #include <limits.h>
10 #include "stdrusty.h"
11 #include "list/list.h"
12 #include <SDL/SDL.h>
13 #include <cwiid.h>
14 #include <assert.h>
15
16 #define MAX_X CWIID_IR_X_MAX
17 #define MAX_Y CWIID_IR_Y_MAX
18
19 struct coord
20 {
21         double x;
22         double y;
23 };
24
25 /* Obtained from http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */
26 /* Faster Line Segment Intersection   */
27 /* Franklin Antonio                   */
28 static bool lines_intersect(const struct coord *start1,
29                             const struct coord *start2,
30                             const struct coord *start3,
31                             const struct coord *start4,
32                             struct coord *intersect)
33 {
34         double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num;
35         struct coord lo, hi;
36
37         Ax = start2->x - start1->x;
38         Bx = start3->x - start4->x;
39
40         if(Ax<0) {                                      /* X bound box test*/
41                 lo.x = start2->x; hi.x = start1->x;
42         } else {
43                 hi.x = start2->x; lo.x = start1->x;
44         }
45         if(Bx>0) {
46                 if(hi.x < start4->x || start3->x < lo.x) return false;
47         } else {
48                 if(hi.x < start3->x || start4->x < lo.x) return false;
49         }
50
51         Ay = start2->y - start1->y;
52         By = start3->y - start4->y;
53
54         if(Ay<0) {                                      /* Y bound box test*/
55                 lo.y = start2->y; hi.y = start1->y;
56         } else {
57                 hi.y = start2->y; lo.y = start1->y;
58         }
59         if(By>0) {
60                 if(hi.y < start4->y || start3->y < lo.y) return false;
61         } else {
62                 if(hi.y < start3->y || start4->y < lo.y) return false;
63         }
64
65
66         Cx = start1->x - start3->x;
67         Cy = start1->y - start3->y;
68         d = By*Cx - Bx*Cy;                              /* alpha numerator*/
69         f = Ay*Bx - Ax*By;                              /* both denominator*/
70         if (f>0) {                                      /* alpha tests*/
71                 if (d < 0 || d > f) return false;
72         } else {
73                 if (d > 0 || d < f) return false;
74         }
75
76         e = Ax*Cy - Ay*Cx;                              /* beta numerator*/
77         if (f > 0) {                                    /* beta tests*/
78                 if (e < 0 || e > f) return false;
79         } else {
80                 if (e > 0 || e < f) return false;
81         }
82
83 /*compute intersection coordinates*/
84         /* Don't worry about tiny values of f (< 1/2 pixel across screen) */
85         if (fabs(f) < 1.0 / (2.0 * MAX_X * MAX_Y))
86                 return false;
87
88         num = d*Ax;                                     /* numerator */
89         intersect->x = start1->x + num / f;             /* intersection x */
90
91         num = d*Ay;
92         intersect->y = start1->y + num / f;             /* intersection y */
93
94         return true;
95 }
96
97 // A set of very useful macros that you will find in most
98 // code that I write whether I use them in a program or
99 // not.
100
101 #define abs(a) (((a)<0) ? -(a) : (a))
102 #define sign(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0)
103
104 // The following code implements a Bresenham line drawing
105 // algorithm. There are 4 separate routines each optimized
106 // for one of the four pixel depths supported by SDL. SDL
107 // support many pixel formats, but it only support 8, 16,
108 // 24, and 32 bit pixels.
109
110 //----------------------------------------------------------
111
112 // Draw lines in 8 bit surfaces.
113
114 static void line8(SDL_Surface *s, 
115                   int x1, int y1, 
116                   int x2, int y2, 
117                   Uint32 color)
118 {
119   int d;
120   int x;
121   int y;
122   int ax;
123   int ay;
124   int sx;
125   int sy;
126   int dx;
127   int dy;
128
129   Uint8 *lineAddr;
130   Sint32 yOffset;
131
132   dx = x2 - x1;  
133   ax = abs(dx) << 1;  
134   sx = sign(dx);
135
136   dy = y2 - y1;  
137   ay = abs(dy) << 1;  
138   sy = sign(dy);
139   yOffset = sy * s->pitch;
140
141   x = x1;
142   y = y1;
143
144   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
145   if (ax>ay)
146   {                      /* x dominant */
147     d = ay - (ax >> 1);
148     for (;;)
149     {
150       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
151         *(lineAddr + x) = (Uint8)color;
152
153       if (x == x2)
154       {
155         return;
156       }
157       if (d>=0)
158       {
159         y += sy;
160         lineAddr += yOffset;
161         d -= ax;
162       }
163       x += sx;
164       d += ay;
165     }
166   }
167   else
168   {                      /* y dominant */
169     d = ax - (ay >> 1);
170     for (;;)
171     {
172       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
173         *(lineAddr + x) = (Uint8)color;
174
175       if (y == y2)
176       {
177         return;
178       }
179       if (d>=0) 
180       {
181         x += sx;
182         d -= ay;
183       }
184       y += sy;
185       lineAddr += yOffset;
186       d += ax;
187     }
188   }
189 }
190
191 //----------------------------------------------------------
192
193 // Draw lines in 16 bit surfaces. Note that this code will
194 // also work on 15 bit surfaces.
195
196 static void line16(SDL_Surface *s, 
197                    int x1, int y1, 
198                    int x2, int y2, 
199                    Uint32 color)
200 {
201   int d;
202   int x;
203   int y;
204   int ax;
205   int ay;
206   int sx;
207   int sy;
208   int dx;
209   int dy;
210
211   Uint8 *lineAddr;
212   Sint32 yOffset;
213
214   dx = x2 - x1;  
215   ax = abs(dx) << 1;  
216   sx = sign(dx);
217
218   dy = y2 - y1;  
219   ay = abs(dy) << 1;  
220   sy = sign(dy);
221   yOffset = sy * s->pitch;
222
223   x = x1;
224   y = y1;
225
226   lineAddr = ((Uint8 *)s->pixels) + (y * s->pitch);
227   if (ax>ay)
228   {                      /* x dominant */
229     d = ay - (ax >> 1);
230     for (;;)
231     {
232       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
233         *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
234
235       if (x == x2)
236       {
237         return;
238       }
239       if (d>=0)
240       {
241         y += sy;
242         lineAddr += yOffset;
243         d -= ax;
244       }
245       x += sx;
246       d += ay;
247     }
248   }
249   else
250   {                      /* y dominant */
251     d = ax - (ay >> 1);
252     for (;;)
253     {
254       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
255         *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
256
257       if (y == y2)
258       {
259         return;
260       }
261       if (d>=0) 
262       {
263         x += sx;
264         d -= ay;
265       }
266       y += sy;
267       lineAddr += yOffset;
268       d += ax;
269     }
270   }
271 }
272
273 //----------------------------------------------------------
274
275 // Draw lines in 24 bit surfaces. 24 bit surfaces require
276 // special handling because the pixels don't fall on even
277 // address boundaries. Instead of being able to store a
278 // single byte, word, or long you have to store 3
279 // individual bytes. As a result 24 bit graphics is slower
280 // than the other pixel sizes.
281
282 static void line24(SDL_Surface *s, 
283                    int x1, int y1, 
284                    int x2, int y2, 
285                    Uint32 color)
286 {
287   int d;
288   int x;
289   int y;
290   int ax;
291   int ay;
292   int sx;
293   int sy;
294   int dx;
295   int dy;
296
297   Uint8 *lineAddr;
298   Sint32 yOffset;
299
300 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
301   color <<= 8;
302 #endif
303
304   dx = x2 - x1;  
305   ax = abs(dx) << 1;  
306   sx = sign(dx);
307
308   dy = y2 - y1;  
309   ay = abs(dy) << 1;  
310   sy = sign(dy);
311   yOffset = sy * s->pitch;
312
313   x = x1;
314   y = y1;
315
316   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
317   if (ax>ay)
318   {                      /* x dominant */
319     d = ay - (ax >> 1);
320     for (;;)
321     {
322       Uint8 *p = (lineAddr + (x * 3));
323       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
324         memcpy(p, &color, 3);
325
326       if (x == x2)
327       {
328         return;
329       }
330       if (d>=0)
331       {
332         y += sy;
333         lineAddr += yOffset;
334         d -= ax;
335       }
336       x += sx;
337       d += ay;
338     }
339   }
340   else
341   {                      /* y dominant */
342     d = ax - (ay >> 1);
343     for (;;)
344     {
345       Uint8 *p = (lineAddr + (x * 3));
346       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
347         memcpy(p, &color, 3);
348
349       if (y == y2)
350       {
351         return;
352       }
353       if (d>=0) 
354       {
355         x += sx;
356         d -= ay;
357       }
358       y += sy;
359       lineAddr += yOffset;
360       d += ax;
361     }
362   }
363 }
364
365 //----------------------------------------------------------
366
367 // Draw lines in 32 bit surfaces. Note that this routine
368 // ignores alpha values. It writes them into the surface
369 // if they are included in the pixel, but does nothing
370 // else with them.
371
372 static void line32(SDL_Surface *s, 
373                    int x1, int y1, 
374                    int x2, int y2, 
375                    Uint32 color)
376 {
377   int d;
378   int x;
379   int y;
380   int ax;
381   int ay;
382   int sx;
383   int sy;
384   int dx;
385   int dy;
386
387   Uint8 *lineAddr;
388   Sint32 yOffset;
389
390   dx = x2 - x1;  
391   ax = abs(dx) << 1;  
392   sx = sign(dx);
393
394   dy = y2 - y1;  
395   ay = abs(dy) << 1;  
396   sy = sign(dy);
397   yOffset = sy * s->pitch;
398
399   x = x1;
400   y = y1;
401
402   lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
403   if (ax>ay)
404   {                      /* x dominant */
405     d = ay - (ax >> 1);
406     for (;;)
407     {
408       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
409         *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
410
411       if (x == x2)
412       {
413         return;
414       }
415       if (d>=0)
416       {
417         y += sy;
418         lineAddr += yOffset;
419         d -= ax;
420       }
421       x += sx;
422       d += ay;
423     }
424   }
425   else
426   {                      /* y dominant */
427     d = ax - (ay >> 1);
428     for (;;)
429     {
430       if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
431         *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
432
433       if (y == y2)
434       {
435         return;
436       }
437       if (d>=0) 
438       {
439         x += sx;
440         d -= ay;
441       }
442       y += sy;
443       lineAddr += yOffset;
444       d += ax;
445     }
446   }
447 }
448
449 //----------------------------------------------------------
450
451 // Examine the depth of a surface and select a line
452 // drawing routine optimized for the bytes/pixel of the
453 // surface.
454
455 static void line(SDL_Surface *s, 
456                  int x1, int y1, 
457                  int x2, int y2, 
458                  Uint32 color)
459 {
460   switch (s->format->BytesPerPixel)
461   {
462   case 1:
463     line8(s, x1, y1, x2, y2, color);
464     break;
465   case 2:
466     line16(s, x1, y1, x2, y2, color);
467     break;
468   case 3:
469     line24(s, x1, y1, x2, y2, color);
470     break;
471   case 4:
472     line32(s, x1, y1, x2, y2, color);
473     break;
474   }
475 }
476
477 struct ball
478 {
479         struct coord pos;
480         struct coord move;
481 };
482
483 struct line_segment
484 {
485         struct coord start, end;
486         struct list_node list;
487         bool ignore;
488         struct timeval expires;
489 };
490
491 static void thick_line(SDL_Surface *s, const struct line_segment *l,
492                        unsigned color)
493 {
494         struct line_segment adj;
495         int x, y, minx = MAX_X, miny = MAX_Y, maxx = 0, maxy = 0;
496
497         SDL_LockSurface(s);
498
499         /* Cheap hack */
500         for (x = -1; x < 2; x++) {
501                 for (y = -1; y < 2; y++) {
502                         adj.start.x = l->start.x + x;
503                         adj.end.x = l->end.x + x;
504                         adj.start.y = l->start.y + y;
505                         adj.end.y = l->end.y + y;
506
507                         if (adj.start.x < minx)
508                                 minx = adj.start.x;
509                         if (adj.start.x > maxx)
510                                 maxx = adj.start.x;
511                         if (adj.start.y < miny)
512                                 miny = adj.start.y;
513                         if (adj.start.y > maxy)
514                                 maxy = adj.start.y;
515                         if (adj.end.x < minx)
516                                 minx = adj.end.x;
517                         if (adj.end.x > maxx)
518                                 maxx = adj.end.x;
519                         if (adj.end.y < miny)
520                                 miny = adj.end.y;
521                         if (adj.end.y > maxy)
522                                 maxy = adj.end.y;
523
524                         line(s, adj.start.x, adj.start.y, adj.end.x, adj.end.y,
525                              color);
526                 }
527         }
528
529         if (minx < 0)
530                 minx = 0;
531         if (miny < 0)
532                 miny = 0;
533         if (maxx >= MAX_X)
534                 maxx = MAX_X-1;
535         if (maxy >= MAX_Y)
536                 maxy = MAX_Y-1;
537         SDL_UpdateRect(s, minx, miny, maxx-minx, maxy-miny);
538         SDL_UnlockSurface(s);
539 }
540
541 static bool intersect(const struct coord *c1, const struct coord *c2,
542                       const struct line_segment *seg, struct coord *intersect)
543 {
544         return lines_intersect(c1, c2, &seg->start, &seg->end, intersect);
545 }
546
547 static double dist(const struct coord *c1, const struct coord *c2)
548 {
549         double x = (c1->x - c2->x), y = (c1->y - c2->y);
550         return sqrt(x * x + y * y);
551 }
552
553 static unsigned rad_to_deg(double rad)
554 {
555         return ((unsigned)(rad / M_PI * 180) + 360) % 360;
556 }
557
558 static void bounce(struct ball *ball, const struct line_segment *line,
559                    struct coord *move, double increase_speed)
560 {
561         double len, speed, lang, iang, oang;
562         struct coord isect, new;
563
564         new.x = ball->pos.x + move->x;
565         new.y = ball->pos.y + move->y;
566
567         /* How far were we supposed to move ball? */
568         len = sqrt(move->x * move->x + move->y * move->y);
569
570         /* How far is it to intersection? */
571         if (!intersect(&ball->pos, &new, line, &isect))
572                 errx(1, "No intersection any more?\n");;
573         len -= dist(&ball->pos, &isect);
574
575         /* Move ball to intersection. */
576         ball->pos = isect;
577         printf("ball is now at %f,%f\n", ball->pos.x, ball->pos.y);
578
579         /* Outgoing angle = 2 * line angle - incident angle. */
580         lang = atan2(line->end.x - line->start.x, line->end.y - line->start.y);
581         iang = atan2(ball->move.x, ball->move.y);
582         oang = 2 * lang - iang, 2*M_PI;
583         printf("lang = %u, iang = %u, oang=%u\n", 
584                rad_to_deg(lang),
585                rad_to_deg(iang),
586                rad_to_deg(oang));
587
588         /* Set new direction for ball, at slightly increased speed */
589         speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y);
590         speed += increase_speed;
591         ball->move.x = sin(oang) * speed;
592         ball->move.y = cos(oang) * speed;
593
594         /* Set move. */
595         move->x = sin(oang) * len;
596         move->y = cos(oang) * len;
597         printf("len = %f, move = %f,%f\n", len, move->x, move->y);
598 }
599
600 static struct line_segment border[] = {
601         { { 0, 0, }, { MAX_X-1, 0 } },
602         { { MAX_X-1, 0, }, { MAX_X-1, MAX_Y-1 } },
603         { { MAX_X-1, MAX_Y-1, }, { 0, MAX_Y-1 } },
604         { { 0, MAX_Y-1, }, { 0, 0 } },
605 };
606
607 static inline float deg_to_rad(float degrees)
608 {
609         return degrees * M_PI / 180;
610 }
611
612 static SDL_Surface *sub_surface(SDL_Surface *screen, int w, int h)
613 {
614         return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
615                                     screen->format->BitsPerPixel,
616                                     screen->format->Rmask,
617                                     screen->format->Gmask,
618                                     screen->format->Bmask,
619                                     screen->format->Amask);
620 }
621
622 static SDL_Surface *ball_surface(SDL_Surface *screen)
623 {
624         SDL_Surface *ball;
625
626         /* Just like the screen surface. */
627         ball = sub_surface(screen, 5, 5);
628
629         /* Lock the surface */
630         SDL_LockSurface(ball);
631
632         /* Black, white corners. */
633         memset(ball->pixels, 0x00, ball->pitch * 5);
634         line(ball, 0, 0, 0, 0, 0xFFFFFFFF);
635         line(ball, 4, 0, 4, 0, 0xFFFFFFFF);
636         line(ball, 0, 4, 0, 4, 0xFFFFFFFF);
637         line(ball, 4, 4, 4, 4, 0xFFFFFFFF);
638         SDL_UnlockSurface(ball);
639
640         return ball;
641 }
642
643 static void clear_ignore(struct list_head *lines)
644 {
645         struct line_segment *i;
646         printf("Unignoring...\n");
647         list_for_each(lines, i, list)
648                 i->ignore = false;
649 }
650
651 int main(int argc, char *argv[])
652 {
653         struct ball ball;
654         SDL_Surface *screen, *ballsur, *savesur = NULL;
655         Uint8  video_bpp;
656         Uint32 videoflags;
657         unsigned int i, time_since_last_ir = INT_MAX;
658         SDL_Rect rect;
659         struct timeval line_life = { 3, 0 };
660         cwiid_wiimote_t *wiimote;
661         struct cwiid_state state;
662         bdaddr_t addr = *BDADDR_ANY;
663         LIST_HEAD(lines);
664         struct cwiid_ir_src *ir, last_ir = { .valid = 0 };
665
666         videoflags = SDL_SWSURFACE;
667
668         if (argv[1] && streq(argv[1], "--fullscreen")) {
669                 videoflags = SDL_SWSURFACE;
670                 argc--;
671                 argv++;
672         }
673
674         if (argc != 5)
675                 errx(1, "Usage: %s [--fullscreen] ballx bally ballangle ballspeed\n"
676                      "   Where ballangle is 0 for north, 90 for east, etc\n",
677                         argv[0]);
678
679         ball.pos.x = atol(argv[1]);
680         ball.pos.y = atol(argv[2]);
681         ball.move.x = sin(deg_to_rad(atof(argv[3]))) * atol(argv[4]);
682         ball.move.y = cos(deg_to_rad(atof(argv[3]))) * atol(argv[4]);
683         printf("ball move = %f,%f\n", ball.move.x, ball.move.y);
684
685         /* Initialize SDL */
686         if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
687                 fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
688                 return(1);
689         }
690
691         video_bpp = 0;
692
693         printf("Put Wiimote in discoverable mode (press 1+2)\n");
694         wiimote = cwiid_open(&addr, 0);
695         if (!wiimote)
696                 errx(1, "Can't find the Wiimote");
697
698         if (cwiid_set_rpt_mode(wiimote, CWIID_RPT_IR))
699                 errx(1, "Can't set IR repeat mode");
700
701         if ( (screen=SDL_SetVideoMode(MAX_X,MAX_Y,video_bpp,videoflags)) == NULL ) {
702                 errx(1, "Couldn't set %dx%dx%d video mode: %s",
703                      MAX_X, MAX_Y,video_bpp, SDL_GetError());
704         }
705
706         /* Set the surface pixels and refresh! */
707         if ( SDL_LockSurface(screen) < 0 ) {
708                 errx(1, "Couldn't lock the display surface: %s",
709                      SDL_GetError());
710         }
711         /* White. */
712         memset(screen->pixels, 0xFF, screen->pitch * screen->h);
713
714         SDL_UnlockSurface(screen);
715         SDL_UpdateRect(screen, 0, 0, 0, 0);
716
717         /* Draw borders, put them in list. */
718         for (i = 0; i < ARRAY_SIZE(border); i++) {
719                 border[i].ignore = false;
720                 border[i].expires.tv_sec = LONG_MAX;
721                 border[i].expires.tv_usec = 0;
722                 list_add(&lines, &border[i].list);
723                 thick_line(screen, &border[i], 0);
724         }
725
726         ballsur = ball_surface(screen);
727
728         for (;;) {
729                 struct coord new, isect, move = ball.move;
730                 struct line_segment *best_l, *l, *next;
731                 double best_d;
732                 SDL_Event event;
733                 struct timeval now;
734                 bool ignored = false;
735
736                 gettimeofday(&now, NULL);
737
738                 /* Expire lines */
739                 list_for_each_safe(&lines, l, next, list) {
740                         if (timercmp(&l->expires, &now, <)) {
741                                 printf("Deleting line %p\n", l);
742                                 list_del(&l->list);
743                                 /* FIXME: Undraw properly. */
744                                 thick_line(screen, l, 0xFFFFFFFF);
745                                 free(l);
746                         }
747                 }
748
749         again:
750                 best_d = MAX_X + MAX_Y;
751                 best_l = NULL;
752                 new.x = ball.pos.x + move.x;
753                 new.y = ball.pos.y + move.y;
754
755                 list_for_each(&lines, l, list) {
756                         if (!l->ignore && intersect(&ball.pos, &new, l, &isect)) {
757                                 double d;
758                                 d = dist(&ball.pos, &isect);
759                                 if (d < best_d) {
760                                         best_l = l;
761                                         best_d = d;
762                                 }
763                         }
764                 }
765
766                 if (best_l) {
767                         printf("Ball bouncing off (%f,%f %f,%f)!\n",
768                                best_l->start.x, best_l->start.y,
769                                best_l->end.x, best_l->end.y);
770                         /* Only increase speed on *first* bounce, to avoid
771                          * mega speed increases. */
772                         bounce(&ball, best_l, &move, ignored ? 0.0 : 0.1);
773
774                         /* If we moved, stop ignoring lines. */
775                         if (ignored && (move.x > 0.001 || move.y > 0.001))
776                                 clear_ignore(&lines);
777
778                         /* Don't hit the same line twice. */
779                         printf("Ignoring that line\n");
780                         best_l->ignore = ignored = true;
781                         goto again;
782                 }
783
784                 if (ignored && (move.x > 0.001 || move.y > 0.001)) {
785                         clear_ignore(&lines);
786                         printf("Moving by %f,%f to %f,%f\n",
787                                move.x, move.y, new.x, new.y);
788                 }
789
790                 /* Restore what was there before ball. */
791                 if (savesur) {
792                         SDL_BlitSurface(savesur, NULL, screen, &rect);
793                         SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
794                 } else {
795                         savesur = sub_surface(screen, ballsur->w, ballsur->h);
796                 }
797
798                 /* Save away image under new ball. */
799                 rect.w = ballsur->w;
800                 rect.h = ballsur->h;
801                 rect.x = new.x - ballsur->w/2;
802                 rect.y = new.y - ballsur->h/2;
803                 SDL_BlitSurface(screen, &rect, savesur, NULL);
804
805                 /* Draw new ball */
806                 SDL_BlitSurface(ballsur, NULL, screen, &rect);
807                 SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
808                 /* That SDL_BlitSurface can crop rect. */
809                 rect.x = new.x - ballsur->w/2;
810                 rect.y = new.y - ballsur->h/2;
811                 ball.pos = new;
812                 SDL_Delay(25);
813
814                 if (SDL_PollEvent(&event)
815                     && (event.type == SDL_QUIT
816                         || (event.type == SDL_KEYDOWN
817                             && event.key.keysym.sym == SDLK_ESCAPE))) {
818                         SDL_Quit();
819                         return 0;
820                 }
821
822                 if (cwiid_get_state(wiimote, &state))
823                         errx(1, "No wii state");
824
825                 /* Find biggest state. */
826                 ir = &state.ir_src[0];
827                 for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
828                         if (!state.ir_src[i].valid)
829                                 continue;
830                         if (!ir->valid || state.ir_src[i].size > ir->size)
831                                 ir = &state.ir_src[0];
832                 }
833
834                 if (ir->valid) {
835                         /* Give it some slack for missing one or two... */
836                         if (time_since_last_ir <= 5) {
837                                 struct line_segment *n = malloc(sizeof(*n));
838                                 /* Wiimote coordinates are backwards for us. */
839                                 n->start.x = last_ir.pos[0];
840                                 n->start.y = MAX_Y - last_ir.pos[1];
841                                 n->end.x = ir->pos[0];
842                                 n->end.y = MAX_Y - ir->pos[1];
843                                 n->ignore = false;
844                                 timeradd(&now, &line_life, &n->expires);
845                                 list_add_tail(&lines, &n->list);
846                                 thick_line(screen, n, 0);
847                         }
848                         time_since_last_ir = 0;
849                         last_ir = *ir;
850                 }
851                 time_since_last_ir++;
852         }
853 }