/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */
/*
 * rlestereo.c - Merge two RLE images to form a single red-green or red-blue
 * 		 image suitable for viewing with them goofy glasses. 
 *
 * Author:      Craig E. Kolb
 * 		Department of Mathematics
 *		Yale Unversity
 * Date:        Mon Jul 30 1990
 * Copyright (C) 1990, Craig E. Kolb
 */
#ifndef lint
char rcsid[] = "$Header: /l/spencer/src/urt/tools/RCS/rlestereo.c,v 3.0.1.3 1992/04/30 14:14:07 spencer Exp $";
#endif
/*
rlestereo()			Tag the file.
*/

#include <stdio.h>
#include "rle.h"

#define LEFTSCALE	0.7		/* Default left scale factor. */
#define RIGHTSCALE	1.0		/* Default right scale factor. */

/*
 * Macro to convert input values to greyscale, taking colormap into
 * account.
 */
#define REDC		0.30
#define GREENC		0.59
#define BLUEC		0.11
#define GREYCONV(r,g,b,m) (REDC*m[0][r]+GREENC*m[1][g]+BLUEC*m[2][b])

float	LeftScale = LEFTSCALE;		/* Scale factor for left channel. */
float	RightScale = RIGHTSCALE;	/* Scale factor for right channel. */
int	GreenFlag = 0;			/* True if second channel is green. */
int	Xres, Yres;			/* Image resolution. */
int	lcolors, rcolors;		/* # channels in left/right images. */
int	RightIndex;			/* Index of second channel (1 or 2). */
int	lchan1, lchan2;			/* Channel indices for left image. */
int	rchan1, rchan2;			/* Channel indices for right image. */
rle_pixel **lmap, **rmap;		/* Colormap for left/right images. */

#ifdef USE_PROTOTYPES
void convert_line(rle_pixel **, rle_pixel **, rle_pixel **);
int get_rle_setup(rle_hdr *, int *, int *);
#else
void convert_line();
int get_rle_setup();
#endif
/*
 * Read two named RLE files and produces a single image suitable for viewing
 * with red-blue or red-green glasses.  The 'left' image is converted to
 * greyscale and written on the red channel.  The 'right' image is converted
 * to greyscale and written on the blue or green channel.  The intensity of the
 * two channels may be scaled in order to compensate for the relative
 * intensities of the two base colors as viewed through the glasses.
 *
 * Options:
 * 
 *	-g		Produce red-green image rather than red-blue.
 *	-l scale	Scale factor for left-eye image (default 0.7).
 *	-r scale	Scale factor for right-eye image (default 1.0).
 */

void
main(argc, argv)
int argc;
char **argv;
{
	int y, i, Xtmp, Ytmp, scaleflag = 0;
	char *leftname = NULL, *rightname = NULL;
	char *outname = NULL;
	FILE *outfile = stdout;
	int oflag;
	rle_pixel **lline, **rline, **outline;
	rle_hdr 	left_hdr, right_hdr, out_hdr;
	int rle_cnt = 0, rle_err;
	char *err_name = NULL;

 	left_hdr = *rle_hdr_init( NULL );
	right_hdr = *rle_hdr_init( NULL ); 
	out_hdr = *rle_hdr_init( NULL );

	if (scanargs(argc, argv,
		"% g%- l%-leftscale!f r%-rightscale!f o%-outfile!s \n\
	leftimage!s rightimage!s",
		&GreenFlag, &scaleflag, &LeftScale, &scaleflag, &RightScale,
		&oflag, &outname,
		&leftname, &rightname) == 0) {
		exit(-1);
	}

	/*
	 * Open left and right images.
	 */
	(void)rle_hdr_init( &left_hdr );
	(void)rle_hdr_init( &right_hdr );
	left_hdr.rle_file = rle_open_f(cmd_name(argv), leftname, "r");
	right_hdr.rle_file = rle_open_f(cmd_name(argv), rightname, "r");
	rle_names( &left_hdr, cmd_name(argv), leftname, 0 );
	rle_names( &right_hdr, cmd_name(argv), rightname, 0 );
	rle_names( &out_hdr, left_hdr.cmd, outname, 0 );

	for ( rle_cnt = 0;; rle_cnt++ )
	{
	    /*
	     * Read headers of both images.
	     */
	    if ( (rle_err = 
		  get_rle_setup(&left_hdr, &Xres, &Yres)) != RLE_SUCCESS )
	    {
		err_name = leftname;
		break;
	    }
	    if ( (rle_err =
		  get_rle_setup(&right_hdr, &Xtmp, &Ytmp)) != RLE_SUCCESS )
	    {
		err_name = rightname;
		break;
	    }

	    /* Open the output file when first header is successfully read. */
	    if ( rle_cnt == 0 )
		outfile = rle_open_f( cmd_name( argv ), outname, "w" );

	    if (Xres != Xtmp || Yres != Ytmp) {
		fprintf(stderr,"Images are of different sizes.\n");
		exit(-1);
	    }

	    (void)rle_hdr_cp( &left_hdr, &out_hdr );
	    out_hdr.ncolors = 3;
	    out_hdr.ncmap = 0;
	    out_hdr.rle_file = outfile;
	    rle_addhist(argv, &left_hdr, &out_hdr);
	    rle_put_setup(&out_hdr);

	    /*
	     * Ignore alpha and any channels > #2.
	     */
	    RLE_CLR_BIT(left_hdr, RLE_ALPHA);
	    RLE_CLR_BIT(right_hdr, RLE_ALPHA);
	    for (i = 3; i < left_hdr.ncolors; i++)
		RLE_CLR_BIT(left_hdr, i);
	    for (i = 3; i < right_hdr.ncolors; i++)
		RLE_CLR_BIT(right_hdr, i);

	    lcolors = left_hdr.ncolors > 3 ? 3 : left_hdr.ncolors;
	    rcolors = right_hdr.ncolors > 3 ? 3 : right_hdr.ncolors;

	    if (lcolors == 1)
		lchan1 = lchan2 = 0;
	    else if (lcolors == 2) {
		lchan1 = 1;
		lchan2 = 0;
	    } else {
		lchan1 = 1;
		lchan2 = 2;
	    }

	    if (rcolors == 1)
		rchan1 = rchan2 = 0;
	    else if (rcolors == 2) {
		rchan1 = 1;
		rchan2 = 0;
	    } else {
		rchan1 = 1;
		rchan2 = 2;
	    }

	    if ( rle_row_alloc(&left_hdr, &lline) < 0 ||
		 rle_row_alloc(&right_hdr, &rline) < 0 ||
		 rle_row_alloc(&out_hdr, &outline) < 0 )
		RLE_CHECK_ALLOC( left_hdr.cmd, 0, "images" );
	    /*
	     * Zero unused channel of output scanline.
	     */
	    if (GreenFlag) {
		RightIndex = 1;
		bzero(outline[2], Xres * sizeof(rle_pixel));
	    } else {
		RightIndex = 2;
		bzero(outline[1], Xres * sizeof(rle_pixel));
	    }

	    /*
	     * In case there's a colormap, DTRT.  We use a gamma of 1.
	     * here because we want the output image to have the same
	     * gamma as the left image.
	     */
	    lmap = buildmap(&left_hdr, 3, 1., 1.0);
	    rmap = buildmap(&right_hdr, 3, 1., 1.0);
	    /*
	     * For each output scanline...
	     */
	    for (y = 0; y < Yres; y++) {
		/*
		 * Read left and right scanline, converting each
		 * to greyscale data.
		 */
		rle_getrow(&left_hdr, lline);
		rle_getrow(&right_hdr, rline);
		convert_line(outline, lline, rline);
		rle_putrow(outline, Xres, &out_hdr);
	    }
	    while ( rle_getskip(&left_hdr) != 32768 )
		;
	    while ( rle_getskip(&right_hdr) != 32768 )
		;

	    rle_row_free(&left_hdr, lline);
	    rle_row_free(&right_hdr, rline);
	    rle_row_free(&out_hdr, outline);

	    rle_puteof( &out_hdr );
	}
	fclose(left_hdr.rle_file);
	fclose(right_hdr.rle_file);

	/* Check for an error.  EOF or EMPTY is ok if at least one image
	 * has been read.  Otherwise, print an error message.
	 */
	if ( rle_cnt == 0 || (rle_err != RLE_EOF && rle_err != RLE_EMPTY) )
	    rle_get_error( rle_err, cmd_name( argv ), err_name );
	exit(0);
}

int
get_rle_setup(the_hdr, xres, yres)
int *xres, *yres;
rle_hdr *the_hdr;
{
    	int err;

	err = rle_get_setup(the_hdr);
	*xres = the_hdr->xmax - the_hdr->xmin + 1;
	*yres = the_hdr->ymax - the_hdr->ymin + 1;
	the_hdr->xmax -= the_hdr->xmin;
	the_hdr->xmin = 0;
	return err;
}

void
convert_line(out, left, right)
rle_pixel **out, **left, **right;
{
	register int i;
	
	/*
	 * Convert input scanlines to 'stereo' output scanline.
	 */
	for (i = 0; i < Xres; i++) {
		out[0][i] = LeftScale * GREYCONV(left[0][i], left[lchan1][i],
				left[lchan2][i], lmap);
		out[RightIndex][i] = RightScale * GREYCONV(right[0][i],
				right[rchan1][i], right[rchan2][i], rmap);
	}
}
