#include <stdio.h>
#include <xil/xil.h>

/*
 * init_cmap()
 * 
 * Initialize the X colormap with a 3-banded XilLookup, using the 'offset'
 * argument to determine the starting pixel value in the X colormap. If the
 * 'offset' argument is negative, automatically calculate the starting pixel
 * value in such a way as to minimize colormap flashing.
 * 
 * Finally, adjust the offset of the XilLookup accordingly.
 */
#define CMAPSIZE        256
#define TOP2 		  2	/* reserve the top two entries of the
				 * colormap to reduce colormap flashing */
void
init_cmap(XilLookup xil_cmap, Display * display, Window window, int offset)
{
    unsigned long junk[CMAPSIZE], pixels[CMAPSIZE], mask;
    XColor cdefs[CMAPSIZE];
    Colormap rcmap;
    int cmapsize;
    int i;
    Xil_unsigned8 cmap_data[CMAPSIZE * 3];
    Xil_unsigned8 *ptr;

    rcmap = XCreateColormap(display, window,
			    DefaultVisual(display, DefaultScreen(display)),
			    AllocNone);

    cmapsize = xil_lookup_get_num_entries(xil_cmap);

    /* determine the offset for the colormap */
    if (offset < 0) {
	offset = 256 - cmapsize - TOP2;
	if (offset < 0)
	    offset = 0;		/* in case cmapsize >= 255 */
    }

    if (offset) {
	if (!XAllocColorCells(display, rcmap, 0, &mask, 0, junk, offset)) {
	    fprintf(stderr, "XAlloc1 failed\n");
	}
    }

    if (!XAllocColorCells(display, rcmap, 0, &mask, 0, pixels, cmapsize)) {
	fprintf(stderr, "XAlloc2 failed\n");
    }

    /* free the unused colors in the front */
    if (offset) {
	XFreeColors(display, rcmap, junk, offset, 0);
    }

    for (i = 0; i < cmapsize; i++) {
	cdefs[i].pixel = i + offset;
    }

    xil_lookup_get_values(xil_cmap, xil_lookup_get_offset(xil_cmap),
			  cmapsize, cmap_data);

    ptr = cmap_data;
    for (i = 0; i < cmapsize; i++) {
	cdefs[i].flags = DoRed | DoGreen | DoBlue;

	/*
	 * since 24-bit XIL images are in BGR order, colormaps are also in
	 * BGR order
	 */
	cdefs[i].blue = *ptr++ << 8;
	cdefs[i].green = *ptr++ << 8;
	cdefs[i].red = *ptr++ << 8;
    }
    XStoreColors(display, rcmap, cdefs, cmapsize);

    /*
     * This will cause the colormap to be installed unless the cursor is
     * moved to another window -- any other window; if this happens, then
     * colormap flashing may occur.
     */
    XSetWindowColormap(display, window, rcmap);
    XInstallColormap(display, rcmap);
    XSync(display, False);


    /* set the offset of the XilLookup */
    xil_lookup_set_offset(xil_cmap, offset);
}
