/*
**      This Program created (under tremendous pressure) by Steve Berry
**      with help and modifications by Mark Thompson and others.
**
**      I hope you guys keep it clean. (If you don't, let me know :-)
**
**      Status: PD all the way.
**
**      Please read the file named DOC, that came with this distribution for
**      information on how to use iff2sun.
**
**	Limitations:
**		  I have only tested this on DPaintII images, it is
**		very possible that it might break with other formats.
**		Unlikely, but possible :*)
**
**	CREDITS:
**			Mark Thompson
**			Steve (Raz) Berry
**
**	Contacts:
**				Steve Berry ...sun!kilowatt!raz or 
**                                             raz%kilowatt.EBay@sun.com
**                                          BIX: razberry
**                              Mark Thompson  ...decvax!savax!thompson
**
**      Revision History:
**
**      10/31/88 First release, does only simple conversion and no color.
**
**      12/88    Re-released with color support. Unfortunately few if any
**               one saw this release (it got lost on the way to the moderator)
**               (This is Mark's claim to fame)
**
**      4/26/89  Added Extra-half-bright support, also looking for the
**               best way to convert HAM (4096) to 8 bit (256) format.
**
**	5/26/89	 Added HAM mode conversion (with convert) and fixed an iff
**		 parsing bug (parse()), and added new argument parsing supplied
**		 by Tony Schene. The original convert.c was supplied by
**		 Tony Kennedy as well as the bug report on DPaintIII images.
*/

#include <sys/types.h>
#include <stdio.h>
#include <rasterfile.h>

#define HAM 0x800       /* Amiga Viewmodes */
#define HALF 0x80
#define HIRES 0x8000
#define LACE 0x4
#define TRUE 1
#define FALSE 0

/* Stupic C needs to be told about functions used before they
   are defined */

unsigned char RGBtoLuma();
long parse();

/* Some variables and arrays */

u_char	rmap[128],rhmap[128];
u_char	gmap[128],ghmap[128];
u_char	bmap[128],bhmap[128];
u_char currentcolor[3];
u_char scanline[1024][6][128]; /* vert, planes, width (bytes) */

long width, hieght, planes, hammode, numcolors;
long temp, compress, i, j, k, l;
int colorpic=FALSE, halfb = FALSE, pixelrep = FALSE;
char *Usage = "Usage: %s [ -chp ] [ infile ] [ outfile ]\n";

main(argc,argv)
int argc;
char **argv;
{
	struct rasterfile header;
	unsigned char clr;
	long formsize, twidth, thieght;
	static char chunk[5];
	FILE *inh, *outh;
	char	*progname= argv[0];
	char c;
	extern char *optarg;
	extern int optind;
        
	chunk[4] = 0;
        
	inh = stdin;
	outh = stdout;

	while ((c = getopt (argc, argv, "chp")) != -1)
		switch (c) {
		case 'c':
			colorpic = TRUE;
			fprintf(stderr,"Color output selected\n");
			break;
		case 'h':
			halfb = TRUE;
			fprintf(stderr,"Extra Half-bright selected\n");
			break;
		case 'p':
			pixelrep = TRUE;
			break;
		default:
			fprintf (stderr, Usage, argv[0]);
			exit (1);
	      }
	if (optind < argc)
		inh = fopen(argv[optind],"r");
	if (++optind < argc)
		outh = fopen(argv[optind],"w");
	if (++optind < argc) {
		fprintf (stderr, Usage, argv[0]);
		exit (1);
	}
        
	if (inh == NULL){
		perror(argv[1]);
		exit(-10);
	}        

	if (outh == NULL){
		perror(argv[2]);
		exit(-10);
	}        

	/* Now comes the fun part... Reading the ILBM's */
        
	if (parse(inh,"FORM")) {
		perror("I don't think that this is an IFF file");
		exit(-10);
	}

	fread(&formsize, 4, 1, inh);    /* length of the FORM */

	if (parse(inh,"ILBM")) {
		perror("I don't think that this is an ILBM");
		exit(-10);
	}

	if (parse(inh,"BMHD")) { 
		perror("Bad format for ILBM.");
		exit(-10);
	}

	cc(chunk);
	fread(chunk, 4, 1, inh);    /* length of the BMHD */

	cc(chunk);
	fread(chunk, 2, 1, inh);    /* width of bitmap */
	width = *((short *)chunk);

	cc(chunk);
	fread(chunk, 2, 1, inh);    /* Height of bitmap */
	hieght = *((short *)chunk);

	fread(chunk, 4, 1, inh);    /* Don't want the orgins */

	cc(chunk);
	fread(chunk, 1, 1, inh);    /* # of Planes */
	planes = *((unsigned char *)chunk);

	fread(chunk, 1, 1, inh);    /* Ignore the Mask */

	cc(chunk);
	fread(chunk, 1, 1, inh);    /* Compression? */

	compress = *((unsigned char *)chunk);

	fread(chunk, 1, 1, inh);    /* just a pad byte */

/***********************************************************************
**	DpaintII does not use the CAMG chunk, so we will have to ignore
**	it for now...
***********************************************************************/

/*	if (planes == 6) {
		perror("Sorry, I can't do HAM or Halfbright.");
		exit(0);
	} */

	if (parse(inh,"CMAP")) {
		perror("Bad format for ILBM, couldn't find Color Map.");
	exit(-10);
	} 

	cc(chunk);
	fread(chunk, 4, 1, inh);    /* # of color registers */
	numcolors = *((long *)chunk);
        
	for(i=0; i<64; i++) {
	  rmap[i]= i;
	  gmap[i]= i;
	  bmap[i]= i;
	}

	numcolors = numcolors/3 ;
	for (i=0;i<numcolors;i++){
		fread(chunk, 3, 1, inh);
		chunk[3] = 0; chunk[4] = 0; 
		chunk[0] = (chunk[0] >> 4) & 0x0f;
		chunk[2] = (chunk[2] >> 4) & 0x0f;
		chunk[1] = (chunk[1] >> 4) & 0x0f;
		if(colorpic==TRUE) {
		  rmap[i] = (chunk[0] << 4) | chunk[0];
		  gmap[i] = (chunk[1] << 4) | chunk[1];
		  bmap[i] = (chunk[2] << 4) | chunk[2];
		} else {
		  rmap[i] = RGBtoLuma(chunk);
		  gmap[i] = RGBtoLuma(chunk);
		  bmap[i] = RGBtoLuma(chunk);
		}
		if (halfb == TRUE) {
		  rhmap[i] = rmap[i]>>1;
		  ghmap[i] = gmap[i]>>1;
		  bhmap[i] = bmap[i]>>1;
		}
	}

	if (numcolors == 2)	/* if a mono image, realign to long word */
		fread(chunk,1,2,inh);

	if (parse(inh,"BODY")){
		perror("No BODY data.");
		exit(0);
	}

	if ((planes == 6) && (halfb == TRUE) && (numcolors == 16)
          || (planes != 6) && (halfb == TRUE)){
	  perror("You specified Half-Bright, but file is not in the correct format\n");
	  exit(0);
	}

	if ((planes == 6) && (halfb != TRUE)) {
	  fprintf(stderr, "Ham mode... raw color output initiated.\n");
	  hammode = TRUE;
	}

	fread(chunk, 4, 1, inh);	/* length of body */

	if (!hammode) {
	  header.ras_magic= 0x59a66a95;
	  if (pixelrep == FALSE)
	    header.ras_width= width;
	  else
	    header.ras_width= width * 2;
	  header.ras_height= hieght;
	  header.ras_depth= 8;
	  if (pixelrep == FALSE)
	    header.ras_length= width * hieght;
	  else
	    header.ras_length= width * 2 * hieght;
	  header.ras_type= RT_STANDARD;
	  header.ras_maptype= RMT_EQUAL_RGB;
	  header.ras_maplength= 3*256;

/* Write out the rasterfile header to the ouput */

	  fwrite(&header, sizeof(header), 1, outh);

/* Write out the red colormap to the ouput */


	  if (fwrite(rmap, sizeof(rmap), 1, outh) == 0) {
	    perror(progname);
	    exit(1);
	  } 
	  if (halfb == TRUE) 
	    fwrite(rhmap, sizeof(rhmap), 1, outh);
	  else 
	    fwrite(rmap, sizeof(rmap), 1, outh);

/* Write out the green colormap to the ouput */
	
	  if (fwrite(gmap, sizeof(gmap), 1, outh) == 0) {
	    perror(progname);
	    exit(1);
	  } 
	  if (halfb == TRUE) 
	    fwrite(ghmap, sizeof(ghmap), 1, outh);
	  else 
	    fwrite(gmap, sizeof(gmap), 1, outh);

/* Write out the blue colormap to the ouput */

	  if (fwrite(bmap, sizeof(bmap), 1, outh) == 0) {
	    perror(progname);
	    exit(1);
	  } 
	  if (halfb == TRUE) 
	    fwrite(bhmap, sizeof(bhmap), 1, outh);
	  else 
	    fwrite(bmap, sizeof(bmap), 1, outh);
	}
	else {
	  twidth = width;
	  if (pixelrep) {
	    twidth = width * 2;
	  }
	  fwrite(&twidth, 4, 1, outh);
	  fwrite(&hieght, 4, 1, outh);
	}

/* This part does all the work */

/* Either we uncompress the file, or we read it in... */

	if (compress == 1)
	  uncompress(planes, width, inh);
	else 
	  for(k = 0;k<hieght;k++)
	    for(i = 0;i<planes;i++) {
	      for(j=0;j<width/8;j++){
		cc(chunk);
		if(feof(inh))
		  continue;
		fread(chunk, 1, 1, inh);
		scanline[k][i][j] = *((unsigned char *)chunk);
	      }
	    }

/* Here we take the data and output it (finally!) */

	currentcolor[0] = rmap[0];
	currentcolor[1] = gmap[0];
	currentcolor[2] = bmap[0];

	for(j = 0;j<hieght;j++){
	  for(i = 0;i<width/8;i++)
	    process_pixel(i,j,outh);
	}
	fclose(inh);
	fclose(outh);
} /* end of main */

/* The uncompression routine 					*/
/* Here we uncompress the data for the number of planes 	*/
/* and store it in the global array scanline[][][] 		*/
/* Credits: Leo (the great Caped one) was the originator of the */
/* code I ripped this off from. 				*/

uncompress(planes, width, inh)
FILE *inh;
long planes, width;
{
	long i,j,count,bytesperrow;
	char len;
	unsigned char byte;

	for(i=0;i<hieght;i++){
		for(j=0;j<planes;j++){
			count = 0;
			bytesperrow = width / 8;
			while(bytesperrow > 0){
				if ((len = getc(inh)) >= 0){
					bytesperrow -= ++len;
					fread(&scanline[i][j][count],len,1,inh);
					count += len;
				} else if (len == -128)
					;
				else if (len < 0){
					len = -len + 1;
					bytesperrow -= len;
					byte = getc(inh);
					while(--len >= 0)
						scanline[i][j][count++] = byte;
				}
			}
			if(bytesperrow)
				perror("Compression is messed.");
		}
		
	}
}


/* RGBtoLuma converts the colortable from the Amiga to Luminance information */
/* This routine was written by Mark Thompson 				     */

unsigned char RGBtoLuma(color)
unsigned char *color;
{
	unsigned char r, g, b;
	unsigned char grey;
	float fgrey;

	r = (color[0] << 4) + color[0];
	g = (color[1] << 4) + color[1];
	b = (color[2] << 4) + color[2];
	fgrey = 0.3 * r + 0.59 * g + 0.11 * b + 0.5;
	grey = fgrey;
	return grey;
}

/* Process the byte for the scanline 		*/
/* Can you say shift 3 times fast? 		*/

process_pixel(byte,scan,outh)
FILE *outh;
unsigned char byte;
long scan;
{
	long j, i, p, result = 0;
	unsigned char temp;

	temp = 0; result = 0;
	for(i=7;i>=0;i--){
		for(p=0;p<planes;p++) 
			result = ((((1 << i) & scanline[scan][p][byte])>>i)<<p) | result;
		result = result & 0x3f;
		temp = result;

		if (hammode) {
		  temp = (result & 0x30) >> 4;
		  switch (temp){
		  case 0x0:
		    temp = result & 0x0f;
		    currentcolor[2] = bmap[temp]<<4;
		    currentcolor[1] = gmap[temp]<<4; 
		    currentcolor[0] = rmap[temp]<<4;
		    break;
		  case 0x1:
		    result = result & 0x0f;
		    currentcolor[2] = result<<4;
		    break;
		  case 0x2:
		    result = result & 0x0f;
		    currentcolor[0] = result<<4;
		    break;
		  case 0x3:
		    result = result & 0x0f;
		    currentcolor[1] = result<<4;
		    break;
		  }

		  fwrite(currentcolor, 1, 3, outh);
		  if (pixelrep == TRUE)
		    fwrite(currentcolor, 1, 3, outh);
		}
		else {
		  fwrite(&temp, 1, 1, outh);
		  if (pixelrep == TRUE)
		    fwrite(&temp, 1, 1, outh);
		}
		result = 0;
	}
}

/* look for a chunk in the file */
long parse(inh, str)
FILE *inh;
char *str;
{
        static char chunk[5];
        chunk[4] = 0;
        while (1){
	  fread(chunk, 2, 1, inh);
	  if (strncmp(chunk,str,2) == 0){
	    fread(chunk, 2, 1, inh);
	    if (strncmp(chunk,&str[2],2) == 0)
	      return FALSE;
	  }
	  if(feof(inh) != 0)
	    return TRUE;
        }
}

/* Clear Chunk variable */

cc(chunk)
char chunk[5];
{
	register int i;
	for(i=0;i<5;i++)
		chunk[i] = 0;
}
