ftp.nice.ch/pub/next/science/chemistry/RasMol.NIHS.bs.tar.gz#/RasMol/Source/outfile.c

This is outfile.c in view mode; [Download] [Up]

/* outfile.c
 * RasMol2 Molecular Graphics
 * Roger Sayle, August 1995
 * Version 2.6
 */
#define OUTFILE
#include "rasmol.h"

#ifdef IBMPC
#include <windows.h>
#include <malloc.h>
#endif
#ifdef APPLEMAC
#include <Types.h>
#include <Errors.h>
#ifdef __CONDITIONALMACROS__
#include <Printing.h>
#else
#include <PrintTraps.h>
#endif
#endif
#ifndef sun386
#include <stdlib.h>
#endif

#include <stdio.h>
#include <ctype.h>
#include <math.h>

#include "outfile.h"
#include "molecule.h"
#include "command.h"
#include "abstree.h"
#include "transfor.h"
#include "render.h"
#include "repres.h"
#include "graphics.h"
#include "pixutils.h"
#include "script.h"


#ifdef EIGHTBIT
#define RComp(x)   (RLut[LutInv[x]])
#define GComp(x)   (GLut[LutInv[x]])
#define BComp(x)   (BLut[LutInv[x]])
#else
#define RComp(x)   (((x)>>16)&0xff)
#define GComp(x)   (((x)>>8)&0xff)
#define BComp(x)   ((x)&0xff)
#endif


#ifdef INVERT
#define InvertY(y) (y)
#else
#define InvertY(y) (-(y))
#endif


/* Sun rasterfile.h macro defns */
#define RAS_MAGIC       0x59a66a95
#define RAS_RLE         0x80
#define RT_STANDARD     1
#define RT_BYTE_ENCODED 2
#define RMT_NONE        0
#define RMT_EQUAL_RGB   1

/* Standard A4 size page: 8.267x11.811 inches */
/* U.S. Normal size page: 8.500x11.000 inches */
#define PAGEHIGH  (11.811*72.0)
#define PAGEWIDE  (8.267*72.0)
#define BORDER    0.90

/* Compression Ratio   0<x<127 */
#define EPSFCompRatio  32

#define Round(x)       ((int)(x))


#define PSBond      0x00
#define PSHBond     0x01
#define PSSSBond    0x02
#define PSAtom      0x03
#define PSRibbon    0x04
#define PSMonit     0x05



typedef void __far* PSItemPtr;


#if defined(IBMPC) || defined(APPLEMAC)
static short __far *ABranch;
static short __far *DBranch;
static short __far *Hash;
static Byte __far *Node;
#else
static short ABranch[4096];
static short DBranch[4096];
static short Hash[256];
static Byte Node[4096];
#endif


/* Apple PICT macros */
#define PICTcliprgn         0x0001
#define PICTpicversion      0x0011
#define PICTpackbitsrect    0x0098
#define PICTdirectbitsrect  0x009a
#define PICTendofpict       0x00ff
#define PICTheaderop        0x0c00

typedef struct {
	Byte len;
	Byte ch;
	} BMPPacket;
	

static BMPPacket BMPBuffer[10];
static int BMPCount,BMPTotal;        
static int BMPPad;

static int GIFClrCode; 
static int GIFEOFCode;

static short RLELineSize;
static Card RLEFileSize;
static int RLEEncode;
static int RLEOutput;
static int RLELength;
static int RLEPixel;
static int RLEChar;


static Byte Buffer[256];
static Byte LutInv[256];
static int LineLength;
static FILE *OutFile;
static Card BitBuffer;
static int BitBufLen;
static int PacketLen;
static int CodeSize;

static Real LineWidth;
static int VectSolid;
static int VectCol;

/* Macros for commonly used loops */
#define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
		     for(group=chain->glist;group;group=group->gnext)    \
		     for(aptr=group->alist;aptr;aptr=aptr->anext)
#define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
#define ForEachBack  for(chain=Database->clist;chain;chain=chain->cnext) \
		     for(bptr=chain->blist;bptr;bptr=bptr->bnext)



#ifdef APPLEMAC
/* External RasMac Function Declaration! */
void SetFileInfo( char*, OSType, OSType, short );
#endif

static void FatalOutputError( ptr )
    char *ptr;
{
    if( CommandActive ) WriteChar('\n');
    WriteString("Output Error: Unable to create file `");
    WriteString( ptr );  WriteString("'!\n");
    CommandActive = False;
}


/*  Integer Output Routines  */
#ifdef FUNCPROTO
static void WriteLSBLong( Card );
static void WriteMSBLong( Card );
#endif

static void WriteByte( val )
    int val;
{
    putc( val, OutFile );
}

static void WriteLSBShort( val )
    int val;
{
    putc( val&0xff, OutFile );
    putc( (val>>8)&0xff, OutFile );
}

static void WriteMSBShort( val )
    int val;
{
    putc( (val>>8)&0xff, OutFile );
    putc( val&0xff, OutFile );
}

static void WriteLSBLong( val )
    Card val;
{
    putc((int)(val&0xff),OutFile);
    putc((int)((val>>8) &0xff),OutFile);
    putc((int)((val>>16)&0xff),OutFile);
    putc((int)((val>>24)&0xff),OutFile);
}

static void WriteMSBLong( val )
    Card val;
{
    putc((int)((val>>24)&0xff),OutFile);
    putc((int)((val>>16)&0xff),OutFile);
    putc((int)((val>>8) &0xff),OutFile);
    putc((int)(val&0xff),OutFile);
}


static void CalcInvColourMap()
{
#ifdef EIGHTBIT
    register int i;

    for( i=0; i<256; i++ )
        if( ULut[i] )
            LutInv[Lut[i]] = i;
#endif
}


#ifdef EIGHTBIT
static int CompactColourMap()
{
    register Pixel __huge *ptr;
    register Long pos, count;
    register int i, cols;

    CalcInvColourMap();
    for( i=0; i<256; i++ )
    {   Buffer[i] = 0;
	Node[i] = 5;
    }

#ifdef IBMPC
    ptr = (Pixel __huge*)GlobalLock(FBufHandle);    
#else
    ptr = FBuffer;
#endif

    cols = 0;
    count = (Long)XRange*YRange;
    for( pos=0; pos<count; pos++ )
    {   i = LutInv[*ptr++];
	if( !Buffer[i] ) 
	{   Node[cols++] = i;
	    Buffer[i] = cols;
	}
    }

    for( i=0; i<256; i++ )
	LutInv[i] = Buffer[LutInv[i]]-1;
#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
    return( cols );
}
#endif




static void WritePPMWord( i )
    int i;
{
    if( i>99 )
    {   putc((i/100)+'0',OutFile); i %= 100;
	putc((i/10) +'0',OutFile); i %= 10;
    } else if( i>9 )
    {   putc((i/10)+'0',OutFile);  i %= 10;
    }
    putc(i+'0',OutFile);
}


int WritePPMFile( name, raw )
    char *name;  int raw;
{
    register Pixel __huge *ptr;
    register int i,col;
    register int x,y;

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name, (raw?"wb":"w") );
#else
    OutFile = fopen(name,"w");
#endif

    if( !OutFile ) 
    {   FatalOutputError(name);
	return( False );
    }

    CalcInvColourMap();
    fprintf(OutFile,"P%c %d %d 255\n",(raw?'6':'3'),XRange,YRange);

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

#ifndef INVERT
    ptr = FBuffer;
#endif

    if( !raw )
    {   col = 0;
	for( y=YRange-1; y>=0; y-- )
	{
#ifdef INVERT
	    ptr = FBuffer + (Long)y*XRange;
#endif
	    for( x=0; x<XRange; x++ )
	    {   i = *ptr++;
		WritePPMWord((int)RComp(i));  WriteByte(' ');
		WritePPMWord((int)GComp(i));  WriteByte(' ');
		WritePPMWord((int)BComp(i));  
		if( ++col == 5 )
		{   WriteByte('\n');
                    col = 0;
		} else WriteByte(' ');
	    }
	}
    } else
	for( y=YRange-1; y>=0; y-- )
	{
#ifdef INVERT
	    ptr = FBuffer + (Long)y*XRange;
#endif
	    for( x=0; x<XRange; x++ )
	    {   i = *ptr++;
		putc((int)RComp(i),OutFile);
		putc((int)GComp(i),OutFile);
		putc((int)BComp(i),OutFile);
	    }
	}

    fclose(OutFile);
#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'\?\?\?\?','\?\?\?\?',134);
#endif
#ifdef IBMPC
    GlobalUnlock(FBufHandle); 
#endif
    return( True );
}


static void WriteGIFCode( code )
    int code;
{
    register int max;

    max = (code==GIFEOFCode)? 0 : 7;
    BitBuffer |= ((Card)code<<BitBufLen);
    BitBufLen += CodeSize;

    while( BitBufLen > max )
    {    
#ifdef IBMPC
	 Buffer[PacketLen++]=(Byte)(BitBuffer&0xff);
#else
	 Buffer[PacketLen++]=BitBuffer;
#endif
	 BitBuffer >>= 8;
	 BitBufLen -= 8;

	if( PacketLen==255 )
	{   WriteByte(0xff);
	    fwrite((char*)Buffer,1,255,OutFile);
	    PacketLen = 0;
	}
    }
}

int WriteGIFFile( name )
    char *name;
{
    register int i,j,cols;
    register int pref,next,last;
    register int isize, ilast;
    register Pixel __huge *ptr;
    register short __far *prev;
    register int x,y,init;

#ifdef EIGHTBIT
    cols = CompactColourMap();
    if( cols<2 ) return( False );

    for( isize=2; isize<8; isize++ )
	if( (1<<isize) >= cols ) break;
    cols = 1<<isize;

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name,"wb");
#else
    OutFile = fopen(name,"w");
#endif
    if( !OutFile ) 
    {    FatalOutputError(name);
	 return( False );
    }
    fputs("GIF87a",OutFile);
    WriteLSBShort(XRange);
    WriteLSBShort(YRange);
    WriteByte(0xf0|(isize-1)); 
    WriteByte(0x00); 
    WriteByte(0x00);

    for( j=0; j<cols; j++ )
    {   i = Node[j];
	WriteByte(RLut[i]);
	WriteByte(GLut[i]);
	WriteByte(BLut[i]);
    }

    WriteByte(',');
    WriteByte(0x00);  WriteByte(0x00);
    WriteByte(0x00);  WriteByte(0x00);
    WriteLSBShort(XRange);
    WriteLSBShort(YRange);
    WriteByte(0x00);  WriteByte(isize);

    PacketLen=0;
    BitBuffer=0;
    BitBufLen=0;

    GIFClrCode = (1<<isize);
    GIFEOFCode = GIFClrCode+1;
    ilast = (GIFClrCode<<1)-GIFEOFCode;
    isize++;

    CodeSize = isize;
    last = ilast;
    next = 1;  
   
    WriteGIFCode(GIFClrCode);
    for( i=0; i<cols; i++ )
	Hash[i]=0;

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);    
#endif

#ifndef INVERT
    ptr = FBuffer;
#endif

    /* Avoid Warnings! */
    prev = (short __far*)0; 
    pref = 0;

    init = False;
    for( y=YRange-1; y>=0; y-- )
    {   
#ifdef INVERT
	ptr = FBuffer + (Long)y*XRange;
#endif
	for( x=0; x<XRange; x++ )
	{   if( !init )
	    {   pref = LutInv[*ptr++];
		prev = Hash+pref;
		init = True;
		continue;
	    }

	    i = LutInv[*ptr++];

	    while( *prev && (Node[*prev] != (Byte)i) )
		prev = ABranch+*prev;

	    if( *prev )
	    {   pref = *prev+GIFEOFCode;
		prev = DBranch+*prev;
	    } else
	    {   WriteGIFCode(pref);
		if( next==last )
		{   if( CodeSize==12 )
		    {   WriteGIFCode(GIFClrCode);
			pref = i;  prev = Hash+i;
			for( i=0; i<cols; i++ )
			    Hash[i] = 0;
			CodeSize = isize;
			last = ilast;
			next = 1; 
			continue;
		    }
		    last = (last<<1)+GIFEOFCode;
		    CodeSize++;
		}
		*prev = next;
		ABranch[next] = 0;
		DBranch[next] = 0;
		Node[next] = i;
		prev = Hash+i;
		pref = i;
		next++;
	    }
	}
    }


    WriteGIFCode(pref);
    WriteGIFCode(GIFEOFCode);
    if( PacketLen )
    {   WriteByte(PacketLen);
	fwrite((char*)Buffer,1,PacketLen,OutFile);
    }

    WriteByte(0x00);
    WriteByte(';');
    fclose(OutFile);

#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'\?\?\?\?','GIFf',134);
#endif
#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
    return( True );
#else
    if( CommandActive ) WriteChar('\n');
    WriteString("Output Error: 24 bit GIF files unsupported!\n");
    CommandActive = False;
    return( False );
#endif
}



static void FlushRastRLE()
{
    if( RLEChar==RAS_RLE )
    {   if( RLEOutput )
	{   WriteByte(RAS_RLE);
	    WriteByte(RLELength-1);
	    if( RLELength!=1 )
		WriteByte(RAS_RLE);
	} else RLEFileSize += (RLELength>1)? 3 : 2;
    } else
	if( RLEOutput )
	{   if( RLELength>2 )
	    {   WriteByte(RAS_RLE);
		WriteByte(RLELength-1);
	    } else if( RLELength==2 )
		WriteByte(RLEChar);
	    WriteByte(RLEChar);
	} else RLEFileSize += MinFun(RLELength,3);
}


static void WriteRastRLECode( val )
    int val;
{
    if( RLEEncode )
    {   if( !RLELength )
	{   RLELength = 1;
	    RLEChar = val;
	} else if( (RLEChar!=val) || (RLELength==256) )
	{   FlushRastRLE();
            RLELength = 1;
            RLEChar = val;
        } else RLELength++;
    } else WriteByte(val);
}

static void WriteRastRLEPad()
{
    if( RLEEncode )
    {   if( !RLELength || (RLELength==256) )
	{   WriteRastRLECode(0x00);
	} else RLELength++;
    } else WriteByte(0x00);
}


static void WriteRastData( output )
    int output;
{
    register Pixel __huge *ptr;
    register int x,y,pad;
#ifndef EIGHTBIT
    register int i;
#endif

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

#ifndef INVERT
    ptr = FBuffer;
#endif

    pad = XRange%2;

    RLEOutput = output;
    RLEFileSize = 0;
    RLELength = 0;

    for( y=YRange-1; y>=0; y-- )
    {   
#ifdef INVERT
	ptr = FBuffer + (Long)y*XRange;
#endif
	for( x=0; x<XRange; x++ )
#ifndef EIGHTBIT
	{   i = *ptr++;
	    WriteRastRLECode((int)BComp(i));
	    WriteRastRLECode((int)GComp(i));
	    WriteRastRLECode((int)RComp(i));
	}
#else
	    WriteRastRLECode((int)LutInv[*ptr++]);
#endif
	if( pad ) WriteRastRLEPad();
    }

    if( RLEEncode && RLELength )
	FlushRastRLE();
#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
}



int WriteRastFile( name, encode )
    char *name;
    int encode;
{
    register int i,size,cols;

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name,"wb");
#else
    OutFile = fopen(name,"w");
#endif

    if( !OutFile )
    {   FatalOutputError(name);
	return(False);
    }
    WriteMSBLong( RAS_MAGIC );
    WriteMSBLong(XRange);  
    WriteMSBLong(YRange);
    RLEEncode = encode;


#ifdef EIGHTBIT
    WriteMSBLong(8);

    if( encode )
    {   WriteRastData(False);
	WriteMSBLong(RLEFileSize);
	WriteMSBLong(RT_BYTE_ENCODED);
    } else
    {   size = (XRange%2)? XRange+1 : XRange;
	WriteMSBLong(size*YRange);
	WriteMSBLong(RT_STANDARD);
    }

    cols = CompactColourMap();
    WriteMSBLong(RMT_EQUAL_RGB);
    WriteMSBLong(cols*3);

    for( i=0; i<cols; i++ ) WriteByte(RLut[Node[i]]);
    for( i=0; i<cols; i++ ) WriteByte(GLut[Node[i]]);
    for( i=0; i<cols; i++ ) WriteByte(BLut[Node[i]]);
#else
    WriteMSBLong(24);

    if( encode )
    {   WriteRastData(False);
	WriteMSBLong(RLEFileSize);
	WriteMSBLong(RT_BYTE_ENCODED);
    } else
    {   size = XRange*3;
	if( size&1 ) size++;
	WriteMSBLong((Long)size*YRange);
	WriteMSBLong(RT_STANDARD);
    }
    WriteMSBLong(RMT_NONE);
    WriteMSBLong(0);
#endif

    WriteRastData(True);
    fclose( OutFile );
#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'\?\?\?\?','\?\?\?\?',134);
#endif
    return( True );
}


static void OutputEPSFByte( val )
    int val;
{
    static char *hex = "0123456789ABCDEF";

    WriteByte( hex[val>>4] );
    WriteByte( hex[val&0x0f] );
    if( (LineLength+=2) > 72 )
    {   WriteByte('\n');
	LineLength = 0;
    }
}

static void EncodeEPSFPixel( val, col )
    int val, col;
{
    register int r, g, b;
    register int i;

    r = RComp(val);
    g = GComp(val);
    b = BComp(val);

    if( col )
    {   OutputEPSFByte( r );
	OutputEPSFByte( g );
	OutputEPSFByte( b );
    } else
    {   i = (20*r + 32*g + 12*b)>>6;
	OutputEPSFByte( i );
    }
}

int WriteEPSFFile( name, col, compr )
    char *name;  int col, compr;
{
    register int x, y, i, j;
    register int xsize, ysize;
    register int xpos, ypos;
    register int rotpage;

    register Pixel __huge *ptr;
    int RLEBuffer[128];

    OutFile = fopen(name,"w");
    if( !OutFile )
    {   FatalOutputError(name);
	return(False);
    }

    CalcInvColourMap();
    if( XRange <= YRange )
    {   rotpage = False; 
	xsize = XRange; 
	ysize = YRange;
    } else
    {   rotpage = True;  
	xsize = YRange; 
	ysize = XRange;
    }

    if( xsize > (int)(BORDER*PAGEWIDE) )
    {   ysize = (int)(ysize*(BORDER*PAGEWIDE)/xsize);
	xsize = (int)(BORDER*PAGEWIDE);
    }
    if( ysize > (int)(BORDER*PAGEHIGH) )
    {   xsize = (int)(xsize*(BORDER*PAGEHIGH)/ysize);
	ysize = (int)(BORDER*PAGEHIGH);
    }

    xpos = (int)(PAGEWIDE-xsize)/2;
    ypos = (int)(PAGEHIGH-ysize)/2;

    fputs("%!PS-Adobe-2.0 EPSF-2.0\n",OutFile);
    fputs("%%Creator: RasMol Version 2.6\n",OutFile);
    fprintf(OutFile,"%%%%Title: %s\n",name);
    fprintf(OutFile,"%%%%BoundingBox: %d %d ",xpos,ypos);
    fprintf(OutFile,"%d %d\n",xpos+xsize,ypos+ysize);

    fputs("%%Pages: 1\n",OutFile);
    fputs("%%EndComments\n",OutFile);
    fputs("%%EndProlog\n",OutFile);
    fputs("%%Page: 1 1\n",OutFile);

    fputs("gsave\n",OutFile);
    fputs("10 dict begin\n",OutFile);
    fprintf(OutFile,"%d %d translate\n",xpos,ypos);
    fprintf(OutFile,"%d %d scale\n",xsize,ysize);
    if( rotpage )
    {   fputs("0.5 0.5 translate\n",OutFile);
	fputs("90 rotate\n",OutFile);
	fputs("-0.5 -0.5 translate\n",OutFile);
    }
    fputc('\n',OutFile);

    if( compr )
    {   fputs("/rlecount 0 def\n",OutFile);
	fputs("/rlebyte 1 string def\n",OutFile);
	fprintf(OutFile,"/pixbuf %d string def\n", col?3:1 );
	fputs("/reppixel { pixbuf } def\n",OutFile);
	fputs("/getpixel { \n",OutFile);
	fputs("  currentfile pixbuf readhexstring pop\n",OutFile);
	fputs("} def\n\n",OutFile);

	if( col )
	{   fputs("/colorimage where {\n",OutFile);
	    fputs("  pop\n",OutFile);
	    fputs("} {\n",OutFile);
	    fputs("  /bytebuf 1 string def\n",OutFile);
	    fputs("  /colorimage { pop pop image } def\n",OutFile);
	    fputs("  /reppixel { bytebuf } def\n",OutFile);
	    fputs("  /getpixel {\n",OutFile);
	    fputs("    currentfile pixbuf readhexstring pop pop\n",OutFile);
	    fputs("    bytebuf 0\n",OutFile);
	    fputs("    pixbuf 0 get 20 mul\n",OutFile);
	    fputs("    pixbuf 1 get 32 mul\n",OutFile);
	    fputs("    pixbuf 2 get 12 mul\n",OutFile);
	    fputs("    add add -6 bitshift put bytebuf\n",OutFile);
	    fputs("  } def\n",OutFile);
	    fputs("} ifelse\n\n",OutFile);
	}

	fputs("/rledecode {\n",OutFile);
	fputs("  rlecount 0 eq {\n",OutFile);
	fputs("    currentfile rlebyte readhexstring pop\n",OutFile);
	fprintf(OutFile,"    0 get dup %d gt {\n",EPSFCompRatio);
	fprintf(OutFile,"      /rlecount exch %d sub def\n",EPSFCompRatio);
	fputs("      /rleflag true def\n",OutFile);
	fputs("    } {\n",OutFile);
	fputs("      /rlecount exch def\n",OutFile);
	fputs("      /rleflag false def\n",OutFile);
	fputs("    } ifelse getpixel\n",OutFile);
	fputs("  } {\n",OutFile);
	fputs("    /rlecount rlecount 1 sub def\n",OutFile);
	fputs("    rleflag { reppixel } { getpixel } ifelse\n",OutFile);
	fputs("  } ifelse\n",OutFile);
	fputs("} def\n",OutFile);
    } else if( col )
    {   fprintf(OutFile,"/scanbuf %d string def\n",XRange*3);
	fputs("/colorimage where {\n",OutFile);
	fputs("  pop\n",OutFile);
	fputs("} {\n",OutFile);
	fputs("  /pixbuf 3 string def\n",OutFile);
	fputs("  /bytebuf 1 string def\n",OutFile);
	fputs("  /colorimage {\n",OutFile);
	fputs("    pop pop pop {\n",OutFile);
	fputs("      currentfile pixbuf readhexstring pop pop\n",OutFile);
	fputs("      bytebuf 0\n",OutFile);
	fputs("      pixbuf 0 get 20 mul\n",OutFile);
	fputs("      pixbuf 1 get 32 mul\n",OutFile);
	fputs("      pixbuf 2 get 12 mul\n",OutFile);
	fputs("      add add -6 bitshift put bytebuf\n",OutFile);
	fputs("    } image\n",OutFile);
	fputs("  } def\n",OutFile);
	fputs("} ifelse\n\n",OutFile);
    } else fprintf(OutFile,"/scanbuf %d string def\n\n",XRange);

    fprintf(OutFile,"%d %d %d\n",XRange,YRange,8);
    fprintf(OutFile,"[%d 0 0 -%d 0 %d]\n",XRange,YRange,YRange);

    if( !compr )
    {   fputs("{ currentfile scanbuf readhexstring pop }\n",OutFile);
    } else fputs("{ rledecode }\n",OutFile);
    if( col ) fputs("false 3 color",OutFile);
    fputs("image\n",OutFile);

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

#ifndef INVERT
    ptr = FBuffer; 
#endif

    RLELength = 0;
    LineLength = 0;
    for( y=YRange-1; y>=0; y-- )
    {
#ifdef INVERT
	ptr = FBuffer + (Long)y*XRange;
#endif
	for( x=0; x<XRange; x++ )
	{   i = *ptr++;
	    if( compr )
	    {   if( RLELength )
		{   if( RLEEncode )
		    {   if( (RLEPixel!=i) || (RLELength==256-EPSFCompRatio) )
			{   OutputEPSFByte(RLELength+EPSFCompRatio-1);
			    EncodeEPSFPixel(RLEPixel,col);
			    RLEEncode = False;
			    RLEBuffer[0] = i;
			    RLELength = 1;
			} else RLELength++;
		    } else if( RLEBuffer[RLELength-1] == i )
		    {   if( RLELength>1 )
			{   OutputEPSFByte(RLELength-2);
			    for( j=0; j<RLELength-1; j++ )
				EncodeEPSFPixel(RLEBuffer[j],col);
			}
			RLEEncode = True;
			RLELength = 2;
			RLEPixel = i;
		    } else if( RLELength == EPSFCompRatio+1 )
		    {   OutputEPSFByte(EPSFCompRatio);
			for( j=0; j<RLELength; j++ )
			     EncodeEPSFPixel(RLEBuffer[j],col);
			RLEEncode = False;
			RLEBuffer[0] = i;
			RLELength = 1;
		    } else RLEBuffer[RLELength++] = i;
		} else
		{   RLEEncode = False;
		    RLEBuffer[0] = i;
		    RLELength = 1;
		}
	    } else EncodeEPSFPixel( i, col );
	}
    }

    if( compr && RLELength )
    {   if( RLEEncode )
	{   OutputEPSFByte(RLELength+EPSFCompRatio-1);
	    EncodeEPSFPixel(RLEPixel,col);
	} else
	{   OutputEPSFByte(RLELength-1);
	    for( j=0; j<RLELength; j++ )
		EncodeEPSFPixel(RLEBuffer[j],col);
	}
    }

    if( LineLength ) 
	fputc('\n',OutFile);
    fputs("end\n",OutFile);
    fputs("grestore\n",OutFile);
    fputs("showpage\n",OutFile);
    fputs("%%Trailer\n",OutFile);
    fputs("%%EOF\n",OutFile);
    fclose( OutFile );
#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'vgrd','TEXT',134);
#endif
#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
    return( True );
}



/* Flush AbsMode buffer */
static void FlushBMPBuffer()
{
    if( RLEOutput )
    {   WriteByte(0x00);
	WriteByte(PacketLen);
	fwrite((char*)Buffer,1,PacketLen,OutFile);
	if( PacketLen%2 ) WriteByte(0x00);    
    } else
	RLEFileSize += (PacketLen%2)+PacketLen+2;
    PacketLen = 0;
}

/* Flush RLEMode buffer */
static void FlushBMPPackets()
{
    register int i;
    
    if( PacketLen )
	FlushBMPBuffer();

    if( RLEOutput )
    {   for( i=0; i<BMPCount; i++ )
	{   WriteByte(BMPBuffer[i].len);
	    WriteByte(BMPBuffer[i].ch);
	}
    } else RLEFileSize += (BMPCount<<1);
    BMPCount = BMPTotal = 0;
}

static void ProcessBMPPacket()
{
    register int cost;
    register int i,j;
    
    BMPBuffer[BMPCount].len = RLELength;
    BMPBuffer[BMPCount].ch = RLEChar;
    BMPTotal += RLELength;
    RLELength = 0;
    BMPCount++; 


    /* RLEMode is more efficient */
    if( BMPTotal > BMPCount+5 )
    {   FlushBMPPackets();
	return;
    }
    
    /* Flush AbsMode buffer */
    if( PacketLen+BMPTotal>255 )
	FlushBMPBuffer();
    

    /* Cannot leave RLEMode */
    if( PacketLen+BMPTotal<3 )
	return;
	
    /* Determine AbsMode cost */
    if( PacketLen )
    {   cost = BMPTotal - (PacketLen%2);
	cost += (cost%2);
    } else cost = (BMPTotal%2)+BMPTotal+2;    

    /* Put RLE Packets into AbsMode buffer */
    if( cost <= (int)(BMPCount<<1) )
    {   for( i=0; i<BMPCount; i++ )
	    for( j=0; j<(int)BMPBuffer[i].len; j++ )
		Buffer[PacketLen++] = BMPBuffer[i].ch;
	BMPCount = BMPTotal = 0;
    }
}
 
/* Collect pixels into RLE Packets */
static void WriteBMPCode( val )
    int val;
{
    if( !RLELength )
    {   RLELength = 1;
	RLEChar = val;
    } else
	if( (RLEChar!=val) || (RLELength==255) )
	{   ProcessBMPPacket();
	    RLELength = 1;
	    RLEChar = val;
	} else
	    RLELength++;
}

static void WriteBMPData( output )
    int output;
{
    register Pixel __huge *ptr;
    register int x,y;
    
    RLEOutput = output;
    RLEFileSize = 0;   BMPCount = 0;
    RLELength = 0;     BMPTotal = 0;
    PacketLen = 0; 

#ifdef INVERT
    ptr = FBuffer;
#endif

    for( y=YRange-1; y>=0; y-- )
    {
#ifndef INVERT
	ptr = FBuffer + (Long)y*XRange;
#endif
	for( x=0; x<XRange; x++ )
	    WriteBMPCode(LutInv[*ptr++]);

	for( x=0; x<BMPPad; x++ )
	    WriteBMPCode(0x00);

	/* Flush RLE codes */
	ProcessBMPPacket();
	FlushBMPPackets();
	
	if( RLEOutput )
	{   /* End of line code */
	    WriteByte(0x00);
	    WriteByte(y?0x00:0x01);
	} else RLEFileSize += 2;
    }
}


    
int WriteBMPFile( name )
    char *name;
{
    register Pixel __huge *ptr;
    register int x,y,i,raw;
    register Card size;

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name,"wb");
#else
    OutFile = fopen(name,"w");
#endif
    if( !OutFile )
    {    FatalOutputError(name);
	 return( False );
    }

#ifdef EIGHTBIT
#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

    CalcInvColourMap();
    /* zero-pad scanlines to long */
    BMPPad = XRange%4;
    if( BMPPad ) 
	 BMPPad = 4-BMPPad; 

    WriteBMPData(False);
    size = (Long)(XRange+BMPPad)*YRange;
    if( RLEFileSize<size )
    {   size = RLEFileSize;
	raw = False;
    } else raw = True;


    WriteByte('B'); 
    WriteByte('M');
    WriteLSBLong(size+1078);
    WriteLSBLong((Card)0);
    WriteLSBLong((Card)1078);

    WriteLSBLong((Card)40);
    WriteLSBLong((Card)XRange);
    WriteLSBLong((Card)YRange);
    WriteByte(0x01);  WriteByte(0x00);
    WriteByte(0x08);  WriteByte(0x00);
    WriteLSBLong(raw? (Card)0 : (Card)1);
    WriteLSBLong(size);
    
    WriteLSBLong((Card)0);
    WriteLSBLong((Card)0);
    WriteLSBLong((Card)256);
    WriteLSBLong((Card)256);

    for( i=0; i<256; i++ )
    {   WriteByte(BLut[i]);
	WriteByte(GLut[i]);
	WriteByte(RLut[i]);
	WriteByte(0x00);
    }

    if( raw )
    {   
#ifdef INVERT
	ptr = FBuffer;
#endif
	for( y=YRange-1; y>=0; y-- )
	{
#ifndef INVERT
	    ptr = FBuffer + (Long)y*XRange;
#endif
	    for( x=0; x<XRange; x++ )
		WriteByte(LutInv[*ptr++]);
	    for( x=0; x<BMPPad; x++ )
		WriteByte(0x00);
	    WriteByte(0x00);
	    WriteByte(y?0x00:0x01);
	}
    } else
	WriteBMPData(True);
    fclose(OutFile);

#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'\?\?\?\?','\?\?\?\?',134);
#endif
#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
    return(True);
#else
    if( CommandActive ) WriteChar('\n');
    WriteString("Output Error: 24 bit BMP files unsupported!\n");
    CommandActive = False;
    return( False );
#endif
}



#ifdef FUNCPROTO
static int FindDepth( PSItemPtr, int );
static void DepthSort( PSItemPtr __far*, char __far*, int );
#endif

static int FindDepth( item, type )
     PSItemPtr item;  int type;
{
    register HBond __far *hbond;
    register Atom __far *atom;
    register Bond __far *bond;
    register int result;

    switch( type )
    {   case(PSAtom):    atom = (Atom __far*)item;
	                 return( atom->z );

        case(PSBond):    bond = (Bond __far*)item;
	                 result = bond->srcatom->z;
	                 if( result < bond->dstatom->z )
	                     result = bond->dstatom->z;
                         return( result );

        case(PSSSBond):  
        case(PSHBond):   hbond = (HBond __far*)item;
                         if( (type==PSHBond)? HBondMode : SSBondMode )
                         {   result = hbond->srcCA->z;
                             if( result < hbond->dstCA->z )
                                 result = hbond->dstCA->z;
                         } else
                         {   result = hbond->src->z;
                             if( result < hbond->dst->z )
                                 result = hbond->dst->z;
                         }
                         return( result );
    }
    return( 0 );
}


static void DepthSort( data, type, count )
    PSItemPtr __far *data;
    char __far *type;
    int count;
{
    register char ttmp;
    register void __far *dtmp;
    register int i, j, k;
    register int depth;
    register int temp;

    for( i=1; i<count; i++ )
    {   dtmp = data[i];  
	ttmp = type[i];

	j = i-1;
	depth = FindDepth(dtmp,ttmp);
	temp = FindDepth(data[j],type[j]);
	while( (depth<temp) || ((depth==temp)&&(ttmp<type[j])) )
	    if( j-- ) 
	    {   temp = FindDepth(data[j],type[j]);
	    } else break;
	j++;

	if( j != i )
	{   for( k=i; k>j; k-- )
	    {    data[k] = data[k-1];
		 type[k] = type[k-1];
	    }
	    data[j] = dtmp;
	    type[j] = ttmp;
	}
    }
}

#ifdef FUNCPROTO
static int ClipVectSphere( Atom __far* );
static int ClipVectBond( Atom __far*, Atom __far* );

static void WriteVectSphere( PSItemPtr __far*, char __far*, int );
static void WriteVectStick( Atom __far*, Atom __far*, int, int );
static void WriteVectWire( Atom __far*, Atom __far*, int, int );

static Long CountPSItems();
static void FetchPSItems( PSItemPtr __far*, char __far* );
static void WritePSItems( PSItemPtr __far*, char __far*, int );
#endif


static int ClipVectSphere( ptr )
    Atom __far *ptr;
{
    register int rad;

    rad = ptr->irad;

    if( ptr->x + rad < 0 )  return( True );
    if( ptr->y + rad < 0 )  return( True );
    if( ptr->x - rad >= XRange )  return( True );
    if( ptr->y - rad >= YRange )  return( True );
    return( False );
}


static int ClipVectBond( src, dst )
    Atom __far *src;
    Atom __far *dst;
{
    if( !src || !dst )  return( True );
    if( (src->x<0) && (dst->x<0) )  return( True );
    if( (src->y<0) && (dst->y<0) )  return( True );
    if( (src->x>=XRange) && (dst->x>=XRange) )  return( True );
    if( (src->y>=YRange) && (dst->y>=YRange) )  return( True );
    return( False );
}



static void WriteVectColour( col )
    int col;
{
    if( col != VectCol )
    {   fprintf(OutFile,"%g ",(Real)RLut[col]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[col]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[col]/255.0);
	fputs("setrgbcolor\n",OutFile);
	VectCol = col;
    }
}


#define MAXSECT 5
typedef struct {
	/* Ellipse */
	Real ephi,epsi;
	Real etheta;
	Real ex,ey;
	Real erad;

	/* Sphere */
	Real sphi,spsi;
	int sx,sy;
	Real srad;
    } SphereSect;


static int VectClipContain( x, y )
    SphereSect *x; SphereSect *y;
{
    if( x->erad != 0.0 )
    {   if( y->erad != 0.0 )
	    /* Simple segment containment test! */
	    return( ((x->sphi+x->spsi)>=(y->sphi+y->spsi)) &&
		    ((x->sphi-x->spsi)<=(y->sphi-y->spsi)) );
    } else if( y->erad == 0.0 )
	return( x->srad >= y->srad );
    return( False );
}


static void WriteVectSphere( data, type, index )
    PSItemPtr __far*data; 
    char __far *type;
    int index;
{
    register int ecount, count;
    register Atom __far *atm;
    register Atom __far *ptr;
    register Long dist2,dist3;
    register int dx, dy, dz;
    register int i,j,k;

    register Real b,d,f,g,x;
    register Real radf,radb;
    register Real phi1,phi2;
    register Real temp,psi;
    register Real theta;

    register SphereSect *sptr;
    SphereSect sect[MAXSECT];

    ptr = (Atom __far*)data[index];
    radf = ptr->radius*Scale;

    count = 0;
    ecount = 0;
    sptr = sect;
    for( i=index-1; i>=0; i-- )
    {   if( type[i] != PSAtom )
	    continue;

	atm = (Atom __far*)data[i];
	/* Atom can't intersect visibly! */
	if( atm->z + atm->irad < ptr->z )
	    continue;

	dx = atm->x - ptr->x; 
	dy = atm->y - ptr->y; 
	dz = atm->z - ptr->z;

	dist2 = (Long)dx*dx + (Long)dy*dy;
	dist3 = dist2 + dz*dz;

	radb = atm->radius*Scale;  
	temp = radf + radb;

	/* Atoms don't intersect! */
	if( dist3 > temp*temp ) continue;


	d = sqrt( (double)dist3 );
	f = (temp*(radf-radb)+dist3)/(2.0*d);
	theta = -dz/d;

	if( f>0 )
	{   temp = radf*radf;
	    /* Intersection not visible! */
	    if( theta*temp > temp-f*f )
		continue;
	} else if( f < -radf )
	    return;

	x = sqrt( (radf-f)*(radf+f) );

	if( dx || dy )
	{   g = sqrt( (double)dist2 );
	    psi = Rad2Deg*atan2(dy,dx);
	    b = (f*(dz*dz))/(d*g);

	    if( AbsFun(b)>x )
		continue;

	    phi1 = b + (f*g)/d;
	    phi1 = Rad2Deg*acos(phi1/radf);
	    if( phi1!=phi1 ) continue;

	    phi2 = (d*b)/g;
	    if( AbsFun(phi2) < x )
	    {   phi2 = Rad2Deg*acos(phi2/x);
		if( phi2!=phi2 ) continue;
		if( phi2 > 90.0 ) 
		    phi2 = 180.0-phi1;
	    } else phi2 = 90.0;

	    sptr->erad = x;
	    sptr->etheta = -theta;
	    sptr->ephi = psi;
	    sptr->epsi = phi2;

	    temp = f/d;
	    sptr->ex = ptr->x+temp*dx;
	    sptr->ey = ptr->y+temp*dy;

	    sptr->srad = radf;
	    sptr->sphi = psi;
	    sptr->spsi = phi1;
	    sptr->sx = ptr->x;
	    sptr->sy = ptr->y;

	} else
	{   x = sqrt( (radf-g)*(radf+g) );

	    sptr->srad = x;
	    sptr->erad = 0.0;
	    sptr->sx = ptr->x;
	    sptr->sy = ptr->y;
	    sptr->sphi = 180;
	    sptr->spsi = -180;
	}

	/* Optimize Segments */
	j = 0;
	while( j<count )
	    if( VectClipContain(sptr,sect+j) )
	    {   /* Delete Segment sect[j] */
		for( k=j; k<count; k++ )
		    sect[k] = sect[k+1];
		count--;  sptr--;
	    } else if( VectClipContain(sect+j,sptr) )
	    {   break;  /* Exclude Segment */
	    } else j++;
	   

	if( j==count )
	{   count++;  sptr++;
	    if( sptr->erad != 0.0 )
		ecount++;
	    if( count==MAXSECT )
		break;
	}
    }

    if( UseOutLine )
    {   temp = (ptr->z-ZOffset)/ImageSize + 1.0;
	if( temp != LineWidth )
	{   fprintf(OutFile,"%g setlinewidth\n",temp);
	    LineWidth = temp;
	}
    }

    if( !VectSolid )
    {   fputs("[] 0 setdash\n",OutFile);
        VectSolid = True;
    }

    if( count )
    {   fputs("gsave\n",OutFile);
	fprintf(OutFile,"%%%% %d %d\n",count,ecount);

	sptr = sect;
	for( i=0; i<count; i++ )
	{   if( sptr->erad != 0.0 )
	    {   fprintf(OutFile,"%g %g %g %g %g %g ClipEllips\n",
			    sptr->erad,sptr->epsi,sptr->etheta,
			    sptr->ephi,sptr->ex,sptr->ey);
	    }

	    if( (i==count-1) || (sptr->erad==0.0) )
	    {   fprintf(OutFile,"%g %g %g %d %d ClipSphere\n",sptr->srad,
				sptr->sphi+sptr->spsi,sptr->sphi-sptr->spsi,
				sptr->sx, sptr->sy );
	    } else fprintf(OutFile,"%g %g %g %d %d ClipBox\n",
				    sptr->srad+sptr->srad+2,
				    sptr->srad+1, sptr->ephi,
				    sptr->sx, sptr->sy );
	    sptr++;
	}

	i = ptr->col + ColourMask;
	fprintf(OutFile,"%g ",(Real)RLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[i]/255.0);
	fprintf(OutFile,"%g Shade\n",radf);
	fputs("grestore\n\n",OutFile);
    } else
    {   i = ptr->col + ColourMask;
	fprintf(OutFile,"%g ",(Real)RLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[i]/255.0);
	fprintf(OutFile,"%g %d %d ",radf,ptr->x,ptr->y);
	fputs("Sphere\n\n",OutFile);
    }
}


static void WriteVectWire( src, dst, col, dash )
    Atom __far *src;
    Atom __far *dst;
    int col, dash;
{
    register Atom __far *tmp;
    register Real radius;
    register Real temp;
    register Real dist;

    register Real midx, midy;
    register Real endx, endy;
    register int col1, col2;
    register int dx, dy, dz;
    register Long dist2;


    if( src->z > dst->z )
    {   tmp = src;
        src = dst;
	dst = tmp;
    }

    if( !col )
    {   col1 = src->col;
	col2 = dst->col;
    } else col1 = col2 = col;

    dx = dst->x - src->x;  
    dy = dst->y - src->y;
    dist2 = dx*dx + dy*dy;
    dist = sqrt( (double)dist2 );

    if( dst->flag & SphereFlag )
    {   radius = dst->radius*Scale;
	if( dist <= radius ) return;

	/* Test for second half obscured! */
	if( (col1!=col2) && (0.5*dist < radius) )
	    col2 = col1;
    }

    if( src->flag & SphereFlag )
    {   radius = src->radius*Scale;
	if( dist <= radius ) return;

	/* Test for first half obscured! */
	if( (col1!=col2) && (0.5*dist < radius) )
	    col1 = col2;
    }


    WriteVectColour( col1+ColourMask );
    temp = ((src->z-ZOffset)+(dst->z-ZOffset))/ImageSize + 1.0;
    if( temp != LineWidth )
    {   fprintf(OutFile,"%g setlinewidth\n",temp);
	LineWidth = temp;
    }

    if( dash )
    {   if( VectSolid )
        {   fputs("[3 3] 0 setdash\n",OutFile);
            VectSolid = False;
        }
    } else
        if( !VectSolid )
        {   fputs("[] 0 setdash\n",OutFile);
            VectSolid = True;
        }


    if( src->flag & SphereFlag )
    {   dz = dst->z - src->z;
	dist = sqrt( (double)(dist2 + dz*dz) );
	endx = src->x + (radius*dx)/dist;
	endy = src->y + (radius*dy)/dist;
	fprintf(OutFile,"%g %g ",endx,endy);
    } else
	fprintf(OutFile,"%d %d ",src->x,src->y);

    if( col1 != col2 )
    {   midx = 0.5*(src->x + dst->x);
	midy = 0.5*(src->y + dst->y);
	fprintf(OutFile,"%g %g Wire\n",midx,midy);

	WriteVectColour( col2+ColourMask );
	fprintf(OutFile,"%g %g ",midx,midy);
    } 
    fprintf(OutFile,"%d %d Wire\n",dst->x,dst->y);
}


static void WriteVectStick( src, dst, col, rad )
    Atom __far *src;  
    Atom __far *dst;
    int col, rad;
{
    register Atom __far *tmp;
    register Real midx, midy;
    register Real relx, rely;
    register Real endx, endy;
    register Real radius, angle;
    register Real dist, dist3;
    register Real temp, ratio;

    register Long dist2;
    register int dx, dy, dz;
    register int col1, col2;
    register int i, inten;

    if( !rad )
    {   WriteVectWire(src,dst,col,False);
	return;
    }

    if( src->z > dst->z )
    {   tmp = src;
        src = dst;
	dst = tmp;
    }

    if( !col )
    {   col1 = src->col;
	col2 = dst->col;
    } else col1 = col2 = col;

    dx = dst->x - src->x;  
    dy = dst->y - src->y;
    dz = dst->z - src->z;
    dist2 = dx*dx + dy*dy;
    dist3 = sqrt( (double)(dist2 + dz*dz) );
    dist = sqrt( (double)dist2 );

    if( dst->flag & SphereFlag )
    {   radius = dst->radius*Scale;
	if( dist <= radius ) return;

	/* Test for nearest half obscured! */
	if( (col1!=col2) && (0.5*dist < radius) )
	    col2 = col1;
    }

    if( src->flag & SphereFlag )
    {   radius = src->radius*Scale;
	if( dist <= radius ) return;

	/* Test for furthest half obscured! */
	if( (col1!=col2) && (0.5*dist < radius) )
	    col1 = col2;
    }

    if( !VectSolid )
    {   fputs("[] 0 setdash\n",OutFile);
        VectSolid = True;
    }

    temp = ((src->z-ZOffset)+(dst->z-ZOffset))/ImageSize + 1.0;
    if( temp != LineWidth )
    {   fprintf(OutFile,"%g setlinewidth\n",temp);
	LineWidth = temp;
    }

    radius = rad*Scale;
    angle = Rad2Deg*atan2((double)dy,(double)dx);
    inten = (int)((dist/dist3)*ColourMask);

    if( col1 != col2 )
    {   midx = 0.5*(src->x + dst->x);
	midy = 0.5*(src->y + dst->y);
	relx = (radius*dx)/dist;
	rely = (radius*dy)/dist;

	fprintf(OutFile,"%g %g moveto\n",midx+rely,midy-relx);
	fprintf(OutFile,"%g %g lineto\n",midx-rely,midy+relx);

	ratio = dz/dist3;

	if( (src->flag&SphereFlag) && (src->radius>rad) )
	{   temp = (Scale*src->radius)/dist3;
	    endx = src->x + temp*dx;
	    endy = src->y + temp*dy;

	    fprintf(OutFile,"%g %g %g ",radius,ratio,angle);
	    fprintf(OutFile,"%g %g StickEnd\n",endx,endy);
	} else
	{   fprintf(OutFile,"%d %d %g ",src->x,src->y,radius);
	    fprintf(OutFile,"%g %g arc\n",angle+90,angle-90);
	}
	fputs("closepath ",OutFile);

	i = col1 + inten;
	fprintf(OutFile,"%g ",(Real)RLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[i]/255.0);
	fputs("setrgbcolor fill\n",OutFile);

	fprintf(OutFile,"%d %d %g ",dst->x,dst->y,radius);
	fprintf(OutFile,"%g %g arc\n",angle-90,angle+90);
	fprintf(OutFile,"%g %g %g ",radius,ratio,angle);
	fprintf(OutFile,"%g %g StickEnd\n",midx,midy);
	fputs("closepath ",OutFile);

	i = col2 + inten;
	fprintf(OutFile,"%g ",(Real)RLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[i]/255.0);
	fputs("setrgbcolor fill\n",OutFile);

	if( UseOutLine )
	{   fprintf(OutFile,"%d %d %g ",dst->x,dst->y,radius);
	    fprintf(OutFile,"%g %g arc\n",angle-90,angle+90);
	    if( (src->flag&SphereFlag) && (src->radius>rad) )
	    {   fprintf(OutFile,"%g %g %g ",radius,ratio,angle);
		fprintf(OutFile,"%g %g StickEnd\n",endx,endy);
	    } else
	    {   fprintf(OutFile,"%d %d %g ",src->x,src->y,radius);
		fprintf(OutFile,"%g %g arc\n",angle+90,angle-90);
	    }
	    fputs("closepath 0 setgray stroke\n",OutFile);
	}
    } else /* col1 == col2! */
    {   fprintf(OutFile,"%d %d %g ",dst->x,dst->y,radius);
	fprintf(OutFile,"%g %g arc\n",angle-90,angle+90);

	if( (src->flag&SphereFlag) && (src->radius>rad) )
	{   temp = (Scale*src->radius)/dist3;
	    endx = src->x + temp*dx;
	    endy = src->y + temp*dy;
	    ratio = dz/dist3;

	    fprintf(OutFile,"%g %g %g ",radius,ratio,angle);
	    fprintf(OutFile,"%g %g StickEnd\n",endx,endy);
	} else
	{   fprintf(OutFile,"%d %d %g ",src->x,src->y,radius);
	    fprintf(OutFile,"%g %g arc\n",angle+90,angle-90);
	}

	i = col1 + inten;
	fprintf(OutFile,"%g ",(Real)RLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)GLut[i]/255.0);
	fprintf(OutFile,"%g ",(Real)BLut[i]/255.0);
	fputs("Stick\n",OutFile);
    }
    VectCol = 0;
}


static void WriteVectDots()
{
    register DotStruct __far *ptr;
    register Real x,y,z;
    register Real xi,yi;
    register int inten;
    register int temp;
    register int zi;
    register int i;


    if( LineWidth != 1.0 )
    {   fputs("1 setlinewidth\n",OutFile);
	LineWidth = 1.0;
    }

    temp = SlabValue - ZOffset;
    for( ptr=DotPtr; ptr; ptr=ptr->next )
	for( i=0; i<ptr->count; i++ )
	{   x = ptr->xpos[i];  
	    y = ptr->ypos[i];  
	    z = ptr->zpos[i];


	    xi = (x*MatX[0]+y*MatX[1]+z*MatX[2]) + XOffset;
	    if( (xi<0.0) || (xi>=XRange) ) continue;
	    yi = (x*MatY[0]+y*MatY[1]+z*MatY[2]) + YOffset;
	    if( (yi<0.0) || (yi>=YRange) ) continue;

	    zi = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2]);
	    if( UseSlabPlane && (zi>=temp) ) continue;

	    inten = (ColourDepth*(zi+ImageRadius))/ImageSize;
	    WriteVectColour( ptr->col[i]+inten );
	    fprintf(OutFile,"%g %g Dot\n",xi,yi);
	}
}


static void WriteVectLabels()
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *aptr;
    register Label *label;
    auto char buffer[80];

    fputs("/Times-Roman",OutFile); /* Courier or Courier-Bold? */
    fprintf(OutFile," findfont %d scalefont setfont\n",FontSize<<1);

    if( UseLabelCol )
    {   if( BackR || BackG || BackB )
	{   fprintf(OutFile,"%g %g %g setrgbcolor\n",
		    LabR/250.0, LabG/250.0, LabB/250.0);
	} else fputs("0 setgray\n",OutFile);
    } else VectCol = 0;

    ForEachAtom
	if( aptr->label )
	{   if( !UseLabelCol && (aptr->col!=VectCol) )
		 WriteVectColour( aptr->col );

	    label = (Label*)aptr->label;
	    FormatLabel(chain,group,aptr,label->label,buffer);
	    fprintf(OutFile,"(%s) %d %d Label\n",buffer,aptr->x,aptr->y);
	}
}


static Long CountPSItems()
{
    register Chain __far *chain;
    register Group __far *group;
    register HBond __far *hptr;
    register Bond __far *bptr;
    register Atom __far *aptr;
    register Long result;

    result = 0;
    if( DrawAtoms )
        ForEachAtom 
	    if( aptr->flag&SphereFlag ) 
	        if( !UseClipping || !ClipVectSphere(aptr) )
		    result++;

    if( DrawBonds )
        ForEachBond 
            if( bptr->flag&DrawBondFlag && (!UseClipping ||
	        !ClipVectBond(bptr->srcatom,bptr->dstatom)) )
		    result++;

    ForEachBack 
        if( bptr->flag&DrawBondFlag && (!UseClipping ||
	    !ClipVectBond(bptr->srcatom,bptr->dstatom)) )
		result++;

    for( hptr=Database->hlist; hptr; hptr=hptr->hnext )
        if( hptr->flag&DrawBondFlag )
        {   if( HBondMode )
            {   if( !ClipVectBond(hptr->srcCA,hptr->dstCA) )
                    result++;
            } else if( !ClipVectBond(hptr->src,hptr->dst) )
                result++;
        }

    for( hptr=Database->slist; hptr; hptr=hptr->hnext )
        if( hptr->flag&DrawBondFlag )
        {   if( SSBondMode )
            {   if( !ClipVectBond(hptr->srcCA,hptr->dstCA) )
                    result++;
            } else if( !ClipVectBond(hptr->src,hptr->dst) )
                result++;
        }
    return( result );
}


static void FetchPSItems( data, type )
    PSItemPtr __far *data;
    char __far *type;
{
    register Chain __far *chain;
    register Group __far *group;
    register HBond __far *hptr;
    register Bond __far *bptr;
    register Atom __far *aptr;
    register int i,flag;

    i = 0;
    if( DrawAtoms )
        ForEachAtom
	    if( aptr->flag&SphereFlag )
	        if( !UseClipping || !ClipVectSphere(aptr) )
	        {   type[i] = PSAtom; 
		    data[i++] = aptr;
	        }

    if( DrawBonds )
        ForEachBond
            if( bptr->flag&DrawBondFlag && (!UseClipping ||
	        !ClipVectBond(bptr->srcatom,bptr->dstatom)) )
	    {   type[i] = PSBond;
	        data[i++] = bptr;
	    } 

    ForEachBack
       if( bptr->flag&DrawBondFlag && (!UseClipping ||
           !ClipVectBond(bptr->srcatom,bptr->dstatom)) )
       {   type[i] = PSBond;
           data[i++] = bptr; 
       } 

    for( hptr=Database->hlist; hptr; hptr=hptr->hnext )
        if( hptr->flag&DrawBondFlag )
        {   if( HBondMode )
            {   flag = !ClipVectBond(hptr->srcCA,hptr->dstCA);
            } else flag = !ClipVectBond(hptr->src,hptr->dst);

            if( flag )
            {   type[i] = PSHBond;
                data[i++] = hptr;
            }
        }

    for( hptr=Database->slist; hptr; hptr=hptr->hnext )
        if( hptr->flag&DrawBondFlag )
        {   if( SSBondMode )
            {   flag = !ClipVectBond(hptr->srcCA,hptr->dstCA);
            } else flag = !ClipVectBond(hptr->src,hptr->dst);

            if( flag )
            {   type[i] = PSSSBond;
                data[i++] = hptr;
            }
        }
}


static void WritePSItems( data, type, count )
    PSItemPtr __far *data;
    char __far *type;
    int count;
{
    register HBond __far *hbond;
    register Bond __far *bond;
    register Atom __far *src;
    register Atom __far *dst;
    register int i;

    for( i=0; i<count; i++ )
        switch( type[i] )
        {   case(PSAtom):   WriteVectSphere(data,type,i);
                            break;

            case(PSBond):   bond = (Bond __far*)data[i];
                            src = bond->srcatom;
                            dst = bond->dstatom;

                            if( bond->flag & WireFlag )
                            {   WriteVectWire(src,dst,bond->col,False);
                            } else if( bond->flag & CylinderFlag )
                            {   WriteVectStick(src,dst,bond->col,bond->radius);
                            } else /* bond->flag & DashFlag */
                                WriteVectWire(src,dst,bond->col,True);
                            break;

            case(PSSSBond): 
            case(PSHBond):  hbond = (HBond __far*)data[i];
                            if( (type[i]==PSHBond)? HBondMode : SSBondMode )
                            {   src = hbond->srcCA;
                                dst = hbond->dstCA;
                            } else
                            {   src = hbond->src;
                                dst = hbond->dst;
                            }

                            if( hbond->flag & WireFlag )
                            {   WriteVectWire(src,dst,hbond->col,True);
                            } else /* bond->flag & CylinderFlag */
                                WriteVectStick(src,dst,hbond->col,
                                                       hbond->radius);
                            break;
        }
}



int WriteVectPSFile( name )
    char *name;
{
    register Real ambi;
    register Real temp, inten;
    register int xsize, ysize;
    register int xpos, ypos;
    register Long count;
    register int i;

    PSItemPtr __far *data;
    char __far *type;

    count = CountPSItems();
    if( !count ) return( True );

#ifdef IBMPC
    if( count > 16383 )
    {   if( CommandActive ) WriteChar('\n');
        WriteString("Output Error: Too many PostScript objects!\n");
        CommandActive = False;
	return( False );
    }
#endif

    /* Allocate arrays for objects! */
    data = (PSItemPtr __far*)_fmalloc((size_t)count*sizeof(PSItemPtr));
    type = (char __far*)_fmalloc((size_t)count*sizeof(char));
    if( !data || !type )
    {   if( CommandActive ) WriteChar('\n');
	WriteString("Output Error: Not enough memory to create PostScript!\n");
	CommandActive = False;

	if( data ) _ffree( data );
	if( type ) _ffree( type );
	return( False );
    }

    OutFile = fopen(name,"w");
    if( !OutFile )
    {   FatalOutputError(name);
	return(False);
    }

    /* Determine the size of the image */
    ysize = (int)(YRange*(BORDER*PAGEWIDE)/XRange);
    if( ysize > (int)(BORDER*PAGEHIGH) )
    {   xsize = (int)(XRange*(BORDER*PAGEHIGH)/YRange);
	ysize = (int)(BORDER*PAGEHIGH);
    } else xsize = (int)(BORDER*PAGEWIDE);

    xpos = (int)(PAGEWIDE-xsize)/2;
    ypos = (int)(PAGEHIGH-ysize)/2;

    fputs("%!PS-Adobe-2.0 EPSF-2.0\n",OutFile);
    fputs("%%Creator: RasMol Version 2.6\n",OutFile);
    fprintf(OutFile,"%%%%Title: %s\n",name);
    fprintf(OutFile,"%%%%BoundingBox: %d %d ",xpos,ypos);
    fprintf(OutFile,"%d %d\n",xpos+xsize,ypos+ysize);

    fputs("%%Pages: 1\n",OutFile);
    fputs("%%EndComments\n",OutFile);
    fputs("%%EndProlog\n",OutFile);
    fputs("%%BeginSetup\n",OutFile);

    fputs("1 setlinecap 1 setlinejoin [] 0 setdash\n",OutFile);
    fputs("1 setlinewidth 0 setgray\n",OutFile);
    fputs("%%EndSetup\n",OutFile);
    fputs("%%Page: 1 1\n",OutFile);

    fputs("gsave\n",OutFile);
    fputs("14 dict begin\n\n",OutFile);
    fputs("/handleerror { showpage } def\n\n",OutFile);
    fputs("/Inten {\n  dup 4 index mul exch\n",OutFile);
    fputs("  dup 4 index mul exch\n",OutFile);
    fputs("  3 index mul setrgbcolor\n} def\n\n",OutFile);

    fputs("/Dot {\n  moveto 0 0 rlineto stroke\n} def\n\n",OutFile);
    fputs("/Wire {\n  moveto lineto stroke\n} def\n\n",OutFile);
#ifdef INVERT
    fputs("/Label {\n  moveto show\n} def\n\n",OutFile);
#else
    fputs("/Label {\n  moveto 1 -1 scale\n",OutFile);
    fputs("  show mtrx setmatrix\n} def\n\n",OutFile);
#endif

    if( UseOutLine )
    {   fputs("/Stick {\n  closepath gsave setrgbcolor fill\n",OutFile);
	fputs("  grestore 0 setgray stroke\n} def\n\n",OutFile);
    } else
	fputs("/Stick {\n  closepath setrgbcolor fill\n} def\n\n",OutFile);

    fputs("/StickEnd {\n  matrix currentmatrix 6 1 roll\n",OutFile);
    fputs("  translate rotate 1 scale\n",OutFile);
    fputs("  0 0 3 2 roll 90 -90 arc\n  setmatrix\n} def\n\n",OutFile);

    if( UseOutLine )
    {   fputs("/Shade {\n  closepath gsave clip\n",OutFile);
    } else fputs("/Shade {\n  closepath clip\n",OutFile);

    if( Ambient < 0.99 )
    {   ambi = 0.5*Ambient;
        fputs("  45 rotate dup -0.81649658092 mul scale\n",OutFile);
        fprintf(OutFile,"  %g Inten fill\n",ambi);
        inten = (1.0-ambi)/31;
        for( i=0; i<31; i++ )
        {   temp = (Real)(i+1)/32;
	    fprintf(OutFile,"  0 %g ",(Real)i/32);
	    fprintf(OutFile,"%g 0 360 arc ",sqrt(1.0-temp*temp));
	    fprintf(OutFile,"%g Inten fill\n",i*inten+ambi);
        }
        if( UseOutLine )
        {   fputs("  grestore 0 setgray stroke",OutFile);
        } else fputc(' ',OutFile);
        fputs(" pop pop pop\n} def\n\n",OutFile);

    } else /* Saturated Colours! */
    {   fputs("  pop setrgbcolor fill\n",OutFile);
        if( UseOutLine )
            fputs("  grestore 0 setgray stroke\n",OutFile);
        fputs("} def\n\n",OutFile);
    }


    fputs("/ClipSphere {\n  translate 0 0 5 2 roll arc\n} def\n\n",OutFile);
    fputs("/ClipBox {\n  translate rotate\n  dup lineto dup neg ",OutFile);
    fputs("dup\n  0 rlineto 0 exch rlineto 0 rlineto closepath\n",OutFile);
    fputs("  clip newpath mtrx setmatrix\n} def\n\n",OutFile);
    fputs("/ClipEllips {\n  translate rotate 1 scale\n",OutFile);
    fputs("  0 0 4 2 roll dup neg arc\n",OutFile);
    fputs("  reversepath mtrx setmatrix\n} def\n\n",OutFile);

    fputs("/Sphere {\n  gsave\n",OutFile);
    fputs("  translate 0 0 2 index 0 360 arc\n",OutFile);
    if( UseOutLine )
    {   fputs("  gsave Shade grestore\n",OutFile);
	fputs("  0 setgray stroke\n",OutFile);
	fputs("  grestore\n} def\n\n",OutFile);
    } else
	fputs("  Shade grestore\n} def\n\n",OutFile);

#ifdef INVERT
    fprintf(OutFile,"%d %d translate\n",xpos,ypos);
    fprintf(OutFile,"%g ",(Real)xsize/XRange);
    fprintf(OutFile,"%g ",(Real)ysize/YRange);
#else
    fprintf(OutFile,"%d %d translate\n",xpos,ypos+ysize);
    fprintf(OutFile,"%g ",(Real)xsize/XRange);
    fprintf(OutFile,"%g ",(Real)-ysize/YRange);
#endif
    fputs("scale\n/mtrx matrix currentmatrix def\n\n",OutFile);

    fputs("newpath 0 0 moveto 0 ",OutFile);
    fprintf(OutFile,"%d rlineto %d 0 rlineto 0 %d",YRange,XRange,-YRange);
    fputs(" rlineto\nclosepath clip ",OutFile);
    if( BackR || BackG || BackB )
    {   fprintf(OutFile,"%g %g %g",BackR/255.0,BackG/255.0,BackB/255.0);
	fputs(" setrgbcolor fill\n\n",OutFile);
    } else fputs("newpath\n\n",OutFile);

    LineWidth = 1.0;
    VectSolid = True;
    VectCol = 0;

    FetchPSItems(data,type);
    if( count>1 )
	DepthSort(data,type,(int)count);

    WritePSItems(data,type,(int)count);
 
    if( !VectSolid )
    {   fputs("[] 0 setdash\n",OutFile);
        VectSolid = True;
    }

    if( DrawDots )
	WriteVectDots();
    if( DrawLabels )
	WriteVectLabels();

    fputs("newpath 0 0 moveto 0 ",OutFile);
    fprintf(OutFile,"%d rlineto %d 0 rlineto 0 %d",YRange,XRange,-YRange);
    fputs(" rlineto\nclosepath 0 setgray 1 setlinewidth stroke\n",OutFile);
    fputs("end grestore\nshowpage\n",OutFile);
    fputs("%%Trailer\n",OutFile);
    fputs("%%EOF\n",OutFile);

    fclose( OutFile );
#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'vgrd','TEXT',134);
#endif
    _ffree( data );
    _ffree( type );
    return(True);
}



static void FlushPICTBuffer()
{
    if( PacketLen )
    {   if( RLEOutput )
        {   WriteByte(PacketLen-1);
            fwrite((char*)Buffer,1,PacketLen,OutFile);
        } else RLELineSize += PacketLen+1;
        PacketLen = 0;
    }
}


static void FlushPICTPacket()
{
    register int i;

    if( RLELength>2 )
    {   FlushPICTBuffer();

	if( RLEOutput )
	{   WriteByte(257-RLELength);
	    WriteByte(RLEChar);
	} else RLELineSize += 2;
    } else 
	for( i=0; i<RLELength; i++ )
	{   Buffer[PacketLen++] = RLEChar;
	    if( PacketLen == 128 ) 
		FlushPICTBuffer();
	}
}


static void WritePICTCode( val )
    int val;
{
    if( !RLELength )
    {   RLEChar = val;
	RLELength = 1;
    } else if( (val!=RLEChar) || (RLELength==128) )
    {   FlushPICTPacket();
	RLEChar = val;
	RLELength = 1;
    } else RLELength++;
}

static void WritePICTData()
{
#ifndef EIGHTBIT
    register Pixel data;
#endif
    register Pixel __huge *ptr;
    register Pixel __huge *tmp;
    register int rowbytes;
    register int x,y;

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

#ifdef EIGHTBIT
    rowbytes = XRange;
#else
    rowbytes = XRange*3;
#endif

    RLEFileSize = 0;

#ifndef INVERT
    ptr = FBuffer;
#endif
    for( y=YRange-1; y>=0; y-- )
    {
#ifdef INVERT
	ptr = FBuffer + (Long)y*XRange;
#endif

	RLELineSize = 0;
	RLEOutput = False;
	PacketLen = 0;
	RLELength = 0;

#ifdef EIGHTBIT
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( LutInv[*tmp++] );
#else
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)RComp(*tmp++) );
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)GComp(*tmp++) );
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)BComp(*tmp++) );
#endif
	FlushPICTPacket();
	FlushPICTBuffer();

#ifdef EIGHTBIT
	if( rowbytes > 250 )
	{   WriteMSBShort(RLELineSize);
	    RLEFileSize += (RLELineSize+2);
	} else
	{   WriteByte(RLELineSize);
	    RLEFileSize += (RLELineSize+1);
	}
#else
	WriteMSBShort(RLELineSize);
	RLEFileSize += (RLELineSize+2);
#endif

	RLEOutput = True;
	PacketLen = 0;
	RLELength = 0;

#ifdef EIGHTBIT
	for( x=0; x<XRange; x++ )
	    WritePICTCode( LutInv[*ptr++] );
#else
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)RComp(*tmp++) );
	tmp = ptr;
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)GComp(*tmp++) );
	for( x=0; x<XRange; x++ )
	    WritePICTCode( (int)BComp(*ptr++) );
#endif
	FlushPICTPacket();
	FlushPICTBuffer();
    }

#ifdef IBMPC
    GlobalUnlock(FBufHandle);
#endif
}


int WritePICTFile( name )
    char *name;
{
#ifdef EIGHTBIT
    register int j,r,g,b;
#endif
    register int cols;
    register int i;

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name,"wb");
#else
    OutFile = fopen(name,"w");
#endif
    if( !OutFile )
    {    FatalOutputError(name);
	 return( False );
    }

#ifdef EIGHTBIT
    cols = CompactColourMap();
#endif

    /* Write out header */
    for( i=0; i<512; i++ )
	WriteByte( 0x00 );

    WriteMSBShort(0);       /* picSize         */
    WriteMSBShort(0);       /* picFrame.top    */
    WriteMSBShort(0);       /* picFrame.left   */
    WriteMSBShort(YRange);  /* picFrame.bottom */
    WriteMSBShort(XRange);  /* picFrame.right  */

    WriteMSBShort(PICTpicversion);
    WriteMSBShort(0x02FF);

    WriteMSBShort(PICTheaderop);
    WriteMSBLong((Card)0xffffffff);
    WriteMSBShort(0);      WriteMSBShort(0);
    WriteMSBShort(0);      WriteMSBShort(0);
    WriteMSBShort(XRange); WriteMSBShort(0);
    WriteMSBShort(YRange); WriteMSBShort(0);
    WriteMSBLong(0);

    WriteMSBShort(PICTcliprgn);
    WriteMSBShort(10);      /* rgnSize */
    WriteMSBShort(0);       /* rgnBBox.top    */
    WriteMSBShort(0);       /* rgnBBox.left   */
    WriteMSBShort(YRange);  /* rgnBBox.bottom */
    WriteMSBShort(XRange);  /* rgnBBox.right  */

#ifdef EIGHTBIT
    WriteMSBShort(PICTpackbitsrect);
#else
    WriteMSBShort(PICTdirectbitsrect);
    WriteMSBShort(0x0000);  /* baseAddr      */
    WriteMSBShort(0x00ff);
#endif
    i = (XRange*sizeof(Pixel)) | 0x8000;
    WriteMSBShort( i );     /* rowBytes      */
    WriteMSBShort(0);       /* bounds.top    */
    WriteMSBShort(0);       /* bounds.left   */
    WriteMSBShort(YRange);  /* bounds.bottom */
    WriteMSBShort(XRange);  /* bounds.right  */
    WriteMSBShort(0);       /* pmVersion     */
#ifdef EIGHTBIT
    WriteMSBShort(0);       /* packType      */
#else
    WriteMSBShort(4);       /* packType      */
#endif
    WriteMSBLong(0);        /* packSize      */
    WriteMSBLong(72);       /* hRes          */
    WriteMSBLong(72);       /* vRes          */

#ifdef EIGHTBIT
    WriteMSBShort(0);       /* pixelType     */
    WriteMSBShort(8);       /* pixelSize     */
    WriteMSBShort(1);       /* cmpCount      */
    WriteMSBShort(8);       /* cmpSize       */
#else
    WriteMSBShort(16);      /* pixelType     */
    WriteMSBShort(32);      /* pixelSize     */
    WriteMSBShort(3);       /* cmpCount      */
    WriteMSBShort(8);       /* cmpSize       */
#endif

    WriteMSBLong(0);        /* planeBytes    */
    WriteMSBLong(0);        /* pmTable       */
    WriteMSBLong(0);        /* pmReserved    */

#ifdef EIGHTBIT
    WriteMSBLong(0);        /* ctSeed        */
    WriteMSBShort(0);       /* ctFlags       */
    WriteMSBShort(cols-1);  /* ctSize        */

    for( i=0; i<cols; i++ )
    {    WriteMSBShort(i);  /* value */
	 j=Node[i]; r=RLut[j]; g=GLut[j]; b=BLut[j];
	 WriteMSBShort( (r<<8)|r );  /* rgb.red */
	 WriteMSBShort( (g<<8)|g );  /* rgb.green */
	 WriteMSBShort( (b<<8)|b );  /* rgb.blue  */
    }
#endif

    WriteMSBShort(0);       /* srcRect.top    */
    WriteMSBShort(0);       /* srcRect.left   */
    WriteMSBShort(YRange);  /* srcRect.bottom */
    WriteMSBShort(XRange);  /* srcRect.right  */
    WriteMSBShort(0);       /* dstRect.top    */
    WriteMSBShort(0);       /* dstRect.left   */
    WriteMSBShort(YRange);  /* dstRect.bottom */
    WriteMSBShort(XRange);  /* dstRect.right  */
    WriteMSBShort(0);       /* mode (srcCopy) */

    WritePICTData();
    if( RLEFileSize & 0x01 ) WriteByte(0x00);
    WriteMSBShort(PICTendofpict);
    fclose(OutFile);
#ifdef APPLEMAC
    SetFileInfo(name,'ttxt','PICT',134);
#endif
    return( True );
}


static void FlushIRISBuffer()
{
    if( PacketLen )
    {   if( RLEOutput )
        {   WriteByte(PacketLen|0x80);
            fwrite((char*)Buffer,1,PacketLen,OutFile);
        } else RLELineSize += PacketLen+1;
        PacketLen = 0;
    }
}


static void FlushIRISPacket()
{
    register int i;

    if( RLELength>2 )
    {   FlushIRISBuffer();

        if( RLEOutput )
        {   WriteByte(RLELength);
            WriteByte(RLEChar);
        } else RLELineSize += 2;
    } else
        for( i=0; i<RLELength; i++ )
        {   Buffer[PacketLen++] = RLEChar;
            if( PacketLen == 127 )
                FlushIRISBuffer();
        }
    RLELength = 0;
}


static void WriteIRISCode( val )
    int val;
{
    if( !RLELength )
    {   RLELength = 1;
        RLEChar = val;
    } else if( (RLEChar!=val) || (RLELength==127) )
    {   FlushIRISPacket();
        RLELength = 1;
        RLEChar = val;
    } else RLELength++;
}


int WriteIRISFile( name )
    char *name;
{
    register Long __far *rowstart;
    register short __far *rowsize;
    register Pixel __huge *ptr;
    register Pixel __huge *tmp;
    register int i,min,max;
    register int x,y,size;

    size = 3*YRange;
    /* Allocate RLE encoded row length table */
    rowsize = (short __far*)_fmalloc(size*sizeof(short));
    rowstart = (Long __far*)_fmalloc(size*sizeof(Long));

    if( !rowsize || !rowstart )
    {   if( CommandActive ) WriteChar('\n');
        WriteString("Output Error: Unable to allocate memory!\n");
        if( rowstart ) _ffree(rowstart);
        if( rowsize ) _ffree(rowsize);
        CommandActive = False;
        return( False );
    }

#if defined(IBMPC) || defined(APPLEMAC)
    OutFile = fopen(name,"wb");
#else
    OutFile = fopen(name,"w");
#endif
    if( !OutFile )
    {    FatalOutputError(name);
	 return( False );
    }

    CalcInvColourMap();

#ifdef IBMPC
    FBuffer = (Pixel __huge*)GlobalLock(FBufHandle);
#endif

#ifdef INVERT
    ptr = FBuffer;
#endif

    max = 0;
    min = 255;
    RLEFileSize = 512 + 2*size*sizeof(Long);

    RLEOutput = False;
    PacketLen = 0;
    RLELength = 0;

    for( y=0; y<YRange; y++ )
    {
#ifndef INVERT
        ptr = FBuffer + (Long)((YRange-1)-y)*XRange;
#endif

        tmp = ptr;
        RLELineSize = 0;
        /* Red Component */
        for( x=0; x<XRange; x++ )
        {   i = RComp(*ptr++);
            if( i<min ) min=i;
            if( i>max ) max=i;
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();

        rowsize[y] = RLELineSize;
        rowstart[y] = RLEFileSize;
        RLEFileSize += RLELineSize;

        ptr = tmp;
        RLELineSize = 0;
        /* Green Component */
        for( x=0; x<XRange; x++ )
        {   i = GComp(*ptr++);
            if( i<min ) min=i;
            if( i>max ) max=i;
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();

        i = y+YRange;
        rowsize[i] = RLELineSize;
        rowstart[i] = RLEFileSize;
        RLEFileSize += RLELineSize;

        ptr = tmp;
        RLELineSize = 0;
        /* Blue Component */
        for( x=0; x<XRange; x++ )
        {   i = BComp(*ptr++);
            if( i<min ) min=i;
            if( i>max ) max=i;
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();

        i = y+(YRange<<1);
        rowsize[i] = RLELineSize;
        rowstart[i] = RLEFileSize;
        RLEFileSize += RLELineSize;
    }


    WriteMSBShort(474);     /* imagic     */
    WriteMSBShort(257);     /* type       */
    WriteMSBShort(3);       /* dim        */
    WriteMSBShort(XRange);  /* xsize      */
    WriteMSBShort(YRange);  /* ysize      */
    WriteMSBShort(3);       /* zsize      */
    WriteMSBLong(min);      /* min        */
    WriteMSBLong(max);      /* max        */
    WriteMSBLong(0);        /* wastebytes */

                            /* name       */
    fputs("RasMol IRIS RGB format output",OutFile);
    for( i=0; i<51; i++ ) WriteByte(0x00);
    WriteMSBLong(0);        /* colormap   */

    for( i=0; i<404; i++ )  WriteByte(0x00);
    for( i=0; i<size; i++ ) WriteMSBLong(rowstart[i]);
    for( i=0; i<size; i++ ) WriteMSBLong(rowsize[i]);

#ifdef INVERT
    ptr = FBuffer;
#endif

    RLEOutput = True;
    for( y=0; y<YRange; y++ )
    {
#ifndef INVERT
        ptr = FBuffer + (Long)((YRange-1)-y)*XRange;
#endif

        tmp = ptr;
        /* Red Component */
        for( x=0; x<XRange; x++ )
        {   i = RComp(*ptr++);
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();

        ptr = tmp;
        /* Green Component */
        for( x=0; x<XRange; x++ )
        {   i = GComp(*ptr++);
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();

        ptr = tmp;
        /* Blue Component */
        for( x=0; x<XRange; x++ )
        {   i = BComp(*ptr++);
            WriteIRISCode(i);
        }
        FlushIRISPacket();
        FlushIRISBuffer();
    }

    _ffree( rowstart );
    _ffree( rowsize );
    fclose( OutFile );

#ifdef APPLEMAC
    /* Avoid ANSI trigraph problems! */
    SetFileInfo(name,'\?\?\?\?','\?\?\?\?',134);
#endif
#ifdef IBMPC
    GlobalUnlock(FBufHandle); 
#endif
    return( True );
}


void InitialiseOutFile()
{
#if defined(IBMPC) || defined(APPLEMAC)
    /* Allocate Tables on FAR Heap */
    ABranch = (short __far*)_fmalloc(4096*sizeof(short));
    DBranch = (short __far*)_fmalloc(4096*sizeof(short));
    Hash = (short __far*)_fmalloc(256*sizeof(short));
    Node = (Byte __far*)_fmalloc(4096*sizeof(Byte));
#endif

    KinemageFlag = False;
    UseOutLine = False;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.