#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	NeXT.fixes
#	README
#	ray2eps.c
# This archive created: Fri Mar 30 19:27:37 1990
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
CC=cc
CFLAGS= -g -O -Wall

all:	ray2eps2 ray2eps8 ray2eps24

ray2eps2:	ray2eps.c
	$(CC) $(CFLAGS) -DTWOBITGREYSCALE ray2eps.c -o ray2eps2 -lm

ray2eps8:	ray2eps.c
	$(CC) $(CFLAGS) -DEIGHTBITGREYSCALE ray2eps.c -o ray2eps8 -lm

ray2eps24:	ray2eps.c
	$(CC) $(CFLAGS) -DTWENTYFOURBITCOLOR ray2eps.c -o ray2eps24 -lm

clean:
	rm -f *.o ray2eps2 ray2eps8 ray2eps24
SHAR_EOF
fi # end of overwriting check
if test -f 'NeXT.fixes'
then
	echo shar: will not over-write existing file "'NeXT.fixes'"
else
cat << \SHAR_EOF > 'NeXT.fixes'
Makefile change for NeXT

Add the following to CFLAGS:

  -Dmalloc=ray_malloc -Drealloc=ray_realloc -Dfree=ray_free

Explanation:

You need to use the supplied malloc/free/realloc as rayshade depends on being
able to access a chunk of memory after it has been free()'d (but before free()
has been called again).  The malloc supplied by NeXT does not allow you to
do this, my guess is that it will vm_deallocate() pages of memory when it
knows all the chunks on the page have been free()'d.  I don't really care who
is right, I just want to be able to run rayshade.

However, you cannot just use the supplied malloc as it will conflict with a
name in the shared library on the NeXT, as the malloc from the shared lib is
always brought in.  (This is probably because symbols within the shared
library get resolved when the library is created if the symbol is defined
within the library itself).  So you have to change the names.


-Jonathan
SHAR_EOF
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

This is a little program I threw together to generate Encapsulated PostScript
files from MTV-style output from rayshade.  The usage is:

ray2eps(2|8|24) input_file > output_file

The Makefile will generate three different executables, one outputs 2-bit
greyscale, one outputs 8-bit greyscale, and the last outputs 24-bit color.
I'm too lazy to combine it into one executable.

The 2-bit output uses Floyd-Steinberg dithering and is suitable for generating
backgrounds for a 2-bit greyscale NeXT display.  It is not suitable for
printing as it optimizes for two-bit output and throws away extra information
that would be useful when printing.

The 8-bit output is good for printing.  The 24-bit output should not be used
on a greyscale device as PostScript seems to be inconsistent in how it treats
greyscale and color image data.  I am log encoding the 8-bit data, and it
displays and prints ok, so it appears that PostScript expects log encoded
image data.  However, when you feed it log encoded color data, they don't
appear to be gamma correcting it before they compute the luminance.  They
are just plugging the values right into the calculation.  This is wrong.
You can see this if you use rayshade to render solids.ray.  The red ball
appears correct if you generate 2 or 8 bit greyscale, but the ball is much
too dim if you use the 24-bit color EPS output.  There's really nothing I can
do about this - if I linearly encode the image data so the luminance
calculation is done correctly, PostScript won't log encode it before it is
displayed and everything will be dim, not just red and blue.

The settransfer operator might let you compensate for this, but it seems to
me that there's an inconsistency here.

The 24-bit data does display correctly in a color Display PostScript window
though.

-Jonathan		apple!netcom!hue
SHAR_EOF
fi # end of overwriting check
if test -f 'ray2eps.c'
then
	echo shar: will not over-write existing file "'ray2eps.c'"
else
cat << \SHAR_EOF > 'ray2eps.c'
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <math.h>

#ifndef TWOBITGREYSCALE		/* define one of these */
#ifndef EIGHTBITGREYSCALE
#ifndef TWENTYFOURBITCOLOR
You
Lose
#endif
#endif
#endif

extern char *optarg;
extern int optind, getopt(int argc, char **argv, char *optstring);
extern void bzero(char *b, int length);

#ifdef TWOBITGREYSCALE
void FSDither82(short *indata, short *errorTerms,
	   u_char *outdata, short row, short npixels);
#endif

void usageexit();

#ifndef LINT
static char rcsid[] = "$Header: /Users/jonathan/src/image/RCS/ray2eps8.c,v 1.1 90/03/07 17:44:33 jonathan Exp Locker: jonathan $";
#endif

/*
 * Program to take MTV output (not RLE!) from rayshade and convert it
 * to some sort of EPS
 *
 * Hacked together out of bits of other programs.
 *
 * You might want to tweak gamma until it looks good to you.  2.0 is a good
 * starting point.
 */
int
main(int argc, char **argv)
{
    int row, col, width, height, c;
    int total_chars = 0;
#ifndef TWENTYFOURBITCOLOR
    u_char r, g, b;
#endif
    u_char *indata, *inp, log[256], exp[256];
    FILE *fp;
    char s[80];
    double gamma = 2.0;
#ifdef TWOBITGREYSCALE
    int num_outbytes;
    u_char *outdata;
    short *bw, *err;
#else
#ifdef EIGHTBITGREYSCALE
    u_char *bw;
#endif
#endif

    while ((c = getopt(argc, argv, "g:")) != EOF)
    {
	switch(c)
	{
	  case 'g':
	    gamma = atof(optarg);
	    break;
	  default:
	    usageexit();
	}
    }
    if (argc != (optind + 1))
	usageexit();
    if ((fp = fopen(argv[optind], "r")) == NULL)
    {
	fprintf(stderr, "ray2eps: Couldn't open %s\n", argv[optind]);
	exit(2);
    }
    for (col = 0; col < 256; col++)
    {
	log[col] = 255 * pow(col / 255.0, 1.0 / gamma);
	exp[col] = 255 * pow(col / 255.0, gamma);
    }

    /*
     * Get dimensions of picture
     */
    fgets(s, sizeof(s), fp);
    sscanf(s, "%d %d", &width, &height);
    fprintf(stderr, "ray2eps: Width is %d Height is %d\n", width, height);

    /*
     * Alloc mem for buffers
     */
    indata = (u_char *) malloc(width * 3);
#ifdef TWOBITGREYSCALE
    bw = (short *) malloc((width + 2) * sizeof(short));
    err = (short *) malloc((width + 2) * sizeof(short));
    num_outbytes = (width + 3) / 4;
    outdata = (u_char *) malloc(num_outbytes);
    if (!indata || !bw || !err || !outdata)
#else
#ifdef EIGHTBITGREYSCALE
    bw = (u_char *) malloc(width);
    if (!indata || !bw)
#else
#ifdef TWENTYFOURBITCOLOR
    if (!indata)
#endif
#endif
#endif
    {
	fputs("ray2eps: ran out of swap space or something\n", stderr);
 	exit(10);
    }

    puts("%!PS-Adobe-2.0 EPSF-1.2");
    puts("%%Creator:ray2eps");
    printf("%%%%Title:%s.eps\n", argv[optind]);
    printf("%%%%Origin:0 %d\n", height);
    printf("%%%%BoundingBox: 0.000 0.000 %d.000 %d.000\n", width, height);
    puts("%%EndComments");
    puts("/picstr 16 string def");
    puts("gsave");
    printf("%d %d scale\n", width, height);
#ifdef TWOBITGREYSCALE
    printf("%d %d 2\n", width, height);
#else
    printf("%d %d 8\n", width, height);
#endif
    printf("[%d 0 0 %d neg 0 %d]\n", width, height, height);
    puts("{currentfile picstr readhexstring pop}");

#ifdef TWOBITGREYSCALE
    puts("image");

    /*
     * Process the image
     */
    for (row = 0; row < height; row++)
    {
	bzero((char *) bw, sizeof(short) * (width + 2));
	if (fread(indata, width * 3, 1, fp) != 1)
	{
	    fputs("ray2eps: short read from input file", stderr);
	    exit(11);
	}
	inp = indata;
        for (col = 0; col < width; col++)
 	{
	    r = *inp++;
	    g = *inp++;
	    b = *inp++;
	    bw[col+1] = log[((r * 77) + (g * 150) + (b * 28)) >> 8];
	}
	for (col = 0; col < width + 2; col++)
	    bw[col] += err[col];
        bzero((char *) err, sizeof(short) * (width + 2));
        bzero((char *) outdata, num_outbytes);
	FSDither82(bw, err, outdata, (short) row, (short) width);
	for (col = 0; col < num_outbytes; col++)
	{
	    total_chars++;
	    printf("%02X", outdata[col]);
	    if (!(total_chars & 0x1f))
		putchar('\n');
	}
    }
#else
#ifdef EIGHTBITGREYSCALE
    puts("image");

    /*
     * Process the image
     */
    for (row = 0; row < height; row++)
    {
	if (fread(indata, width * 3, 1, fp) != 1)
	{
	    fputs("ray2eps: short read from input file", stderr);
	    exit(11);
	}
	inp = indata;
        for (col = 0; col < width; col++)
 	{
	    r = *inp++;
	    g = *inp++;
	    b = *inp++;
	    bw[col] = log[((r * 77) + (g * 150) + (b * 28)) >> 8];
	}
	for (col = 0; col < width; col++)
	{
	    total_chars++;
	    printf("%02X", bw[col]);
	    if (!(total_chars & 0x1f))
		putchar('\n');
	}
    }
#else
#ifdef TWENTYFOURBITCOLOR
    puts("false 3 colorimage");

    /*
     * Process the image
     */
    for (row = 0; row < height; row++)
    {
	if (fread(indata, width * 3, 1, fp) != 1)
	{
	    fputs("ray2eps: short read from input file", stderr);
	    exit(11);
	}
	inp = indata;
        for (col = 0; col < (3 * width); col++)
 	{
	    total_chars++;
	    printf("%02X", log[*inp++]);
	    if (!(total_chars & 0x1f))
		putchar('\n');
	}
    }
#endif
#endif
#endif

    puts("grestore");
    return(0);
}


void
usageexit()
{
    fputs("usage: ray2eps [-g gamma] input_file\n", stderr);
    exit(1);
}

#ifdef TWOBITGREYSCALE
/*
 * F-S dither 8-bit data to 2-bit
 */
void
FSDither82(register short *indata, register short *errorTerms,
	   register u_char *outdata, short row, short npixels)
{
    register u_char pattern, mask;
    register short i, error;

    if (row & 1)			/* odd, go right to left */
    {
	indata += npixels;		/* point to last pixel */
	errorTerms += npixels;
	outdata += ((npixels + 3) >> 2) - 1;
	if ((npixels & 0x3) == 0)
	    pattern = 0x03;
	else
	    pattern = 0x03 << (2 * (4 - (npixels & 0x3)));
	for (i = 0; i < npixels; i++, indata--, errorTerms--)
	{
	    if (*indata < 0x2b)
	    	error = *indata;
	    else if (*indata < 0x80)
	    {
		mask = 0x55;
		*outdata |= mask & pattern;
		error = *indata - 0x55;
	    }
	    else if (*indata < 0xd5)
	    {
		mask = 0xaa;
		*outdata |= mask & pattern;
		error = *indata - 0xaa;
	    }
	    else
	    {
		mask = 0xff;
		*outdata |= mask & pattern;
		error = *indata - 0xff;
	    }
	    if (error)		/* propagate it */
	    {
		*(indata - 1) += (7 * error) / 16;  /* error can be neg. */
		*(errorTerms + 1) += (3 * error) / 16;
		*errorTerms += (5 * error) / 16;
		*(errorTerms - 1) += error / 16;
	    }	    
 	    if (pattern == 0xc0)
	    {
	    	pattern = 0x03;	 /* reset mask, point to next output pixel */
		*outdata--;
	    }
	    else
	        pattern <<= 2;
	}
    }
    else			/* even, go left to right */
    {
	pattern = 0xc0;
	indata++;
	errorTerms++;
	for (i = 0; i < npixels; i++, indata++, errorTerms++)
	{
	    if (*indata < 0x2b)
	    	error = *indata;
	    else if (*indata < 0x80)
	    {
		mask = 0x55;
		*outdata |= mask & pattern;
		error = *indata - 0x55;
	    }
	    else if (*indata < 0xd5)
	    {
		mask = 0xaa;
		*outdata |= mask & pattern;
		error = *indata - 0xaa;
	    }
	    else
	    {
		mask = 0xff;
		*outdata |= mask & pattern;
		error = *indata - 0xff;
	    }
	    if (error)		/* propagate it */
	    {
		*(indata + 1) += (7 * error) / 16;	/* error can be neg. */
		*(errorTerms + 1) += error / 16;
		*errorTerms += (5 * error) / 16;
		*(errorTerms - 1) += (3 * error) / 16;
	    }	    
	    if (pattern == 0x03)
	    {
		outdata++;	/* reset pattern, point to next output pixel */
		pattern = 0xc0;
	    }
	    else
	        pattern >>= 2;	
	}
    }
}
#endif
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0

