#ifndef lint
static const char	RCSid[] = "$Id: meta2tga.c,v 1.6 2004/02/04 18:49:24 greg Exp $";
#endif
/*
 *  Program to convert meta-files to Targa 8-bit color-mapped format
 */

#include  "copyright.h"

#include  "rtprocess.h"
#include  "meta.h"
#include  "plot.h"
#include  "rast.h"
#include  "targa.h"

#define  MAXALLOC  30000
#define  DXSIZE  400		/* default x resolution */
#define  DYSIZE  400		/* default y resolution */
#define  XCOM  "pexpand +vOCImsp -DP %s | psort +y"


char  *progname;

SCANBLOCK	outblock;

int  dxsize = DXSIZE, dysize = DYSIZE;

int  maxalloc = MAXALLOC;

int  ydown = 0;

static char  outname[64];
static char  *outtack = NULL;

static FILE  *fout;

static int  lineno = 0; 

static short  condonly = FALSE,
	      conditioned = FALSE;

static int putthead(struct hdStruct  *hp, char  *ip, FILE  *fp);



char *
findtack(s)			/* find place to tack on suffix */
register char *s;
{
	while (*s && *s != '.')
		s++;
	return(s);
}


int
main(
	int  argc,
	char  **argv
)

{
 FILE  *fp;
 char  comargs[200], command[300];

  fout = stdout;
 progname = *argv++;
 argc--;

 condonly = FALSE;
 conditioned = FALSE;
 
 while (argc && **argv == '-')  {
    switch (*(*argv+1))  {
       case 'c':
	  condonly = TRUE;
	  break;
       case 'r':
	  conditioned = TRUE;
	  break;
       case 'm':
	  minwidth = atoi(*++argv);
	  argc--;
	  break;
       case 'x':
	  dxsize = atoi(*++argv);
	  argc--;
	  break;
       case 'y':
	  dysize = atoi(*++argv);
	  argc--;
	  break;
       case 'o':
	  strcpy(outname, *++argv);
	  outtack = findtack(outname);
	  argc--;
	  break;
       default:
	  error(WARNING, "unknown option");
	  break;
       }
    argv++;
    argc--;
    }

 if (conditioned) {
    if (argc)
       while (argc)  {
	  fp = efopen(*argv, "r");
	  plot(fp);
	  fclose(fp);
	  argv++;
	  argc--;
	  }
    else
       plot(stdin);
    if (lineno)
	nextpage();
 } else  {
    comargs[0] = '\0';
    while (argc)  {
       strcat(comargs, " ");
       strcat(comargs, *argv);
       argv++;
       argc--;
       }
    sprintf(command, XCOM, comargs);
    if (condonly)
       return(system(command));
    else  {
       if ((fp = popen(command, "r")) == NULL)
          error(SYSTEM, "cannot execute input filter");
       plot(fp);
       pclose(fp);
       if (lineno)
	  nextpage();
       }
    }

 return(0);
 }



void
thispage(void)		/* rewind current file */
{
    if (lineno)
	error(USER, "cannot restart page in thispage");
}


void
initfile(void)		/* initialize this file */
{
    static int  filenum = 0;
    /*
    static unsigned char  cmap[24] = {255,255,255, 255,152,0, 0,188,0, 0,0,255,
			179,179,0, 255,0,255, 0,200,200, 0,0,0};
     */
    static unsigned char  cmap[24] = {0,0,0, 0,0,255, 0,188,0, 255,152,0,
			0,200,200, 255,0,255, 179,179,0, 255,255,255};
    struct hdStruct  thead;
    register int  i;

    if (outtack != NULL) {
	sprintf(outtack, "%d.tga", ++filenum);
	fout = efopen(outname, "w");
    }
    if (fout == NULL)
	error(USER, "no output file");
    thead.mapType = CM_HASMAP;
    thead.dataType = IM_CCMAP;
    thead.mapOrig = 0;
    thead.mapLength = 256;
    thead.CMapBits = 24;
    thead.XOffset = 0;
    thead.YOffset = 0;
    thead.x = dxsize;
    thead.y = dysize;
    thead.dataBits = 8;
    thead.imType = 0;
    putthead(&thead, NULL, fout);
    for (i = 0; i < 8*3; i++)
	putc(cmap[i], fout);
    while (i++ < 256*3)
	putc(0, fout);
}



void
nextpage(void)		/* advance to next page */

{

    if (lineno == 0)
	return;
    if (fout != NULL) {
	while (lineno < dysize) {
	    nextblock();
	    outputblock();
	}
	fclose(fout);
	fout = NULL;
    }
    lineno = 0;

}



#define MINRUN	4

extern void
printblock(void)		/* output scanline block to file */

{
    int  i, c2;
    register unsigned char  *scanline;
    register int  j, beg, cnt = 0;

    if (lineno == 0)
	initfile();
    for (i = outblock.ybot; i <= outblock.ytop && i < dysize; i++) {
	scanline = outblock.cols[i-outblock.ybot];
	for (j = outblock.xleft; j <= outblock.xright; j += cnt) {
	    for (beg = j; beg <= outblock.xright; beg += cnt) {
		for (cnt = 1; cnt < 128 && beg+cnt <= outblock.xright &&
			scanline[beg+cnt] == scanline[beg]; cnt++)
		    ;
		if (cnt >= MINRUN)
		    break;			/* long enough */
	    }
	    while (j < beg) {		/* write out non-run */
		if ((c2 = beg-j) > 128) c2 = 128;
		putc(c2-1, fout);
		while (c2--)
		    putc(scanline[j++], fout);
	    }
	    if (cnt >= MINRUN) {		/* write out run */
		putc(127+cnt, fout);
		putc(scanline[beg], fout);
	    } else
		cnt = 0;
	}
	lineno++;
    }
    
}


void
putint2(			/* put a 2-byte positive integer */
	register int  i,
	register FILE	*fp
)
{
	putc(i&0xff, fp);
	putc(i>>8&0xff, fp);
}


int
putthead(		/* write header to output */
	struct hdStruct  *hp,
	char  *ip,
	register FILE  *fp
)
{
	if (ip != NULL)
		putc(strlen(ip), fp);
	else
		putc(0, fp);
	putc(hp->mapType, fp);
	putc(hp->dataType, fp);
	putint2(hp->mapOrig, fp);
	putint2(hp->mapLength, fp);
	putc(hp->CMapBits, fp);
	putint2(hp->XOffset, fp);
	putint2(hp->YOffset, fp);
	putint2(hp->x, fp);
	putint2(hp->y, fp);
	putc(hp->dataBits, fp);
	putc(hp->imType, fp);

	if (ip != NULL)
		fputs(ip, fp);

	return(ferror(fp) ? -1 : 0);
}
