/* Move objs. */ #include #include #include #include #include #include #include /* include xpm binary */ #include "scifi_bg_chip2.xpm" #define USE_XPM_NAME scifi_bg_chip2_xpm #define WIN_X 0 #define WIN_Y 0 #define BORDER 0 #define OUT_W 640 #define OUT_H 360 #define IMG_W 8 #define IMG_H 10 #ifndef M_PI #define M_PI 3.14159265358979 #endif #define deg2rad(x) (x * M_PI / 180.0) #define OBJ_MAX 16 #define BG_COUNT 3 #define BG_W 16 #define BG_H 6 #define BG_CHIP_W 64 #define BG_CHIP_H 64 static int bg_layer[][16 * 6] = { {43, 44, 29, 30, 43, 44, 27, 28, 43, 44, 29, 30, 43, 44, 27, 28, 51, 52, 37, 38, 51, 52, 35, 36, 51, 52, 37, 38, 51, 52, 35, 36, 27, 28, 43, 44, 27, 28, 29, 31, 51, 52, 43, 44, 27, 28, 29, 30, 35, 36, 51, 52, 35, 36, 37, 37, 37, 38, 51, 52, 35, 36, 37, 38, 29, 30, 27, 28, 43, 44, 27, 28, 43, 44, 27, 28, 29, 30, 27, 28, 37, 38, 35, 36, 51, 52, 35, 36, 51, 52, 35, 36, 37, 38, 35, 36}, {0, 24, 41, 48, 48, 26, 0, 24, 48, 48, 26, 40, 48, 48, 48, 26, 0, 49, 0, 0, 0, 40, 48, 41, 26, 0, 32, 48, 48, 26, 0, 49, 48, 41, 48, 25, 48, 25, 48, 48, 41, 48, 33, 48, 48, 33, 48, 41, 0, 0, 0, 32, 48, 33, 48, 48, 26, 0, 40, 48, 26, 40, 26, 0, 48, 48, 25, 41, 48, 41, 48, 25, 41, 48, 25, 25, 41, 48, 41, 48, 0, 0, 49, 0, 0, 0, 0, 40, 48, 48, 42, 49, 0, 0, 0, 0}, {1, 2, 3, 14, 15, 0, 6, 1, 1, 2, 3, 1, 1, 7, 0, 6, 12, 13, 7, 0, 0, 0, 0, 12, 13, 3, 2, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 8, 9, 3, 2, 10, 11, 0, 0, 4, 1, 1, 1, 2, 3, 2, 3, 2, 3, 1, 3, 1, 3, 2, 3, 2, 3}}; /* obj work */ typedef struct { Bool enable; int base_pix_id; int add_pix_id; float x, y; float dx, dy; int w, h; int counter; } Obj; /* Pixmap pix and mask */ typedef struct { Pixmap pix; Pixmap mask; } Pixmaps; /* global work */ struct state { Display *dpy; Window root; Window win; int screen; int disp_w, disp_h; unsigned long black, white; XWindowAttributes xgwa; GC gc, mask_gc; Pixmaps pix; Pixmaps *pixs; int pixs_size; Pixmap smallbuf; Pixmap largebuf; int xpm_w, xpm_h; float bg_x[BG_COUNT]; float bg_y[BG_COUNT]; float bg_dx[BG_COUNT]; float bg_dy[BG_COUNT]; Obj objs[OBJ_MAX]; int count; int enemy_born_timer; }; /* draw transparent image */ static void draw_image(Display *dpy, Drawable dst, GC gc, Pixmaps *src, int x, int y, int w, int h) { XSetClipMask(dpy, gc, src->mask); XSetClipOrigin(dpy, gc, x, y); XCopyArea(dpy, src->pix, dst, gc, 0, 0, w, h, x, y); XSetClipMask(dpy, gc, None); } static void init_objs(struct state *st) { int i; for (i = 0; i < OBJ_MAX; i++) st->objs[i].enable = False; st->enemy_born_timer = 0; } static void create_obj(struct state *st, Obj *o, int x, int y, int pix_id) { o->enable = True; o->x = x; o->y = y; o->w = 64; o->h = 64; /* o->dx = -((rand() % 8) * 0.5 + 1.0); */ o->dx = -2.5; o->dy = 0; o->base_pix_id = 8 * 9; o->add_pix_id = pix_id % 8; o->counter = 0; } static void update_obj(struct state *st, Obj *o) { if (!o->enable) return; /* move */ o->x += o->dx; o->y += o->dy; /* update anime pattern */ o->counter++; if (o->counter >= 3) { o->counter = 0; o->add_pix_id++; if (o->add_pix_id >= 8) o->add_pix_id = 0; } if (o->x < -(o->w / 2) || o->y < -(o->h / 2) || o->y > OUT_H + (o->h / 2)) { o->enable = False; } } static int get_empty_obj_work(struct state *st) { int i; for (i = 0; i < OBJ_MAX; i++) if (!st->objs[i].enable) return i; return -1; } static void update_objs(struct state *st) { int i; /* born enemy */ st->enemy_born_timer--; if (st->enemy_born_timer <= 0) { int y = rand() % (OUT_H - 36 * 2) + 36; int pix_id = 0; int cnt = rand() % 3 + 3; st->enemy_born_timer = 110 + rand() % 90; for (i = 0; i < cnt; i++) { int idx = get_empty_obj_work(st); if (idx < 0) break; /* not found empty work */ { int x = OUT_W + 64 + (64 * 1.00) * i; create_obj(st, &st->objs[idx], x, y, pix_id); pix_id = (pix_id + 6) % 8; } } } /* move objs */ for (i = 0; i < OBJ_MAX; i++) if (st->objs[i].enable) update_obj(st, &st->objs[i]); } static void draw_objs(struct state *st) { int i; for (i = 0; i < OBJ_MAX; i++) { if (st->objs[i].enable) { int id = st->objs[i].base_pix_id + st->objs[i].add_pix_id; int w = st->objs[i].w; int h = st->objs[i].h; int x = st->objs[i].x - (w / 2); int y = st->objs[i].y - (h / 2); draw_image(st->dpy, st->smallbuf, st->gc, &st->pixs[id], x, y, w, h); } } } /* get a color value from a color name */ static unsigned long get_color(Display *dpy, char *colorname) { Colormap cmap; XColor near_color, true_color; cmap = DefaultColormap(dpy, DefaultScreen(dpy)); XAllocNamedColor(dpy, cmap, colorname, &near_color, &true_color); return near_color.pixel; } static int load_images(struct state *st) { XpmAttributes attr; attr.valuemask = 0; if (XpmCreatePixmapFromData(st->dpy, st->win, USE_XPM_NAME, &st->pix.pix, &st->pix.mask, &attr)) { fprintf(stderr, "Error not load xpm."); return 1; } /* get xpm width and height */ st->xpm_w = attr.width; st->xpm_h = attr.height; /* free xpm attributes */ XpmFreeAttributes(&attr); return 0; } static Pixmaps * split_pixmaps(struct state *st, Pixmaps src, int src_w, int src_h, int div_x, int div_y) { Pixmaps *pixs, *p; int w, h; GC pix_gc, mask_gc; st->pixs_size = div_x * div_y; pixs = (Pixmaps *)malloc(sizeof(Pixmaps) * st->pixs_size); pix_gc = XCreateGC(st->dpy, src.pix, 0, 0); XSetGraphicsExposures(st->dpy, pix_gc, False); mask_gc = XCreateGC(st->dpy, src.mask, 0, 0); XSetGraphicsExposures(st->dpy, mask_gc, False); w = src_w / div_x; h = src_h / div_y; int ix, iy; p = pixs; for (iy = 0; iy < div_y; iy++) { int y = h * iy; for (ix = 0; ix < div_x; ix++) { int x; x = w * ix; p->pix = XCreatePixmap(st->dpy, st->win, w, h, st->xgwa.depth); XCopyArea(st->dpy, src.pix, p->pix, pix_gc, x, y, w, h, 0, 0); p->mask = XCreatePixmap(st->dpy, st->win, w, h, 1); XCopyArea(st->dpy, src.mask, p->mask, mask_gc, x, y, w, h, 0, 0); p++; } } XFreeGC(st->dpy, pix_gc); XFreeGC(st->dpy, mask_gc); return pixs; } static void init_pixmaps(struct state *st) { /* create Pixmaps */ st->largebuf = XCreatePixmap(st->dpy, st->win, st->disp_w, st->disp_h, st->xgwa.depth); st->smallbuf = XCreatePixmap(st->dpy, st->win, OUT_W, OUT_H, st->xgwa.depth); XSetForeground(st->dpy, st->gc, get_color(st->dpy, "green")); XFillRectangle(st->dpy, st->largebuf, st->gc, 0, 0, st->disp_w, st->disp_h); XSetForeground(st->dpy, st->gc, get_color(st->dpy, "black")); XFillRectangle(st->dpy, st->smallbuf, st->gc, 0, 0, OUT_W, OUT_H); } static void free_pixmaps(struct state *st) { /* free split pixmaps */ { int i; for (i = 0; i < st->pixs_size; i++) { XFreePixmap(st->dpy, st->pixs[i].pix); XFreePixmap(st->dpy, st->pixs[i].mask); } free(st->pixs); } XFreePixmap(st->dpy, st->pix.pix); XFreePixmap(st->dpy, st->pix.mask); XFreePixmap(st->dpy, st->largebuf); XFreePixmap(st->dpy, st->smallbuf); } static void init_gc(struct state *st) { st->gc = XCreateGC(st->dpy, st->pix.pix, 0, 0); st->mask_gc = XCreateGC(st->dpy, st->pix.mask, 0, 0); XSetGraphicsExposures(st->dpy, st->gc, False); XSetGraphicsExposures(st->dpy, st->mask_gc, False); } static void free_gc(struct state *st) { XFreeGC(st->dpy, st->gc); XFreeGC(st->dpy, st->mask_gc); } /* scale Pixmap */ static void scale_pixmap(Display *dpy, Drawable win, Pixmap *src, Pixmap *dst, int src_w, int src_h, int dst_w, int dst_h) { GC gc; float xscale, yscale; int x, y; xscale = (float)src_w / dst_w; yscale = (float)src_h / dst_h; gc = XCreateGC(dpy, win, 0, 0); XSetGraphicsExposures(dpy, gc, False); for (x = dst_w - 1; x >= 0; x--) XCopyArea(dpy, *src, *dst, gc, (int)(x * xscale), 0, 1, src_h, x, 0); if (src_h <= dst_h) { for (y = dst_h - 1; y >= 0; y--) XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y); } else { for (y = 0; y < dst_h; y++) XCopyArea(dpy, *dst, *dst, gc, 0, (int)(y * yscale), dst_w, 1, 0, y); } XFreeGC(dpy, gc); } static void get_target_size(int src_w, int src_h, int scrw, int scrh, int *tgt_w, int *tgt_h) { double xscale, yscale, scale; xscale = (double)scrw / src_w; yscale = (double)scrh / src_h; scale = (xscale <= yscale) ? xscale : yscale; *tgt_w = (int)(src_w * scale); *tgt_h = (int)(src_h * scale); } static void draw_tilemap(struct state *st) { int src_w, src_h; int bgw, bgh; int xcnt, ycnt; int n; src_w = OUT_W; src_h = OUT_H; bgw = BG_CHIP_W * BG_W; bgh = BG_CHIP_H * BG_H; xcnt = (OUT_W / BG_CHIP_W) + 1 + ((OUT_W % BG_CHIP_W == 0) ? 0 : 1); ycnt = (OUT_H / BG_CHIP_H) + 1 + ((OUT_H % BG_CHIP_H == 0) ? 0 : 1); XSetGraphicsExposures(st->dpy, st->gc, False); XSetGraphicsExposures(st->dpy, st->mask_gc, False); for (n = 0; n < BG_COUNT; n++) { int bx, by, dx, dy, xc, yc; bx = (int)st->bg_x[n]; by = (int)st->bg_y[n]; while (bx < 0) bx += bgw; while (by < 0) by += bgh; bx = bx % bgw; by = by % bgh; dx = bx % BG_CHIP_W; dy = by % BG_CHIP_H; for (yc = 0; yc < ycnt; yc++) { int iy = ((yc * BG_CHIP_H + by) % bgh) / BG_CHIP_H; for (xc = 0; xc < xcnt; xc++) { int ix, id, x, y; ix = ((xc * BG_CHIP_W + bx) % bgw) / BG_CHIP_W; id = bg_layer[n][(iy % BG_H) * BG_W + (ix % BG_W)]; if (id == 0) continue; x = xc * BG_CHIP_W - dx; y = yc * BG_CHIP_H - dy; draw_image(st->dpy, st->smallbuf, st->gc, &st->pixs[id], x, y, BG_CHIP_W, BG_CHIP_H); } } } } static void clear_window(struct state *st) { int scrw = st->xgwa.width; int scrh = st->xgwa.height; if (1) { XClearWindow(st->dpy, st->win); } else { XSetGraphicsExposures(st->dpy, st->gc, False); XSetForeground(st->dpy, st->gc, st->black); XFillRectangle(st->dpy, st->win, st->gc, 0, 0, scrw, scrh); } } /* update and draw */ static void update(struct state *st) { int i; int scrw, scrh; int src_w, src_h; int aw, ah; scrw = st->xgwa.width; /* window width */ scrh = st->xgwa.height; /* window height */ src_w = OUT_W; src_h = OUT_H; update_objs(st); get_target_size(src_w, src_h, scrw, scrh, &aw, &ah); /* draw tilemap */ draw_tilemap(st); draw_objs(st); /* scaling to screen resolution */ scale_pixmap(st->dpy, st->win, &st->smallbuf, &st->largebuf, src_w, src_h, aw, ah); /* draw image (Pixmap) */ { int x = (scrw - aw) / 2; int y = (scrh - ah) / 2; XSetGraphicsExposures(st->dpy, st->gc, False); XCopyArea(st->dpy, st->largebuf, st->win, st->gc, 0, 0, aw, ah, x, y); } /* change bg position */ { int i; for (i = 0; i < BG_COUNT; i++) { st->bg_x[i] += st->bg_dx[i]; st->bg_y[i] += st->bg_dy[i]; } } st->count++; } static void init_bg_pos(struct state *st) { int i; for (i = 0; i < BG_COUNT; i++) { st->bg_x[i] = 0.0; st->bg_y[i] = 0.0; } /* init spped */ st->bg_dx[BG_COUNT - 1] = 2.0; st->bg_dy[BG_COUNT - 1] = 0.5; for (i = BG_COUNT - 2; i >= 0; i--) { st->bg_dx[i] = st->bg_dx[i + 1] / 2.0; st->bg_dy[i] = st->bg_dy[i + 1] / 2.0; } } int main(void) { struct state st; /* open display */ st.dpy = XOpenDisplay(NULL); st.root = DefaultRootWindow(st.dpy); st.screen = DefaultScreen(st.dpy); /* get display size */ st.disp_w = DisplayWidth(st.dpy, st.screen); st.disp_h = DisplayHeight(st.dpy, st.screen); printf("Screen: %d x %d\n", st.disp_w, st.disp_h); /* get color black and white */ st.white = WhitePixel(st.dpy, st.screen); st.black = BlackPixel(st.dpy, st.screen); /* create window */ st.win = XCreateSimpleWindow(st.dpy, st.root, WIN_X, WIN_Y, st.disp_w, st.disp_h, BORDER, st.white, st.black); XSelectInput(st.dpy, st.win, KeyPressMask | ExposureMask); XMapWindow(st.dpy, st.win); /* wait display window */ { XEvent evt; do { XNextEvent(st.dpy, &evt); } while (evt.type != Expose); } XMoveWindow(st.dpy, st.win, WIN_X, WIN_Y); /* get window attributes */ XGetWindowAttributes(st.dpy, st.win, &st.xgwa); /* load image */ if (load_images(&st) == 1) return 1; init_gc(&st); /* create graphics context */ init_pixmaps(&st); /* init Pixmaps */ /* split pixmap */ st.pixs = split_pixmaps(&st, st.pix, st.xpm_w, st.xpm_h, IMG_W, IMG_H); init_bg_pos(&st); init_objs(&st); clear_window(&st); st.count = 0; /* main loop */ { int busy_loop; XEvent evt; busy_loop = 1; while (busy_loop) { struct timespec start, end; double diff; timespec_get(&start, TIME_UTC); /* event */ while (XPending(st.dpy)) { XNextEvent(st.dpy, &evt); switch (evt.type) { /* case Expose: if (evt.xexpose.count == 0) { } break; */ case KeyPress: busy_loop = 0; break; default: break; } } update(&st); XFlush(st.dpy); timespec_get(&end, TIME_UTC); diff = (end.tv_sec + (double)end.tv_nsec / 1000000000.0) - (start.tv_sec + (double)start.tv_nsec / 1000000000.0); printf("%lf msec\n", diff * 1000); /* wait */ { int waitusec = (int)(16666 - (diff * 1000 * 1000)); /* printf("wait %d usec\n", waitusec); */ if (waitusec > 0) usleep(waitusec); } } } free_pixmaps(&st); free_gc(&st); XDestroyWindow(st.dpy, st.win); XCloseDisplay(st.dpy); return 0; }