X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=prpong.c;fp=prpong.c;h=0000000000000000000000000000000000000000;hb=3b07a088e47dffe99415cb01f42ea89c9185bdc5;hp=660fc8ae8a60402800f2664301aedb9a2df23cca;hpb=4b884e9e3bff9f777f705d364627ce49ff4cedd6;p=ponghero.git diff --git a/prpong.c b/prpong.c deleted file mode 100644 index 660fc8a..0000000 --- a/prpong.c +++ /dev/null @@ -1,1306 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include "stdrusty.h" -#include "list/list.h" -#include "talloc/talloc.h" -#include "container_of/container_of.h" -#include -#include -#include -#include -#include - -#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++; - } -}