[comp.graphics] QRT Post-Processor for VGA

mckenney@talos.UUCP ( APL Consultant) (03/23/89)

A few weeks ago I downloaded the QRT source, documentation, and sample files
from the Cleveland Area-Amiga Users' Group BBS. I am extremely impressed with
the work Mr. Koren has put into this software. I have ported it to PC-DOS, and
have it up and running under Microsoft C 5.1 (compact model). In the process I
wound up making the following changes:

   - Changed text/source file line delimiter from \x0A to \x0A\x0D
   - Set CNUM to 256, so the post-processor can do color reduction
   - Fix for malloc(strlen()) bug
   - Added #ifdefs for MSC which call appropriate #include files
   - Added qrtfn.h containing function declarations in ANSI form
   - Fixed side-effect problem with toupper() macro
   - Installed calls for def_colorinfo() for all new CINFOs
   - Added ACTIVITY option to RAY.C to show activity while tracing
   - Added "default to VGA" in QRT.H specifications
   - Fixed fopen() calls to use BINARY mode
   - Changed byte array definitions from 'short' to 'unsigned char' in
      Screen_Trace() and Dump_Line().
   - Limited trace statement in Screen_Trace() to 0..255 to prevent
      misleading trace information.
   - Update defaults for ambient light and threshold in QRT.C
   - Corrected CNUM to CNUM-1 in a number of places
   - Changed ASPECT from .56 to 1.20 for 320x200 mode

A QRT post-processor which generates .PIC files suitable for GRASP (PICTOR)
and PC Paint is attached for those interested.

Further work will probably be in two areas:

    1) Better palette color selection through a pre-scan of the raw data file.

    2) A method for producing a quick 'preview' of a scene. This would allow
       me to play around with object placement and correct any obvious errors
       before I turn the machine loose for several hours.

For those of you interested in timings, the PIANO.QRT file took 95 minutes to
process on an Everex System 1800 (10MHz, 1ws) with an 80287 installed.

The following files are available from the Cleveland Area-Amiga Users' Group
BBS at (216) 292-4404:

QRTSRC14.ARC    57344  08-24-88  Source for QRT 1.4 (C)
QRTDOC4A.ARC    56320  09-24-88  Includes 'UserMan.Doc' from 1.4
QRTINP14.ARC    16512  11-05-88  6 QRT inp scripts, plus QRT news
TABLE.ARC       72704  08-24-88  Demo for QRT1.4-glass table
PIANO.ARC        4736  06-25-88  QRT image spec for grand piano
MIRRORS.ARC      2560  06-15-88  QRT source (not pic)

/*-------------- QRTIBM.C --------------------------------------------------*/
/****************************************************************************
	QRTIBM Version 1.0	IBM VGA Post-processor for QRT

	Syntax:  QRTIBM Input[.RAW] [ Output[.PIC] ]

	Written by:   Frank McKenney, McKenney Associates
	Last Updated: 03/22/89
	Compiler: Microsoft C 5.1	Model: Small
 **********************************************************************

 QRTIBM is a QRT post-processor which converts QRT raw output (.RAW)
 files to GRASP/PICTOR (.PIC) Mode L format (320x200, 256-color).

 The format of the QRT raw data file is as follows:

	Offset	Length	Description
	------	------	-----------
	     0	     2	XRES - X resolution (pixels), Intel format (low,high)
	     2	     2	YRES - Y resolution (pixels), Intel format (low,high)
	     4	  ...	Up to YRES sets of scan line information. Each line
			is (2+3*XRES) bytes long, formatted as follows:
      --------	------
	    +0	     2  Line number, Intel format (low,high) Top is line 0.
	    +2	  XRES	Red intensity values (1 byte each, 0-255)
       +XRES+2	  XRES	Green intensity values (1 byte each, 0-255)
     +2*XRES+2	  XRES	Blue intensity values (1 byte each, 0-255)

 Note 1: Scan lines may be omitted from the file, but the scan line
        number will always be in the range 0..YRES-1.

 Note 2: The GRASP .PIC format assumes that scan line 0 is at the BOTTOM
	of the screen, while QRT assumes it to be at the TOP. As a result,
	we have to work our way backwards through the input file.

 Note 3: The current version of QRTIBM assumes that QRT's CNUM value
	(the number of shades per color) has been set to 255, and maps
	the resulting R/G/B values into 2/3/3 bits (respectively). This
	yields a reasonable variety of colors within the 256 color limit
	imposed by the VGA adapter.
	 It is possible that the palette could be improved through a pre-
	scan of the input. Suggestions are welcomed.

*****************************************************************************/

#include <stdio.h>
#include <string.h>

/* #define DEBUG */
#define TRACK_RGB

#define MAXXRES 320	/* Largest X resolution currently supported	 */
#define LineSizeL (2L + (3L * (long)xres))
#define MIN(a,b)    (((a) < (b)) ? (a) : (b))
#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
#define OBUF_SIZE 8192	/* Just a nice large buffer			*/

char obuf[OBUF_SIZE];	/* Output buffer (.PIC file)	*/
	/* Temporary (!) Kluge */
char pichdr[17] = 	/* File header for uncompressed MCGA/VGA image */
  "\x34\x12\x40\x01\xC8\x00\x00\x00\x00\x00\x08\xFF\x4C\x04\x00\x00\x03";
char InFile[65], OutFile[65];	/* Input and output file names */

main(argc,argv)
int argc;
char *argv[];
{
    int xres, yres, scanline, lastline;
    int i, j, rv, gv, bv, iv, v;
    float iflt;
    unsigned char r[MAXXRES], g[MAXXRES], b[MAXXRES];
    long inpos;
    FILE *in, *out;
    char *p;
#ifdef TRACK_RGB
    int maxr = 0, maxg = 0, maxb = 0;	/* Track .RAW file RGB values */
#endif

    /* Quick parameter check / help message */
    if (argc < 2 || argc > 3)
        {
        printf("Usage: %s Input[.RAW] Output[.PIC]\n",argv[0]);
        exit(1);
        }

    strcpy(InFile,argv[1]);
    if (argc == 3)	/* Output file name supplied			*/
	strcpy(OutFile,argv[2]);
    else		/* Default to same base name as input file	*/
	{
	strcpy(OutFile,InFile);
	if ( (p=strchr(OutFile,'.')) != NULL )
	    *p = '\0';	/*   (but don't retain any extension).		*/
	}

    if ( strchr(InFile,'.') == NULL )
	strcat(InFile,".RAW");

    if ( strchr(OutFile,'.') == NULL )
	strcat(OutFile,".PIC");

    /* Open input and output files in BINARY Mode. Abort if error */
    if ((in = fopen(InFile,"rb")) == NULL)
        {
        printf("Unable to open input file %s\n",InFile);
        exit(1);
        }
    if ((out = fopen(OutFile,"wb")) == NULL)
        {
        printf("Unable to open output file %s\n",OutFile);
        exit(1);
        }

    /* Set up buffer for output file */
    setvbuf(out,obuf,_IOFBF,sizeof(obuf));

    /* Retrieve X and Y pixel counts from input file */
    xres  =  fgetc(in) & 0x00FF;        /* Reconstruct word */
    xres |= (fgetc(in) & 0x00FF) << 8;
    yres  =  fgetc(in) & 0x00FF;        /* Reconstruct word */
    yres |= (fgetc(in) & 0x00FF) << 8;

    printf("Input:     %s\n",InFile);
    printf("Output:    %s\n",OutFile);
    printf("Screen:    %dh x %dv\n",xres,yres);

    /* Write out .PIC header for Mode L (kluge for now) */
    for (i=0; i<sizeof(pichdr); i++)
	fputc(pichdr[i],out);

    for (i=0; i<256; i++)    /* Make up a .PIC palette */
	{
	/* Set up palette so we can index it with rrrgggbb */
  #define MAX_IVAL 63
  #define N_REDS    8
  #define N_GREENS  8
  #define N_BLUES   4
  #define K1_RED   ((float)(MAX_IVAL)/(N_REDS-1))
  #define K1_GREEN ((float)(MAX_IVAL)/(N_GREENS-1))
  #define K1_BLUE  ((float)(MAX_IVAL)/(N_BLUES-1))
        rv = K1_RED   * ((i & 0xE0) >> 5);	rv = MIN(MAX_IVAL,rv);
        gv = K1_GREEN * ((i & 0x1C) >> 2);	gv = MIN(MAX_IVAL,gv);
        bv = K1_BLUE  *  (i & 0x03);		bv = MIN(MAX_IVAL,bv);
        fputc(rv,out);
        fputc(gv,out);
        fputc(bv,out);
        }

    fputc('\x00',out); fputc('\x00',out);  /* Mark as unpacked file */

    /* Seek to end of file, just past end of last scan line.	*/
    /* Read resulting position and check for validity.		*/
    fseek(in, 0L, SEEK_END);
    inpos = ftell(in);    /* Works since file opened in binary mode */

    if ( (inpos - 4) % LineSizeL )
        {
        printf("Input file has one or more partial scan lines\n");
        exit(1);
        }
    if ( inpos > (long)(4L + (long)yres * LineSizeL) )
        {
        printf("Input file not valid - too large for resolution\n");
        exit(1);
        }

    for (lastline = yres - 1; lastline >= 0; lastline--)
	{
	inpos -= LineSizeL;		/* Back up to previous line in file */
	fseek(in, inpos, SEEK_SET);

	/* Get scan line number from file and validate */
	scanline =   fgetc(in) & 0xFF;	/* Reconstruct word */
	scanline += (fgetc(in) & 0xFF) << 8;
#ifdef DEBUG
	printf("File pos: %ld, file scanline %.3d, lastline: %.3d\n",
		inpos, scanline, lastline);
#endif
	if ( scanline > yres )
	    {
	    printf("Input contains bad scan line (%d) at position %ld\n",
		scanline, inpos);
	    exit(1);
	    }
	if ( scanline > lastline )
	    {
	    printf("Input scan line %d out of order at position %ld\n",
		scanline, inpos);
	    exit(1);
	    }

	/* Possibly provide blank (Black) scan lines */
	while ( lastline > scanline )
	    {
#ifdef DEBUG
	    printf("Filling scan line %.3d\n",lastline);
#endif
	    for (i=0; i < xres; i++)	/* Write one line of black */
		fputc('\x00',out);
	    lastline--;
	    }

	/* Read Red, Green, and Blue intensity values from file */
	for (i=0; i < xres; i++)
	    r[i] = fgetc(in);
	for (i=0; i < xres; i++)
	    g[i] = fgetc(in);
	for (i=0; i < xres; i++)
	    b[i] = fgetc(in);

	/* Convert intensity values to palette index */
	/* and write out to file.	    */
	for (i=0; i < xres; i++)
	    {
	    rv = r[i];	    gv = g[i];	    bv = b[i];
#ifdef TRACK_RGB
	    maxr = MAX(rv,maxr);
	    maxg = MAX(gv,maxg);
	    maxb = MAX(bv,maxb);
#endif
	    /* Create a one byte rrrgggbb palette index from RGB values */
	    rv = (rv+15) >> 5;  gv = (gv+15) >> 5;  bv = (bv+31) >> 6;
	    rv = MIN(0x07,rv);  gv = MIN(0x07,gv);  bv = MIN(0x03,bv);
	    v = (rv << 5) | (gv << 2) | bv;
	    fputc(v,out);
	    } /* End for (each pixel in scan line) */
	} /* End for (each scan line) */

#ifdef TRACK_RGB
    printf("Max R/G/B: %d/%d/%d\n",maxr,maxg,maxb);
#endif

    fclose(in);			/* Close Files */
    fclose(out);
    exit(0);
}
/*-------------- End of QRTIBM.C -------------------------------------------*/
--------------------------------------------------------
Frank McKenney, President  | {uunet,rti}!talos!mckenney
McKenney Associates	   |
3464 Northview Place	   |   guest account - access
Richmond, Virginia 23225   |  provided as a courtesy by
USA     (804) 320-4887	   |     Philip Morris USA
--------------------------------------------------------