/* ** X11 routines for XOIDS ** ** by Tim Ebling ** tebling@oce.orst.edu ** ** This is actually a hacked version of the X11 device driver ** from the VOGLE graphics library. Not much is left of the ** original though :) ** */ #include #include #include #include #include #include #include #include #include "oids.h" #define LARGEX11R2 "courier12f.snf" #define SMALLX11R2 "courier10f.snf" #define LARGEX11R3 "-adobe-courier-medium-r-normal--24-240-75-75-m-150-iso8859-1" #define SMALLX11R3 "-adobe-courier-medium-r-normal--10-100-75-75-m-60-iso8859-1" #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define CMAPSIZE 256 #define EV_MASK KeyReleaseMask|KeyPressMask|ExposureMask|VisibilityChangeMask|StructureNotifyMask static Window winder; static Display *display; static int screen; static unsigned long carray[CMAPSIZE]; static Colormap colormap; static Drawable theDrawable; static GC theGC; static GC unclippedGC; static XGCValues theGCvalues; static Pixmap bbuf; /* Back buffer pixmap */ static int back_used; /* Have we backbuffered ? */ static XFontStruct *font_id; static XFontStruct *font_info; static unsigned long colour; static unsigned int h, w; static XRectangle eng_outlinel, eng_outliner; static unsigned int wo7, wo40; /* * X_init * * initialises X11 display. */ void X_init() { int i; int x, y, prefx, prefy, prefxs, prefys; unsigned int bw, depth, mask; Window rootw, childw; char *av[2], name[50]; XEvent event; XSetWindowAttributes theWindowAttributes; XSizeHints theSizeHints; unsigned long theWindowMask; XWMHints theWMHints; av[0] = "X11"; av[1] = (char *)NULL; if ((display = XOpenDisplay((char *)NULL)) == (Display *)NULL) { fprintf(stderr,"X_init: can't connect to X server\n"); exit(1); } winder = DefaultRootWindow(display); screen = DefaultScreen(display); vdevice.depth = DefaultDepth(display, screen); colormap = DefaultColormap(display, screen); /* * Set our standard colors... */ if (vdevice.depth == 1) { /* * Black and white - anything that's not black is white. */ carray[0] = BlackPixel(display, screen); for (i = 1; i < CMAPSIZE; i++) carray[i] = WhitePixel(display, screen); } else { /* * Color, try to get our colors close to what's in the * default colormap. */ X_mapcolor(0, 0, 0, 0); X_mapcolor(1, 255, 0, 0); X_mapcolor(2, 0, 255, 0); X_mapcolor(3, 255, 255, 0); X_mapcolor(4, 0, 0, 255); X_mapcolor(5, 255, 0, 255); X_mapcolor(6, 0, 255, 255); X_mapcolor(7, 255, 255, 255); } /* * NEED TO USE XGRABPOINTER here??? */ XQueryPointer(display, winder, &rootw, &childw, &x, &y, &x, &y, &mask); if (childw == None) childw = rootw; XGetGeometry(display, childw, &rootw, &x, &y, &w, &h, &bw, &depth); /* * Tell the window manager not to mess with this window... * (and hope the bastard of a thing listens) * Unless it's using prefsize of prefposition of course. */ theWindowAttributes.override_redirect = True; prefx = 0; prefy = 0; prefxs = WINDOW_WIDTH; prefys = WINDOW_HEIGHT; if (prefx > -1) { theWindowAttributes.override_redirect = False; x = prefx; y = prefy; } if (prefxs > -1) { theWindowAttributes.override_redirect = False; w = prefxs; h = prefys; } x += bw; y += bw; w -= 2 * bw; h -= 2 * bw; /*theWindowMask = CWBackPixel|CWBorderPixel|CWOverrideRedirect;*/ theWindowMask = CWOverrideRedirect; winder = XCreateWindow(display, winder, x, y, w, h, bw, (int)vdevice.depth, InputOutput, CopyFromParent, theWindowMask, &theWindowAttributes ); theWMHints.initial_state = NormalState; theWMHints.input = True; theWMHints.flags = StateHint | InputHint; XSetWMHints(display, winder, &theWMHints); theSizeHints.flags = PPosition|PSize; theSizeHints.x = x; theSizeHints.y = y; theSizeHints.width = w; theSizeHints.height = h; XSetNormalHints(display, winder, &theSizeHints); sprintf(name, "XOIDS!"); XSetStandardProperties(display, winder, name, name, None, av, 1, &theSizeHints ); XSelectInput(display, winder, EV_MASK); theDrawable = (Drawable)winder; /* Colors */ theGCvalues.foreground = WhitePixel(display, screen); theGCvalues.background = BlackPixel(display, screen); theGCvalues.function = GXcopy; /* * Let us know about the window size. */ vdevice.sizeX = vdevice.sizeY = MIN(h, w) - 1; vdevice.sizeSx = w; vdevice.sizeSy = h; /* * Create Graphics Context and Drawable */ theGC = XCreateGC(display, RootWindow(display, screen), (GCForeground | GCBackground | GCFunction), &theGCvalues); unclippedGC = XCreateGC(display, RootWindow(display, screen), (GCForeground | GCBackground | GCFunction), &theGCvalues); X_color(0); colour = BLACK; XMapRaised(display, winder); XFlush(display); /* * Wait for Exposure event. */ do { XNextEvent(display, &event); } while (event.type != Expose); /* * Set the input Focus to us. */ XSetInputFocus(display, winder, RevertToParent, CurrentTime); /* Turn off graphics exposures - if left on, a HUGE number of */ /* NoExpose events are generated, slowing things considerably */ XSetGraphicsExposures(display, theGC, False); XSetGraphicsExposures(display, unclippedGC, False); /* Set keyboard auto-repeat to off */ XAutoRepeatOff(display); /* Set the clipping region = the score box */ clip_rect.x = 0; clip_rect.y = P->height + 4; clip_rect.width = vdevice.sizeSx; clip_rect.height = vdevice.sizeSy - (int) (P->height + 4); /* Set outlines for engine heat bars */ wo7 = (int) (vdevice.sizeSx / 7); wo40 = (int) (vdevice.sizeSx / 40); eng_outlinel.x = P->width + 150; eng_outlinel.y = 7; eng_outlinel.height = (int) P->height - 11; eng_outlinel.width = wo7; eng_outliner.x = 6 * wo7 - 5; eng_outliner.y = 7; eng_outliner.height = P->height - 11; eng_outliner.width = wo7; back_used = 0; } /* ** XPM_MAKE_PIXMAPS ** */ void Xpm_make_pixmaps(obj) Sprite *obj; { int i, status; Sprite *root_obj; XpmAttributes attributes; attributes.valuemask = XpmCloseness|XpmReturnExtensions|XpmColormap; attributes.extensions = NULL; attributes.colormap = colormap; attributes.closeness = 40000; root_obj = obj; X_frontbuf(); X_color(BLACK); for (i=0;inum_pixmaps;i++) { status = XpmCreatePixmapFromData(display, DefaultRootWindow(display), obj->pixmap_data[i], &obj->pixmaps[i], &obj->clipmasks[i], &attributes); if (i == 0) { X_draw_one_object(obj, (int) ((vdevice.sizeSx - obj->width) / 2), (int) ((vdevice.sizeSy / 2) + 50)); } X_update(0); } switch (status) { case XpmColorError: printf("Could not parse or allocate requested color\n"); break; case XpmNoMemory: printf("Not enough memory\n"); break; case XpmColorFailed: printf("Failed to parse or alloc some color\n"); break; } XFillRectangle(display, winder, theGC, (int) (vdevice.sizeSx - obj->width) / 2, (int) (vdevice.sizeSy / 2) + 50, obj->width, obj->height); XFlush(display); obj->orig_pixmaps = obj->pixmaps; obj->orig_clipmasks = obj->clipmasks; while (obj = obj->next) { for (i=0;inum_pixmaps;i++) { obj->pixmaps[i] = root_obj->pixmaps[i]; obj->clipmasks[i] = root_obj->clipmasks[i]; } obj->orig_pixmaps = obj->pixmaps; obj->orig_clipmasks = obj->clipmasks; }; X_backbuf(); X_color(BLACK); } /* end XPM_MAKE_PIXMAPS */ /* ** X_ROTATE_PIXMAP_DATA ** ** Rotates the given pixmap of height h and width w by angle alpha. ** Alpha ranges from 0 (no rotation) to MAPS_PER_360 (360 degrees). ** ** Output is not interpolated - "holes" may result. */ char **X_rotate_pixmap_data(orig_pmap, h, w, alpha) char **orig_pmap; unsigned int h, w; unsigned int alpha; { char **rot_pmap; unsigned int i, x, y; unsigned int w2, colors, h2, perchar; int m, n; char pix_val, blank_val; float wo2, ho2, x2, y2; wo2 = w / 2; ho2 = h / 2; sscanf(orig_pmap[0], "%d %d %d %d", &w2, &h2, &colors, &perchar); /* Copy header */ rot_pmap = (char **) calloc(colors + h + 1, sizeof(char *)); for (i=0;i 0) { rot_pmap[n+colors+1][m] = pix_val; } } } for (m=colors+1;mnum_pixmaps; for (i=1;ipixmap_data[i] = X_rotate_pixmap_data(obj->pixmap_data[0], obj->height, obj->width, i); } } /* end X_SPIN_PIXMAP360 */ /* ** X_INIT_PIXMAPS ** */ void X_init_pixmaps() { int i, j, k, len1, len2, wid1, wid2; char *str1 = "ROTATING PIXMAPS"; char *str2 = "Be patient, or else you won't get to play"; font_info = XLoadQueryFont(display, "9x15"); len1 = strlen(str1); len2 = strlen(str2); wid1 = XTextWidth(font_info, str1, len1); wid2 = XTextWidth(font_info, str2, len2); X_color(YELLOW); XDrawString(display, winder, theGC, (vdevice.sizeSx / 2) - wid1 / 3, vdevice.sizeSy / 2 - 50, str1, len1); X_color(RED); XDrawString(display, winder, theGC, (vdevice.sizeSx / 2) - wid2 / 3, vdevice.sizeSy / 2, str2, len2); X_color(BLACK); Xpm_make_pixmaps(P); Xpm_make_pixmaps(P->next); Xpm_make_pixmaps(Slrb); Xpm_make_pixmaps(Homer); Xpm_make_pixmaps(Resur); Xpm_make_pixmaps(Power_Up); Xpm_make_pixmaps(Meta); Xpm_make_pixmaps(Flame); Xpm_make_pixmaps(Big_O); for (i=0;i<4;i++) Xpm_make_pixmaps(Shrd[i]); for (i=0;inum_pixmaps;k++) { Med_O[i][j].pixmaps[k] = Med_O[0]->pixmaps[k]; Med_O[i][j].clipmasks[k] = Med_O[0]->clipmasks[k]; } } } } for (i=0;inum_pixmaps;k++) { Sml_O[i][j].pixmaps[k] = Sml_O[0]->pixmaps[k]; Sml_O[i][j].clipmasks[k] = Sml_O[0]->clipmasks[k]; } } } } X_frontbuf(); X_clear(); X_backbuf(); X_clear(); XSetClipRectangles(display, theGC, 0, 0, &clip_rect, 1, Unsorted); } /* end X_INIT_PIXMAPS */ /* * X_exit * * cleans up before returning the window to normal. */ void X_exit() { XAutoRepeatOn(display); XFlush(display); XFreeGC(display, theGC); if (back_used) XFreePixmap(display, bbuf); XUnmapWindow(display, winder); XDestroyWindow(display, winder); } /* ** X_clear_key_buffer ** */ void X_clear_key_buffer() { XEvent *event; event = (XEvent *) calloc(1, sizeof(XEvent)); while (XCheckWindowEvent(display, winder, (KeyPressMask | KeyReleaseMask), event)); } /* end X_clear_key_buffer */ /* ** X_get_menu_keys ** */ int X_get_menu_keys() { static int r, dl; XEvent *event; char cc[1]; KeySym key; event = (XEvent *) calloc(1, sizeof(XEvent)); if (dl) dl--; if (r == ENTER) r = 0; XCheckWindowEvent(display, winder, (KeyPressMask | KeyReleaseMask), event); if (event->type == KeyPress) { XLookupString((XKeyEvent *) event, &cc[0], 1, &key, NULL); dl = 0; switch (key) { case XK_Up: case XK_KP_8: r = UPARROW; break; case XK_Down: case XK_KP_2: r = DOWNARROW; break; case XK_Left: case XK_KP_4: r = LEFTARROW; break; case XK_Right: case XK_KP_6: r = RIGHTARROW; break; case XK_Return: case XK_KP_Enter: r = ENTER; break; default: break; } } else if (event->type == KeyRelease) { r = 0; dl = 0; } if (dl) { return(0); } else { dl = 20; return(r); } } /* end X_GET_MENU_KEYS */ /* ** X_check_keypress ** */ void X_check_keypress() { XEvent event; KeySym key; char c[1]; XComposeStatus compose; c[0] = '\0'; while (XCheckWindowEvent(display, winder, (KeyReleaseMask | KeyPressMask), &event)) { XLookupString( (XKeyEvent *) &event, &c[0], 1, &key, &compose); switch (event.type) { case KeyPress: switch (key) { case XK_Up: case XK_KP_8: case XK_R8: keyboard_state = keyboard_state | KEY_THRUST1; break; case XK_Left: case XK_KP_4: case XK_R10: keyboard_state = keyboard_state | KEY_LEFT1; break; case XK_Right: case XK_KP_6: case XK_R12: keyboard_state = keyboard_state | KEY_RIGHT1; break; case XK_Shift_R: keyboard_state = keyboard_state | KEY_FIRE1; break; case XK_Return: keyboard_state = keyboard_state | KEY_HYPER1; break; case XK_F: case XK_f: keyboard_state = keyboard_state | KEY_THRUST2; break; case XK_C: case XK_c: keyboard_state = keyboard_state | KEY_LEFT2; break; case XK_B: case XK_b: keyboard_state = keyboard_state | KEY_RIGHT2; break; case XK_Shift_L: keyboard_state = keyboard_state | KEY_FIRE2; break; case XK_space: keyboard_state = keyboard_state | KEY_HYPER2; break; case XK_Q: case XK_q: keyboard_state = keyboard_state | KEY_QUIT; break; case XK_P: case XK_p: keyboard_state = keyboard_state | KEY_PAUSE; break; case XK_Escape: keyboard_state = keyboard_state | KEY_ESC; break; case XK_underscore: case XK_minus: if (delay < 2000) delay += 10; break; case XK_plus: case XK_equal: if (delay > 0) delay -= 10; break; default: break; } break; case KeyRelease: switch (key) { case XK_Up: case XK_KP_8: case XK_R8: keyboard_state = keyboard_state & ~KEY_THRUST1; break; case XK_Left: case XK_KP_4: case XK_R10: keyboard_state = keyboard_state & ~KEY_LEFT1; break; case XK_Right: case XK_KP_6: case XK_R12: keyboard_state = keyboard_state & ~KEY_RIGHT1; break; case XK_Shift_R: keyboard_state = keyboard_state & ~KEY_FIRE1; break; case XK_F: case XK_f: keyboard_state = keyboard_state & ~KEY_THRUST2; break; case XK_C: case XK_c: keyboard_state = keyboard_state & ~KEY_LEFT2; break; case XK_B: case XK_b: keyboard_state = keyboard_state & ~KEY_RIGHT2; break; case XK_Shift_L: keyboard_state = keyboard_state & ~KEY_FIRE2; break; default: break; } break; default: break; } } } /* end X_CHECK_KEYPRESS */ /* ** X_DRAW_OBJECT ** */ void X_draw_object(obj) Sprite *obj; { do { if ((obj->state == EXPLODING || obj->state == REVIVING) && obj->death_sprite) X_draw_object(obj->death_sprite); if (obj->state <= DYING) { XSetClipOrigin(display, theGC, (int) obj->x - obj->wo2, (int) obj->y - obj->ho2); XSetClipMask(display, theGC, obj->clipmasks[obj->curr_map]); XCopyArea(display, obj->pixmaps[obj->curr_map], theDrawable, theGC, 0, 0, obj->width, obj->height, (int) obj->x - obj->wo2, (int) obj->y - obj->ho2); } } while (obj = obj->next_draw); XSetClipRectangles(display, theGC, 0, 0, &clip_rect, 1, Unsorted); } /* END X_DRAW_OBJECT */ /* ** X_DRAW_ONE_OBJECT ** */ void X_draw_one_object(obj, x, y) Sprite *obj; int x, y; { XSetClipOrigin(display, theGC, x, y); XSetClipMask(display, theGC, obj->clipmasks[0]); XCopyArea(display, obj->pixmaps[0], theDrawable, theGC, 0, 0, obj->width, obj->height, x, y); XSetClipRectangles(display, theGC, 0, 0, &clip_rect, 1, Unsorted); } /* END X_DRAW_ONE_OBJECT */ /* ** X_DRAW_LINK ** ** Draws a line from the object to obj->next */ void X_draw_link(obj, col) Sprite *obj; int col; { static int old_x, old_y, old_xl, old_yl; if (!(obj->state || obj->next->state)) { X_frontbuf(); X_color(BLACK); XDrawLine(display, winder, theGC, (int) obj->ox, (int) obj->oy, (int) obj->next_draw->ox, (int) obj->next_draw->oy); X_color(col); XDrawLine(display, winder, theGC, (int) obj->x, (int) obj->y, (int) obj->next_draw->x, (int) obj->next_draw->y); X_color(BLACK); X_backbuf(); if (old_x) { old_x = old_y = 0; } } else if (!obj->state) { X_frontbuf(); X_color(BLACK); if (!old_x) { old_x = (int) obj->ox; old_y = (int) obj->oy; old_xl = (int) (obj->ox - 2*link.length * sin(link.ang - link.ang_vec)); old_yl = (int) (obj->oy - 2*link.length * cos(link.ang - link.ang_vec)); } XDrawLine(display, winder, theGC, old_x, old_y, old_xl, old_yl); old_x = (int) obj->x; old_y = (int) obj->y; old_xl = (int) (obj->x - 2*link.length * sin(link.ang - link.ang_vec)); old_yl = (int) (obj->y - 2*link.length * cos(link.ang - link.ang_vec)); X_color(col); XDrawLine(display, winder, theGC, old_x, old_y, old_xl, old_yl); X_color(BLACK); X_backbuf(); } else if (!obj->next->state) { X_frontbuf(); X_color(BLACK); if (!old_x) { old_x = (int) obj->next->ox; old_y = (int) obj->next->oy; old_xl = (int) (obj->next->ox + 2*link.length * sin(link.ang - link.ang_vec)); old_yl = (int) (obj->next->oy + 2*link.length * cos(link.ang - link.ang_vec)); } XDrawLine(display, winder, theGC, old_x, old_y, old_xl, old_yl); old_x = (int) obj->next->x; old_y = (int) obj->next->y; old_xl = (int) (obj->next->x + 2*link.length * sin(link.ang - link.ang_vec)); old_yl = (int) (obj->next->y + 2*link.length * cos(link.ang - link.ang_vec)); X_color(col); XDrawLine(display, winder, theGC, old_x, old_y, old_xl, old_yl); X_color(BLACK); X_backbuf(); } } /* end X_DRAW_LINK */ /* ** X_DRAW_STARS ** */ void X_draw_stars(col, b) int col, b; { int x0, y0, x_or, y_or, x_rot, y_rot, i; x_or = 0; y_or = 0; if (b) num_bursts = 0; X_color(col); for (x0 = x_or;x0 < vdevice.sizeSx;x0 += 600) { for (y0 = y_or;y0 < vdevice.sizeSy;y0 += 400) { for (i=0;iname, P->score); if (num_players > 1) sprintf(str2, "%s Score: %d", P->next->name, P->next->score); X_frontbuf(); X_color(BLACK); XFillRectangle(display, theDrawable, unclippedGC, 0, 0, vdevice.sizeSx, P->height + 3); XFlush(display); if (num_players > 1) { X_draw_one_object(P->next, 5, 0); X_draw_one_object(P, eng_outliner.x - 175, 0); } else { for (i=0;ilives;i++) { X_draw_one_object(P, i * (int) (P->width + 5) + 5, 0); } } X_color(WHITE); if (num_players > 1) { XDrawString(display, theDrawable, unclippedGC, 10 + P->width, P->height - 7, str2, strlen(str2)); XDrawString(display, theDrawable, unclippedGC, eng_outliner.x - 170 + P->width, P->height - 7, str1, strlen(str1)); XDrawRectangle(display, theDrawable, unclippedGC, eng_outlinel.x, eng_outlinel.y, eng_outlinel.width, eng_outlinel.height); } else { XDrawString(display, theDrawable, unclippedGC, 10 + (P->lives > 0 ? P->lives : 1) * (P->width + 5), P->height - 7, str1, strlen(str1)); } XDrawRectangle(display, theDrawable, unclippedGC, eng_outliner.x, eng_outliner.y, eng_outliner.width, eng_outliner.height); XDrawLine(display, theDrawable, unclippedGC, 0, P->height + 3, vdevice.sizeSx, P->height + 3); X_color(BLACK); X_backbuf(); } /* end X_DRAW_STATUS_BAR */ /* ** X_update_status_bar ** */ void X_update_status_bar() { int new_val; XFillRectangle(display, theDrawable, unclippedGC, eng_outliner.x, eng_outliner.y, eng_outliner.width, eng_outliner.height); XFlush(display); new_val = (int) (wo7 * P->engine / 1000); if (P->engine > 750) { X_color(RED); } else if (P->engine > 500) { X_color(YELLOW); } else X_color(GREEN); XFillRectangle(display, theDrawable, unclippedGC, eng_outliner.x+1, eng_outliner.y+1, new_val, eng_outliner.height-2); if (num_players > 1) { X_color(BLACK); XFillRectangle(display, theDrawable, unclippedGC, eng_outlinel.x, eng_outlinel.y, eng_outlinel.width, eng_outlinel.height); XFlush(display); new_val = (int) (wo7 * P->next->engine / 1000); if (P->next->engine > 750) { X_color(RED); } else if (P->next->engine > 500) { X_color(YELLOW); } else X_color(GREEN); XFillRectangle(display, theDrawable, unclippedGC, eng_outlinel.x+1, eng_outlinel.y+1, new_val, eng_outlinel.height-2); } X_color(BLACK); } /* end UPDATE_STATUS_BAR */ /* * X_FLASH_SCREEN * * Clear the screen (or current buffer ) */ void X_flash_screen(d) int d; { int i; X_frontbuf(); X_color(WHITE); XSetClipRectangles(display, theGC, 0, 0, &clip_rect, 1, Unsorted); for (i=0;icurr_map] - y1*sin_table[obj->curr_map]; n1 = -x1*sin_table[obj->curr_map] - y1*cos_table[obj->curr_map]; X_color(RED); for (i=1;icurr_map] - y2*sin_table[obj->curr_map]; n2 = -x2*sin_table[obj->curr_map] - y2*cos_table[obj->curr_map]; XDrawLine(display, theDrawable, theGC, m1 + (int) obj->x, n1 + (int) obj->y, m2 + (int) obj->x, n2 + (int) obj->y); m1 = m2; n1 = n2; } X_color(BLACK); } /* end X_DRAW_THRUST */ /* ** X_DRAW_BURSTS ** */ void X_draw_bursts(flag) int flag; { int i,j,x,y; for (i=0;ishots) { X_color(obj->shot_color); for (i=0;ishots;i++) { curr = obj->S[i]; for (j=0;j<4;j++) XDrawLine(display, theDrawable, theGC, (int) curr->x + curr->pts_x[j], (int) curr->y + curr->pts_y[j], (int) curr->x + curr->pts_x[j+1], (int) curr->y + curr->pts_y[j+1]); } } } while (obj = obj->next); X_color(BLACK); } /* end X_DRAW_SHOTS */ /* ** X_CLEAR_SHOTS ** */ void X_clear_shots(obj) Sprite *obj; { int i, j; float s, c; struct Shot *curr; X_color(BLACK); do { if (obj->shots) { for (i=0;ishots;i++) { curr = obj->S[i]; for (j=0;j<4;j++) XDrawLine(display, theDrawable, theGC, (int) curr->ox + curr->pts_x[j], (int) curr->oy + curr->pts_y[j], (int) curr->ox + curr->pts_x[j+1], (int) curr->oy + curr->pts_y[j+1]); } } } while (obj = obj->next); } /* end X_CLEAR_SHOTS */ /* ** X_CLEAR_OBJECT ** */ void X_clear_object(obj) Sprite *obj; { do { if ((obj->state == EXPLODING || obj->state == REVIVING) && obj->death_sprite) X_clear_object(obj->death_sprite); if (obj->state <= DYING) XFillRectangle(display, theDrawable, theGC, (int) obj->ox - obj->wo2, (int) obj->oy - obj->ho2, obj->width, obj->height); } while (obj = obj->next_draw); } /* end X_CLEAR_OBJECT */ /* ** X_CLEAR_ONE_OBJECT ** */ void X_clear_one_object(obj) Sprite *obj; { XFillRectangle(display, theDrawable, theGC, (int) obj->x - obj->wo2, (int) obj->y - obj->ho2, obj->width, obj->height); } /* end X_CLEAR_ONE_OBJECT */ /* ** ** X_COPY_STATUS_BAR_TO_WINDOW ** */ void X_copy_status_bar_to_window() { XFlush(display); if (num_players > 1) XCopyArea(display, theDrawable, winder, unclippedGC, eng_outlinel.x+1, eng_outlinel.y+1, eng_outlinel.width-2, eng_outlinel.height-2, eng_outlinel.x+1, eng_outlinel.y+1 ); XCopyArea(display, theDrawable, winder, unclippedGC, eng_outliner.x+1, eng_outliner.y+1, eng_outliner.width-2, eng_outliner.height-2, eng_outliner.x+1, eng_outliner.y+1 ); XFlush(display); } /* end X_COPY_STATUS_BAR_TO_WINDOW */ /* * X_COPY_OBJECT_TO_WINDOW * * Swap the back and from buffers. (Really, just copy the * back buffer to the screen). */ void X_copy_object_to_window(obj) Sprite *obj; { int i, sz; struct Shot *curr; XFlush(display); X_backbuf(); do { sz = Weapon[obj->wpn].size + 2; if ((obj->state == EXPLODING || obj->state == REVIVING) && obj->death_sprite) X_copy_object_to_window(obj->death_sprite); if (obj->state <= DYING) { XCopyArea(display, theDrawable, winder, theGC, (int) obj->x - obj->wo2, (int) obj->y - obj->ho2, obj->width, obj->height, (int) obj->x - obj->wo2, (int) obj->y - obj->ho2 ); XCopyArea(display, theDrawable, winder, theGC, (int) obj->ox - obj->wo2, (int) obj->oy - obj->ho2, obj->width, obj->height, (int) obj->ox - obj->wo2, (int) obj->oy - obj->ho2 ); } if (obj->shots) { for (i=0;ishots;i++) { curr = obj->S[i]; XCopyArea(display, theDrawable, winder, theGC, (int) curr->x-sz, (int) curr->y-sz, 2*sz, 2*sz, (int) curr->x-sz, (int) curr->y-sz ); XCopyArea(display, theDrawable, winder, theGC, (int) curr->ox-sz, (int) curr->oy-sz, 2*sz, 2*sz, (int) curr->ox-sz, (int) curr->oy-sz ); } } XFlush(display); } while (obj = obj->next_draw); XSetFunction(display, theGC, GXcopy); } /* end X_COPY_OBJECT_TO_WINDOW */ /* * X_draw * * draws a line from the current graphics position to (x, y). * * Note: (0, 0) is defined as the top left of the window in X (easy * to forget). */ X_draw(x, y) int x, y; { XDrawLine(display, theDrawable, theGC, vdevice.cpVx, vdevice.sizeSy - vdevice.cpVy, x, vdevice.sizeSy - y ); XFlush(display); } /* ** X_point ** ** Draw a point! ** */ void X_point(x, y) int x, y; { XDrawPoint(display, winder, theGC, x, y); } /* end X_point */ /* * X_getkey * * grab a character from the keyboard - blocks until one is there. */ int X_getkey() { char c; XEvent event; do { XNextEvent(display, &event); if (event.type == KeyPress) { if (XLookupString( (XKeyEvent *) &event, &c, 1, NULL, NULL) > 0) return((int) c); else return(0); } } while (event.type != KeyPress); return(0); } /* ** X_UPDATE ** ** Flush the X server's queue and handle visilibity and ** window resizing events. ** */ void X_update(game_flag) unsigned int game_flag; { XEvent event; /* Check for expose events */ if (XCheckWindowEvent(display, winder, VisibilityChangeMask, &event)) { X_frontbuf(); X_clear(); if (game_flag) { X_backbuf(); X_draw_status_bar(); } } /* Check for window resize */ if (XCheckWindowEvent(display, winder, StructureNotifyMask, &event)) { if (event.type == ConfigureNotify) { vdevice.sizeSx = event.xconfigure.width; vdevice.sizeSy = event.xconfigure.height; if (vdevice.sizeSx < 320) vdevice.sizeSx = 320; if (vdevice.sizeSy < 200) vdevice.sizeSy = 200; /* Set the clipping region = the score box */ clip_rect.x = 0; clip_rect.y = P->height + 4; clip_rect.width = vdevice.sizeSx; clip_rect.height = vdevice.sizeSy - (int) (P->height + 4); XSetClipRectangles(display, theGC, 0, 0, &clip_rect, 1, Unsorted); /* Change the size of the back buffer */ XFreePixmap(display, bbuf); bbuf = XCreatePixmap(display, (Drawable)winder, (unsigned int)vdevice.sizeSx, (unsigned int)vdevice.sizeSy, (unsigned int)vdevice.depth ); /* Set outlines for engine heat bars */ wo7 = (int) (vdevice.sizeSx / 7); wo40 = (int) (vdevice.sizeSx / 40); eng_outlinel.x = 150 + P->width; eng_outlinel.y = 7; eng_outlinel.height = (int) P->height - 11; eng_outlinel.width = wo7; eng_outliner.x = 6 * wo7 - 5; eng_outliner.y = 7; eng_outliner.height = P->height - 11; eng_outliner.width = wo7; X_frontbuf(); X_clear(); if (game_flag) { X_backbuf(); X_clear(); X_draw_status_bar(); } } } /* Use XSYNC so that keyboard is ALWAYS updated! */ XSync(display, 0); } /* end X_UPDATE */ /* * X_checkkey * * Check if there has been a keyboard key pressed. * and return it if there is. */ int X_checkkey() { char c; XEvent event; if (!XCheckWindowEvent(display, winder, KeyPressMask, &event)) return(0); if (event.type == KeyPress) if (XLookupString( (XKeyEvent *) &event, &c, 1, NULL, NULL) > 0) return((int)c); return(0); } /* * X_locator * * return the window location of the cursor, plus which mouse button, * if any, is been pressed. */ int X_locator(wx, wy) int *wx, *wy; { Window rootw, childw; int x, y; unsigned int mask; XQueryPointer(display, winder, &rootw, &childw, &x, &y, wx, wy, &mask); *wy = (int)vdevice.sizeSy - *wy; return(mask >> 8); } /* * X_clear * * Clear the screen (or current buffer )to current colour */ void X_clear() { X_color(BLACK); XFillRectangle(display, theDrawable, theGC, 0, 0, vdevice.sizeSx, vdevice.sizeSy ); } /* * X_color * * set the current drawing color index. */ void X_color(ind) int ind; { colour = carray[ind]; XSetForeground(display, theGC, colour); XSetForeground(display, unclippedGC, colour); } /* * X_mapcolor * * change index i in the color map to the appropriate r, g, b, value. */ int X_mapcolor(i, r, g, b) int i; int r, g, b; { int stat; XColor tmp; if (i >= CMAPSIZE) return(-1); /* * For Black and White. * If the index is 0 and r,g,b != 0 then we are remapping black. * If the index != 0 and r,g,b == 0 then we make it black. */ if (vdevice.depth == 1) { if (i == 0 && (r != 0 || g != 0 || b != 0)) carray[i] = WhitePixel(display, screen); else if (i != 0 && r == 0 && g == 0 && b == 0) carray[i] = BlackPixel(display, screen); } else { tmp.red = (unsigned short)(r / 255.0 * 65535); tmp.green = (unsigned short)(g / 255.0 * 65535); tmp.blue = (unsigned short)(b / 255.0 * 65535); tmp.flags = 0; tmp.pixel = (unsigned long)i; if ((stat = XAllocColor(display, colormap, &tmp)) == 0) { fprintf(stderr, "XAllocColor failed (status = %d)\n", stat); exit(1); } carray[i] = tmp.pixel; } XFlush(display); return(0); } /* * X_font * * Set up a hardware font. Return 1 on success 0 otherwise. * */ X_font(fontfile) char *fontfile; { XGCValues xgcvals; if (font_id != (XFontStruct *)NULL) XFreeFont(display, font_id); if (strcmp(fontfile, "small") == 0) { if ((font_id = XLoadQueryFont(display, SMALLX11R2)) == (XFontStruct *)NULL) { /* X11 R2 */ if ((font_id = XLoadQueryFont(display, SMALLX11R3)) == (XFontStruct *)NULL) /* X11 R3 */ return(0); else fontfile = SMALLX11R3; } else fontfile = SMALLX11R2; } else if (strcmp(fontfile, "large") == 0) { if ((font_id = XLoadQueryFont(display, LARGEX11R2)) == (XFontStruct *)NULL) { /* X11 R2 */ if ((font_id = XLoadQueryFont(display, LARGEX11R3)) == (XFontStruct *)NULL) /* X11 R3 */ return(0); else fontfile = LARGEX11R3; } else fontfile = LARGEX11R2; } else if ((font_id = XLoadQueryFont(display, fontfile)) == (XFontStruct *)NULL) return(0); vdevice.hheight = font_id->max_bounds.ascent + font_id->max_bounds.descent; vdevice.hwidth = font_id->max_bounds.width; xgcvals.font = XLoadFont(display, fontfile); XChangeGC(display, theGC, GCFont, &xgcvals); return(1); } /* * X_char * * outputs one char - is more complicated for other devices */ X_char(c) char c; { char *s = " "; s[0] = c; XDrawString(display, theDrawable, theGC, vdevice.cpVx, (int)(vdevice.sizeSy - vdevice.cpVy), s, 1); XFlush(display); } /* * X_string * * Display a string centered at the specified height */ void X_string(s, y) char *s; int y; { int len, wid; len = strlen(s); wid = XTextWidth(font_info, s, len); XDrawString(display, theDrawable, theGC, (int) (vdevice.sizeSx / 2 - wid / 3), y, s, len); XSync(display, 0); } /* * X_fill * * fill a polygon */ X_fill(n, x, y) int n, x[], y[]; { XPoint plist[128]; int i; if (n > 128) perror("xoids: more than 128 points in a polygon"); for (i = 0; i < n; i++) { plist[i].x = x[i]; plist[i].y = vdevice.sizeSy - y[i]; } XFillPolygon(display, theDrawable, theGC, plist, n, Nonconvex, CoordModeOrigin); vdevice.cpVx = x[n-1]; vdevice.cpVy = y[n-1]; XFlush(display); } #define GC_COPY_MASK ~0 /* * X_backbuf * * Set up double buffering by allocating the back buffer and * setting drawing into it. */ void X_backbuf() { if (!back_used) bbuf = XCreatePixmap(display, (Drawable)winder, (unsigned int)vdevice.sizeSx, (unsigned int)vdevice.sizeSy, (unsigned int)vdevice.depth ); theDrawable = (Drawable)bbuf; back_used = 1; } /* * X_swapbuf * * Swap the back and from buffers. (Really, just copy the * back buffer to the screen). */ void X_swapbuf() { XCopyArea(display, theDrawable, winder, theGC, 0, P->height + 4, vdevice.sizeSx+1, vdevice.sizeSy-P->height-3, 0, P->height + 4 ); XSync(display, 0); /* Not XFlush */ } /* * X_frontbuf * * Make sure we draw to the screen. */ void X_frontbuf() { theDrawable = (Drawable)winder; } /* ** X_PRINT_QUEUE ** */ void X_print_queue() { int q; q = XEventsQueued(display, QueuedAlready); fprintf(stderr, "Queued: %d events\n", q); } /* end X_PRINT_QUEUE */