/* usage: suit (scale) (y-offset) */
/* click to window to terminate program */

#include <stdio.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "largeclub.bm"
#include "largespade.bm"
#include "largeheart.bm"
#include "largediamond.bm"

static unsigned char grey[90][90];

static void bitmap_to_grey(char *bm, int w, int h, int scale, int scanline)
{   int i, j;
    char *b, *bb;
    unsigned char *g, *gg;
    int scancol, scancol0, xoffset;

    memset(grey, 0, sizeof(grey));
    b = bm;
    g = grey[5]+5;	/* start offset */
    i = (w - scale) / 2;
    xoffset = i % scale;
    scancol0 = xoffset ? scale - xoffset : 0;

    /* make a picture of bitmap, offsetting it (scanline, scancol0) */
    --scanline;
    for (i = 0; i < h; ++i) {
	int c;
	/* start a new scanline */
	if (++scanline >= scale) {
	    scanline -= scale;
	    g += 90;
	}
	gg = g;		/* restart at this line */
	bb = b;
	scancol = scancol0;
	--scancol;
	/* first, skip xoffset pixel */
	for (j = 0; j < w; ++j) {
	    if (++scancol >= scale) {
		++gg;
		scancol -= scale;
	    }
	    if (!(j % 8))
		c = *bb++;
	    /* c has bit in pos 0 */
	    if (c & 1)
		++*gg;
	    c >>= 1;
	}
	b += (w + 7) >> 3;
    }
}

#define NAME "scaled suit"

#define NUMCOLORS 64

void main(int argc, char *argv[])
{
  Display *my_display;
  Colormap my_colormap;
  GC my_gc;
  XGCValues my_gcv;
  Window root, my_root;
  Visual *my_visual;
  unsigned long w_mask, gc_mask;
  XSetWindowAttributes my_attrib;
  XSizeHints xsh;
  XEvent event;
  XWMHints xwmh = {
    (InputHint|StateHint),
    True,
    NormalState,
    0,0,0,0,0,0 };
  unsigned int i, j, screen, error, planes;
  unsigned long  pixel_mask[256], plane_mask[8];
  XColor color;
  /* std values: */
  int scale = 4, yoff = 0;

  if (argc > 1)
      scale = atoi(argv[1]);
  if (argc > 2)
      yoff = atoi(argv[2]);

  if (scale < 2 || scale > 20 || (scale&1)) {
      fprintf(stderr, "scale must be an even integer from 2 to 20\n");
      exit(1);
  }
  if (yoff < 0 || yoff >= scale) {
      fprintf(stderr, "yoff must be in range [0..scale)\n");
      exit(1);
  }

  if( (my_display = XOpenDisplay( NULL ) ) == NULL ) {
      fprintf( stderr, "cannot open display\n" );
      exit(1);
  }
  screen = XDefaultScreen( my_display );
  my_gc = XDefaultGC( my_display, screen );
  my_visual = XDefaultVisual( my_display, screen );
  my_colormap = XDefaultColormap( my_display, screen );
  root = XRootWindow( my_display, screen );
  w_mask = CWColormap|CWBackPixel;
  xsh.flags = PPosition | PSize;
  xsh.height = 120;
  xsh.width = 120;
  xsh.x = 10;
  xsh.y = 100;

  my_root = XCreateSimpleWindow( my_display, root, xsh.x,xsh.y,xsh.width,
				xsh.height, 0,
				WhitePixel( my_display, screen),
				BlackPixel( my_display, screen));
  XSetStandardProperties( my_display, my_root, NAME, NAME,
			 None, NULL, 0, &xsh);
  XSetWMHints( my_display, my_root, &xwmh );
  XSelectInput( my_display, my_root, ExposureMask|ButtonPressMask );
  XMapRaised( my_display, my_root );

  color.flags = DoRed|DoGreen|DoBlue;

  for( i = 0; i <= NUMCOLORS; i++ ) {
      color.red = color.green = color.blue = (NUMCOLORS-i)*65535/NUMCOLORS;
      if (!XAllocColor(my_display, my_colormap, &color))
	  goto nocolors;
      pixel_mask[i] = color.pixel;
  }


  color.red = 65535;
  for( i = 0; i <= NUMCOLORS; i++ ) {
      color.blue = color.green = (NUMCOLORS-i)*65535/NUMCOLORS;
      if (!XAllocColor(my_display, my_colormap, &color))
	  goto nocolors;
      pixel_mask[1+NUMCOLORS+i] = color.pixel;
  }
 nocolors:
  error = XSetWindowColormap( my_display, my_root, my_colormap );

  my_gcv.function = GXcopy;
  my_gcv.plane_mask = AllPlanes;
  my_gcv.line_width = 0;
  my_gcv.line_style = LineSolid;
  my_gcv.join_style = JoinMiter;
  my_gcv.fill_style = FillSolid;
  gc_mask = GCFunction|GCPlaneMask|GCLineWidth|
            GCLineStyle|GCJoinStyle|GCFillStyle;

  error = XChangeGC( my_display, my_gc, gc_mask, &my_gcv );

  while(1) {
      XNextEvent( my_display, &event );
      if( event.type == Expose && event.xexpose.count == 0 ) {
	  while(XCheckTypedEvent(my_display,Expose,&event))
	      ;
	  bitmap_to_grey(largespade_bits, largespade_width, largespade_height, scale, yoff);
	  for( i = 0; i < 60; ++i ) {
	      for( j = 0; j < 60; ++j ) {
		  error = XSetForeground( my_display, my_gc, pixel_mask[
			(int)grey[j][i] * NUMCOLORS / scale / scale ]);
		  XDrawRectangle( my_display, my_root, my_gc , i, j, 1, 1);
	      }
	  }
	  bitmap_to_grey(largeclub_bits, largeclub_width, largeclub_height, scale, yoff);
	  for( i = 0; i < 60; ++i ) {
	      for( j = 0; j < 60; ++j ) {
		  error = XSetForeground( my_display, my_gc, pixel_mask[
			(int)grey[j][i] * NUMCOLORS / scale / scale ]);
		  XDrawRectangle( my_display, my_root, my_gc , 60+i, j, 1, 1);
	      }
	  }
	  bitmap_to_grey(largediamond_bits, largediamond_width, largediamond_height, scale, yoff);
	  for( i = 0; i < 60; ++i ) {
	      for( j = 0; j < 60; ++j ) {
		  error = XSetForeground( my_display, my_gc, pixel_mask[
			1 + NUMCOLORS + 
			(int)grey[j][i] * NUMCOLORS / scale / scale ]);
		  XDrawRectangle( my_display, my_root, my_gc , 60+i, 60+j, 1, 1);
	      }
	  }
	  bitmap_to_grey(largeheart_bits, largeheart_width, largeheart_height, scale, yoff);
	  for( i = 0; i < 60; ++i ) {
	      for( j = 0; j < 60; ++j ) {
		  error = XSetForeground( my_display, my_gc, pixel_mask[
			1 + NUMCOLORS + 
			(int)grey[j][i] * NUMCOLORS / scale / scale ]);
		  XDrawRectangle( my_display, my_root, my_gc , i, 60+j, 1, 1);
	      }
	  }

      }
      if(event.type == ButtonPress )
	  exit(1);
  }
}
