/* display.c -- contains code for displaying an image using ICR 
 * this code is plucked from hdfrseq.c
 */
#include "he.h"

#ifdef SUN
#include <pixrect/pixrect_hs.h>
#include <memory.h>
#define DEVICE "/dev/fb"

struct pixrect
    *screen,
    *img = NULL;
struct mpr_data
    *stuff;
#endif SUN

#define SCRX 1152
#define SCRY 900

/* HEdisplay -- stub function for displaying an image using ICR */
int HEdisplay(cmd)
    HE_CMD *cmd;
{
    register int i;
    int center = 1;
    int xwhere = 0;
    int ywhere = 0;
    int factor = 1;
    int large = 0;

    for (i = 1; i < cmd->argc; i++)
	if (cmd->argv[i][0] == '-')
	    switch (findOpt(cmd->argv[i] + 1)) 
	    {
	    case HE_HELP:
		puts("display [-position <xpos> <ypos>] [-expansion <exp>] [-large]");
		puts("\t-position\tImage position on console screen");
		puts("\t-expansion\tImage expansion factor");
		puts("\t-large\t\tMake image as large as posible");
		return HE_OK;
	    case HE_POSITION:
		center = 0;
		xwhere = atoi(cmd->argv[++i]);
		ywhere = atoi(cmd->argv[++i]);
		if ((xwhere < 0) || (xwhere > SCRX) ||
		    (ywhere < 0) || (ywhere > SCRY))
		{
		    fprintf(stderr, "Invalid position.\n");
		    return HE_FAIL;
		}
		break;

	    case HE_EXPANSION:
		factor = atoi(cmd->argv[++i]);
		if (factor < 1) factor = 1;
		break;

	    case HE_LARGE:
		large = 1;
		break;
	    case HE_NOTFOUND:
		unkOpt(cmd->argv[i]);
		return HE_FAIL;
	    case HE_AMBIG:
		ambigOpt(cmd->argv[i]);
		return HE_FAIL;
	    default:
		irrOpt(cmd->argv[i]);
		return HE_FAIL;
	    }
	else
	{
	    unkArg(cmd->argv[i]);
	    return HE_FAIL;
	}
    return display(center, xwhere, ywhere, factor, large);
}


int oldcf=0;			/* old value of compression flag */
int oldx=0,oldy=0;		/* old values of xdim and ydim */
int coldx=0,coldy=0;		/* old values of xdim and ydim for CI8s */
int xdim=0,ydim=0;  		/* size of image on disk */
int xwhere,ywhere;		/* where to put it on the screen */
int ispal;
int large;			/* should make images as large as possible */
int center;			/* should center the images */
int oldxs=0,oldys=0;		/* old sizes */
int xsize=0,ysize=0;		/* what final size on screen, after blow-up */
int factor;

unsigned char rgb[768];		/* storage for a palette */
char *wherebig=NULL;	/* where to store small image */
char *wheresmall=NULL;	/* where to store image-related stuff */

int getSpace()
{
    /*  
     *  Don't allocate anything if the image is the same size as before.
     */
    if (oldx != xdim || oldy != ydim) {
	oldx = xdim; oldy = ydim; 
	
	if (wheresmall)
	    free(wheresmall);
	
	if (NULL == (wheresmall = (char *) malloc(xdim*ydim))) {
	    puts(" Cannot allocate memory, fatal error");
	    exit(1);
	}
	
    }
    return(0);
}


/*
 *  Allocate the space for the pixrect if displaying locally
 */
#ifdef SUN
int getPix()
{
    /*
     *  If local expansion is desired, allocate the space for it in the
     *  pixrect.  Allocation will take place because xsize and ysize will
     *  be set before calling this routine.
     *
     *  only re-allocate if the image changes size.
     */
    if (!he_remote && (oldxs != xsize || oldys != ysize)) {
	oldxs = xsize ; oldys = ysize;
	if (img)
	    pr_destroy(img);

	img = mem_create(xsize,ysize,8); /* to size of image */
	if (factor > 1) {
	    stuff = mpr_d(img);
	    wherebig = (char *)stuff->md_image;
	    /* pointer inside pixrect */
	}
	else {
	    stuff = mpr_d(img);
	    wheresmall = (char *)stuff->md_image;
	}
    }
    return(0);
}

#endif

/*************************************************************************/
/*  largeset
 *  Set up the xfact, yfact, xsize and ysize for expanding the image
 *  locally.  
 *
 */
int largeSet()
{
    int
	tmp;

    if (large) {
	factor = SCRX/xdim;	/* how much blow-up can we do? */
				/* calculate expansion factor  */
	tmp = SCRY/ydim;

	/* take minimum expansion factor */
	if (factor > tmp) factor = tmp;
    }
    
    xsize = factor*xdim;	/* re-calculate actual pixel dimensions */
    ysize = factor*ydim;
    
    return(factor > 1);		/* is expansion necessary? */
}

int isRig(tag)
    uint16 tag;
{
    switch (tag) {

    case DFTAG_RIG:
	return 1;

    default:
	break;

    }

    return 0;
}

void goTo(desc)
    int desc;
{
    /* goto element of he_desc[desc] */
    /* ask swami */

    /* right now this only works for r8 */
    DFR8readref(he_file, he_desc[desc].ref);
}

int display(c, x, y, f, l)
    int c, x, y, f, l;
{

    center = c;
    xwhere = x;
    ywhere = y;
    factor = f;
    large = l;

    if (!isRig(he_desc[he_currDesc].tag)) {

	fprintf(stderr, "Current element not a image group.\n");
	return HE_FAIL;
    }

    goTo(he_currDesc);

    if (DFR8getdims(he_file, &xdim, &ydim, &ispal)<0) {
	fprintf(stderr, "Error getting image group.\n");
	return HE_FAIL;
    }

#ifdef SUN
    if (!he_remote) {
	if (largeSet())	/* set expansion needs */
	    getSpace();	/* get local space for pre-expansion */
	getPix();		/* allocate pixrect */
    }
#endif

    if (he_remote)
	getSpace();		/* get space for image in mem */


/*
*  Try to successfully load the palette and image from the file
*/
    if (DFR8getimage(he_file, wheresmall, xdim, ydim, rgb) < 0) {
	fprintf(stderr, "Error getting image group.\n");
	return HE_FAIL;
    }

    if (he_remote) 
	rImage(ispal);	/* display remote image with [palette] */

#ifdef SUN
    else
	pixImage(ispal);	/* display image on Sun with [palette] */
#endif

    return HE_OK;

}


#ifdef SUN
/***********************************************************************/
/*  piximage
*  On the Sun console, display the image as the parameters specify.
*  Handles centering (center)
*  Uses xwhere and ywhere, xsize and ysize.
*  Performs expansion if xfact or yfact > 1
*  Takes the palette from the rgb[] if asked to.
*  Will pause if step=1.
*/
int pixImage(usepal)
    int usepal;
{
    unsigned char r[256],g[256],b[256],*pp;
    int j;

/*
*  compute centering values, based on new size
*/
    if (center) {
	xwhere = (SCRX-xsize)/2;
	ywhere = (SCRY-ysize)/2;
	if (xwhere < 0) 
	    xwhere = 0;
	if (ywhere < 0)
	    ywhere = 0;
    }


/*
*  Do the image expansion, if called for.
*  The creative pointering makes sure that wherebig and wheresmall are
*  always set to the correct pointers.  img is always the target pixrect.
*/
    if (factor > 1)
	bigImg(wherebig,wheresmall);

/*
*  Set the display palette to the new palette.
*/
    if (usepal) {
	pp = rgb;		/* array of rgbrgbrgbrgb */
	for (j=0; j<256; j++) {
	    r[j] = *pp++;
	    g[j] = *pp++;
	    b[j] = *pp++;
	}

	pr_putcolormap(screen, 2, 254, &r[2], &g[2], &b[2]);
    }

/*
*  Display the image using pixrects
*/
    pr_rop(screen,xwhere,ywhere,xsize,ysize,PIX_SRC,img,0,0);
}

#endif

/*****************************************************************************/
/*  rimage
*  Remote display of the image using the ICR.
*  Just print the codes to stdout using the protocol.
*/
int rImage(usepal)
    int usepal;
{
    int i,j,newxsize;
    unsigned char *space,*thisline;
    unsigned char *thischar;
    register unsigned char c;

/*
*  Open the window with the W command
*/

    printf("\033^W;%d;%d;%d;%d;0;rseq^",xwhere,ywhere,xdim*factor,ydim*factor);

/*
*  If a palette should be used, send it with the M command.
*/
    if (usepal) {
	(void)printf("\033^M;0;256;768;rseq^");  /* start map */

	thischar = rgb;
	for (j=0; j<768; j++) {
	    c = *thischar++;
	    if (c > 31 && c < 123) {
		putchar(c);
	    }
	    else {
		putchar((c>>6)+123);
		putchar((c & 0x3f) + 32);
	    }
	}
    }

/*
*  Send the data for the image with RLE encoding for efficiency.
*  Encode each line and send it.
*/
    space = (unsigned char *) malloc(ydim+128);
    thisline = (unsigned char *) wheresmall;

    for (i = 0; i < ydim; i++) {
        newxsize = rleIt(thisline,space,xdim);
	thisline += xdim;	/* increment to next line */

        (void)printf("\033^R;0;%d;%d;%d;rseq^",i*factor,factor,newxsize); 

        thischar = space;
        for (j = 0; j < newxsize; j++) {

/***********************************************************************/
/*  Encoding of bytes:
*
*  123 precedes #'s 0-63
*  124 precedes #'s 64-127
*  125 precedes #'s 128-191
*  126 precedes #'s 192-255
*  overall:  realchar = (specialchar - 123)*64 + (char-32)
*            specialchar = r div 64 + 123
*            char = r mod 64 + 32
*/
/***********************************************************************/

	    c = *thischar++;      /* get byte to send */

	    if (c > 31 && c < 123) {
		putchar(c);
	    }
	    else {
		putchar((c>>6)+123);
		putchar((c & 0x3f) + 32);
	    }
        }
    }

/*
*  pause for the user
*/

    free(space);
    return HE_OK;
}

/*****************************************************************************/
/* expandimg
*  copy an image memory to memory, expanding byte by byte to get a larger image.
*  no aliasing, just byte replication
*/
int bigImg(targ,src)
    unsigned char *targ,*src;
{
    register i,j,line;
    register unsigned char *p,*q,*oldq;

    for (line = 0; line < ydim; line++) {
	p = src+line*xdim;
	oldq = q = targ+line*xsize*factor;

	for (i=0; i<xdim; i++,p++)
	    for (j=0; j<factor; j++)
		*q++ = *p;
		
	for (i=1; i<factor ; i++) {
	    DFmovmem(oldq,q,xsize); /* make one copy of the line */
	    q += xsize;
	}

    }
    return HE_OK;
}


/********************************************************************/
/*  rleit
*  compress the data to go out with a simple run-length encoded scheme.
*
*/
int rleIt(buf,bufto,len)
    int len;
    char *buf,*bufto;
{
    register char *p,*q,*cfoll,*clead;
    char *begp;
    int i;

    p = buf;
    cfoll = bufto;		/* place to copy to */
    clead = cfoll + 1;
	
    begp = p;
    while (len > 0) {		/* encode stuff until gone */

	q = p + 1;
	i = len-1;
	while (*p == *q && i+120 > len && i) {
	    q++;
	    i--;
	}
		
	if (q > p + 2) {	/* three in a row */
	    if (p > begp) {
		*cfoll = p - begp;
		cfoll = clead;
	    }
	    *cfoll++ = 128 | (q-p); /* len of seq */
	    *cfoll++ = *p;	/* char of seq */
	    len -= q-p;		/* subtract len of seq */
	    p = q;
	    clead = cfoll+1;
	    begp = p;
	}
	else {
	    *clead++ = *p++;	/* copy one char */
	    len--;
	    if (p > begp + 120) {
		*cfoll = p - begp;
		cfoll = clead++;
		begp = p;
	    }
	}
	
    }
/*
*  fill in last bytecount
*/
    if (p > begp) 
	*cfoll = (p - begp);
    else
	clead--;		/* don't need count position */
	
    return((int)(clead - bufto)); /* how many stored as encoded */
}

/* end of display.c */
