xlib_playground

Xlib playground for experiments.
Log | Files | Refs

ex6.c (20506B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <time.h>
      4 #include <unistd.h>
      5 #include <string.h>
      6 #include <math.h>
      7 
      8 #include <X11/Xlib.h>
      9 
     10 /* macros */
     11 #define INIT_WIDTH (800)
     12 #define INIT_HEIGHT (600)
     13 #define FPS (60)
     14 #define SUB_TICK (4)
     15 #define NUM_RECT (200)
     16 #define GRAVITY (1000)
     17 #define max(a, b) ((a) > (b) ? (a) : (b))
     18 #define min(a, b) ((a) < (b) ? (a) : (b))
     19 #define WORLD_WIDTH (80)
     20 #define WORLD_HEIGHT (60)
     21 #define BLOCK_SIZE (10)
     22 
     23 // #define COUNT_FPS
     24 
     25 enum keys {
     26 	KEY_D,
     27 	KEY_S,
     28 	KEY_A,
     29 	KEY_W,
     30 	KEY_Q,
     31 	KEY_SPACE,
     32 	NUM_KEY, //number of keys in this enum
     33 };
     34 enum key_state {
     35 	KEY_UP,
     36 	KEY_DOWN,
     37 };
     38 enum next_menu {
     39 	START_MENU,
     40 	GAME_PLAY,
     41 	GAME_OVER,
     42 	QUIT,
     43 };
     44 
     45 struct rect {
     46 	float ppx, ppy; // previous position
     47 	float px, py;   // top left corner
     48 	float vx, vy;
     49 	float ax, ay;
     50 	int w, h;
     51 	int m;
     52 };
     53 
     54 struct circle {
     55 	float ppx, ppy;
     56 	float px, py;
     57 	float vx, vy;
     58 	float ax, ay;
     59 	int r;
     60 	int m;
     61 };
     62 
     63 char world_map[WORLD_WIDTH * WORLD_HEIGHT + 1] =
     64 "................................................................................"
     65 "................................................................................"
     66 "................................................................................"
     67 "................................................................................"
     68 "................................................................................"
     69 "........b......................................................................."
     70 "................................................................................"
     71 "................................................................................"
     72 "....b..........................................................................."
     73 "................................................................................"
     74 "................b..............................................................."
     75 "..........................................................b..........b.........."
     76 "................................................................................"
     77 ".......................b........................................................"
     78 "...........................................b...................................."
     79 "...........................................b...................................."
     80 "................................................................................"
     81 "..................b............................................................."
     82 "................................................................................"
     83 "...........................................b...................................."
     84 "................................................................................"
     85 "................................................................................"
     86 "...........................b...................................................."
     87 "................................................................................"
     88 "................................................................................"
     89 "................................................................................"
     90 "................................................................................"
     91 "................................................................................"
     92 "................................................................................"
     93 "....................................bbbbbbbbbb.................................."
     94 "................................................................................"
     95 "................................................................................"
     96 "................................................................................"
     97 "................................................................................"
     98 "................................................................................"
     99 "................................................................................"
    100 "..............................................bbbbbbbbbb........................"
    101 "................................................................................"
    102 "................................................................................"
    103 "................................................................................"
    104 "................................................................................"
    105 "....................................bbbbbbbbbb.................................."
    106 "................................................................................"
    107 "................................................................................"
    108 "................................................................................"
    109 "................................................................................"
    110 "..........................bbbbbbbbbb............................................"
    111 "................................................................................"
    112 "................................................................................"
    113 "................................................................................"
    114 "................................................................................"
    115 "................bbbbbbbbbb......................................................"
    116 "................................................................................"
    117 "................................................................................"
    118 "...p............................................................................"
    119 "bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb"
    120 "........................b.......b......................b...b...................."
    121 "........................b.......b......................b...b...................."
    122 "........................b.......b......................b...b...................."
    123 "........................b.......b......................b...b....................";
    124 
    125 /* variables */
    126 Display      *display;
    127 Window        window;
    128 unsigned int  win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
    129 GC            gc, sgc[NUM_RECT];
    130 Atom          wm_delete_window;
    131 struct rect   block[NUM_RECT];
    132 struct rect   player;
    133 int           player_is_falling;
    134 int           next_menu = START_MENU;
    135 
    136 
    137 /* function prototypes */
    138 void setup(void);
    139 void cleanup(void);
    140 void start_menu(void);
    141 void game_play(void);
    142 void receive_events(int[]);
    143 void handle_inputs(int[]);
    144 void rect_next_tick(struct rect *, long);
    145 int  rect_test_collision(struct rect *, struct rect *);
    146 void rect_handle_collision_mf(struct rect *, struct rect *);
    147 void rect_handle_collision(struct rect *, struct rect *);
    148 void rect_handle_collision_elastic(struct rect *, struct rect *);
    149 void circle_next_tick(struct circle *, long);
    150 int  circle_test_collision(struct circle *, struct circle *);
    151 void update_falling_status(struct rect *, long);
    152 void game_over(void);
    153 
    154 
    155 void
    156 setup(void)
    157 {
    158 	if ((display = XOpenDisplay(NULL)) == NULL){
    159 	    fprintf(stderr, "ERROR: could not open display\n");
    160 	    exit(1);
    161 	}
    162 	window = XCreateSimpleWindow(
    163 	                    display,
    164 	                    XDefaultRootWindow(display),
    165 	                    0, 0,
    166 	                    win_width, win_height,
    167 	                    0, 0,
    168 						0);
    169 	XStoreName(display, window, "UNKO");
    170 	gc = XCreateGC(display, window, 0, NULL);
    171 	XSetForeground(display, gc, 0x00FFFF);
    172 	for (int i = 0; i < NUM_RECT; i++){
    173 		sgc[i] = XCreateGC(display, window, 0, NULL);
    174 		XSetForeground(display, sgc[i], 0x00FF00);
    175 	}
    176 
    177 	wm_delete_window = XInternAtom(display,
    178 	                               "WM_DELETE_WINDOW", False);
    179 	XSetWMProtocols(display, window, &wm_delete_window, 1);
    180 
    181 	XSelectInput(display, window,
    182 	             ExposureMask | KeyPressMask | KeyReleaseMask);
    183 
    184 	XMapWindow(display, window);
    185 }
    186 
    187 void
    188 start_menu(void)
    189 {
    190 	XEvent event;
    191 	char *menu_char_q = "press q to quit.";
    192 	char *menu_char_s = "press <space> to start.";
    193 
    194 	XClearArea(display, window,
    195 			   0, 0,                  // position
    196 			   win_width, win_height, // width and height
    197 			   False);
    198 	XDrawString(display, window, gc,
    199 				win_width/2 - strlen(menu_char_q)/2, win_height/2,
    200 				menu_char_q, strlen(menu_char_q));
    201 	XDrawString(display, window, gc,
    202 				win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20,
    203 				menu_char_s, strlen(menu_char_s));
    204 
    205 	while (next_menu == START_MENU) {
    206 		XNextEvent(display, &event);
    207 		switch (event.type) {
    208 		case Expose: {
    209 			XDrawString(display, window, gc,
    210 						win_width/2 - strlen(menu_char_q)/2,
    211 						win_height/2,
    212 						menu_char_q, strlen(menu_char_q));
    213 			XDrawString(display, window, gc,
    214 						win_width/2 - strlen(menu_char_s)/2,
    215 						win_height/2 + 20,
    216 						menu_char_s, strlen(menu_char_s));
    217 
    218 		} break;
    219 		case KeyPress: {
    220 			switch (XLookupKeysym(&event.xkey, 0)) {
    221 			case 'q':
    222 				next_menu = QUIT;
    223 				break;
    224 			case ' ':
    225 				next_menu = GAME_PLAY;
    226 				break;
    227 			default:
    228 				break;
    229 			}
    230 		} break;
    231 		case ClientMessage: {
    232 			if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
    233 				next_menu = QUIT;
    234 			}
    235 		} break;
    236 		default:
    237 			break;
    238 		}
    239 	}
    240 }
    241 
    242 void
    243 receive_events(int key_state[])
    244 {
    245 	XEvent event;
    246 	XWindowAttributes wattr;
    247 
    248 	while (XPending(display) > 0) {
    249 		XNextEvent(display, &event);
    250 		switch (event.type) {
    251 		case Expose: {
    252 			XGetWindowAttributes(display, window, &wattr);
    253 			win_width = wattr.width;
    254 			win_height = wattr.height;
    255 		} break;
    256 		case KeyPress: {
    257 			switch (XLookupKeysym(&event.xkey, 0)) {
    258 			case 'q':
    259 				//next_menu = GAME_OVER;
    260 				key_state[KEY_Q] = KEY_DOWN;
    261 				break;
    262 			case 'd':
    263 				key_state[KEY_D] = KEY_DOWN;
    264 				break;
    265 			case 'a':
    266 				key_state[KEY_A] = KEY_DOWN;
    267 				break;
    268 			case 'w':
    269 				key_state[KEY_W] = KEY_DOWN;
    270 				break;
    271 			case 's':
    272 				key_state[KEY_S] = KEY_DOWN;
    273 				break;
    274 			case ' ':
    275 				key_state[KEY_SPACE] = KEY_DOWN;
    276 				break;
    277 			default:
    278 				break;
    279 			}
    280 		} break;
    281 		case KeyRelease: {
    282 			switch (XLookupKeysym(&event.xkey, 0)) {
    283 			case 'q':
    284 				key_state[KEY_Q] = KEY_UP;
    285 				break;
    286 			case 'd':
    287 				key_state[KEY_D] = KEY_UP;
    288 				break;
    289 			case 'a':
    290 				key_state[KEY_A] = KEY_UP;
    291 				break;
    292 			case 'w':
    293 				key_state[KEY_W] = KEY_UP;
    294 				break;
    295 			case 's':
    296 				key_state[KEY_S] = KEY_UP;
    297 				break;
    298 			case ' ':
    299 				key_state[KEY_SPACE] = KEY_UP;
    300 				break;
    301 			default:
    302 				break;
    303 			}
    304 		} break;
    305 		case ClientMessage: {
    306 			if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
    307 				next_menu = QUIT;
    308 			}
    309 		} break;
    310 		default:
    311 			break;
    312 		}
    313 	}
    314 }
    315 
    316 void
    317 handle_inputs(int key_state[])
    318 {
    319 	if (key_state[KEY_Q] == KEY_DOWN){
    320 		next_menu = GAME_OVER;
    321 		return;
    322 	}
    323 	if (key_state[KEY_D] == KEY_DOWN) {
    324 		if (player.vx > 0) {
    325 			player.ax = 500;
    326 		} else {
    327 			player.ax = 1000;
    328 		}
    329 	} else if (key_state[KEY_A] == KEY_DOWN) {
    330 		if (player.vx > 0) {
    331 			player.ax = -1000;
    332 		} else {
    333 			player.ax = -500;
    334 		}
    335 	} else {
    336 		if (player_is_falling)
    337 			player.ax = -player.vx;
    338 		else
    339 			player.ax = -3 * player.vx;
    340 	}
    341 
    342 	if (player.vx < -200) player.vx = -200;
    343 	if (player.vx > 200) player.vx = 200;
    344 	/*
    345 	if (key_state[KEY_S] == KEY_DOWN)
    346 		player.vy += 300;
    347 	if (key_state[KEY_W] == KEY_DOWN)
    348 		player.vy += -300;
    349 	*/
    350 	if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN)
    351 		player.vy = -450;
    352 }
    353 
    354 void
    355 rect_next_tick(struct rect *s, long ndt) // nano second
    356 {
    357 	s->ppx = s->px;
    358 	s->ppy = s->py;
    359 	s->vx += s->ax * ndt / 1000 / 1000 / 1000;
    360 	s->vy += s->ay * ndt / 1000 / 1000 / 1000;
    361 	s->px += s->vx * ndt / 1000 / 1000 / 1000;
    362 	s->py += s->vy * ndt / 1000 / 1000 / 1000;
    363 
    364 	// bind within the window
    365 	if (s->px < 0) {
    366 		s->px = 0;
    367 		//s->vx *= -1;
    368 	}
    369 	if (win_width < s->px + s->w) {
    370 		s->px = win_width - s->w;
    371 		//s->vx *= -1;
    372 	}
    373 	/*
    374 	if (s->py < 0) {
    375 		s->py = 0;
    376 		s->vy *= -1;
    377 	}
    378 	if (win_height < s->py + s->h) {
    379 		s->py = win_height - s->h;
    380 		s->vy *= -1;
    381 	}
    382 	*/
    383 	// game over when fall out of the screen
    384 	if (s->py > win_height)
    385 		next_menu = GAME_OVER;
    386 }
    387 
    388 void
    389 circle_next_tick(struct circle *c, long ndt)
    390 {
    391 	c->ppx = c->px;
    392 	c->ppy = c->py;
    393 	c->vx += c->ax * ndt / 1000 / 1000 / 1000;
    394 	c->vy += c->ay * ndt / 1000 / 1000 / 1000;
    395 	c->px += c->vx * ndt / 1000 / 1000 / 1000;
    396 	c->py += c->vy * ndt / 1000 / 1000 / 1000;
    397 
    398 	// bind within the window
    399 	if (c->px - c->r < 0) {
    400 		c->px = c->r;
    401 		c->vx *= -1;
    402 	}
    403 	if (win_width < c->px + c->r) {
    404 		c->px = win_width - c->r;
    405 		c->vx *= -1;
    406 	}
    407 	if (c->py - c->r < 0) {
    408 		c->py = c->r;
    409 		c->vy *= -1;
    410 	}
    411 	if (win_height < c->py + c->r) {
    412 		c->py = win_height - c->r;
    413 		c->vy *= -1;
    414 	}
    415 }
    416 
    417 int
    418 rect_test_collision(struct rect *s1, struct rect *s2)
    419 {
    420 	return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w &&
    421 	       s2->py < s1->py + s1->h && s1->py < s2->py + s2->h;
    422 }
    423 
    424 int
    425 circle_test_collision(struct circle *c1, struct circle *c2)
    426 {
    427 	return (c1->px - c2->px) * (c1->px - c2->px) +
    428 	       (c1->py - c2->py) * (c1->py - c2->py) <
    429 		   (c1->r + c2->r) * (c1->r + c2->r);
    430 }
    431 
    432 /*
    433  * Handle collision of a moving rect against fixed rect
    434  */
    435 void
    436 rect_handle_collision_mf(struct rect *sm, struct rect *sf)
    437 {
    438 	if (!rect_test_collision(sm, sf))
    439 		return;
    440 	if (sm->ppx + sm->w <= sf->ppx && sf->px < sm->px + sm->w) {
    441 		// collisioin from left to right
    442 		sm->px = sf->px - sm->w;
    443 		sm->vx = 0;
    444 	}
    445 	if (sf->ppx + sf->w <= sm->ppx && sm->px < sf->px + sf->w) {
    446 		// collision from right to left
    447 		sm->px = sf->px + sf->w;
    448 		sm->vx = 0;
    449 	}
    450 
    451 	if (sm->ppy + sm->h <= sf->ppy && sf->py < sm->py + sm->h) {
    452 		// collision from up to down
    453 		sm->py = sf->py - sm->h;
    454 		sm->vy = 0;
    455 	}
    456 	if (sf->ppy + sf->h <= sm->ppy && sm->py < sf->py + sf->h) {
    457 		// collision from dohn to up
    458 		sm->py = sf->py + sf->h;
    459 		sm->vy = 0;
    460 	}
    461 
    462 }
    463 
    464 /*
    465  * Handle collision of a moving rect against another moving rect
    466  */
    467 void
    468 rect_handle_collision_mm(struct rect *s1, struct rect *s2)
    469 {
    470 	if (!rect_test_collision(s1, s2))
    471 		return;
    472 
    473 	float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
    474 	float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py);
    475 
    476 	if (lapx < lapy) {
    477 		if (s1->px + s1->w < s2->px + s2->w / 2) {
    478 			s1->px -= lapx / 2;
    479 			s2->px += lapx / 2;
    480 		} else {
    481 			s1->px += lapx / 2;
    482 			s2->px -= lapx / 2;
    483 		}
    484 	} else {
    485 		if (s1->py + s1->h < s2->py + s2->h / 2) {
    486 			s1->py -= lapy / 2;
    487 			s2->py += lapy / 2;
    488 		} else {
    489 			s1->py += lapy / 2;
    490 			s2->py -= lapy / 2;
    491 		}
    492 	}
    493 }
    494 
    495 void
    496 circle_handle_collision_mm(struct circle *c1, struct circle *c2)
    497 {
    498 	if (!circle_test_collision(c1, c2))
    499 		return;
    500 
    501 	float col_px = c2->px - c1->px;
    502 	float col_py = c2->py - c1->py;
    503 	float col_pr = sqrtf(col_px * col_px + col_py * col_py);
    504 	col_px /= col_pr;
    505 	col_py /= col_pr;
    506 
    507 	c1->px = c1->px - col_px  / 2;
    508 	c1->py = c1->py - col_py  / 2;
    509 	c2->px = c2->px + col_px  / 2;
    510 	c2->py = c2->py + col_py  / 2;
    511 }
    512 
    513 void
    514 rect_handle_collision_elastic(struct rect *s1, struct rect *s2)
    515 {
    516 	if(!rect_test_collision(s1, s2))
    517 		return;
    518 
    519 	rect_handle_collision_mm(s1, s2);
    520 
    521 	float v1, v2;
    522 	float m1 = s1->m;
    523 	float m2 = s2->m;
    524 
    525 	float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
    526 	float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py);
    527 
    528 	if (lapx < lapy) {
    529 		v1 = s1->vx;
    530 		v2 = s2->vx;
    531 		s1->vx = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
    532 		s2->vx = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2;
    533 	} else {
    534 		v1 = s1->vy;
    535 		v2 = s2->vy;
    536 		s1->vy = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1;
    537 		s2->vy = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2;
    538 	}
    539 }
    540 
    541 void
    542 circle_handle_collision_elastic(struct circle *c1, struct circle *c2)
    543 {
    544 	if(!circle_test_collision(c1, c2))
    545 		return;
    546 
    547 	circle_handle_collision_mm(c1, c2);
    548 
    549 	float col_px = c2->px - c1->px;
    550 	float col_py = c2->py - c1->py;
    551 	float col_pr = sqrtf(col_px * col_px + col_py * col_py);
    552 	col_px /= col_pr;
    553 	col_py /= col_pr;
    554 	float nor_px = col_py;
    555 	float nor_py = -col_px;
    556 
    557 	float m1 = c1->m;
    558 	float m2 = c2->m;
    559 
    560 	float col_1v = c1->vx * col_px + c1->vy * col_py;
    561 	float col_2v = c2->vx * col_px + c2->vy * col_py;
    562 
    563 	float col_1vxn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_px;
    564 	float col_1vyn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_py;
    565 	float col_2vxn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_px;
    566 	float col_2vyn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_py;
    567 
    568 	float nor_1vx = nor_px * (c1->vx * nor_px + c1->vy * nor_py);
    569 	float nor_1vy = nor_py * (c1->vx * nor_px + c1->vy * nor_py);
    570 	float nor_2vx = nor_px * (c2->vx * nor_px + c2->vy * nor_py);
    571 	float nor_2vy = nor_py * (c2->vx * nor_px + c2->vy * nor_py);
    572 
    573 	c1->vx = col_1vxn + nor_1vx;
    574 	c1->vy = col_1vyn + nor_1vy;
    575 	c2->vx = col_2vxn + nor_2vx;
    576 	c2->vy = col_2vyn + nor_2vy;
    577 }
    578 
    579 void
    580 update_falling_status(struct rect *player, long ndt)
    581 {
    582 	int collision = 0;
    583 	struct rect r = {0};
    584 	r.ppx = player->ppx;
    585 	r.ppy = player->ppy;
    586 	r.px = player->px;
    587 	r.py = player->py;
    588 	r.vx = 0;
    589 	r.vy = 0;
    590 	r.ax = 0;
    591 	r.ay = GRAVITY;
    592 	r.w = player->w;
    593 	r.h = player->h;
    594 	r.m = player->m;
    595 
    596 	rect_next_tick(&r, ndt);
    597 	for (int i = 0; i < NUM_RECT; i++)
    598 		if (rect_test_collision(&r, &block[i]))
    599 			collision = 1;
    600 
    601 	if (collision == 1)
    602 		player_is_falling = 0;
    603 	else
    604 		player_is_falling = 1;
    605 }
    606 
    607 void
    608 game_play(void)
    609 {
    610 	int  key_state[NUM_KEY];
    611 	long t0, t1, dt;
    612 #ifdef COUNT_FPS
    613 	int fps_count = 0;
    614 #endif
    615 	struct timespec ts;
    616 
    617 	int bi = 0;
    618 	for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) {
    619 		if (world_map[i] == 'b') {
    620 			block[bi].ppx = block[bi].px = i % WORLD_WIDTH * BLOCK_SIZE;
    621 			block[bi].ppy = block[bi].py = i / WORLD_WIDTH * BLOCK_SIZE;
    622 			block[bi].ax = 0;
    623 			block[bi].ay = 0;
    624 			block[bi].vx = 0;
    625 			block[bi].vy = 0;
    626 			block[bi].w = block[bi].h = BLOCK_SIZE;
    627 			block[bi].m = block[bi].w * block[bi].h;
    628 			bi++;
    629 		} else if (world_map[i] == 'p') {
    630 			player.ppx = player.px =  i % WORLD_WIDTH * BLOCK_SIZE;
    631 			player.ppy = player.py = i / WORLD_WIDTH * BLOCK_SIZE;
    632 			player.vx = 0;
    633 			player.vy = 0;
    634 			player.ax = 0;
    635 			player.ay = GRAVITY;
    636 			player.w = player.h = BLOCK_SIZE;
    637 			player.m = player.w * player.h;
    638 		}
    639 	}
    640 
    641 	while (next_menu == GAME_PLAY){
    642 		clock_gettime(CLOCK_MONOTONIC, &ts);
    643 		t0 = ts.tv_nsec;
    644 		receive_events(key_state);
    645 		handle_inputs(key_state);
    646 
    647 
    648 		clock_gettime(CLOCK_MONOTONIC, &ts);
    649 		t0 = ts.tv_nsec;
    650 
    651 		int collision[NUM_RECT] = {0};
    652 		for (int k = 0; k < SUB_TICK; k++) {
    653 			update_falling_status(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK);
    654 			if (player_is_falling)
    655 				player.ay = GRAVITY;
    656 			else
    657 				player.ay = 0;
    658 			rect_next_tick(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK);
    659 			for (int i = 0; i < NUM_RECT; i++)
    660 				rect_next_tick(&block[i], 1000 * 1000 * 1000 / FPS / SUB_TICK);
    661 
    662 			for (int i = 0; i < NUM_RECT; i++){
    663 				rect_handle_collision_mf(&player, &block[i]);
    664 				if (rect_test_collision(&player, &block[i]))
    665 					collision[i] = 1;
    666 			}
    667 		}
    668 		for (int i = 0; i < NUM_RECT; i++)
    669 			if (collision[i] == 1)
    670 				XSetForeground(display, sgc[i], 0xFFFF00);
    671 			else
    672 				XSetForeground(display, sgc[i], 0x90FF90);
    673 
    674 		// fix fps
    675 		// TODO: This method create some strange stripe when
    676 		// rendered in 60fps on a 60fps monitor.
    677 		dt = 0;
    678 		while (dt < 1.0 * 1000 * 1000 * 1000 / FPS){
    679 			clock_gettime(CLOCK_MONOTONIC, &ts);
    680 			t1 = ts.tv_nsec;
    681 			dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
    682 		}
    683 #ifdef COUNT_FPS
    684 		// count fps.
    685 		fps_count++;
    686 		if (t1 < t0){
    687 			printf("fps: %u\n", fps_count);
    688 			fps_count = 0;
    689 		}
    690 #endif
    691 
    692 		XClearArea(display, window,
    693 				   0, 0,                  // position
    694 				   win_width, win_height, // width and height
    695 				   False);
    696 		for (int i = 0; i < NUM_RECT; i++) {
    697 			XDrawRectangle(display, window, sgc[i],
    698 						   block[i].px,
    699 						   block[i].py,    // position
    700 						   block[i].w, block[i].h);
    701 		}
    702 		XDrawRectangle(display, window, gc,
    703 					   player.px,
    704 					   player.py,    // position
    705 					   player.w, player.h);
    706 		char status_string[128];
    707 		snprintf(status_string, 128, "falling: %d", player_is_falling);
    708 		XDrawString(display, window, gc,
    709 		            0, 20,
    710 		            status_string,
    711 					strlen(status_string));
    712 	}
    713 }
    714 
    715 void
    716 game_over(void)
    717 {
    718 	char *menu_char = "GAME OVER";
    719 
    720 	XClearArea(display, window,
    721 			   0, 0,                  // position
    722 			   win_width, win_height, // width and height
    723 			   False);
    724 	XDrawString(display, window, gc,
    725 				win_width/2 - strlen(menu_char)/2, win_height/2,
    726 				menu_char, strlen(menu_char));
    727 	XFlush(display);
    728 
    729 	sleep(1);
    730 	next_menu = START_MENU;
    731 }
    732 
    733 void
    734 cleanup(void)
    735 {
    736 	XCloseDisplay(display);
    737 }
    738 
    739 int
    740 main(void)
    741 {
    742 	setup();
    743 	while (next_menu != QUIT){
    744 		switch (next_menu){
    745 		case START_MENU:
    746 			start_menu();
    747 			break;
    748 		case GAME_PLAY:
    749 			game_play();
    750 			break;
    751 		case GAME_OVER:
    752 			game_over();
    753 			break;
    754 		default:
    755 			break;
    756 		}
    757 	}
    758 
    759 	cleanup();
    760 	return 0;
    761 }