/* 
 * unexp.c - take an exponential RLE file and make an integer file.
 * 
 * Author:	John W. Peterson
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Wed Aug 21 17:02:45 1985
 *
 *		Based on code by Spencer Thomas
 */

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

#define MAX(i,j)   ( (i) > (j) ? (i) : (j) )

#define RLE_EXPONENT (in_hdr.ncolors-1) /* Assume last channel is exp */

rle_pixel **in_rows;
rle_pixel **out_rows;

int truncations = 0;
rle_hdr in_hdr, out_hdr;
rle_pixel r_in, g_in, b_in;

void
main(argc,argv)
int argc;
char *argv[];
{
    register int x, chan;
    int y;
    int scan_flag = 0;
    int max_flag = 0;
    int verbose_flag = 0;
    int print_flag = 0;
    int oflag = 0;
    float maxval, tmp, expnt, tmp_max;
    char *infilename = NULL, *outfilename = NULL;
    FILE *outfile = stdout;
    int rle_cnt, rle_err;
    long start;

    if (scanargs(argc, argv, "% v%- p%- s%- m%-maxval!f o%-outfile!s infile!s",
                 &verbose_flag, &print_flag, &scan_flag, &max_flag, &maxval, 
		 &oflag, &outfilename, &infilename ) == 0)
    {
	exit(-1);
    }

    (void)rle_hdr_init( &in_hdr );
    in_hdr.rle_file = rle_open_f(cmd_name( argv ), infilename, "r");
    rle_names( &in_hdr, cmd_name( argv ), infilename, 0 );
    rle_names( &out_hdr, in_hdr.cmd, outfilename, 0 );
    for ( rle_cnt = 0; ; rle_cnt++ )
    {
	start = ftell( in_hdr.rle_file );
	if ( start < 0 && !max_flag && !scan_flag )
	{
	    fprintf( stderr,
		     "%s: Can't pipe input unless either -m or -s is given.\n",
		     cmd_name( argv ) );
	    exit( 1 );
	}

	if ( (rle_err = rle_get_setup( &in_hdr )) != RLE_SUCCESS )
	    break;

	if (! rle_getcom( "exponential_data", &in_hdr ))
	    fprintf(stderr, "%s: warning - no exponential_data comment\n",
		    cmd_name( argv ));

	if (in_hdr.ncolors < 2)
	{
	    fprintf(stderr, 
		    "%s: File does not contain exponent channel.\n",
		    cmd_name( argv ));
	    exit(-4);
	}

	if ( rle_row_alloc( &in_hdr, &in_rows ) < 0 )
	    RLE_CHECK_ALLOC( cmd_name( argv ), 0, 0 );

	/* If maximum value isn't given, slosh through file to find it */
	if (! max_flag)
	{
	    maxval = 0.0;
	    for (y = in_hdr.ymin; y <= in_hdr.ymax; y++)
	    {
		if ((verbose_flag) && (y % 100) == 0)
		    fprintf(stderr, "Scanning row %d...\n", y);
	    
		rle_getrow( &in_hdr, in_rows );

		for (x = in_hdr.xmin; x <= in_hdr.xmax; x++)
		{
		    expnt = ldexp( 1/256.0, in_rows[RLE_EXPONENT][x] - 127);
		    tmp = -2000.0;
		    for (chan = 0; chan < RLE_EXPONENT; chan++)
			tmp = MAX( tmp, (float)in_rows[chan][x] );

		    tmp *= expnt;
		    maxval = MAX( maxval, tmp );
		}
	    }
	    if (scan_flag || print_flag || verbose_flag)
		fprintf(stderr, "Maximum value: %1.8g\n", maxval);

	    if (scan_flag) exit(0);

	    fseek( in_hdr.rle_file, start, 0 );
    
	    rle_get_setup( &in_hdr );
	}

	/* Open output file */

	(void)rle_hdr_cp( &in_hdr, &out_hdr );
	rle_delcom( "exponential_data", &out_hdr );
	out_hdr.ncolors = in_hdr.ncolors - 1;
	if ( rle_cnt == 0 )
	    outfile = rle_open_f( cmd_name( argv ), outfilename, "w" );
	out_hdr.rle_file = outfile;

	rle_addhist( argv, &in_hdr, &out_hdr );

	rle_put_setup( &out_hdr );

	out_hdr.xmin = 0;
	out_hdr.xmax -= in_hdr.xmin;

	if (rle_row_alloc( &out_hdr, &out_rows ) < 0)
	    RLE_CHECK_ALLOC( cmd_name( argv ), 0, 0 );

	/*
	 * Convert byte/exponent form into straight RLE.
	 * Alpha is passed straight through.
	 */

	if ( maxval == 0.0 )
	    maxval = 1.0;
	else
	    maxval /= 255;	/* Pre-scale to 0-255 */

	for (y = in_hdr.ymin; y <= in_hdr.ymax; y++)
	{
	    if (((y % 100) == 0) && verbose_flag)
		fprintf(stderr, "Processing row %d...\n", y);
	
	    rle_getrow( &in_hdr, in_rows );

	    for (x = in_hdr.xmin; x <= in_hdr.xmax; x++)
	    {
		/* Only bother with pixels with coverage */
		if (in_rows[RLE_ALPHA][x]) 
		{
		    expnt = ldexp( 1/256.0, in_rows[RLE_EXPONENT][x] - 127 );
		    tmp_max = -1000;
		    for( chan = 0; chan < RLE_EXPONENT; chan++ )
			tmp_max = MAX( tmp_max, in_rows[chan][x] );

		    tmp = expnt / maxval * tmp_max;
		    if (tmp > 255)
		    {
			tmp = 255 / tmp;
			truncations++;
		    }
		    else
			tmp = 1.0;

		    tmp *= expnt / maxval;
		    for( chan = 0; chan < RLE_EXPONENT; chan++ )
			out_rows[chan][x-in_hdr.xmin] = (rle_pixel) (int)
			    (in_rows[chan][x] * tmp);
		    out_rows[RLE_ALPHA][x-in_hdr.xmin] = 
			in_rows[RLE_ALPHA][x];
		}
		else
		    for( chan = RLE_ALPHA; chan < RLE_EXPONENT; chan++ )
			out_rows[chan][x-in_hdr.xmin] = 0;
	    	
	    }
	    rle_putrow( out_rows, (in_hdr.xmax - in_hdr.xmin) + 1,
			&out_hdr );
	}
	rle_puteof( &out_hdr );

	if (truncations)
	    fprintf(stderr,"%s: %d bytes truncated (sorry...)\n",
		    cmd_name( argv ), truncations);

	rle_row_free( &in_hdr, in_rows );
	rle_row_free( &out_hdr, out_rows );
    }

    /* 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 ), infilename );

    exit( 0 );
}
