]> git.ozlabs.org Git - ponghero.git/blobdiff - prpong.c
Prepare for release: rename to ponghero and pull in ccan.
[ponghero.git] / prpong.c
diff --git a/prpong.c b/prpong.c
deleted file mode 100644 (file)
index 660fc8a..0000000
--- a/prpong.c
+++ /dev/null
@@ -1,1306 +0,0 @@
-#define _GNU_SOURCE
-#include <math.h>
-#include <err.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <sys/time.h>
-#include <time.h>
-#include <limits.h>
-#include "stdrusty.h"
-#include "list/list.h"
-#include "talloc/talloc.h"
-#include "container_of/container_of.h"
-#include <SDL/SDL.h>
-#include <SDL/SDL_image.h>
-#include <cwiid.h>
-#include <assert.h>
-#include <unistd.h>
-
-#define EXPIRY_SECS 3
-
-#define MAX_X CWIID_IR_X_MAX
-#define MAX_Y CWIID_IR_Y_MAX
-
-#define LEFT_PLAYER 1
-#define RIGHT_PLAYER 2
-
-static LIST_HEAD(objects);
-
-struct coord
-{
-       double x;
-       double y;
-};
-
-/* Obtained from http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */
-/* Faster Line Segment Intersection   */
-/* Franklin Antonio                   */
-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;
-       struct coord lo, hi;
-
-       Ax = start2->x - start1->x;
-       Bx = start3->x - start4->x;
-
-       if(Ax<0) {                                      /* X bound box test*/
-               lo.x = start2->x; hi.x = start1->x;
-       } else {
-               hi.x = start2->x; lo.x = start1->x;
-       }
-       if(Bx>0) {
-               if(hi.x < start4->x || start3->x < lo.x) return false;
-       } else {
-               if(hi.x < start3->x || start4->x < lo.x) return false;
-       }
-
-       Ay = start2->y - start1->y;
-       By = start3->y - start4->y;
-
-       if(Ay<0) {                                      /* Y bound box test*/
-               lo.y = start2->y; hi.y = start1->y;
-       } else {
-               hi.y = start2->y; lo.y = start1->y;
-       }
-       if(By>0) {
-               if(hi.y < start4->y || start3->y < lo.y) return false;
-       } else {
-               if(hi.y < start3->y || start4->y < lo.y) 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;
-       }
-
-       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;
-       }
-
-/*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;
-
-       num = d*Ax;                                     /* numerator */
-       intersect->x = start1->x + num / f;             /* intersection x */
-
-       num = d*Ay;
-       intersect->y = start1->y + num / f;             /* intersection y */
-
-       return true;
-}
-
-// A set of very useful macros that you will find in most
-// code that I write whether I use them in a program or
-// not.
-
-#define abs(a) (((a)<0) ? -(a) : (a))
-#define sign(a) (((a)<0) ? -1 : (a)>0 ? 1 : 0)
-
-// The following code implements a Bresenham line drawing
-// algorithm. There are 4 separate routines each optimized
-// for one of the four pixel depths supported by SDL. SDL
-// support many pixel formats, but it only support 8, 16,
-// 24, and 32 bit pixels.
-
-//----------------------------------------------------------
-
-// Draw lines in 8 bit surfaces.
-
-static void line8(SDL_Surface *s, 
-                  int x1, int y1, 
-                  int x2, int y2, 
-                  Uint32 color)
-{
-  int d;
-  int x;
-  int y;
-  int ax;
-  int ay;
-  int sx;
-  int sy;
-  int dx;
-  int dy;
-
-  Uint8 *lineAddr;
-  Sint32 yOffset;
-
-  dx = x2 - x1;  
-  ax = abs(dx) << 1;  
-  sx = sign(dx);
-
-  dy = y2 - y1;  
-  ay = abs(dy) << 1;  
-  sy = sign(dy);
-  yOffset = sy * s->pitch;
-
-  x = x1;
-  y = y1;
-
-  lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
-  if (ax>ay)
-  {                      /* x dominant */
-    d = ay - (ax >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *(lineAddr + x) = (Uint8)color;
-
-      if (x == x2)
-      {
-        return;
-      }
-      if (d>=0)
-      {
-        y += sy;
-        lineAddr += yOffset;
-        d -= ax;
-      }
-      x += sx;
-      d += ay;
-    }
-  }
-  else
-  {                      /* y dominant */
-    d = ax - (ay >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *(lineAddr + x) = (Uint8)color;
-
-      if (y == y2)
-      {
-        return;
-      }
-      if (d>=0) 
-      {
-        x += sx;
-        d -= ay;
-      }
-      y += sy;
-      lineAddr += yOffset;
-      d += ax;
-    }
-  }
-}
-
-//----------------------------------------------------------
-
-// Draw lines in 16 bit surfaces. Note that this code will
-// also work on 15 bit surfaces.
-
-static void line16(SDL_Surface *s, 
-                   int x1, int y1, 
-                   int x2, int y2, 
-                   Uint32 color)
-{
-  int d;
-  int x;
-  int y;
-  int ax;
-  int ay;
-  int sx;
-  int sy;
-  int dx;
-  int dy;
-
-  Uint8 *lineAddr;
-  Sint32 yOffset;
-
-  dx = x2 - x1;  
-  ax = abs(dx) << 1;  
-  sx = sign(dx);
-
-  dy = y2 - y1;  
-  ay = abs(dy) << 1;  
-  sy = sign(dy);
-  yOffset = sy * s->pitch;
-
-  x = x1;
-  y = y1;
-
-  lineAddr = ((Uint8 *)s->pixels) + (y * s->pitch);
-  if (ax>ay)
-  {                      /* x dominant */
-    d = ay - (ax >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
-
-      if (x == x2)
-      {
-        return;
-      }
-      if (d>=0)
-      {
-        y += sy;
-        lineAddr += yOffset;
-        d -= ax;
-      }
-      x += sx;
-      d += ay;
-    }
-  }
-  else
-  {                      /* y dominant */
-    d = ax - (ay >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *((Uint16 *)(lineAddr + (x << 1))) = (Uint16)color;
-
-      if (y == y2)
-      {
-        return;
-      }
-      if (d>=0) 
-      {
-        x += sx;
-        d -= ay;
-      }
-      y += sy;
-      lineAddr += yOffset;
-      d += ax;
-    }
-  }
-}
-
-//----------------------------------------------------------
-
-// Draw lines in 24 bit surfaces. 24 bit surfaces require
-// special handling because the pixels don't fall on even
-// address boundaries. Instead of being able to store a
-// single byte, word, or long you have to store 3
-// individual bytes. As a result 24 bit graphics is slower
-// than the other pixel sizes.
-
-static void line24(SDL_Surface *s, 
-                   int x1, int y1, 
-                   int x2, int y2, 
-                   Uint32 color)
-{
-  int d;
-  int x;
-  int y;
-  int ax;
-  int ay;
-  int sx;
-  int sy;
-  int dx;
-  int dy;
-
-  Uint8 *lineAddr;
-  Sint32 yOffset;
-
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-  color <<= 8;
-#endif
-
-  dx = x2 - x1;  
-  ax = abs(dx) << 1;  
-  sx = sign(dx);
-
-  dy = y2 - y1;  
-  ay = abs(dy) << 1;  
-  sy = sign(dy);
-  yOffset = sy * s->pitch;
-
-  x = x1;
-  y = y1;
-
-  lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
-  if (ax>ay)
-  {                      /* x dominant */
-    d = ay - (ax >> 1);
-    for (;;)
-    {
-      Uint8 *p = (lineAddr + (x * 3));
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        memcpy(p, &color, 3);
-
-      if (x == x2)
-      {
-        return;
-      }
-      if (d>=0)
-      {
-        y += sy;
-        lineAddr += yOffset;
-        d -= ax;
-      }
-      x += sx;
-      d += ay;
-    }
-  }
-  else
-  {                      /* y dominant */
-    d = ax - (ay >> 1);
-    for (;;)
-    {
-      Uint8 *p = (lineAddr + (x * 3));
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        memcpy(p, &color, 3);
-
-      if (y == y2)
-      {
-        return;
-      }
-      if (d>=0) 
-      {
-        x += sx;
-        d -= ay;
-      }
-      y += sy;
-      lineAddr += yOffset;
-      d += ax;
-    }
-  }
-}
-
-//----------------------------------------------------------
-
-// Draw lines in 32 bit surfaces. Note that this routine
-// ignores alpha values. It writes them into the surface
-// if they are included in the pixel, but does nothing
-// else with them.
-
-static void line32(SDL_Surface *s, 
-                   int x1, int y1, 
-                   int x2, int y2, 
-                   Uint32 color)
-{
-  int d;
-  int x;
-  int y;
-  int ax;
-  int ay;
-  int sx;
-  int sy;
-  int dx;
-  int dy;
-
-  Uint8 *lineAddr;
-  Sint32 yOffset;
-
-  dx = x2 - x1;  
-  ax = abs(dx) << 1;  
-  sx = sign(dx);
-
-  dy = y2 - y1;  
-  ay = abs(dy) << 1;  
-  sy = sign(dy);
-  yOffset = sy * s->pitch;
-
-  x = x1;
-  y = y1;
-
-  lineAddr = ((Uint8 *)(s->pixels)) + (y * s->pitch);
-  if (ax>ay)
-  {                      /* x dominant */
-    d = ay - (ax >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
-
-      if (x == x2)
-      {
-        return;
-      }
-      if (d>=0)
-      {
-        y += sy;
-        lineAddr += yOffset;
-        d -= ax;
-      }
-      x += sx;
-      d += ay;
-    }
-  }
-  else
-  {                      /* y dominant */
-    d = ax - (ay >> 1);
-    for (;;)
-    {
-      if (y >= 0 && y < MAX_Y && x >= 0 && x < MAX_X)
-        *((Uint32 *)(lineAddr + (x << 2))) = (Uint32)color;
-
-      if (y == y2)
-      {
-        return;
-      }
-      if (d>=0) 
-      {
-        x += sx;
-        d -= ay;
-      }
-      y += sy;
-      lineAddr += yOffset;
-      d += ax;
-    }
-  }
-}
-
-//----------------------------------------------------------
-
-// Examine the depth of a surface and select a line
-// drawing routine optimized for the bytes/pixel of the
-// surface.
-
-static void line(SDL_Surface *s, 
-                 int x1, int y1, 
-                 int x2, int y2, 
-                 Uint32 color)
-{
-  switch (s->format->BytesPerPixel)
-  {
-  case 1:
-    line8(s, x1, y1, x2, y2, color);
-    break;
-  case 2:
-    line16(s, x1, y1, x2, y2, color);
-    break;
-  case 3:
-    line24(s, x1, y1, x2, y2, color);
-    break;
-  case 4:
-    line32(s, x1, y1, x2, y2, color);
-    break;
-  }
-}
-
-/* Bounding box to be updated. */
-static bool needs_update;
-static struct coord start_update, end_update;
-
-struct object
-{
-       /* List of all objects. */
-       struct list_node list;
-       /* Bounding box. */
-       struct coord start, end;
-
-       void (*redraw)(SDL_Surface *s, struct object *me);
-};
-
-struct ball
-{
-       struct object object;
-
-       struct coord pos;
-       struct coord move;
-       SDL_Surface *image;
-};
-
-struct line_segment
-{
-       struct object object;
-
-       struct coord start, end;
-       struct list_node list;
-       bool ignore;
-       struct timeval expires;
-       /* Does someone score if they hit this line ? */
-       struct score *score;
-};
-
-struct score
-{
-       struct object object;
-
-       SDL_Surface *image;
-       unsigned int value;
-       SDL_Surface *won;
-};
-
-static void thick_line(SDL_Surface *s, const struct line_segment *l,
-                      unsigned color)
-{
-       struct line_segment adj;
-       int x, y, minx = MAX_X, miny = MAX_Y, maxx = 0, maxy = 0;
-
-       SDL_LockSurface(s);
-
-       /* Cheap hack */
-       for (x = -1; x < 2; x++) {
-               for (y = -1; y < 2; y++) {
-                       adj.start.x = l->start.x + x;
-                       adj.end.x = l->end.x + x;
-                       adj.start.y = l->start.y + y;
-                       adj.end.y = l->end.y + y;
-
-                       if (adj.start.x < minx)
-                               minx = adj.start.x;
-                       if (adj.start.x > maxx)
-                               maxx = adj.start.x;
-                       if (adj.start.y < miny)
-                               miny = adj.start.y;
-                       if (adj.start.y > maxy)
-                               maxy = adj.start.y;
-                       if (adj.end.x < minx)
-                               minx = adj.end.x;
-                       if (adj.end.x > maxx)
-                               maxx = adj.end.x;
-                       if (adj.end.y < miny)
-                               miny = adj.end.y;
-                       if (adj.end.y > maxy)
-                               maxy = adj.end.y;
-
-                       line(s, adj.start.x, adj.start.y, adj.end.x, adj.end.y,
-                            color);
-               }
-       }
-
-       if (minx < 0)
-               minx = 0;
-       if (miny < 0)
-               miny = 0;
-       if (maxx >= MAX_X)
-               maxx = MAX_X-1;
-       if (maxy >= MAX_Y)
-               maxy = MAX_Y-1;
-       SDL_UpdateRect(s, minx, miny, maxx-minx, maxy-miny);
-       SDL_UnlockSurface(s);
-}
-
-static bool intersect(const struct coord *c1, const struct coord *c2,
-                     const struct line_segment *seg, struct coord *intersect)
-{
-       return lines_intersect(c1, c2, &seg->start, &seg->end, intersect);
-}
-
-static double dist(const struct coord *c1, const struct coord *c2)
-{
-       double x = (c1->x - c2->x), y = (c1->y - c2->y);
-       return sqrt(x * x + y * y);
-}
-
-static unsigned rad_to_deg(double rad)
-{
-       return ((unsigned)(rad / M_PI * 180) + 360) % 360;
-}
-
-static void bounce(struct ball *ball, const struct line_segment *line,
-                  struct coord *move, double increase_speed)
-{
-       double len, speed, lang, iang, oang;
-       struct coord isect, new;
-
-       new.x = ball->pos.x + move->x;
-       new.y = ball->pos.y + move->y;
-
-       /* How far were we supposed to move ball? */
-       len = sqrt(move->x * move->x + move->y * move->y);
-
-       /* How far is it to intersection? */
-       if (!intersect(&ball->pos, &new, line, &isect))
-               errx(1, "No intersection any more?\n");;
-       len -= dist(&ball->pos, &isect);
-
-       /* Move ball to intersection. */
-       ball->pos = isect;
-       printf("ball is now at %f,%f\n", ball->pos.x, ball->pos.y);
-
-       /* Outgoing angle = 2 * line angle - incident angle. */
-       lang = atan2(line->end.x - line->start.x, line->end.y - line->start.y);
-       iang = atan2(ball->move.x, ball->move.y);
-       oang = 2 * lang - iang, 2*M_PI;
-       printf("lang = %u, iang = %u, oang=%u\n", 
-              rad_to_deg(lang),
-              rad_to_deg(iang),
-              rad_to_deg(oang));
-
-       /* Set new direction for ball, at slightly increased speed */
-       speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y);
-       speed += increase_speed;
-       ball->move.x = sin(oang) * speed;
-       ball->move.y = cos(oang) * speed;
-
-       /* 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[] = {
-       { .start = { 0, 0, }, .end = { MAX_X-1, 0 } },
-       { .start = { MAX_X-1, 0, }, .end = { MAX_X-1, MAX_Y-1 } },
-       { .start = { MAX_X-1, MAX_Y-1, }, .end = { 0, MAX_Y-1 } },
-       { .start = { 0, MAX_Y-1, }, .end = { 0, 0 } },
-};
-
-static inline float deg_to_rad(float degrees)
-{
-       return degrees * M_PI / 180;
-}
-
-static SDL_Surface *sub_surface(SDL_Surface *screen, int w, int h)
-{
-       return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
-                                   screen->format->BitsPerPixel,
-                                   screen->format->Rmask,
-                                   screen->format->Gmask,
-                                   screen->format->Bmask,
-                                   screen->format->Amask);
-}
-
-static SDL_Surface *ball_surface(SDL_Surface *screen)
-{
-       SDL_Surface *ball;
-
-       /* Just like the screen surface. */
-       ball = sub_surface(screen, 5, 5);
-
-       /* Lock the surface */
-       SDL_LockSurface(ball);
-
-       /* Black, white corners. */
-       memset(ball->pixels, 0x00, ball->pitch * 5);
-       line(ball, 0, 0, 0, 0, 0xFFFFFFFF);
-       line(ball, 4, 0, 4, 0, 0xFFFFFFFF);
-       line(ball, 0, 4, 0, 4, 0xFFFFFFFF);
-       line(ball, 4, 4, 4, 4, 0xFFFFFFFF);
-       SDL_UnlockSurface(ball);
-
-       return ball;
-}
-
-static void clear_ignore(struct list_head *lines)
-{
-       struct line_segment *i;
-       printf("Unignoring...\n");
-       list_for_each(lines, i, list)
-               i->ignore = false;
-}
-
-static uint16_t *find_valid_point(struct cwiid_state *state)
-{
-       unsigned int i;
-
-       for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
-               if (state->ir_src[i].valid)
-                       return state->ir_src[i].pos;
-       }
-       return NULL;
-}
-
-static void calibrate(SDL_Surface *screen,
-                     const char *filename,
-                     cwiid_wiimote_t *wiimote,
-                     struct coord *calib, unsigned x, unsigned y)
-{
-       SDL_Surface *img = IMG_Load(filename);
-       uint16_t *pos;
-       struct cwiid_state state;
-       int last_x = MAX_X, last_y = MAX_Y, count = 0;
-       SDL_Rect rect = { .x = screen->w/2 - img->w/2,
-                         .y = screen->h/2 - img->h/2 };
-
-       SDL_BlitSurface(img, NULL, screen, &rect);
-       SDL_UpdateRect(screen, 0, 0, 0, 0);
-       SDL_FreeSurface(img);
-
-       SDL_Delay(500);
-
-       /* Must see it for a full half second. */
-       while (count < 20) {
-               SDL_Event event;
-
-               if (cwiid_get_state(wiimote, &state))
-                       errx(1, "No wii state");
-
-               pos = find_valid_point(&state);
-               if (!pos) {
-                       if (count)
-                               count--;
-               } else {
-                       /* Allow some jitter */
-                       if (abs(pos[0]-last_x) < 3 && abs(pos[1]-last_y) < 3)
-                               count++;
-                       last_x = pos[0];
-                       last_y = pos[1];
-               }
-
-               SDL_Delay(25);
-               if (SDL_PollEvent(&event)
-                   && (event.type == SDL_QUIT
-                       || (event.type == SDL_KEYDOWN
-                           && event.key.keysym.sym == SDLK_ESCAPE))) {
-                       SDL_Quit();
-                       exit(0);
-               }
-       }
-
-       calib->x = last_x;
-       calib->y = last_y;
-       SDL_Delay(500);
-       printf("Calibration point: %u,%u\n", last_x, last_y);
-}
-
-static bool map_coord(unsigned int x, unsigned int y,
-                     const struct coord calib[],
-                     struct coord *res)
-{
-       struct coord line_start, line_end;
-       struct coord pos = { x, y }, intersect;
-       double d1, d2;
-
-       /* Calibration layout:
-        *
-        *   0    1
-        *
-        *   3    2
-        *
-        * We figure out the distance to each side, and then map using:
-        *
-        * x = d1 / (d1 + d2) * (rawend - rawstart) + rawstart
-        */
-       line_start.x = 0;
-       line_end.x = MAX_X-1;
-       line_start.y = line_end.y = y;
-
-       if (!lines_intersect(&calib[0], &calib[3], &line_start, &line_end,
-                            &intersect))
-               return false;
-       d1 = dist(&pos, &intersect);
-       if (!lines_intersect(&calib[1], &calib[2], &line_start, &line_end,
-                            &intersect))
-               return false;
-       d2 = dist(&pos, &intersect);
-       res->x = d1 / (d1 + d2) * MAX_X;
-
-       line_start.y = 0;
-       line_end.y = MAX_Y-1;
-       line_start.x = line_end.x = x;
-
-       if (!lines_intersect(&calib[0], &calib[1], &line_start, &line_end,
-                            &intersect))
-               return false;
-       d1 = dist(&pos, &intersect);
-       if (!lines_intersect(&calib[3], &calib[2], &line_start, &line_end,
-                            &intersect))
-               return false;
-       d2 = dist(&pos, &intersect);
-       res->y = d1 / (d1 + d2) * MAX_Y;
-
-       return true;
-}
-
-static void add_update(const struct object *obj)
-{
-       if (!needs_update) {
-               start_update = obj->start;
-               end_update = obj->end;
-               needs_update = true;
-               return;
-       }
-       if (obj->start.x < start_update.x)
-               start_update.x = obj->start.x;
-       if (obj->start.y < start_update.y)
-               start_update.y = obj->start.y;
-       if (obj->end.x > end_update.x)
-               end_update.x = obj->end.x;
-       if (obj->end.y > end_update.y)
-               end_update.y = obj->end.y;
-}
-
-static void destroy_object(struct object *object)
-{
-       list_del(&object->list);
-       add_update(object);
-}
-
-static void add_object(struct list_head *list,
-                      struct object *obj,
-                      unsigned int startx, unsigned int starty,
-                      unsigned int width, unsigned int height,
-                      void (*redraw)(SDL_Surface *s, struct object *me))
-{
-       list_add_tail(list, &obj->list);
-       obj->start.x = startx;
-       obj->start.y = starty;
-       obj->end.x = startx + width;
-       obj->end.y = starty + height;
-       obj->redraw = redraw;
-       add_update(obj);
-}
-
-static void redraw_line(SDL_Surface *s, struct object *me)
-{
-       struct line_segment *l = container_of(me, struct line_segment, object);
-
-       thick_line(s, l, 0);
-}
-
-static int destroy_line(struct line_segment *l)
-{
-       list_del(&l->list);
-       destroy_object(&l->object);
-       return 0;
-}
-
-static void line_object_setup(struct list_head *lines,
-                             struct list_head *objects,
-                             struct line_segment *l)
-{
-       unsigned int tmp, startx, endx, starty, endy;
-
-       list_add_tail(lines, &l->list);
-
-       startx = l->start.x;
-       starty = l->start.y;
-       endx = l->end.x;
-       endy = l->end.y;
-
-       /* Find bounding box */
-       if (startx > endx) {
-               tmp = endx;
-               endx = startx;
-               startx = tmp;
-       }
-       if (starty > endy) {
-               tmp = endy;
-               endy = starty;
-               starty = tmp;
-       }
-       /* Padding for thick lines (beware underflow) */
-       if (startx > 0)
-               startx--;
-       if (starty > 0)
-               starty--;
-       endx++;
-       endy++;
-
-       add_object(objects, &l->object, startx, starty,
-                  endx - startx, endy - starty, redraw_line);
-}
-
-static void add_line(struct list_head *lines,
-                    unsigned int startx, unsigned int starty,
-                    unsigned int endx, unsigned int endy,
-                    const struct coord calib[])
-{
-       struct line_segment *l = talloc(NULL, struct line_segment);
-       struct timeval now;
-
-       if (!map_coord(startx, starty, calib, &l->start)
-           || !map_coord(endx, endy, calib, &l->end)) {
-               talloc_free(l);
-               return;
-       }
-
-       l->ignore = false;
-       l->score = NULL;
-       gettimeofday(&now, NULL);
-       l->expires = now;
-       l->expires.tv_sec += EXPIRY_SECS;
-
-       line_object_setup(lines, &objects, l);
-       talloc_set_destructor(l, destroy_line);
-}
-
-static void redraw_ball(SDL_Surface *s, struct object *me)
-{
-       struct ball *b = container_of(me, struct ball, object);
-       SDL_Rect rect = { .x = b->pos.x - b->image->w/2,
-                         .y = b->pos.y - b->image->h/2 };
-
-       SDL_BlitSurface(b->image, NULL, s, &rect);
-}
-
-static void redraw_score(SDL_Surface *s, struct object *me)
-{
-       struct score *score = container_of(me, struct score, object);
-       SDL_Rect rect = { .x = score->object.start.x,
-                         .y = score->object.start.y };
-
-       SDL_BlitSurface(score->image, NULL, s, &rect);
-}
-
-static SDL_Surface *score(struct score *s)
-{
-       char filename[40];
-
-       s->value++;
-       SDL_FreeSurface(s->image);
-       sprintf(filename, "images/%u.png", s->value);
-       s->image = IMG_Load(filename);
-       /* No more images?  You won! */
-       if (!s->image)
-               return s->won;
-
-       add_update(&s->object);
-       return NULL;
-}
-
-/* Due to rounding, we exaggerate bounding box by 1 here. */
-static void do_updates(struct list_head *objects, SDL_Surface *screen)
-{
-       struct object *i;
-       unsigned int y, startx, starty, endx, endy;
-
-       /* Clip */
-       if (start_update.x <= 0)
-               startx = 0;
-       else
-               startx = start_update.x - 1;
-       if (start_update.y <= 0)
-               starty = 0;
-       else
-               starty = start_update.y - 1;
-
-       endx = end_update.x+1;
-       endy = end_update.y+1;
-
-       if (endx > screen->w)
-               endx = screen->w;
-       if (endy > screen->h)
-               endy = screen->h;
-
-       SDL_LockSurface(screen);
-       /* First we clear the area to white. */
-       for (y = starty; y < endy; y++) {
-               memset(screen->pixels + y * screen->pitch
-                      + screen->format->BytesPerPixel * startx,
-                      0xFF,
-                      (endx - startx) * screen->format->BytesPerPixel);
-       }
-       SDL_UnlockSurface(screen);
-
-       /* Now redraw everything which overlaps it */
-       list_for_each(objects, i, list) {
-               if (i->end.x < startx)
-                       continue;
-               if (i->end.y < starty)
-                       continue;
-               if (i->start.x > endx)
-                       continue;
-               if (i->start.y > endy)
-                       continue;
-               i->redraw(screen, i);
-       }
-
-       SDL_UpdateRect(screen, startx, starty, endx - startx, endy - starty);
-
-       /* Reset bounding box */
-       needs_update = false;
-}
-
-static bool same_side(const struct ball *ball, unsigned int x)
-{
-       return (ball->pos.x >= MAX_X/2) == (x >= MAX_X/2);
-}
-
-int main(int argc, char *argv[])
-{
-       struct ball ball;
-       SDL_Surface *screen;
-       Uint8  video_bpp;
-       Uint32 videoflags;
-       unsigned int i, time_since_last_ir = INT_MAX;
-       cwiid_wiimote_t *wiimote;
-       struct cwiid_state state;
-       struct coord calib[4];
-       bdaddr_t addr = *BDADDR_ANY;
-       bool mouse = false, needs_calibration = true, drawing = false;
-       LIST_HEAD(lines);
-       struct cwiid_ir_src *ir, last_ir = { .valid = 0 };
-       struct score left, right;
-
-       videoflags = SDL_SWSURFACE;
-
-       if (argv[1] && streq(argv[1], "--fullscreen")) {
-               videoflags |= SDL_FULLSCREEN;
-               argc--;
-               argv++;
-       }
-
-       if (argv[1] && strstarts(argv[1], "--calib=")) {
-               needs_calibration = false;
-               if (sscanf(argv[1], "--calib=%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
-                          &calib[0].x, &calib[0].y,
-                          &calib[1].x, &calib[1].y,
-                          &calib[2].x, &calib[2].y,
-                          &calib[3].x, &calib[3].y) != 8)
-                       errx(1, "Not enough calibration points");
-               argc--;
-               argv++;
-       }
-
-       if (argv[1] && streq(argv[1], "--mouse")) {
-               mouse = true;
-               needs_calibration = false;
-               calib[0].x = calib[0].y = 0;
-               calib[1].x = MAX_X - 1;
-               calib[1].y = 0;
-               calib[2].x = MAX_X - 1;
-               calib[2].y = MAX_Y - 1;
-               calib[3].x = 0;
-               calib[3].y = MAX_Y - 1;
-               argc--;
-               argv++;
-       }
-
-       if (argc != 2)
-               errx(1, "Usage: %s [--fullscreen] [--calib=x,y,x,y,x,y,x,y] [--mouse] speed\n",
-                       argv[0]);
-
-       /* Initialize SDL */
-       if (SDL_Init(SDL_INIT_VIDEO) < 0) {
-               fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
-               return(1);
-       }
-
-       video_bpp = 0;
-
-       if (!mouse) {
-               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());
-       }
-
-       /* Set the surface pixels and refresh! */
-       if (SDL_LockSurface(screen) < 0) {
-               errx(1, "Couldn't lock the display surface: %s",
-                    SDL_GetError());
-       }
-       /* White. */
-       memset(screen->pixels, 0xFF, screen->pitch * screen->h);
-
-       SDL_UnlockSurface(screen);
-       SDL_UpdateRect(screen, 0, 0, 0, 0);
-
-       if (needs_calibration) {
-               /* Calibration */
-               calibrate(screen, "images/top-left.png",
-                         wiimote, &calib[0], 0, 0);
-               calibrate(screen, "images/top-right.png",
-                         wiimote, &calib[1], MAX_X - 1, 0);
-               calibrate(screen, "images/bottom-right.png",
-                         wiimote, &calib[2], MAX_X - 1, MAX_Y - 1);
-               calibrate(screen, "images/bottom-left.png",
-                         wiimote, &calib[3], 0, MAX_Y - 1);
-       }
-
-       /* Create borders, put them in list. */
-       for (i = 0; i < ARRAY_SIZE(border); i++) {
-               border[i].ignore = false;
-               border[i].expires.tv_sec = LONG_MAX;
-               border[i].expires.tv_usec = 0;
-               line_object_setup(&lines, &objects, &border[i]);
-       }
-
-       /* Set up scores. */
-       left.value = right.value = 0;
-       left.image = IMG_Load("images/0.png");
-       left.won = IMG_Load("images/left-won.png");
-       right.image = IMG_Load("images/0.png");
-       right.won = IMG_Load("images/right-won.png");
-       if (!left.image || !right.image || !left.won || !right.won)
-               err(1, "Opening score images");
-
-       add_object(&objects, &left.object,
-                  MAX_X/6 - left.image->w/2, 10,
-                  left.image->w, left.image->h, redraw_score);
-       add_object(&objects, &right.object,
-                  MAX_X - MAX_X/6 - left.image->w/2, 10,
-                  left.image->w, left.image->h, redraw_score);
-
-       /* Hit right border = score to left, and vice versa. */
-       border[1].score = &left;
-       border[3].score = &right;
-
-       srandom(time(NULL));
-       ball.pos.x = MAX_X/2;
-       ball.pos.y = MAX_Y/2;
-       ball.move.x = (random() % 2 ? -1 : 1) * atoi(argv[1]);
-       ball.move.y = 0;
-       ball.image = ball_surface(screen);
-       add_object(&objects, &ball.object,
-                  ball.pos.x - ball.image->w/2,
-                  ball.pos.y - ball.image->h/2,
-                  ball.image->w, ball.image->h, redraw_ball);
-
-       for (;;) {
-               struct coord new, isect, move = ball.move;
-               struct line_segment *best_l, *l, *next;
-               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, <))
-                               talloc_free(l);
-               }
-
-       again:
-               best_d = MAX_X + MAX_Y;
-               best_l = NULL;
-               new.x = ball.pos.x + move.x;
-               new.y = ball.pos.y + move.y;
-
-               list_for_each(&lines, l, list) {
-                       if (!l->ignore && intersect(&ball.pos, &new, l, &isect)) {
-                               double d;
-                               d = dist(&ball.pos, &isect);
-                               if (d < best_d) {
-                                       best_l = l;
-                                       best_d = d;
-                               }
-                       }
-               }
-
-               if (best_l) {
-                       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);
-                       /* 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 (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 = ignored = true;
-                       if (best_l->score) {
-                               SDL_Surface *won = score(best_l->score);
-                               if (won) {
-                                       SDL_Rect rect;
-
-                                       rect.x = MAX_X/2 - won->w/2;
-                                       rect.y = MAX_Y/2 - won->h/2;
-                                       rect.w = won->w;
-                                       rect.h = won->h;
-                                       SDL_BlitSurface(won, NULL, screen,
-                                                       &rect);
-                                       SDL_UpdateRect(screen,
-                                                      rect.x, rect.y,
-                                                      rect.w, rect.h);
-                                       SDL_Delay(5000);
-                                       exit(0);
-                               }
-                       }
-                       goto again;
-               }
-
-               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);
-               }
-
-               /* We also need to redraw under old ball. */
-               add_update(&ball.object);
-
-               /* Move ball. */
-               ball.pos = new;
-               ball.object.start.x = ball.pos.x - ball.image->w/2;
-               ball.object.start.y = ball.pos.y - ball.image->h/2;
-               ball.object.end.x = ball.pos.x + ball.image->w/2;
-               ball.object.end.y = ball.pos.y + ball.image->h/2;
-
-               /* Need to draw under new ball. */
-               add_update(&ball.object);
-
-               /* Clears, redraws and resets the updates */
-               do_updates(&objects, screen);
-
-               SDL_Delay(25);
-
-               while (SDL_PollEvent(&event)) {
-                       if (event.type == SDL_QUIT
-                           || (event.type == SDL_KEYDOWN
-                               && event.key.keysym.sym == SDLK_ESCAPE)) {
-                               SDL_Quit();
-                               return 0;
-                       }
-                       if (mouse) {
-                               switch (event.type) {
-                               case SDL_MOUSEBUTTONDOWN:
-                                       drawing = true;
-                                       break;
-                               case SDL_MOUSEBUTTONUP:
-                                       drawing = false;
-                                       break;
-                               case SDL_MOUSEMOTION:
-                                       if (!drawing ||
-                                           !same_side(&ball, event.motion.x))
-                                               break;
-
-                                       add_line(&lines, event.motion.x,
-                                                event.motion.y,
-                                                event.motion.x
-                                                + event.motion.xrel,
-                                                event.motion.y
-                                                + event.motion.yrel,
-                                                calib);
-                               }
-                       }
-               }
-
-               if (mouse)
-                       continue;
-
-               if (cwiid_get_state(wiimote, &state))
-                       errx(1, "No wii state");
-
-               /* Find biggest state. */
-               ir = &state.ir_src[0];
-               for (i = 0; i < CWIID_IR_SRC_COUNT; i++) {
-                       if (!state.ir_src[i].valid)
-                               continue;
-                       /* Only look at dots on same side as ball */
-                       if (!same_side(&ball, state.ir_src[i].pos[0]))
-                               continue;
-                       if (!ir->valid || state.ir_src[i].size > ir->size)
-                               ir = &state.ir_src[i];
-               }
-
-               if (ir->valid) {
-                       /* Give it some slack for missing one or two... */
-                       if (time_since_last_ir <= 5
-                           && same_side(&ball, last_ir.pos[0])) {
-                               add_line(&lines, last_ir.pos[0],
-                                        last_ir.pos[1],
-                                        ir->pos[0],
-                                        ir->pos[1],
-                                        calib);
-                       }
-                       time_since_last_ir = 0;
-                       last_ir = *ir;
-               }
-               time_since_last_ir++;
-       }
-}