From 799de455ce16b8b7368a67de4ce1c9213347e866 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 17 Jan 2008 21:46:29 +1100 Subject: [PATCH] Mostly works now. --- prpong.c | 258 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 95 deletions(-) diff --git a/prpong.c b/prpong.c index c62d0fc..09d5113 100644 --- a/prpong.c +++ b/prpong.c @@ -4,66 +4,62 @@ #include #include #include +#include +#include +#include #include "stdrusty.h" +#include "list/list.h" #include +#include -#define MAX_X 512 -#define MAX_Y 512 +#define MAX_X CWIID_IR_X_MAX +#define MAX_Y CWIID_IR_Y_MAX /* Obtained from http://tog.acm.org/GraphicsGems/gemsiii/insectc.c */ /* Faster Line Segment Intersection */ /* Franklin Antonio */ -/* return values */ -#define DONT_INTERSECT 0 -#define DO_INTERSECT 1 -#define PARALLEL 2 - -/* The SAME_SIGNS macro assumes arithmetic where the exclusive-or */ -/* operation will work on sign bits. This works for twos-complement,*/ -/* and most other machine arithmetic. */ -#define SAME_SIGNS( a, b ) \ - (((long) ((unsigned long) a ^ (unsigned long) b)) >= 0 ) - - /* The use of some short working variables allows this code to run */ /* faster on 16-bit computers, but is not essential. It should not */ /* affect operation on 32-bit computers. The short working variables*/ /* to not restrict the range of valid input values, as these were */ /* constrained in any case, due to algorithm restrictions. */ -static int lines_intersect(long x1, long y1, long x2, long y2, long x3, long y3, - long x4,long y4, long *x, long *y) +static bool lines_intersect(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4, + double *x, double *y) { - long Ax,Bx,Cx,Ay,By,Cy,d,e,f,num,offset; - short x1lo,x1hi,y1lo,y1hi; + double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num; + double x1lo,x1hi,y1lo,y1hi; Ax = x2-x1; Bx = x3-x4; if(Ax<0) { /* X bound box test*/ - x1lo=(short)x2; x1hi=(short)x1; + x1lo=x2; x1hi=x1; } else { - x1hi=(short)x2; x1lo=(short)x1; + x1hi=x2; x1lo=x1; } if(Bx>0) { - if(x1hi < (short)x4 || (short)x3 < x1lo) return DONT_INTERSECT; + if(x1hi < x4 || x3 < x1lo) return false; } else { - if(x1hi < (short)x3 || (short)x4 < x1lo) return DONT_INTERSECT; + if(x1hi < x3 || x4 < x1lo) return false; } Ay = y2-y1; By = y3-y4; if(Ay<0) { /* Y bound box test*/ - y1lo=(short)y2; y1hi=(short)y1; + y1lo=y2; y1hi=y1; } else { - y1hi=(short)y2; y1lo=(short)y1; + y1hi=y2; y1lo=y1; } if(By>0) { - if(y1hi < (short)y4 || (short)y3 < y1lo) return DONT_INTERSECT; + if(y1hi < y4 || y3 < y1lo) return false; } else { - if(y1hi < (short)y3 || (short)y4 < y1lo) return DONT_INTERSECT; + if(y1hi < y3 || y4 < y1lo) return false; } @@ -72,32 +68,30 @@ static int lines_intersect(long x1, long y1, long x2, long y2, long x3, long y3, 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 DONT_INTERSECT; + if(d<0 || d>f) return false; } else { - if(d>0 || d0 || d0) { /* beta tests*/ - if(e<0 || e>f) return DONT_INTERSECT; + if(e<0 || e>f) return false; } else { - if(e>0 || e0 || estart.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, - 0); + 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, @@ -521,12 +549,12 @@ static bool intersect(const struct coord *c1, const struct coord *c2, return lines_intersect(c1->x, c1->y, c2->x, c2->y, seg->start.x, seg->start.y, seg->end.x, seg->end.y, - &intersect->x, &intersect->y) == DO_INTERSECT; + &intersect->x, &intersect->y); } static double dist(const struct coord *c1, const struct coord *c2) { - long x = (c1->x - c2->x), y = (c1->y - c2->y); + float x = (c1->x - c2->x), y = (c1->y - c2->y); return sqrt(x * x + y * y); } @@ -553,6 +581,7 @@ static void bounce(struct ball *ball, const struct line_segment *line, /* 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); @@ -565,13 +594,14 @@ static void bounce(struct ball *ball, const struct line_segment *line, /* Set new direction for ball, at same speed */ speed = sqrt(ball->move.x * ball->move.x + ball->move.y * ball->move.y); - ball->move.x = round(sin(oang) * speed); - ball->move.y = round(cos(oang) * speed); + speed *= 1.01; + ball->move.x = sin(oang) * speed; + ball->move.y = cos(oang) * speed; /* Set remainder. */ - remainder->x = round(sin(oang) * len); - remainder->y = round(cos(oang) * len); - printf("len = %f, remainder = %li,%li\n", len, remainder->x, remainder->y); + remainder->x = sin(oang) * len; + remainder->y = cos(oang) * len; + printf("len = %f, remainder = %f,%f\n", len, remainder->x, remainder->y); } static struct line_segment border[] = { @@ -617,35 +647,36 @@ static SDL_Surface *ball_surface(SDL_Surface *screen) 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; +} + int main(int argc, char *argv[]) { struct ball ball; - struct line_segment lines[ARRAY_SIZE(border) + 1]; - static int isect_count = 0; SDL_Surface *screen, *ballsur, *savesur = NULL; Uint8 video_bpp; Uint32 videoflags; - int i; - SDL_Event event; - struct line_segment *last_l = NULL; + unsigned int i; SDL_Rect rect; + bool creating_lines = false; + struct timeval line_life = { 5, 0 }; + LIST_HEAD(lines); - if (argc != 9) - errx(1, "Usage: %s ballx bally ballangle ballspeed linestartx linestarty lineendx linendy\n" + if (argc != 5) + errx(1, "Usage: %s ballx bally ballangle ballspeed\n" " Where ballangle is 0 for north, 90 for east, etc\n", argv[0]); ball.pos.x = atol(argv[1]); ball.pos.y = atol(argv[2]); - ball.move.x = roundf(sin(deg_to_rad(atof(argv[3]))) * atol(argv[4])); - ball.move.y = roundf(cos(deg_to_rad(atof(argv[3]))) * atol(argv[4])); - printf("ball move = %li,%li\n", ball.move.x, ball.move.y); - - memcpy(lines, border, sizeof(border)); - lines[ARRAY_SIZE(border)].start.x = atof(argv[5]); - lines[ARRAY_SIZE(border)].start.y = atof(argv[6]); - lines[ARRAY_SIZE(border)].end.x = atof(argv[7]); - lines[ARRAY_SIZE(border)].end.y = atof(argv[8]); + ball.move.x = sin(deg_to_rad(atof(argv[3]))) * atol(argv[4]); + ball.move.y = cos(deg_to_rad(atof(argv[3]))) * atol(argv[4]); + printf("ball move = %f,%f\n", ball.move.x, ball.move.y); /* Initialize SDL */ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { @@ -670,28 +701,38 @@ int main(int argc, char *argv[]) /* White. */ memset(screen->pixels, 0xFF, screen->pitch * screen->h); - /* Draw lines. */ - for (i = 0; i < ARRAY_SIZE(lines); i++) - thick_line(screen, &lines[i]); - SDL_UnlockSurface(screen); SDL_UpdateRect(screen, 0, 0, 0, 0); + /* Draw 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; + list_add(&lines, &border[i].list); + thick_line(screen, &border[i], 0); + } + ballsur = ball_surface(screen); - do { + for (;;) { struct coord new, isect, move = ball.move; - struct line_segment *best_l; - unsigned i; + struct line_segment *best_l, *l, *next; double best_d; -#if 0 - SDL_Rect rect; - - rect.x = ball.pos.x - ballsur->w/2; - rect.y = ball.pos.y - ballsur->h/2; - rect.w = ballsur->w; - rect.h = ballsur->h; -#endif + SDL_Event event; + struct timeval now; + + gettimeofday(&now, NULL); + + /* Expire lines */ + list_for_each_safe(&lines, l, next, list) { + if (timercmp(&l->expires, &now, <)) { + list_del(&l->list); + /* FIXME: Undraw properly. */ + thick_line(screen, l, 0xFFFFFFFF); + free(l); + } + } again: best_d = MAX_X + MAX_Y; @@ -699,32 +740,38 @@ int main(int argc, char *argv[]) new.x = ball.pos.x + move.x; new.y = ball.pos.y + move.y; - printf("Ball at %li,%li (%li,%li)\n", ball.pos.x, ball.pos.y, - move.x, move.y); - - for (i = 0; i < ARRAY_SIZE(lines); i++) { - if (last_l == &lines[i]) - continue; - if (intersect(&ball.pos, &new, &lines[i], &isect)) { + 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 = &lines[i]; + best_l = l; best_d = d; } } } + if (best_l) { - printf("Ball bouncing off (%lu,%lu %lu,%lu)!\n", + 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); bounce(&ball, best_l, &move); + + /* If we moved, stop ignoring lines. */ + if (move.x > 0.001 || move.y > 0.001) + clear_ignore(&lines); + /* Don't hit the same line twice. */ - last_l = best_l; - isect_count++; + printf("Ignoring that line\n"); + best_l->ignore = true; goto again; } + if (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); + } + /* Restore what was there before ball. */ if (savesur) { SDL_BlitSurface(savesur, NULL, screen, &rect); @@ -747,9 +794,30 @@ int main(int argc, char *argv[]) rect.x = new.x - ballsur->w/2; rect.y = new.y - ballsur->h/2; ball.pos = new; - SDL_Delay(5); - } while (!SDL_PollEvent(&event) || event.type != SDL_QUIT); - SDL_Quit(); - return 0; + SDL_Delay(25); + + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + SDL_Quit(); + return 0; + } + if (event.type == SDL_MOUSEBUTTONDOWN) + creating_lines = true; + else if (event.type == SDL_MOUSEBUTTONUP) + creating_lines = false; + + if (creating_lines && event.type == SDL_MOUSEMOTION) { + struct line_segment *n = malloc(sizeof(*n)); + n->start.x = event.motion.x - event.motion.xrel; + n->start.y = event.motion.y - event.motion.yrel; + n->end.x = event.motion.x; + n->end.y = event.motion.y; + n->ignore = false; + timeradd(&now, &line_life, &n->expires); + list_add_tail(&lines, &n->list); + thick_line(screen, n, 0); + } + } + } } #endif -- 2.39.2