/*
 * pcard.c -- Code to paint a card.
 *            This code is pretty much lifted entirely from spider.
 */

#include <stdlib.h>
#include <assert.h>

#include "fc.h"
#include "card.h"

#include <X11/Xmu/Drawing.h>

#include "rank.bm"
#include "suit.bm"
#include "face.bm"

/* ---------- Macros ---------- */
/* card info */
#define	MID_CARD_X	(CARD_WIDTH/2)
#define	MID_CARD_Y	(CARD_HEIGHT/2)

/* 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)

#define	FACECARD_WIDTH	47
#define	FACECARD_HEIGHT	92

#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)

#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 S(x,y) src[(H-1-(y))*W+(x)]
#define D(x,y) dst[(H-1-(y))*W+(x)]

/* ---------- Static variables ---------- */
int screen;
Window cardwin;

GC cardgc;
GC backgc;
GC blackgc;
GC whitegc;
GC redgc;
GC redblackgc;
Pixmap redmap;
int card_is_clipped;

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 XRectangle	cliprects[1] = { { 0, 0, CARD_WIDTH + 1, 0} };
   
/* ---------- Bitmaps ---------- */
/* substitue gray1 for Green on mono */
#define gray1_width 16
#define gray1_height 16
static char gray1_bits[] = {
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};

static unsigned 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
};

/* ---------- Function declarations ---------- */
static Pixmap make_red_map(char *, int, int);
void flip_bits(unsigned char *, unsigned char *, int, int);
void rot_180(unsigned char *, unsigned char *, int, int);
void draw_king(suit_e, int, int);
void draw_queen(suit_e, int, int);
void draw_jack(suit_e, int, int);
void draw_eight_pips(suit_e, int, int);
void draw_six_pips(suit_e, int, int);
void draw_four_pips(suit_e, int, int);
void draw_two_pips(suit_e, int, int);
void draw_pip(suit_e, int, int);
void draw_did(suit_e, int, int);
void draw_center_pip(suit_e, int, int);
void draw_rank(int, int, pipn_e, suit_e);

/* ------------------------------------------------------------------------ */
void
gfx_init(Display *d, int s, Window w)
{
     static inited = FALSE;
     XGCValues gcv;
     long gcflags;
     Colormap cmap;
     XColor color;
     unsigned long redpixel;

     /* Only do this once. */
     if (inited) return;
     inited = TRUE;
     
     dpy = d;
     screen = s;
     cardwin = w;

     /* make gc for white */
     gcv.foreground = WhitePixel(dpy, screen);
     gcv.background = BlackPixel(dpy, screen);
     gcv.graphics_exposures = False;
     gcflags = GCForeground | GCBackground | GCGraphicsExposures;
     
     whitegc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
     
     /* make gc for black */
     gcv.foreground = BlackPixel(dpy, screen);
     gcv.background = WhitePixel(dpy, screen);
     gcflags = GCForeground | GCBackground | GCGraphicsExposures;
     
     blackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags, &gcv);
     
     if (is_color) {
		cmap = DefaultColormap(dpy, screen);
		color.flags = DoRed | DoGreen | DoBlue;

		color.red = 52428;	/* 0.8 */
		color.green = color.blue = 0;
		XAllocColor(dpy, cmap, &color);
		redpixel = color.pixel;

		gcv.foreground = redpixel;
		gcv.background = WhitePixel(dpy, screen);
		gcflags = GCForeground | GCBackground | GCGraphicsExposures;

		redgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags,
				  &gcv);

		gcv.background = BlackPixel(dpy, screen);
		redblackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags,
				       &gcv);
     }
     else {
		redmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
			gray1_bits, gray1_width, gray1_height);
		gcv.tile = redmap;
		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);

		gcv.background = BlackPixel(dpy, screen);
		redblackgc = XCreateGC(dpy, RootWindow(dpy, screen), gcflags,
				       &gcv);
     }
     make_card_maps();
}

/* ------------------------------------------------------------------------ */
void
make_card_maps()
{
     unsigned char *new_bits;
     int r;
     int i;

     for (r = ace - 1; r < king; r++)	{
	  rank_map[(int)r] = XCreateBitmapFromData(dpy, 
						   RootWindow(dpy, screen),
						   rank_bits[(int)r], rank_width, rank_height);
	  
	  new_bits = (unsigned char *) calloc(sizeof(rank_bits[(int)r]),
					      1);
	  rot_180((unsigned char *)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);
	  free((char *)new_bits);
     }

	for (r = ace - 1; r < king; r++)	{
		new_bits = (unsigned char *) calloc(sizeof(rank_bits[(int)r]),
							1);
		rot_180((unsigned char *)rank_bits[(int)r], new_bits, 
				rank_width, rank_height);
		if (is_color)	{
			rank_map_red[(int)r] = XCreateBitmapFromData(dpy, 
				RootWindow(dpy, screen),
				rank_bits[(int)r], rank_width, rank_height);

			rank_r_map_red[(int)r] = XCreateBitmapFromData(dpy, 
				RootWindow(dpy, screen),
				new_bits, rank_width, rank_height);
		} else	{
			rank_map_red[(int)r] = make_red_map(rank_bits[(int)r],
						rank_width, rank_height);

			rank_r_map_red[(int)r] = make_red_map((char *)new_bits, 
						rank_width, rank_height);
		}
		free((char *)new_bits);
	}

	i = (int)spades;
	/* make all the card bitmaps */
	suit_map[i] = XCreateBitmapFromData(dpy, 
		RootWindow(dpy, screen),
		spade_bits, spade_width, spade_height);

	new_bits = (unsigned char *) calloc(sizeof(spade_bits), 1);
	flip_bits((unsigned char *)spade_bits, new_bits, spade_width, 
				spade_height);
	suit_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, spade_width, spade_height);
	free((char *)new_bits);

	suit_sm_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		spade_sm_bits, spade_sm_width, spade_sm_height);

	new_bits = (unsigned char *) calloc(sizeof(spade_sm_bits), 1);
	flip_bits((unsigned char *)spade_sm_bits, new_bits, spade_sm_width,
			spade_sm_height);
	suit_sm_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, spade_sm_width, spade_sm_height);
	free((char *)new_bits);

	suit_lg_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		spade_lg_bits, spade_lg_width, spade_lg_height);

	jack_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		jack_s_bits, jack_s_width, jack_s_height);

	queen_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		queen_s_bits, queen_s_width, queen_s_height);

	king_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		king_s_bits, king_s_width, king_s_height);

	i = (int)hearts;
	/* make all the card bitmaps */
	new_bits = (unsigned char *) calloc(sizeof(heart_bits), 1);
	flip_bits((unsigned char *)heart_bits, new_bits, heart_width, 
					heart_height);

	if (is_color)	{
		suit_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			heart_bits, heart_width, heart_height);
		suit_r_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			new_bits, heart_width, heart_height);
	} else	{
		suit_map[i] = make_red_map(heart_bits, heart_width, 
						heart_height);
		suit_r_map[i] = make_red_map((char *)new_bits, heart_width, 
						heart_height);
	}

	free((char *)new_bits);

	new_bits = (unsigned char *) calloc(sizeof(heart_sm_bits), 1);
	flip_bits((unsigned char *)heart_sm_bits, new_bits, heart_sm_width, 
		heart_sm_height);
	suit_sm_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, heart_sm_width, heart_sm_height);

	if (is_color)	{
		suit_sm_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			heart_sm_bits, heart_sm_width, heart_sm_height);
		suit_sm_r_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			new_bits, heart_sm_width, heart_sm_height);
	} else	{
		suit_sm_map[i] = make_red_map(heart_sm_bits, heart_sm_width, 
						heart_height);
		suit_sm_r_map[i] = make_red_map((char *)new_bits, 
			heart_sm_width, heart_sm_height);
	}
	free((char *)new_bits);

	suit_lg_map[i] = suit_map[i];

	if (is_color)	{
		jack_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			jack_h_bits, jack_h_width, jack_h_height);

		queen_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			queen_h_bits, queen_h_width, queen_h_height);

		king_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			king_h_bits, king_h_width, king_h_height);
	} else	{
		jack_map[i] = make_red_map(jack_h_bits, jack_h_width, 
							jack_h_height);

		queen_map[i] = make_red_map(queen_h_bits, queen_h_width, 
							queen_h_height);

		king_map[i] = make_red_map(king_h_bits, king_h_width, 
							king_h_height);
	}


	i = (int)diamonds;
	/* make all the card bitmaps */
	new_bits = (unsigned char *) calloc(sizeof(diamond_bits), 1);
	flip_bits((unsigned char *)diamond_bits, new_bits, diamond_width, 
		diamond_height);

	if (is_color)	{
		suit_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			diamond_bits, diamond_width, diamond_height);
		suit_r_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			new_bits, diamond_width, diamond_height);
	} else	{
		suit_map[i] = make_red_map(diamond_bits, diamond_width, 
						diamond_height);
		suit_r_map[i] = make_red_map((char *)new_bits, diamond_width, 
						diamond_height);
	}

	free((char *)new_bits);

	new_bits = (unsigned char *) calloc(sizeof(diamond_sm_bits), 1);
	flip_bits((unsigned char *)diamond_sm_bits, new_bits, 
				diamond_sm_width, diamond_sm_height);
	suit_sm_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, diamond_sm_width, diamond_sm_height);

	if (is_color)	{
		suit_sm_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			diamond_sm_bits, diamond_sm_width, diamond_sm_height);
		suit_sm_r_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			new_bits, diamond_sm_width, diamond_sm_height);
	} else	{
		suit_sm_map[i] = make_red_map(diamond_sm_bits, diamond_sm_width, 
						diamond_height);
		suit_sm_r_map[i] = make_red_map((char *)new_bits, 
				diamond_sm_width, diamond_sm_height);
	}
	free((char *)new_bits);

	suit_lg_map[i] = suit_map[i];

	if (is_color)	{
		jack_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			jack_d_bits, jack_d_width, jack_d_height);

		queen_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			queen_d_bits, queen_d_width, queen_d_height);

		king_map[i] = XCreateBitmapFromData(dpy, 
			RootWindow(dpy, screen),
			king_d_bits, king_d_width, king_d_height);
	} else	{
		jack_map[i] = make_red_map(jack_d_bits, jack_d_width, 
							jack_d_height);

		queen_map[i] = make_red_map(queen_d_bits, queen_d_width, 
							queen_d_height);

		king_map[i] = make_red_map(king_d_bits, king_d_width, 
							king_d_height);
	}

	i = (int)clubs;
	/* make all the card bitmaps */
	suit_map[i] = XCreateBitmapFromData(dpy, 
		RootWindow(dpy, screen),
		club_bits, club_width, club_height);

	new_bits = (unsigned char *) calloc(sizeof(club_bits), 1);
	flip_bits((unsigned char *)club_bits, new_bits, club_width, 
		club_height);
	suit_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, club_width, club_height);
	free((char *)new_bits);

	suit_sm_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		club_sm_bits, club_sm_width, club_sm_height);

	new_bits = (unsigned char *) calloc(sizeof(club_sm_bits), 1);
	flip_bits((unsigned char *)club_sm_bits, new_bits, club_sm_width, 
		club_sm_height);
	suit_sm_r_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		new_bits, club_sm_width, club_sm_height);
	free((char *)new_bits);

	suit_lg_map[i] = suit_map[i];


	jack_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		jack_c_bits, jack_c_width, jack_c_height);

	queen_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		queen_c_bits, queen_c_width, queen_c_height);

	king_map[i] = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		king_c_bits, king_c_width, king_c_height);

     return;
}

/* ------------------------------------------------------------------------ */
/*
 * delta is 0 if the card is fully showing
 */
void
paint_card(int x, int y, pipn_e rank, suit_e suit, int delta, int invert)
{
	if (suit == spades || suit == clubs)	{
	     cardgc = (invert ? whitegc : blackgc);
	     backgc = (invert ? blackgc : whitegc);
	} else	{
	     cardgc = (invert ? redblackgc : redgc);
	     backgc = (invert ? blackgc : whitegc);
	}

	if (delta)	{
		if (round_cards)
			cliprects[0].height = delta + ROUND_H;
		else
			cliprects[0].height = delta;
		XSetClipRectangles(dpy, cardgc, x, y, cliprects, 1, Unsorted);
		XSetClipRectangles(dpy, backgc, x, y, cliprects, 1, Unsorted);

		if (round_cards)	{
		     if (cardgc != blackgc && backgc != blackgc)
			XSetClipRectangles(dpy, blackgc, x, y, cliprects, 1,
					   Unsorted);

		    /* add in ROUND_H to height so only the top is rounded */
		    /* fill the background */
		    XmuFillRoundedRectangle(dpy, cardwin, backgc, x, y, 
			CARD_WIDTH, delta + ROUND_H, ROUND_W, ROUND_H);
		    /* draw border on card */
		    XmuDrawRoundedRectangle(dpy, cardwin, blackgc, x, y, 
			CARD_WIDTH, delta + ROUND_H, ROUND_W, ROUND_H);
		}
		else {
		    /* fill the background */
		    XFillRectangle(dpy, cardwin, backgc, x, y, 
					CARD_WIDTH, delta);
		    /* draw border on card */
		    XDrawRectangle(dpy, cardwin, blackgc, x, y, 
					CARD_WIDTH, delta);
		}
		card_is_clipped = True;
	}
	else {	/* fill all the card */
		if (round_cards)	{
		    /* fill the background */
		     XmuFillRoundedRectangle(dpy, cardwin, backgc, x, y, 
					     CARD_WIDTH, CARD_HEIGHT,
					     ROUND_W, ROUND_H);
		     /* draw border on card */
		     XmuDrawRoundedRectangle(dpy, cardwin, blackgc, x, y, 
					     CARD_WIDTH, CARD_HEIGHT,
					     ROUND_W, ROUND_H);
		}
		else {
		     /* fill the background */
		     XFillRectangle(dpy, cardwin, backgc, x, y, 
				    CARD_WIDTH, CARD_HEIGHT);
		     /* draw border on card */
		     XDrawRectangle(dpy, cardwin, blackgc, x, y, 
				    CARD_WIDTH, CARD_HEIGHT);
		}
		card_is_clipped = False;
	}

	switch (rank)	{
	case	king:
		draw_king(suit, x, y);
		break;
	case	queen:
		draw_queen(suit, x, y);
		break;
	case	jack:
		draw_jack(suit, x, y);
		break;

	case	10:
		draw_pip(suit, MID_CARD_X + x, CARD_TEN_Y1 + y);
		draw_did(suit, MID_CARD_X + x, CARD_TEN_Y2 + y);
		draw_eight_pips(suit, x, y);
		break;

	case	9:
		draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y);
		draw_eight_pips(suit, x, y);
		break;

	      case	8:
		draw_did(suit, x + MID_CARD_X, y + CARD_EIGHT_Y);
		/* fall thru */
	case	7:
		draw_pip(suit, MID_CARD_X + x, CARD_SEVEN_Y + y);
		/* fall thru */
	case	6:
		draw_six_pips(suit, x, y);
		break;

	case	5:
		draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y);
		/* fall thru */
	case	4:
		draw_four_pips(suit, x, y);
		break;

	case	3:
		draw_pip(suit, x + MID_CARD_X, y + MID_CARD_Y);
		/* fall thru */
	      case 2:
		draw_two_pips(suit, x, y);
		break;
	case	ace:
		draw_center_pip(suit, x + MID_CARD_X, y + MID_CARD_Y);
		break;
	default:
		assert(0);
	}

	draw_rank(x, y, rank - 1, suit);

	/* clear the clip mask */
	XSetClipMask(dpy, cardgc, None);
	XSetClipMask(dpy, backgc, None);
	if (round_cards)	{
	     if (cardgc != blackgc && backgc != blackgc)
		XSetClipMask(dpy, blackgc, None);
	}
}

/* ------------------------------------------------------------------------ */
void
draw_king(suit_e suit, int x, int y)
{
	XCopyPlane(dpy, king_map[suit], cardwin, cardgc,
		0, 0, FACECARD_WIDTH, FACECARD_HEIGHT,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);

	XDrawRectangle(dpy, cardwin, cardgc,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
		FACECARD_WIDTH, FACECARD_HEIGHT);
}

/* ------------------------------------------------------------------------ */
void
draw_queen(suit_e suit, int x, int y)
{
	XCopyPlane(dpy, queen_map[suit], cardwin, cardgc,
		0, 0, FACECARD_WIDTH, FACECARD_HEIGHT,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);

	XDrawRectangle(dpy, cardwin, cardgc,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
		FACECARD_WIDTH, FACECARD_HEIGHT);
}

/* ------------------------------------------------------------------------ */
void
draw_jack(suit_e suit, int x, int y)
{
	XCopyPlane(dpy, jack_map[suit], cardwin, cardgc, 
		0, 0, FACECARD_WIDTH, FACECARD_HEIGHT,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2, 1);

	XDrawRectangle(dpy, cardwin, cardgc,
		x + (CARD_WIDTH - FACECARD_WIDTH)/2, 
		y + (CARD_HEIGHT - FACECARD_HEIGHT)/2,
		FACECARD_WIDTH, FACECARD_HEIGHT);
}

/* ------------------------------------------------------------------------ */
void
draw_eight_pips(suit_e suit, int x, int y)
{
	draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y);

	draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y);

	if (card_is_clipped)
		return;

	/* these are only visible when its not clipped */
	draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW2_Y);
	draw_did(suit, x + CARD_COL1_X, y + CARD_ROW4_Y);
	draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y);

	draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW2_Y);
	draw_did(suit, x + CARD_COL3_X, y + CARD_ROW4_Y);
	draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y);
}

/* ------------------------------------------------------------------------ */
void
draw_six_pips(suit_e suit, int x, int y)
{
	draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y);

	draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y);

	if (card_is_clipped)
		return;

	/* these are only visible when its not clipped */
	draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW3_Y);
	draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y);

	draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW3_Y);
	draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y);
}

/* ------------------------------------------------------------------------ */
void
draw_four_pips(suit_e suit, int x, int y)
{
	draw_pip(suit, x + CARD_COL1_X, y + CARD_ROW1_Y);
	draw_did(suit, x + CARD_COL1_X, y + CARD_ROW5_Y);

	draw_pip(suit, x + CARD_COL3_X, y + CARD_ROW1_Y);
	draw_did(suit, x + CARD_COL3_X, y + CARD_ROW5_Y);
}

/* ------------------------------------------------------------------------ */
void
draw_two_pips(suit_e suit, int x, int y)
{
	draw_pip(suit, x + MID_CARD_X, y + CARD_ROW1_Y);
	draw_did(suit, x + MID_CARD_X, y + CARD_ROW5_Y);
}

/* ------------------------------------------------------------------------ */
void
draw_center_pip(suit_e suit, int x, int y)
{
     int	w, h;

	if (card_is_clipped)
		return;

	switch(suit)	{
	case	spades:
		w = spade_lg_width;
		h = spade_lg_height;
		break;
	case	diamonds:
		w = diamond_width;
		h = diamond_height;
		break;
	case	hearts:
		w = heart_width;
		h = heart_height;
		break;
	case	clubs:
		w = club_width;
		h = club_height;
		break;
	default:
		assert(0);
	}
	XCopyPlane(dpy, suit_lg_map[suit], cardwin, cardgc, 
		0, 0, w, h,
		x - w/2, y - h/2, 1);
}

/* ------------------------------------------------------------------------ */
void
draw_did(suit_e suit, int x, int y)
{
     int	w, h;

	if (card_is_clipped)	/* a clipped card never shows any did's */
		return;

	switch(suit)	{
	case	spades:
		w = spade_width;
		h = spade_height;
		break;
	case	diamonds:
		x++;
		w = diamond_width;
		h = diamond_height;
		break;
	case	hearts:
		y++;
		w = heart_width;
		h = heart_height;
		break;
	case	clubs:
		y++;
		w = club_width;
		h = club_height;
		break;
	default:
		assert(0);
	}
	XCopyPlane(dpy, suit_r_map[suit], cardwin, cardgc, 
		0, 0, w, h,
		x - w/2, y - h/2, 1);
}

/* ------------------------------------------------------------------------ */
void
draw_pip(suit_e suit, int x, int y)
{
     int	w, h;

	switch(suit)	{
	case	spades:
		w = spade_width;
		h = spade_height;
		break;
	case	diamonds:
		x++;
		w = diamond_width;
		h = diamond_height;
		break;
	case	hearts:
		y++;
		w = heart_width;
		h = heart_height;
		break;
	case	clubs:
		y++;
		w = club_width;
		h = club_height;
		break;
	default:
		assert(0);
	}
	XCopyPlane(dpy, suit_map[suit], cardwin, cardgc, 
		0, 0, w, h,
		x - w/2, y - h/2, 1);
}

/* ------------------------------------------------------------------------ */
void
draw_rank(int x, int y, pipn_e rank, suit_e suit)
{
     int	w, h;

	if (suit == hearts || suit == diamonds)	{
		XCopyPlane(dpy, rank_map_red[rank], cardwin, 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], cardwin, 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], cardwin, 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], cardwin, cardgc,
			0, 0, RANK_WIDTH, RANK_HEIGHT,
			x + (CARD_WIDTH - RANK_WIDTH - RANK_LOC_X), 
			y + (CARD_HEIGHT - RANK_HEIGHT - RANK_LOC_Y), 1);
	}

	switch (suit)	{
		case	spades:
			w = spade_sm_width;
			h = spade_sm_height;
			break;
		case	hearts:
			w = heart_sm_width;
			h = heart_sm_height;
			break;
		case	diamonds:
			x++;	/* offset the smaller width */
			w = diamond_sm_width;
			h = diamond_sm_height;
			break;
		case	clubs:
			w = club_sm_width;
			h = club_sm_height;
			break;
		default:
			assert(0);
	}
	XCopyPlane(dpy, suit_sm_map[suit], cardwin, cardgc,
		0, 0, w, h,
		x + SMALL_LOC_X, y + SMALL_LOC_Y, 1);

	if (!card_is_clipped)
	    XCopyPlane(dpy, suit_sm_r_map[suit], cardwin, cardgc,
		0, 0, w, h,
		x + (CARD_WIDTH - w - SMALL_LOC_X), 
		y + (CARD_HEIGHT - h - SMALL_LOC_Y), 1);
}

/* ------------------------------------------------------------------------ */
void 
rot_180(unsigned char *src, unsigned char *dst, int W, int H)
{
     int     x, y;
     int	width = W;
     unsigned char	*new;
     int	bit;

	W = (W + 7)/8;
	for (y = 0; y < H; y++) {
		for (x = 0; x < W; x++) {
		     D (x, y) = _reverse_byte[S (W - 1 - x, H - 1 - y)];
		}
	}

	/* shift it over */
	new = (unsigned char *)calloc((unsigned)W*H, (unsigned)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((char *)dst, (char *)new, W*H);
     free((char *)new);
}

/* ------------------------------------------------------------------------ */
void
flip_bits(unsigned char *src, unsigned char *dst, int W, int H)
{
int	x, y;

	W = (W + 7)/8;
	for (y = 0; y < H; y++)	{
		for (x = 0; x < W; x++)	{
			D (x, y) = S (x, H - 1 - y);
		}
	}
}

/* ------------------------------------------------------------------------ */
static Pixmap
make_red_map(char *bits, int width, int height)
{
Pixmap	tmpmap, newmap;
static GC	cleargc = (GC) 0;
XGCValues	xgcv;


	if (cleargc == (GC) 0)	{
		xgcv.function = GXclear;
		cleargc = XCreateGC(dpy, RootWindow(dpy, screen), GCFunction, 
								&xgcv);
	}

	tmpmap = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
		bits, width, height);

	newmap = XCreatePixmap(dpy, RootWindow(dpy, screen), width, height, 1);

	/* clear pixmap */
	XFillRectangle(dpy, newmap, cleargc, 0, 0, width, height);

	XSetClipMask(dpy, redgc, tmpmap);
	XFillRectangle(dpy, newmap, redgc, 0, 0, width, height);
	XSetClipMask(dpy, redgc, None);
	XFreePixmap(dpy, tmpmap);

	return (newmap);
}

