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