/************************************************************************
 *									*
 *		    Copyright (c) 1988, David B. Wecker			*
 *			    All Rights Reserved				*
 *									*
 * This file is part of DBW_uRAY					*
 *									*
 * DBW_uRAY is distributed in the hope that it will be useful, but	*
 * WITHOUT ANY WARRANTY. No author or distributor accepts		*
 * responsibility to anyone for the consequences of using it or for	*
 * whether it serves any particular purpose or works at all, unless	*
 * he says so in writing. Refer to the DBW_uRAY General Public		*
 * License for full details.						*
 *									*
 * Everyone is granted permission to copy, modify and redistribute	*
 * DBW_uRAY, but only under the conditions described in the		*
 * DBW_uRAY General Public License. A copy of this license is		*
 * supposed to have been given to you along with DBW_uRAY so you	*
 * can know your rights and responsibilities. It should be in a file	*
 * named COPYING. Among other things, the copyright notice and this	*
 * notice must be preserved on all copies.				*
 ************************************************************************
 *									*
 * Authors:								*
 *	DBW - David B. Wecker						*
 *									*
 * Versions:								*
 *	V1.0 881023 DBW	- First released version			*
 *	V1.1 881110 DBW - Fixed scan coherence code			*
 *	V1.2 881125 DBW - Removed ALL scan coherence code (useless)	*
 *			  added "fat" extent boxes			*
 *									*
 ************************************************************************/

#include "uray.h"


/************************************************************************/
/************ module to write output files ******************************/
/************************************************************************/


void wfil(fil,cnt,val)	    /* write a number to a file (68000 order) */
FILE	*fil;
short	cnt;
char	val[];
    {

#ifdef MCH_AMIGA
    fwrite(val,cnt,1,fil);
#else
    while (cnt--) fwrite(&val[cnt],1,1,fil);
#endif

    }

short rfil(fil,cnt,val)	    /* read a number from a file (68000 order) */
FILE	*fil;
short	cnt;
char	val[];
    {

#ifdef MCH_AMIGA
    if (fread(val,cnt,1,fil) != 1)		   return(-1);
#else
    while (cnt--) if (fread(&val[cnt],1,1,fil) != 1) return(-1);
#endif

    return(0);
    }


/* create output files */
void coutputs() {
    int		i;

    /* first create the output .tmp file */
    if (bpp) {
	sprintf(str,"%s.tmp",basnam);
	fp = fopen(str,"w");
	if (!fp) leave("Bad output file");

	/* write out the header */
	wfil(fp,sizeof(short),&startrow);
	wfil(fp,sizeof(short),&endrow);
	wfil(fp,sizeof(short),&cols);
	wfil(fp,sizeof(short),&bpp);
	}

    /* second, create the output .ilbm file */
    sprintf(str,"%s.ilbm",basnam);
    fp2 = fopen(str,"w");
    if (!fp2) leave("Bad output file (ilbm)");

    /* write out the header */
    sprintf(str,"FORM");    fwrite(str,1,4,fp2);
    pos1 = ftell(fp2);
    lng = FORMsize;	    wfil(fp2,sizeof(long),&lng);
    sprintf(str,"ILBM");    fwrite(str,1,4,fp2);

    sprintf(str,"BMHD");    fwrite(str,1,4,fp2);
    lng = BMHDsize;	    wfil(fp2,4,&lng);
    wrd = cols;		    wfil(fp2,2,&wrd);   /* width */
    wrd = rows;		    wfil(fp2,2,&wrd);   /* height */
    wrd = startrow;	    wfil(fp2,2,&wrd);   /* top */
    wrd = 0;		    wfil(fp2,2,&wrd);   /* left */
    byt = DEPTH;	    wfil(fp2,1,&byt);   /* Depth */
    byt = 0;		    wfil(fp2,1,&byt);   /* mask */
    byt = 1;		    wfil(fp2,1,&byt);   /* compress */
    byt = 0;		    wfil(fp2,1,&byt);   /* pad */
    wrd = 0;		    wfil(fp2,2,&wrd);   /* transparency */
    byt = 10;		    wfil(fp2,1,&byt);   /* aspect x */
    byt = 11;		    wfil(fp2,1,&byt);   /* aspect y */
    wrd = cols;		    wfil(fp2,2,&wrd);   /* page width */
    wrd = rows;		    wfil(fp2,2,&wrd);   /* page height */

    sprintf(str,"CAMG");    fwrite(str,1,4,fp2);
    lng = CAMGsize;	    wfil(fp2,4,&lng);
    lng	= HAM | LACE;	    wfil(fp2,4,&lng);

    sprintf(str,"CMAP");    fwrite(str,1,4,fp2);
    lng = CMAPsize;	    wfil(fp2,4,&lng);
    pos3 = ftell(fp2);
    colors[0][0] = colors[0][1] = colors[0][2] = 0;
    lstcolor	  = 1;
    fwrite(colors,1,48,fp2);
    fwrite(colors,1,48,fp2);

    sprintf(str,"BODY");    fwrite(str,1,4,fp2);
    pos2 = ftell(fp2);
    lng = BODYsize;	    wfil(fp2,4,&lng);

    lsize = 0L;
    }

/* write a scan line to the output files */
void woutputs(sline)
short	sline;
    {
    int		    i,j,k,c,d,old[3],new[3],x,pxl,scr,addok,
		    index,bdist,ndist,maxdist,dcol,dval;
    unsigned char   buf[512],planes[6][128],b1,b2;

    /* print out 'dots' so the user knows we're working */
    if (sline % 50 == 0 || sline == startrow)    
			    printf("Row %4d: ",sline);
    printf(".");
    if (sline % 50 == 49)   printf("\n");
    else		    fflush(stdout);

    /* write out a scan line to .tmp file */
    if (bpp) {
	wfil(fp,sizeof(short),&sline);

	/* now write out each color of the scan line */
	for (i=0; i<3; i++) {

	    /* write out 24 bits per pixel */
	    if (cols == obpsl) fwrite(outary[i],1,obpsl,fp);

	    /* or 12 bits per pixel (need to pack it) */
	    else {
		for (x=0; x<cols; x++) {
		    b1   = outary[i][x];
		    b2   = b1 >> 4;
		    if (x & 1)	buf[x>>1] |= b2 & 0x0F;
		    else	buf[x>>1]  = b1 & 0xF0;
		    }
		fwrite(buf,1,obpsl,fp);
		}
	    }
	fflush(fp);
	}

    /* initialize the HAM encoding */
    for (i=0; i<3; i++) old[i] = 0;
    for (d=0; d<6; d++)
	for (i=0; i<MAXBYTE; i++)
	    planes[d][i] = 0;

    /* allow 1 new color to be added to colors[] per scan line (max) */
    addok = 1;

    /* set the amount of error for adding new colors[] */
    if (sline < (rows>>1))  maxdist = 127;
    else		    maxdist = 63;

    for (x=0; x<cols; x++,dcol++) {

	/* first get the desired old values (dither as necessary) */
	for (i=0; i<3; i++) {
	    dval    = ((int)outary[i][x]) & 0xF;
	    new[i]  = ((int)outary[i][x]) & 0xF0;
	    if (dval && new[i] != 0xF0 && dval > (random() & 0xF))
		new[i] += 0x10;
	    }

	/* get the best absolute color */
	bdist = 9999;
	for (i=0; i<lstcolor; i++) {
	    ndist = 0;
	    for (j=0; j<3; j++) 
		ndist += ABS(new[j] - (int)colors[i][j]);
	    if (ndist < bdist) {
		bdist = ndist;
		index = i;
		}
	    }

	/* now find worst color (to make relative change) */
	ndist = 0;
	j     = -1;
	for (i = 0; i<3; i++) {
	    if ((k=ABS(new[i] - old[i])) > j) { 
		c   = i; 
		j   = k;
		}
	    ndist += k;
	    }

	/* subtract off the gun we want to fix */
	ndist -= j;

	/* if relative is best, flag it (index = -1) (unless first pixel) */
	if (x > 0 && ndist < bdist) {
	    bdist = ndist;
	    index = -1;
	    }

	/* decide if we need a new color in the color table */
	if (addok && lstcolor < 16 && bdist > maxdist) {
	    for (i=0; i<3; i++) colors[lstcolor][i] = (unsigned char)new[i];
	    addok = 0;
	    bdist = 0;
	    index = lstcolor++;
#	    if DEBUG_ilbm
		printf("Adding color %2d: %02x%02x%02x\n",index,
		    new[0],new[1],new[2]);
#		endif
	    }

	/* now change the gun (for relative) */
	if (index == -1) {
	    pxl = (old[c] = new[c]) >> 4;
	    switch (c) {
		case 0: pxl |= 0x20;  break;
		case 1: pxl |= 0x30;  break;
		case 2: pxl |= 0x10;  break;
		}
	    }
	else {
	    pxl = index;
	    for (i=0; i<3; i++) old[i] = (int)colors[index][i];
	    }

#	if DEBUG_ilbm
	    printf("%4d,%4d: %02x (%d)\n",sline,x,pxl,bdist);
#	    endif

	/* and store the pixel away */
	j = x >> 3;
	k = 7 - (x & 0x7);
	for (i=0; i<DEPTH; i++) {
	    planes[i][j] |= (pxl & 1) << k;
	    pxl >>= 1;
	    }
	}

    /* now pack the row away (RKM run length encoding) */
    for (i=0; i < DEPTH; i++) {
	wrd    = PackRow(planes[i],buf,MAXBYTE);
	lsize += (long)wrd;
	fwrite(buf,1,wrd,fp2);
	}
    }
