/*****************************************************************************/ /* */ /* */ /* X patience version 2 -- module X-gfx1.c */ /* */ /* card graphics for the X interface */ /* written by Heiko Eissfeldt and Michael Bischoff */ /* based on the gfx.c module from Spider by Dave Lemke */ /* see COPYRIGHT.xpat2 for Copyright details */ /* */ /* */ /*****************************************************************************/ #include "X-pat.h" #ifndef NO_XPM #include #endif #ifndef NO_ROUND_CARDS #include #endif #ifdef SAVE_IMAGES #ifdef NO_XPM #error "Cannot define SAVE_IMAGES with NO_XPM" #endif static void write_pixmap(const char *filename, Pixmap pict, Pixmap clip) { if (XpmWriteFileFromPixmap(dpy, filename, pict, clip, NULL) != XpmSuccess) fprintf(stderr, "error writing xpm file %s\n", filename); } #endif static int read_pixmap(const char *filename, Pixmap *pict) { #ifndef NO_XPM if (XpmReadFileToPixmap(dpy, table, filename, pict, NULL, NULL) == XpmSuccess) { /* add nice outline which may vary (-cround option) */ #ifndef NO_ROUND_CARDS if (ROUND_W) XmuDrawRoundedRectangle(dpy, *pict, blackgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); else #endif XDrawRectangle(dpy, *pict, blackgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1); return 1; } #endif *pict = 0; return 0; } /* card INFO: taken from spider */ /* these are for the large cards */ /* all small card info is variable */ #define FCARD_WIDTH 79 #define FCARD_HEIGHT 123 /* this is the size of the bounding rectangle of the pictures for internal cards */ #define FACECARD_WIDTH 48 #define FACECARD_HEIGHT 92 #define RANK_WIDTH 9 #define RANK_HEIGHT 14 #define RANK_LOC_X 4 #define RANK_LOC_Y 7 #define SMALL_LOC_X 4 #define SMALL_LOC_Y (RANK_HEIGHT + RANK_LOC_Y + 3) #define MID_CARD_X (CARD_WIDTH/2) #define MID_CARD_Y (CARD_HEIGHT/2) #define CARD_COL1_X (3 * CARD_WIDTH/10) #define CARD_COL2_X (CARD_WIDTH/2) #define CARD_COL3_X (7 * CARD_WIDTH/10) /* 5 diff rows for the two main columns */ /* 1 and 5 are top and bottom, 3 is the middle */ /* 2 & 4 are for the 10 & 9 */ #define CARD_ROW1_Y (CARD_HEIGHT/5) #define CARD_ROW2_Y (2 * CARD_HEIGHT/5) #define CARD_ROW3_Y (CARD_HEIGHT/2) #define CARD_ROW4_Y (CARD_HEIGHT - 2 * CARD_HEIGHT/5) #define CARD_ROW5_Y (CARD_HEIGHT - CARD_HEIGHT/5) /* between 1 & 3, 3 & 5 */ #define CARD_SEVEN_Y (7 * CARD_HEIGHT/20) #define CARD_EIGHT_Y (CARD_HEIGHT - 7 * CARD_HEIGHT/20) /* between rows 1 & 2, 4 & 5 */ #define CARD_TEN_Y1 (3 * CARD_HEIGHT/10) #define CARD_TEN_Y2 (CARD_HEIGHT - 3 * CARD_HEIGHT/10) /* pip info */ #define PIP_WIDTH 10 #define PIP_HEIGHT 10 #define NUM_RANKS 13 #define NUM_SUITS 4 #define CARDS_PER_DECK (NUM_RANKS * NUM_SUITS) static GC cardgc; /* gc in use when drawing cards */ static GC backgc; /* gc in use when drawing cardbacks */ static GC redgc; /* gc for red parts of the cards */ /* default cards: */ #include "rank.bm" /* rank symbol bitmaps */ #include "face.bm" /* bitmaps for jack, queen and king */ #include "suit.bm" /* suit bitmaps */ #include "logo.bm" /* bitmap used for cardbacks */ static struct suit_tab { char *bits; int w; int h; } suit_tab[] = { { club_bits, club_width, club_height }, { spade_bits, spade_width, spade_height }, { heart_bits, heart_width, heart_height }, { diamond_bits, diamond_width, diamond_height } }, suit_sm_tab[] = { { club_sm_bits, club_sm_width, club_sm_height }, { spade_sm_bits, spade_sm_width, spade_sm_height }, { heart_sm_bits, heart_sm_width, heart_sm_height }, { diamond_sm_bits, diamond_sm_width, diamond_sm_height } }, suit_lg_tab[] = { { NULL, club_width, club_height }, { spade_lg_bits, spade_lg_width, spade_lg_height }, { NULL, heart_width, heart_height }, { NULL, diamond_width, diamond_height } }; static Pixmap rank_map[NUM_RANKS], rank_r_map[NUM_RANKS]; static Pixmap rank_map_red[NUM_RANKS], rank_r_map_red[NUM_RANKS]; static Pixmap suit_map[NUM_SUITS], suit_r_map[NUM_SUITS]; static Pixmap suit_sm_map[NUM_SUITS], suit_sm_r_map[NUM_SUITS]; static Pixmap suit_lg_map[NUM_SUITS]; static Pixmap jack_map[NUM_SUITS], queen_map[NUM_SUITS], king_map[NUM_SUITS]; static Pixmap joker_map; #include "Joker.bm" #ifdef STATIC_CLIPMAPS #include "clip7.bm" #include "clip4.bm" #endif static GC cardbackgc; #ifndef NO_ROUND_CARDS static Pixmap cardclipmap; #endif static int mem_option; static const char *xpmdir; static Pixmap cardpicts[58]; /* clipping rectangles */ static XRectangle cliprects[1] = {{ 0, 0, 0, 0 }}; static int card_is_clipped; /* optimizer for card drawing */ #include "gray1.bm" static void make_GCs(unsigned long red, unsigned long cbcolor) { XGCValues gcv; long gcflags; Pixmap tmpmap; GC logogc; Pixmap logomap; gcv.graphics_exposures = False; /* make GC for RED */ if (graphic.is_color) { gcv.foreground = red; gcv.background = WhitePixel(dpy, screen); gcflags = GCForeground | GCBackground | GCGraphicsExposures; redgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv); } else { gcv.tile = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), gray1_bits, gray1_width, gray1_height); gcv.fill_style = FillTiled; gcv.foreground = BlackPixel(dpy, screen); gcv.background = WhitePixel(dpy, screen); gcflags = GCTile | GCForeground | GCBackground | GCFillStyle | GCGraphicsExposures; redgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv); } /* make GC for cardbacks */ tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), logo_bits, logo_width, logo_height); logomap = XCreatePixmap(dpy, RootWindow(dpy, screen), logo_width, logo_height, DefaultDepth(dpy, screen)); gcv.foreground = BlackPixel(dpy, screen); gcv.background = WhitePixel(dpy, screen); gcv.graphics_exposures = True; gcflags = GCForeground | GCBackground | GCGraphicsExposures; cardbackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv); if (graphic.is_color) { gcv.foreground = cbcolor; gcv.background = WhitePixel(dpy, screen); gcflags = GCForeground | GCBackground; logogc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv); XCopyPlane(dpy, tmpmap, logomap, logogc, 0, 0, logo_width, logo_height, 0, 0, 1); XFreeGC(dpy, logogc); } else { XCopyPlane(dpy, tmpmap, logomap, whitegc, 0, 0, logo_width, logo_height, 0, 0, 1); } XFreePixmap(dpy, tmpmap); gcv.tile = logomap; gcv.fill_style = FillTiled; gcflags |= GCTile | GCFillStyle | GCGraphicsExposures; backgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv); } #define S(x,y) src[(H-1-(y))*W+(x)] #define D(x,y) dst[(H-1-(y))*W+(x)] /* table for left-right mirroring of bitmaps */ static char _reverse_byte[0x100] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; static void copy_upside_down(char *src, char *dst, int W, int H) { int x, y; W = (W + 7)/8; /* round up to bytes */ for (y = 0; y < H; y++) { for (x = 0; x < W; x++) { D (x, y) = S (x, H - 1 - y); } } } /* copy a bitmap rotated from source to dest */ static void rot_180(char *src, char *dst, int W, int H) { int x, y; int width = W; char *new; int bit; W = (W + 7)/8; /* round up to bytes */ for (y = 0; y < H; y++) { for (x = 0; x < W; x++) { D (x, y) = _reverse_byte[(unsigned char)(S (W - 1 - x, H - 1 - y))]; } } /* shift it over (bit correction) */ new = calloc((size_t)W*H, 1); for (y = 0; y < H; y++) { for (x = 0; x < W*8; x++) { bit = (*(dst + (x + (W*8 - width))/8 + y * W) & (1 << ((x + (W*8 - width)) % 8))) ? 1 : 0; *(new + x/8 + y*W) = (bit << (x%8)) | (*(new + x/8 + y*W) & ~(1 << (x%8))); } } memcpy(dst, new, W*H); free(new); } /* large cards: */ /* * make a 'red' pixmap by setting the clipmask to the desired shape and * pushing 'red' through it */ static Pixmap make_color_map(char *bits, int width, int height, Suit suit) { Pixmap tmpmap, newmap; static GC cleargc = (GC) 0; XGCValues xgcv; if (suit == Spade || suit == Club || graphic.is_color) return XCreateBitmapFromData(dpy, RootWindow(dpy, screen), bits, width, height); /* get a graphic context, if not yet gotten */ if (cleargc == (GC) 0) { xgcv.function = GXclear; cleargc = XCreateGC(dpy, RootWindow(dpy, screen), GCFunction, &xgcv); } tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), bits, width, height); /* turn data into bitmap */ /* allocate a pixmap */ newmap = XCreatePixmap(dpy, RootWindow(dpy, screen), width, height, 1); /* clear red_map to white */ XFillRectangle(dpy, newmap, cleargc, 0, 0, width, height); /* use bitmap tmpmap as clipmap for red GC */ XSetClipMask(dpy, redgc, tmpmap); /* color red_map to red using the mask */ XFillRectangle(dpy, newmap, redgc, 0, 0, width, height); XSetClipMask(dpy, redgc, None); /* clear clipping mask in the red GC */ XFreePixmap(dpy, tmpmap); /* release bitmap */ return (newmap); } #ifdef LOADCARDS #include "X-loadcards.c" #endif /* build jack to king bitmaps of the internal cardset by mirroring the first half */ static char *compose_picture(char *tmp, const char *orgbits) { int cardsize = 6 * 45; /* omit one scanline */ memcpy(tmp, orgbits, cardsize); rot_180(tmp, tmp+cardsize+6, 47, 45); memset(tmp + cardsize, 0xff, 6); /* add a horizontal line in the middle */ return tmp; } static void build_internal_cardset(void) { char new_bits[120/8 * 200]; /* sufficient for the largest bitmap here */ Rank r; int i; ROUND_W = ROUND_H = 9; STD_DELTA = 25; /* create bitmaps for rank symbols normal and rotated */ for (r = Ace; r <= King; r++) { rank_map[(int)r] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), rank_bits[(int)r], rank_width, rank_height); rot_180(rank_bits[(int)r], new_bits, rank_width, rank_height); rank_r_map[(int)r] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), new_bits, rank_width, rank_height); if (graphic.is_color) { rank_map_red[(int)r] = rank_map[(int)r]; rank_r_map_red[(int)r] = rank_r_map[(int)r]; } else { rank_map_red[(int)r] = make_color_map( rank_bits[(int)r], rank_width, rank_height, Heart); rank_r_map_red[(int)r] = make_color_map( new_bits, rank_width, rank_height, Heart); } } for (i = 0; i < 4; ++i) { struct suit_tab *bp; char *king_bits[] = { king_c_bits, king_s_bits, king_h_bits, king_d_bits }; char *queen_bits[] = { queen_c_bits, queen_s_bits, queen_h_bits, queen_d_bits }; char *jack_bits[] = { jack_c_bits, jack_s_bits, jack_h_bits, jack_d_bits }; bp = suit_tab + i; copy_upside_down(bp->bits, new_bits, bp->w, bp->h); suit_map[i] = make_color_map(bp->bits, bp->w, bp->h, (Suit)i); suit_r_map[i] = make_color_map(new_bits, bp->w, bp->h, (Suit)i); bp = suit_sm_tab + i; copy_upside_down(bp->bits, new_bits, bp->w, bp->h); suit_sm_map[i] = make_color_map(bp->bits, bp->w, bp->h, (Suit)i); suit_sm_r_map[i] = make_color_map(new_bits, bp->w, bp->h, (Suit)i); bp = suit_lg_tab + i; suit_lg_map[i] = bp->bits ? make_color_map(bp->bits, bp->w, bp->h, (Suit)i) : suit_map[i]; jack_map[i] = make_color_map(compose_picture(new_bits, jack_bits[i]), 47, 91, (Suit)i); queen_map[i] = make_color_map(compose_picture(new_bits, queen_bits[i]), 47, 91, (Suit)i); king_map[i] = make_color_map(compose_picture(new_bits, king_bits[i]), 47, 91, (Suit)i); } joker_map = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), Joker_bits, Joker_width, Joker_height); /* turn data into bitmap */ } void init_cards(const char *cardset, int rx, int ry, unsigned long red, unsigned long cbcolor, int mem, const char *xpm, int closeness) { #ifdef NO_ROUND_CARDS rx = ry = 0; #endif mem_option = mem; if (xpm && *xpm != '.' && *xpm != '/') { char *s; s = malloc(strlen(LIBDIR) + strlen(xpm) + 2); sprintf(s, "%s/%s", LIBDIR, xpm); xpmdir = s; } else xpmdir = xpm; /* directory where to load from the Xpm-files */ card.cardset = cardset; make_GCs(red, cbcolor); if (cardset) { /* read external cardset */ #ifdef LOADCARDS read_bitmap(cardset) #endif ; } else { /* build internal cardset */ CARD_WIDTH = -1; if (xpm) { char s[200]; FILE *fp; sprintf(s, "%s/Cards.conf", xpmdir); if ((fp = fopen(s, "r"))) { if (fscanf(fp, "%d %d", &CARD_WIDTH, &CARD_HEIGHT) != 2) CARD_WIDTH = -1; fclose(fp); } } if (CARD_WIDTH < 49 || CARD_WIDTH > 120 || CARD_HEIGHT < 95 || CARD_HEIGHT > 200) { CARD_WIDTH = FCARD_WIDTH; CARD_HEIGHT = FCARD_HEIGHT; } build_internal_cardset(); } cliprects[0].width = CARD_WIDTH + 1; /* sanity checks: */ if (2 * rx >= (int)CARD_WIDTH) rx = CARD_WIDTH / 2; if (2 * ry >= (int)CARD_HEIGHT) ry = CARD_HEIGHT / 2; /* assign values */ if (rx >= 0) card.rx = rx; if (ry >= 0) card.ry = ry; card.back_delta_x = (CARD_WIDTH - logo_width)/2; card.back_delta_y = (CARD_HEIGHT - logo_height)/2; /* finally, compute a clipping mask for the cards */ /* apply this clip mask to cardbackgc */ #ifndef NO_ROUND_CARDS #ifndef STATIC_CLIPMAPS if (ROUND_W) { cardclipmap = XCreatePixmap(dpy, RootWindow(dpy, screen), CARD_WIDTH+1, CARD_HEIGHT+1, 1); { XGCValues gcv; long gcflags, f, b; GC clipgc; b = 0; f = 1; /* first, clear the clipmap */ /* (is it possible to do it easier?) */ gcv.foreground = b; gcv.background = f; gcv.graphics_exposures = False; gcflags = GCForeground | GCBackground | GCGraphicsExposures; clipgc = XCreateGC(dpy, cardclipmap, gcflags, &gcv); XFillRectangle(dpy, cardclipmap, clipgc, 0, 0, CARD_WIDTH, CARD_HEIGHT); XFreeGC(dpy, clipgc); /* make gc for clipgc */ gcv.foreground = f; gcv.background = b; gcv.graphics_exposures = False; gcflags = GCForeground | GCBackground | GCGraphicsExposures; clipgc = XCreateGC(dpy, cardclipmap, gcflags, &gcv); XmuFillRoundedRectangle(dpy, cardclipmap, clipgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); XmuDrawRoundedRectangle(dpy, cardclipmap, clipgc, 0, 0, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); XFreeGC(dpy, clipgc); } #ifdef DEBUG XWriteBitmapFile(dpy, "clip.mask.bm", cardclipmap, CARD_WIDTH, CARD_HEIGHT, -1, -1); #endif /* fill the background */ XSetClipMask(dpy, cardbackgc, cardclipmap); } #else switch (ROUND_H) { case 3: case 4: case 5: cardclipmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), clip4_bits, clip4_width, clip4_height); XSetClipMask(dpy, cardbackgc, cardclipmap); break; case 6: case 7: case 8: case 9: cardclipmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), clip7_bits, clip7_width, clip7_height); XSetClipMask(dpy, cardbackgc, cardclipmap); break; } #endif #endif } static void paint_cardback(int x, int y, int w, int h, Drawable d) { #define INSETa 1 #define INSETb 1 /* change the origin so cards will have the same back anywhere * on the table */ /* * there should be a tile centered in the card, with the * surrounding tiles being partial */ XSetClipMask(dpy, backgc, None); XSetClipMask(dpy, blackgc, None); #ifndef NO_ROUND_CARDS if (ROUND_W) { XmuFillRoundedRectangle(dpy, d, blackgc, x, y, (w == CARD_WIDTH) ? w-1 : w + ROUND_W * 2, (h == CARD_HEIGHT) ? h-1 : h + ROUND_H * 2, ROUND_W, ROUND_H); } else #endif XFillRectangle(dpy, d, blackgc, x, y, w, h); XSetTSOrigin(dpy, backgc, x + card.back_delta_x, y + card.back_delta_y); #ifndef NO_ROUND_CARDS if (ROUND_W) XmuFillRoundedRectangle(dpy, d, backgc, x + INSETa, y + INSETa, (w == CARD_WIDTH ? CARD_WIDTH - INSETa - INSETb - 1 : w + ROUND_W * 2), (h == CARD_HEIGHT ? CARD_HEIGHT - INSETa - INSETb - 1 : h + ROUND_H * 2), ROUND_W, ROUND_H); else #endif XFillRectangle(dpy, d, backgc, x + INSETa, y + INSETa, (w == CARD_WIDTH ? CARD_WIDTH - INSETa - INSETb - 1 : w - 1), (h == CARD_HEIGHT ? CARD_HEIGHT - INSETa - INSETb - 1 : h - 1)); /* correction */ #ifndef NO_ROUND_CARDS if (ROUND_W) { XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, (w == CARD_WIDTH ? w-1 : w + ROUND_W * 2), (h == CARD_HEIGHT ? h-1 : h + ROUND_H * 2), ROUND_W, ROUND_H); XmuDrawRoundedRectangle(dpy, d, blackgc, x+1, y+1, (w == CARD_WIDTH ? w-3 : w + ROUND_W * 2), (h == CARD_HEIGHT ? h-3 : h + ROUND_H * 2), ROUND_W-1, ROUND_H-1); } else #endif XDrawRectangle(dpy, d, blackgc, x+1, y+1, (w == CARD_WIDTH ? w-2 : w), (h == CARD_HEIGHT ? h-2 : h)); } /* * NOTE -- for all the pip drawers except the one that actually plots the * bits, the location is the card's location. the drawer's take the * pip's center as location. */ /* * draws right-side-up pip * * location is for center of pip */ static void draw_pip(Suit suit, int x, int y, Drawable d) { XCopyPlane(dpy, suit_map[suit], d, cardgc, 0, 0, suit_tab[suit].w, suit_tab[suit].h, x - 15/2, y - 19/2, 1); } /* * draws upside-down pip * * location is for center of pip */ static void draw_did(Suit suit, int x, int y, Drawable d) { if (card_is_clipped) /* a clipped card never shows any did's */ return; XCopyPlane(dpy, suit_map[suit], d, cardgc, 0, 0, suit_tab[suit].w, suit_tab[suit].h, x - 15/2, y - 19/2, 1); } /* * draws big center pip */ static void draw_center_pip(Suit suit, int x, int y, Drawable d) { int w, h; if (card_is_clipped) /* a clipped card never shows any big's */ return; w = suit_lg_tab[suit].w; h = suit_lg_tab[suit].h; XCopyPlane(dpy, suit_lg_map[suit], d, cardgc, 0, 0, w, h, x - w/2, y - h/2, 1); } /* * draw_two_pips */ static void draw_two_pips(Suit suit, int x, int y, Drawable d) { draw_pip(suit, x + MID_CARD_X, y + CARD_ROW1_Y, d); draw_did(suit, x + MID_CARD_X, y + CARD_ROW5_Y, d); } /* * draw_four_pips */ static void draw_four_pips(Suit suit, int x, int y, Drawable d) { draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d); draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d); draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d); draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d); } static void draw_six_pips(Suit suit, int x, int y, Drawable d) { draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d); draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d); if (card_is_clipped) return; /* these are only visible when its not clipped */ draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW3_Y, d); draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d); draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW3_Y, d); draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d); } static void draw_eight_pips(Suit suit, int x, int y, Drawable d) { draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y, d); draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y, d); if (card_is_clipped) return; /* these are only visible when its not clipped */ draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW2_Y, d); draw_did(suit, x + CARD_COL1_X, y + CARD_ROW4_Y, d); draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y, d); draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW2_Y, d); draw_did(suit, x + CARD_COL3_X, y + CARD_ROW4_Y, d); draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y, d); } static void draw_jack(Suit suit, int x, int y, Drawable d) { XCopyPlane(dpy, jack_map[suit], d, cardgc, 0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1, x + 1 + (CARD_WIDTH - FACECARD_WIDTH)/2, y + 1 + (CARD_HEIGHT - FACECARD_HEIGHT)/2, 1); XDrawRectangle(dpy, d, cardgc, x + (CARD_WIDTH - FACECARD_WIDTH)/2, y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, FACECARD_WIDTH, FACECARD_HEIGHT); } static void draw_queen(Suit suit, int x, int y, Drawable d) { XCopyPlane(dpy, queen_map[suit], d, cardgc, 0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1, x + 1+(CARD_WIDTH - FACECARD_WIDTH)/2, y + 1+(CARD_HEIGHT - FACECARD_HEIGHT)/2, 1); XDrawRectangle(dpy, d, cardgc, x + (CARD_WIDTH - FACECARD_WIDTH)/2, y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, FACECARD_WIDTH, FACECARD_HEIGHT); } static void draw_king(Suit suit, int x, int y, Drawable d) { XCopyPlane(dpy, king_map[suit], d, cardgc, 0, 0, FACECARD_WIDTH-1, FACECARD_HEIGHT-1, x + 1+(CARD_WIDTH - FACECARD_WIDTH)/2, y + 1+(CARD_HEIGHT - FACECARD_HEIGHT)/2, 1); XDrawRectangle(dpy, d, cardgc, x + (CARD_WIDTH - FACECARD_WIDTH)/2, y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, FACECARD_WIDTH, FACECARD_HEIGHT); } static void draw_rank(int x, int y, Rank rank, Suit suit, Drawable d) { if (suit == Heart || suit == Diamond) { XCopyPlane(dpy, rank_map_red[rank], d, cardgc, 0, 0, RANK_WIDTH, RANK_HEIGHT, x + RANK_LOC_X, y + RANK_LOC_Y, 1); if (!card_is_clipped) XCopyPlane(dpy, rank_r_map_red[rank], d, cardgc, 0, 0, RANK_WIDTH, RANK_HEIGHT, x + (CARD_WIDTH - RANK_WIDTH - RANK_LOC_X), y + (CARD_HEIGHT - RANK_HEIGHT - RANK_LOC_Y), 1); } else { XCopyPlane(dpy, rank_map[rank], d, cardgc, 0, 0, RANK_WIDTH, RANK_HEIGHT, x + RANK_LOC_X, y + RANK_LOC_Y, 1); if (!card_is_clipped) XCopyPlane(dpy, rank_r_map[rank], d, cardgc, 0, 0, RANK_WIDTH, RANK_HEIGHT, x + (CARD_WIDTH - RANK_WIDTH - RANK_LOC_X), y + (CARD_HEIGHT - RANK_HEIGHT - RANK_LOC_Y), 1); } { int w, h, o; w = suit_sm_tab[suit].w; h = suit_sm_tab[suit].h; o = (suit == Diamond); XCopyPlane(dpy, suit_sm_map[suit], d, cardgc, 0, 0, w, h, x + o + SMALL_LOC_X, y + SMALL_LOC_Y, 1); if (!card_is_clipped) XCopyPlane(dpy, suit_sm_r_map[suit], d, cardgc, 0, 0, w, h, x - o + (CARD_WIDTH - w - SMALL_LOC_X), y + (CARD_HEIGHT - h - SMALL_LOC_Y), 1); } } static void paint_joker(int x, int y, Drawable d) { #ifndef NO_ROUND_CARDS if (ROUND_W) { XSetClipMask(dpy, blackgc, cardclipmap); XSetClipOrigin(dpy, blackgc, x, y); } #endif XCopyPlane(dpy, joker_map, d, blackgc, 0, 0, CARD_WIDTH, CARD_HEIGHT, x, y, 1); #ifndef NO_ROUND_CARDS if (ROUND_W) XSetClipMask(dpy, blackgc, None); if (ROUND_W) XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); else #endif /* draw border on card */ XDrawRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1); } static void paint_large_card(int x, int y, int rank, Suit suit, Drawable d) { if (suit == Spade || suit == Club) { cardgc = blackgc; } else { cardgc = redgc; } #ifndef NO_ROUND_CARDS if (ROUND_W) { /* fill the background */ XmuFillRoundedRectangle(dpy, d, whitegc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); /* draw border on card */ XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); } else #endif { /* fill the background */ XFillRectangle(dpy, d, whitegc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1); /* draw border on card */ XDrawRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1); } card_is_clipped = False; switch (rank) { case King: draw_king(suit, x, y, d); break; case Queen: draw_queen(suit, x, y, d); break; case Jack: draw_jack(suit, x, y, d); break; case Ten: draw_pip(suit, MID_CARD_X + x, CARD_TEN_Y1 + y, d); draw_did(suit, MID_CARD_X + x, CARD_TEN_Y2 + y, d); draw_eight_pips(suit, x, y, d); break; case Nine: draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d); draw_eight_pips(suit, x, y, d); break; case Eight: draw_did(suit, x + MID_CARD_X, y + CARD_EIGHT_Y, d); /* fall thru */ case Seven: draw_pip(suit, MID_CARD_X + x, CARD_SEVEN_Y + y, d); /* fall thru */ case Six: draw_six_pips(suit, x, y, d); break; case Five: draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d); /* fall thru */ case Four: draw_four_pips(suit, x, y, d); break; case Three: draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d); /* fall thru */ case Deuce: draw_two_pips(suit, x, y, d); break; case 13: case Ace: draw_center_pip(suit, x + MID_CARD_X, y + MID_CARD_Y, d); break; default: assert(0); } if (rank != 13) draw_rank(x, y, rank, suit, d); /* clear the clip mask */ XSetClipMask(dpy, cardgc, None); #ifndef NO_ROUND_CARDS if (ROUND_W) { if (!x &&!y) { /* special: if round card and initial call, repaint rounding */ /* this is for extremely rounded card which get over-painted */ XmuDrawRoundedRectangle(dpy, d, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); } XSetClipMask(dpy, whitegc, None); if (cardgc != blackgc) XSetClipMask(dpy, blackgc, None); } #endif } void PaintCard(int x, int y, int c, int w, int h) { static Suit Suittab[4] = { Club, Spade, Heart, Diamond }; static int initial_call = 1; /* initial-call-flag */ /* JOKERs not yet fully implemented */ if (c == NOTHING) return; if (c != OUTLINE) { #ifdef LOADCARDS if (card.cardset) { /* externally loaded cards: */ if (IS_JOKER(c)) c = SUIT(c) + SUITSYMBOL; /* do this instead */ if (c < numcards) { paint_external_card(x, y, c); return; } else if (c == CARDBACK) { if (!w) w = CARD_WIDTH; if (!h) h = CARD_HEIGHT; paint_cardback(x, y, w, h, table); return; } else { /* must be suit symbol */ c = OUTLINE; /* do outline as replacement */ /* and fall thru */ } } else #endif { /* do default cards */ if (!mem_option) { if (IS_JOKER(c)) paint_joker(x, y, table); /* do this instead */ else if (c != CARDBACK) paint_large_card(x, y, RANK(c), Suittab[SUIT(c)], table); else { if (!w) w = CARD_WIDTH; if (!h) h = CARD_HEIGHT; paint_cardback(x, y, w, h, table); } return; } else { if (initial_call) { int i; initial_call = 0; cardpicts[57] = 0; /* Joker is loaded on request */ for (i = 0; i <= 56; ++i) { if (xpmdir && (i < 52 || i >= 56)) { char s[200]; if (i == CARDBACK) { strcpy(s, xpmdir); strcat(s, "/Cardback.xpm"); } else sprintf(s, "%s/%s.%s.xpm", xpmdir, US_rank_name[RANK(i)], US_suit_name[SUIT(i)]); if (read_pixmap(s, &cardpicts[i])) continue; /* load succeeded */ } /* no file found, must create internal card */ cardpicts[i] = XCreatePixmap(dpy, table, CARD_WIDTH, CARD_HEIGHT, DefaultDepth(dpy, screen)); if (i == CARDBACK) paint_cardback(0, 0, CARD_WIDTH, CARD_HEIGHT, cardpicts[i]); else paint_large_card(0, 0, RANK(i), Suittab[SUIT(i)], cardpicts[i]); } #ifdef SAVE_IMAGES for (i = 0; i < 52; ++i) { char s[20]; sprintf(s, "%s.%s.xpm", US_rank_name[RANK(i)], US_suit_name[SUIT(i)]); write_pixmap(s, cardpicts[i], cardclipmap); } #endif } if (IS_JOKER(c)) { c = 57; if (!cardpicts[c]) { /* must load or draw joker */ if (xpmdir) { char s[200]; sprintf(s, "%s/Joker.xpm", xpmdir); (void)read_pixmap(s, &cardpicts[c]); } if (!cardpicts[c]) { cardpicts[c] = XCreatePixmap(dpy, table, CARD_WIDTH, CARD_HEIGHT, DefaultDepth(dpy, screen)); paint_joker(0, 0, cardpicts[c]); } } } w += ROUND_W; h += ROUND_H; if (w == ROUND_W || w > CARD_WIDTH) w = CARD_WIDTH; if (h == ROUND_H || h > CARD_HEIGHT) h = CARD_HEIGHT; XSetClipOrigin(dpy, cardbackgc, x, y); XCopyArea(dpy, cardpicts[c], table, cardbackgc, 0, 0, w, h, x, y); return; } } } /* if (c == OUTLINE) */ /* to be sure the place is clear: */ XClearArea(dpy, table, x, y, CARD_WIDTH, CARD_HEIGHT, False); #ifndef NO_ROUND_CARDS if (ROUND_W) XmuDrawRoundedRectangle(dpy, table, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1, ROUND_W, ROUND_H); else #endif XDrawRectangle(dpy, table, blackgc, x, y, CARD_WIDTH-1, CARD_HEIGHT-1); }