commit 6533d405743a388096f4ca2c1afbfad1a9ebdffd
parent bb2c7d6509bd44795b856e6e639c0d41f053db13
Author: Matsuda Kenji <info@mtkn.jp>
Date: Wed, 4 Jan 2023 10:19:43 +0900
copy ex8 to ex9
Diffstat:
A | ex9/Makefile | | | 14 | ++++++++++++++ |
A | ex9/main.c | | | 407 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/main.h | | | 109 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/util.c | | | 260 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/world_map.h | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/x.c | | | 139 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 994 insertions(+), 0 deletions(-)
diff --git a/ex9/Makefile b/ex9/Makefile
@@ -0,0 +1,14 @@
+INCS=-I/usr/X11R6/include
+CFLAGS=-Wall -W -Wextra -Wpointer-arith -Wbad-function-cast -std=c11
+LIBS=-L/usr/X11R6/lib -lX11 -lXext -lm
+IN=*.c
+OUT=main
+
+all: $(IN)
+ $(CC) $(INCS) $(CFLAGS) -o $(OUT) $(IN) $(LIBS)
+
+run: all
+ ./$(OUT)
+
+clean:
+ rm -f $(OUT)
diff --git a/ex9/main.c b/ex9/main.c
@@ -0,0 +1,407 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "main.h"
+#include "world_map.h"
+
+/* macros */
+#define FPS (60)
+#define SUB_TICK (4)
+#define NUM_BLOCK (200)
+#define GRAVITY (1000)
+
+/*
+#define COUNT_FPS
+*/
+
+enum keys {
+ KEY_D,
+ KEY_S,
+ KEY_A,
+ KEY_W,
+ KEY_Q,
+ KEY_SPACE,
+ NUM_KEY, //number of keys in this enum
+};
+enum key_state {
+ KEY_UP,
+ KEY_DOWN,
+};
+enum next_menu {
+ START_MENU,
+ GAME_PLAY,
+ GAME_OVER,
+ QUIT,
+};
+
+/* variables */
+struct Object *player;
+int player_is_falling;
+enum next_menu next_menu = START_MENU;
+
+
+/* function prototypes */
+/* menus */
+void start_menu(void);
+void game_play(void);
+void game_over(void);
+/* events */
+void receive_events(enum key_state[]);
+void handle_inputs(enum key_state[]);
+/* sort */
+void sort_ll(struct OL *ol, struct Object *player);
+
+void
+start_menu(void)
+{
+ char *menu_char_q = "press q to quit.";
+ char *menu_char_s = "press <space> to start.";
+
+ x_clear_area();
+ x_draw_string(0x00FFFF,
+ WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_q)/2,
+ WORLD_HEIGHT * BLOCK_SIZE/2,
+ menu_char_q, strlen(menu_char_q));
+ x_draw_string(0x00FFFF,
+ WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_s)/2,
+ WORLD_HEIGHT * BLOCK_SIZE/2 + 20,
+ menu_char_s, strlen(menu_char_s));
+
+ while (next_menu == START_MENU) {
+ char c;
+ int event = x_next_event(&c);
+
+ switch (event) {
+ case XEXPOSE:
+ x_draw_string(0x00FFFF,
+ WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_q)/2,
+ WORLD_HEIGHT * BLOCK_SIZE/2,
+ menu_char_q, strlen(menu_char_q));
+ x_draw_string(0x00FFFF,
+ WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_s)/2,
+ WORLD_HEIGHT * BLOCK_SIZE/2 + 20,
+ menu_char_s, strlen(menu_char_s));
+
+ break;
+ case XWINDEL:
+ next_menu = QUIT;
+ break;
+ case XKEYPRESS:
+ switch (c) {
+ case 'q':
+ next_menu = QUIT;
+ break;
+ case ' ':
+ next_menu = GAME_PLAY;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void
+game_play(void)
+{
+ enum key_state key_state[NUM_KEY];
+ long t0, t1, dt;
+#ifdef COUNT_FPS
+ int fps_count = 0;
+#endif
+ struct timespec ts;
+ struct OH *blh[WORLD_WIDTH]; // block list header
+ struct OL *blc;
+
+ for (int xi = 0; xi < WORLD_WIDTH; xi++)
+ blh[xi] = create_ol();
+
+ for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) {
+ if (world_map[i] == 'b') {
+ int xi = i % WORLD_WIDTH;
+ // TODO: don't forget to free these things.
+ append_ol(blh[xi], create_object(i % WORLD_WIDTH * BLOCK_SIZE,
+ i / WORLD_WIDTH * BLOCK_SIZE,
+ 0, 0, 0, 0,
+ BLOCK_SIZE, BLOCK_SIZE,
+ BLOCK_SIZE * BLOCK_SIZE));
+ } else if (world_map[i] == 'p') {
+ player = create_object(i % WORLD_WIDTH * BLOCK_SIZE,
+ i / WORLD_WIDTH * BLOCK_SIZE,
+ 0, 0, 0, GRAVITY,
+ BLOCK_SIZE, BLOCK_SIZE,
+ BLOCK_SIZE * BLOCK_SIZE);
+ }
+ }
+
+ while (next_menu == GAME_PLAY){
+ receive_events(key_state);
+ handle_inputs(key_state);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t0 = ts.tv_nsec;
+
+ for (int k = 0; k < SUB_TICK; k++) {
+ next_tick(player, 1e9 / FPS / SUB_TICK);
+
+ // game over when fall out of the world
+ if (player->p.y > WORLD_HEIGHT * BLOCK_SIZE) {
+ next_menu = GAME_OVER;
+ break;
+ }
+ // bind within the world
+ if (player->p.x < 0) {
+ player->p.x = 0;
+ }
+ if (WORLD_WIDTH * BLOCK_SIZE < player->p.x +
+ player->body.rectangle.w) {
+ player->p.x = WORLD_WIDTH * BLOCK_SIZE -
+ player->body.rectangle.w;
+ }
+
+ struct OH *collidings;
+ collidings = create_ol();
+
+ player_is_falling = 1;
+ for (int xi = (int) player->p.x / BLOCK_SIZE;
+ xi <= (int) player->p.x / BLOCK_SIZE + 1 && xi < WORLD_WIDTH;
+ xi++) {
+ blc = blh[xi]->first;
+ while (blc != NULL) {
+ if (is_on_floor_before(player, blc->o)) {
+ player_is_falling = 0;
+ }
+ if (test_collision(player, blc->o))
+ append_ol(collidings, blc->o);
+ blc = blc->next;
+ }
+ }
+ if (collidings->first != NULL) {
+ sort_ol(collidings, player);
+ blc = collidings->first;
+ while (blc != NULL) {
+ handle_collision_mf(player, blc->o);
+ blc = blc->next;
+ }
+ }
+ free_ol(collidings);
+ }
+
+ // fix fps
+ // TODO: This method create some strange stripe when
+ // rendered in 60fps on a 60fps monitor.
+ dt = 0;
+ while (dt < 1.0 * 1e9 / FPS){
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ t1 = ts.tv_nsec;
+ dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1e9;
+ }
+#ifdef COUNT_FPS
+ // count fps.
+ fps_count++;
+ if (t1 < t0){
+ printf("fps: %u\n", fps_count);
+ fps_count = 0;
+ }
+#endif
+
+ x_clear_area();
+ for (int xi = 0; xi < WORLD_WIDTH; xi++) {
+ blc = blh[xi]->first;
+ while (blc != NULL) {
+ x_draw_rectangle(0x00FF00,
+ blc->o->p.x, blc->o->p.y, // position
+ blc->o->body.rectangle.w,
+ blc->o->body.rectangle.h);
+ blc = blc->next;
+ }
+ }
+ x_draw_rectangle(0x009FFF,
+ player->p.x, player->p.y, // position
+ player->body.rectangle.w, player->body.rectangle.h);
+ char status_string[128];
+ snprintf(status_string, 128, "falling: %d", player_is_falling);
+ x_draw_string(0x00FFFF,
+ 0, 20,
+ status_string,
+ strlen(status_string));
+ }
+ for (int xi = 0; xi < WORLD_WIDTH; xi++)
+ free_obj_and_ol(blh[xi]);
+}
+
+void
+game_over(void)
+{
+ char *menu_char = "GAME OVER";
+
+ x_clear_area();
+ x_draw_string(0x00FFFF,
+ WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char)/2,
+ WORLD_HEIGHT * BLOCK_SIZE/2,
+ menu_char, strlen(menu_char));
+ x_flush();
+
+ sleep(1);
+ while(x_pending() > 0) {
+ x_next_event(NULL);
+ }
+ next_menu = START_MENU;
+}
+
+void
+receive_events(enum key_state key_state[])
+{
+ while (x_pending() > 0) {
+ char c;
+ int event = x_next_event(&c);
+
+ switch (event) {
+ case XWINDEL:
+ next_menu = QUIT;
+ break;
+ case XKEYPRESS:
+ switch (c) {
+ case 'q':
+ key_state[KEY_Q] = KEY_DOWN;
+ break;
+ case 'd':
+ key_state[KEY_D] = KEY_DOWN;
+ break;
+ case 'a':
+ key_state[KEY_A] = KEY_DOWN;
+ break;
+ case 'w':
+ key_state[KEY_W] = KEY_DOWN;
+ break;
+ case 's':
+ key_state[KEY_S] = KEY_DOWN;
+ break;
+ case ' ':
+ key_state[KEY_SPACE] = KEY_DOWN;
+ break;
+ default:
+ break;
+ }
+ break;
+ case XKEYRELEASE:
+ switch (c) {
+ case 'q':
+ key_state[KEY_Q] = KEY_UP;
+ break;
+ case 'd':
+ key_state[KEY_D] = KEY_UP;
+ break;
+ case 'a':
+ key_state[KEY_A] = KEY_UP;
+ break;
+ case 'w':
+ key_state[KEY_W] = KEY_UP;
+ break;
+ case 's':
+ key_state[KEY_S] = KEY_UP;
+ break;
+ case ' ':
+ key_state[KEY_SPACE] = KEY_UP;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+void
+handle_inputs(enum key_state key_state[])
+{
+ if (key_state[KEY_Q] == KEY_DOWN){
+ next_menu = GAME_OVER;
+ return;
+ }
+ if (key_state[KEY_D] == KEY_DOWN && key_state[KEY_A] != KEY_DOWN) {
+ if (player->v.x > 0) {
+ player->a.x = 500;
+ } else {
+ player->a.x = 1000;
+ }
+ } else if (key_state[KEY_A] == KEY_DOWN && key_state[KEY_D] != KEY_DOWN) {
+ if (player->v.x > 0) {
+ player->a.x = -1000;
+ } else {
+ player->a.x = -500;
+ }
+ } else {
+ if (player_is_falling)
+ player->a.x = -player->v.x;
+ else
+ player->a.x = -3 * player->v.x;
+ }
+
+ if (player->v.x < -200) player->v.x = -200;
+ if (player->v.x > 200) player->v.x = 200;
+ /*
+ if (key_state[KEY_S] == KEY_DOWN)
+ player->v.y += 300;
+ if (key_state[KEY_W] == KEY_DOWN)
+ player->v.y += -300;
+ */
+ if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN) {
+ player->v.y = -450;
+ }
+}
+
+void
+swap_ll(struct OL *oi, struct OL *oj)
+{
+ struct Object *tmp;
+ tmp = oi->o;
+ oi->o = oj->o;
+ oj->o = tmp;
+}
+
+void
+sort_ll(struct OL *ol, struct Object *player)
+{
+ if (ol == NULL)
+ return;
+ struct OL *oi, *oj;
+ for (oi = ol; oi->next != NULL; oi = oi->next) {
+ for (oj = oi->next; oj != NULL; oj = oj->next) {
+ if (object_dist(oj->o, player) < object_dist(oi->o, player))
+ swap_ll(oi, oj);
+ }
+ }
+}
+
+int
+main(void)
+{
+ x_setup_window(0, 0,
+ WORLD_WIDTH * BLOCK_SIZE, WORLD_HEIGHT * BLOCK_SIZE,
+ 0x000000, "UNKO");
+ while (next_menu != QUIT){
+ switch (next_menu){
+ case START_MENU:
+ start_menu();
+ break;
+ case GAME_PLAY:
+ game_play();
+ break;
+ case GAME_OVER:
+ game_over();
+ break;
+ default:
+ break;
+ }
+ }
+
+ x_clean_up();
+ return 0;
+}
diff --git a/ex9/main.h b/ex9/main.h
@@ -0,0 +1,109 @@
+/*
+ * util.c
+ */
+enum object_shape {
+ SRECTANGLE,
+ STRIANGLE,
+ SCIRCLE,
+};
+
+struct Point {
+ float x;
+ float y;
+};
+
+struct Rectangle { // origin is top left corner
+ int w, h;
+};
+
+struct Triangle {
+ struct Point v2;
+ struct Point v3;
+};
+
+struct Circle { // origin is center
+ float r;
+};
+
+union Body {
+ struct Circle circle;
+ struct Triangle triangle;
+ struct Rectangle rectangle;
+};
+
+struct Object {
+ enum object_shape shape;
+ struct Point pp;
+ struct Point p;
+ struct Point v;
+ struct Point a;
+ union Body body;
+ int m;
+};
+
+struct OH {
+ struct OL *first;
+};
+
+/*
+ * linked list which starts with OH and
+ * terminates with ->next == NULL
+ */
+struct OL {
+ struct Object *o;
+ struct OL *next;
+};
+struct OH *create_ol(void);
+void free_ol(struct OH *);
+void free_obj_and_ol(struct OH *);
+void append_ol(struct OH *, struct Object *);
+void swap_ol(struct OL *, struct OL *);
+void sort_ol(struct OH *, struct Object *);
+int object_dist(struct Object *, struct Object *);
+
+struct rect {
+ struct Point pp;
+ struct Point p;
+ struct Point v;
+ struct Point a;
+ int w, h;
+ int m;
+};
+
+struct circle {
+ struct Point pp;
+ struct Point p;
+ struct Point v;
+ struct Point a;
+ int r;
+ int m;
+};
+
+int test_collision(struct Object *, struct Object *); // 1 if collide, 0 if not
+void next_tick(struct Object *o, long);
+void handle_collision_mf(struct Object *, struct Object *);
+int object_is_falling(struct Object *o, struct Object *fb, int num_f);
+struct Object *create_object(float, float, float, float, float, float,
+ int, int, int);
+int is_on_floor_before(struct Object *, struct Object *);
+/*
+ * x.c
+ */
+enum event_type {
+ XKEYPRESS,
+ XKEYRELEASE,
+ XEXPOSE,
+ XWINDEL,
+ NOEVENT,
+};
+
+int x_setup_window(int, int, unsigned int, unsigned int, unsigned long, char *);
+void x_clear_area(void);
+void x_draw_string(unsigned long color, int x, int y, const char *str, int length);
+void x_draw_rectangle(unsigned long color, int x, int y,
+ unsigned int w, unsigned int h);
+void x_flush(void);
+void x_clean_up(void);
+int x_next_event(char *c);
+int x_pending(void);
+void x_get_win_wh(int *, int *);
diff --git a/ex9/util.c b/ex9/util.c
@@ -0,0 +1,260 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "main.h"
+
+static int test_collision_rr(struct Object *, struct Object *);
+static void rect_next_tick(struct Object *, long);
+static void rect_handle_collision_mf(struct Object *, struct Object *);
+
+struct Object *
+create_object(float px, float py, float vx, float vy, float ax, float ay,
+ int w, int h, int m)
+{
+ struct Object *o;
+ o = (struct Object *)malloc(sizeof(struct Object));
+ o->pp.x = o->p.x = px;
+ o->pp.y = o->p.y = py;
+ o->v.x = vx;
+ o->v.y = vy;
+ o->a.x = ax;
+ o->a.y = ay;
+ o->shape = SRECTANGLE;
+ o->body.rectangle.w = w;
+ o->body.rectangle.h = h;
+ o->m = m;
+ return o;
+}
+
+void
+free_object(struct Object *o)
+{
+ free(o);
+}
+
+/*
+ * 1 if collide, 0 if not
+ */
+int
+test_collision(struct Object *o1, struct Object *o2)
+{
+ if (o1->shape == SRECTANGLE && o2->shape == SRECTANGLE)
+ return test_collision_rr(o1, o2);
+ else {
+ fprintf(stderr, "test_collision for other shapes is not implemented yet\n");
+ return -1;
+ }
+}
+
+static int
+test_collision_rr(struct Object *o1, struct Object *o2)
+{
+ if (o1->shape != SRECTANGLE || o2->shape != SRECTANGLE) {
+ fprintf(stderr, "test_collision_rr: invalid objects\n");
+ return -1;
+ }
+ return o1->p.x < o2->p.x + o2->body.rectangle.w &&
+ o2->p.x < o1->p.x + o1->body.rectangle.w &&
+ o2->p.y < o1->p.y + o1->body.rectangle.h &&
+ o1->p.y < o2->p.y + o2->body.rectangle.h;
+}
+
+void
+next_tick(struct Object *o, long ndt)
+{
+ switch (o->shape) {
+ case SRECTANGLE:
+ rect_next_tick(o, ndt);
+ break;
+ default:
+ fprintf(stderr, "next_tick: not implemented for other shapes\n");
+ break;
+ }
+}
+
+static void
+rect_next_tick(struct Object *o, long ndt)
+{
+ if (o->shape != SRECTANGLE) {
+ fprintf(stderr, "rect_next_tick: invalid object shape\n");
+ return;
+ }
+ o->pp.x = o->p.x;
+ o->pp.y = o->p.y;
+ o->v.x += o->a.x * ndt / 1e9;
+ o->v.y += o->a.y * ndt / 1e9;
+ o->p.x += o->v.x * ndt / 1e9;
+ o->p.y += o->v.y * ndt / 1e9;
+}
+
+void
+handle_collision_mf(struct Object *om, struct Object *of)
+{
+ // TODO: too many testing?
+ if (!test_collision(om, of))
+ return;
+ if (om->shape == SRECTANGLE && of->shape == SRECTANGLE)
+ rect_handle_collision_mf(om, of);
+ else {
+ fprintf(stderr, "handle_collision_mf: not implemented for other shapes\n");
+ return;
+ }
+}
+
+/*
+ * Handle collision of a moving rect against fixed rect
+ */
+static void
+rect_handle_collision_mf(struct Object *om, struct Object *of)
+{
+ // TODO: too many testing?
+ if (!test_collision(om, of))
+ return;
+ if (om->pp.x + om->body.rectangle.w <= of->pp.x &&
+ of->p.x < om->p.x + om->body.rectangle.w) {
+ // collisioin from left to right
+ om->p.x = of->p.x - om->body.rectangle.w;
+ om->v.x = 0;
+ }
+ if (of->pp.x + of->body.rectangle.w <= om->pp.x &&
+ om->p.x < of->p.x + of->body.rectangle.w) {
+ // collision from right to left
+ om->p.x = of->p.x + of->body.rectangle.w;
+ om->v.x = 0;
+ }
+
+ if (om->pp.y + om->body.rectangle.h <= of->pp.y &&
+ of->p.y < om->p.y + om->body.rectangle.h) {
+ // collision from up to down
+ om->p.y = of->p.y - om->body.rectangle.h;
+ om->v.y = 0;
+ }
+ if (of->pp.y + of->body.rectangle.h <= om->pp.y &&
+ om->p.y < of->p.y + of->body.rectangle.h) {
+ // collision from down to up
+ om->p.y = of->p.y + of->body.rectangle.h;
+ om->v.y = 0;
+ }
+
+}
+
+/*
+ * Test if object o is not on top of one of fb (floor blocks).
+ * o: object to be tested, fb: floor blocks, num_f: count of fb.
+ */
+int
+object_is_falling(struct Object *o, struct Object *fb, int num_f)
+{
+ struct Object p = *o;
+
+ p.v.x = 0; p.v.y = 1;
+ p.a.x = 0; p.a.y = 0;
+
+ next_tick(&p, 1e9);
+
+ for (int i = 0; i < num_f; i++)
+ if (test_collision(&p, &fb[i]))
+ return 0;
+ return 1;
+}
+
+struct OH *
+create_ol(void)
+{
+ struct OH *oh;
+ oh = (struct OH *)malloc(sizeof(struct OH));
+ oh->first = NULL;
+ return oh;
+}
+
+void
+free_ol(struct OH *oh)
+{
+ if (oh == NULL)
+ return;
+ struct OL *ol0, *ol1;
+ ol0 = ol1 = oh->first;
+ while (ol1 != NULL) {
+ ol1 = ol0->next;
+ free(ol0);
+ ol0 = ol1;
+ }
+ free(oh);
+}
+
+void
+free_obj_and_ol(struct OH *oh)
+{
+ if (oh == NULL)
+ return;
+ struct OL *ol0, *ol1;
+ ol0 = ol1 = oh->first;
+ while (ol1 != NULL) {
+ ol1 = ol0->next;
+ free(ol0->o);
+ free(ol0);
+ ol0 = ol1;
+ }
+
+}
+
+void
+append_ol(struct OH *oh, struct Object *o)
+{
+ struct OL *cur;
+
+ if (oh->first == NULL) {
+ oh->first = (struct OL *)malloc(sizeof(struct OL));
+ cur = oh->first;
+ } else {
+ cur = oh->first;
+ while (cur->next != NULL)
+ cur = cur->next;
+ cur->next = (struct OL *)malloc(sizeof(struct OL));
+ cur = cur->next;
+ }
+ cur->o = o;
+ cur->next = NULL;
+}
+
+void
+swap_ol(struct OL *ol0, struct OL *ol1)
+{
+ struct Object *tmp;
+ tmp = ol0->o;
+ ol0->o = ol1->o;
+ ol1->o = tmp;
+}
+
+void
+sort_ol(struct OH *oh, struct Object *player)
+{
+ if (oh == NULL)
+ return;
+ struct OL *oi, *oj;
+ for (oi = oh->first; oi->next != NULL; oi = oi->next) {
+ for (oj = oi->next; oj != NULL; oj = oj->next) {
+ if (object_dist(oj->o, player) < object_dist(oi->o, player))
+ swap_ol(oi, oj);
+ }
+ }
+}
+
+int
+object_dist(struct Object *o1, struct Object *o2)
+{
+ return (o1->p.x - o2->p.x) * (o1->p.x - o2->p.x) +
+ (o1->p.y - o2->p.y) * (o1->p.y - o2->p.y);
+}
+
+int
+is_on_floor_before(struct Object *player, struct Object *floor)
+{
+ struct Object o = *player;
+ o.p.x = o.pp.x; o.p.y = o.pp.y;
+ o.v.x = 0; o.v.y = 5;
+ o.a.x = 0; o.a.y = 0;
+ next_tick(&o, 1e9);
+ int col = test_collision(&o, floor);
+ return col;
+}
diff --git a/ex9/world_map.h b/ex9/world_map.h
@@ -0,0 +1,65 @@
+#define WORLD_WIDTH (80)
+#define WORLD_HEIGHT (60)
+#define BLOCK_SIZE (10)
+
+char world_map[WORLD_WIDTH * WORLD_HEIGHT + 1] =
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................b..............................................................."
+"..........................................................b..........b.........."
+"................................................................................"
+".......................b........................................................"
+"...........................................b...................................."
+"...........................................b...................................."
+"................................................................................"
+"..................b............................................................."
+"................................................................................"
+"...........................................b...................................."
+"................................................................................"
+"................................................................................"
+"...........................b...................................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"....................................bbbbbbbbbb.................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"..............................................bbbbbbbbbb........................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"....................................bbbbbbbbbb.................................."
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"..........................bbbbbbbbbb............................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................................................................................"
+"................bbbbbbbbbb......................................................"
+"................................................................................"
+"................................................................................"
+"...p............................................................................"
+"bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb"
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b...................."
+"........................b.......b......................b...b....................";
diff --git a/ex9/x.c b/ex9/x.c
@@ -0,0 +1,139 @@
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+
+#include "main.h"
+
+Display *display;
+Atom wm_delete_window;
+GC gc;
+Window window;
+unsigned int win_width, win_height;
+
+/*
+ * Creates a window
+ * If succeeded, returns 0
+ * If error occured, returns -1
+ */
+int
+x_setup_window(int x, int y,
+ unsigned int w, unsigned int h,
+ unsigned long bc, char *win_name)
+{
+ if ((display = XOpenDisplay(NULL)) == NULL){
+ fprintf(stderr, "ERROR: could not open display\n");
+ return -1;
+ }
+ window = XCreateSimpleWindow(
+ display,
+ XDefaultRootWindow(display),
+ x, y,
+ w, h,
+ 0, 0, // I don't need border?
+ bc);
+ win_width = w;
+ win_height = h;
+
+ XStoreName(display, window, win_name);
+ gc = XCreateGC(display, window, 0, NULL);
+
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, window, &wm_delete_window, 1);
+
+ XSelectInput(display, window,
+ ExposureMask | KeyPressMask | KeyReleaseMask);
+
+ XMapWindow(display, window);
+ return 0;
+}
+
+/*
+ * Clears the window with the background color.
+ * I don't know what the return value of XClearArea means...
+ */
+void
+x_clear_area(void)
+{
+ XClearArea(display, window,
+ 0, 0,
+ win_width, win_height,
+ False);
+}
+
+/*
+ * Draws a string with specified color.
+ */
+void
+x_draw_string(unsigned long color, int x, int y, const char *str, int length)
+{
+ XSetForeground(display, gc, color);
+ XDrawString(display, window, gc, x, y, str, length);
+}
+
+void
+x_draw_rectangle(unsigned long color, int x, int y,
+ unsigned int w, unsigned int h)
+{
+ XSetForeground(display, gc, color);
+ XDrawRectangle(display, window, gc, x, y, w, h);
+}
+
+void
+x_flush(void)
+{
+ XFlush(display);
+}
+
+void
+x_clean_up(void)
+{
+ XCloseDisplay(display);
+}
+
+int
+x_next_event(char *c)
+{
+ XEvent event;
+ XWindowAttributes wattr;
+
+ XNextEvent(display, &event);
+ if (c == NULL)
+ return NOEVENT;
+ switch (event.type) {
+ case Expose:
+ XGetWindowAttributes(display, window, &wattr);
+ win_width = wattr.width;
+ win_height = wattr.height;
+ return XEXPOSE;
+ break;
+ case ClientMessage:
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ return XWINDEL;
+ }
+ break;
+ case KeyPress:
+ *c = XLookupKeysym(&event.xkey, 0);
+ return XKEYPRESS;
+ break;
+ case KeyRelease:
+ *c = XLookupKeysym(&event.xkey, 0);
+ return XKEYRELEASE;
+ break;
+ default:
+ break;
+ }
+ return NOEVENT;
+}
+
+int
+x_pending(void)
+{
+ return XPending(display);
+}
+
+void
+x_get_win_wh(int *w, int *h)
+{
+ *w = win_width;
+ *h = win_height;
+}