#include <stdio.h>
#include <math.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>

/*
This is a quick and dirty hack.  It uses globals everywhere and only
supports one window.  But it was quick to write.
*/

Display *GblDisplay = NULL;
Window GblWindow;
Visual *GblVisual;
Window GblRootWindow;
XImage *GblImage;
char *GblImageData;
float *GblImageSrc = NULL;
int GblImageSrcSize;
GC GblGC;

int GblNumColors = 16;
int GblBaseColor;

Colormap GblColorMap;
unsigned long GblMasks[256];
unsigned long GblPixels[256];
XColor GblColors[256];

imageXregister( a,N)
float *a;
int N;
{
    GblImageSrc = a;
    GblImageSrcSize=N;
}


imageXdraw( a, N)
float *a;
int N;
{
    char*			pPix;
    int				i;
    int				value;

    pPix=GblImageData;
    for (i=0; i<N*N; i++, a++) {
   	value=(int)((*a)*(GblNumColors-1));
   	*pPix++=GblBaseColor+value;
    }
    XPutImage( GblDisplay, GblWindow, GblGC, GblImage,
      0, 0, 0, 0, N, N);
    listenX();
}

openX( N)
    int N;
{
    int rgbOfs, rgbRange, i;

    Screen GblScreen;
    int GblScreenNum;
    Status st;

    GblDisplay = XOpenDisplay( NULL);
    if ( GblDisplay == NULL ) {
	fprintf( stderr, "Couldnt open display\n");
	exit(1);
    }
    GblScreenNum = DefaultScreen( GblDisplay);
    GblRootWindow = RootWindow( GblDisplay, GblScreenNum);
    GblColorMap = DefaultColormap( GblDisplay, GblScreenNum);
    GblVisual = DefaultVisual( GblDisplay, GblScreenNum);
    GblGC = DefaultGC( GblDisplay, GblScreenNum);

    st = XAllocColorCells( GblDisplay, GblColorMap, True, 
      GblMasks, 0, GblPixels, GblNumColors);
    if ( st == 0 ) {
	fprintf( stderr, "Couldnt alloc colors\n");
	exit(1);
    }
    GblBaseColor = GblPixels[0];
    printf("Colors: base=%d, last=%d, num=%d\n",
      GblBaseColor, GblPixels[GblNumColors-1], GblNumColors);
    for (i=0; i < GblNumColors; i++) {
		GblColors[i].pixel = GblPixels[i];
		GblColors[i].flags = DoRed|DoGreen|DoBlue;
    }
    i=0;
    while (i<GblNumColors/4) {
	GblColors[i].red = 0;
	GblColors[i].green = (i*240000)/GblNumColors;
	GblColors[i].blue = 60000;
	i++;
    }
    while (i<GblNumColors/2) {
	GblColors[i].red = 0;
	GblColors[i].green = 60000;
	GblColors[i].blue = ((GblNumColors/2-i)*240000)/GblNumColors;
	i++;
    }
    while (i<(3*GblNumColors)/4) {
	GblColors[i].red = ((i-GblNumColors/2)*240000)/GblNumColors;
	GblColors[i].green = 60000;
	GblColors[i].blue = 0;
	i++;
    }
    while (i<GblNumColors) {
	GblColors[i].red = 60000;
	GblColors[i].green = ((GblNumColors-i)*240000)/GblNumColors;
	GblColors[i].blue = 0;
	i++;
    }
    XStoreColors( GblDisplay, GblColorMap, GblColors, GblNumColors);

    GblImageData = (char*) malloc( N*N);
    GblImage = XCreateImage( GblDisplay, GblVisual, 8, ZPixmap,
      0, GblImageData, N, N, 8, 0);
    listenX();
}


openWindow( N, winName)
    int N;
    char *winName;
{
    XSizeHints size_hints;

    GblWindow = XCreateSimpleWindow( GblDisplay, GblRootWindow,
      100, 100, N, N,
      5, 1, 0);
    if ( GblWindow == (Window)NULL ) {
	fprintf( stderr, "Couldnt open window\n");
	exit(1);
    }
    size_hints.flags = PPosition | PSize | PMinSize;
    size_hints.x = 100;
    size_hints.y = 100;
    size_hints.width = N;
    size_hints.height = N;
    size_hints.min_width = N;
    size_hints.min_height = N;
    XSetStandardProperties( GblDisplay, GblWindow,
      winName, winName, None, NULL, 0, &size_hints);
    XSelectInput( GblDisplay, GblWindow, 
      ExposureMask);
    XMapWindow( GblDisplay, GblWindow);
    listenX();
}


listenX()
{
    int N;
    XPoint p1, p2;
    /* XPending() does flush */
    while( XPending(GblDisplay) > 0 ) {
	XEvent event;
	XNextEvent( GblDisplay, &event);
	switch ( event.type ) {
	case Expose:
	    /* purge other exposes */
	    while ( XCheckTypedEvent( GblDisplay, Expose, &event) )
		;
	    if ( GblImageSrc )
	        imageXdraw( GblImageSrc, GblImageSrcSize);
 	    break;
        }
    }
}