xlib_playground

Xlib playground for experiments.
Log | Files | Refs

commit 24091625e1a39f6df615f44416749ba5e0cfa6d2
parent ad942f879d3fa0060e08e1d16a5c3aec54ce77de
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue, 10 Jan 2023 09:28:42 +0900

add new files

Diffstat:
Aex9/draw.c | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/draw.h | 21+++++++++++++++++++++
Aex9/object.c | 186+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/object.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 410 insertions(+), 0 deletions(-)

diff --git a/ex9/draw.c b/ex9/draw.c @@ -0,0 +1,140 @@ +#include <stdio.h> +#include <stdint.h> + +#include <X11/Xlib.h> + +#include "draw.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; +} diff --git a/ex9/draw.h b/ex9/draw.h @@ -0,0 +1,21 @@ +/* + * 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/object.c b/ex9/object.c @@ -0,0 +1,186 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "object.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(enum object_type t, uint32_t color, + 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->type = t; + o->color = color; + o->shape = SRECTANGLE; + 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->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; +} + +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; +} + +void handle_collision(struct Object *o0, struct Object *o1) { + (* col_func[o0->type][o1->type])(o0, o1); +} diff --git a/ex9/object.h b/ex9/object.h @@ -0,0 +1,63 @@ +enum object_shape { + SRECTANGLE, + STRIANGLE, + SCIRCLE, +}; + +enum object_type { + TPLAYER, + TBLOCK, + TENEMY, + TFLAG, + NUM_OBJ_TYPE, +}; + +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_type type; + enum object_shape shape; + uint32_t color; + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + union Body body; + int m; +}; + +extern void (* col_func[NUM_OBJ_TYPE][NUM_OBJ_TYPE])(struct Object *, struct Object *); + +int object_dist(struct Object *, struct Object *); +void handle_collision(struct Object *, struct Object *); +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(enum object_type, uint32_t, + float, float, float, float, float, float, + int, int, int); +void free_object(struct Object *); +int is_on_floor_before(struct Object *, struct Object *);