/* Copyright (c) 1990 Commodore-Amiga, Inc.
 *
 * This example is provided in electronic form by Commodore-Amiga, Inc. for
 * use with the 1.3 revisions of the Addison-Wesley Amiga reference manuals. 
 * The 1.3 Addison-Wesley Amiga Reference Manual series contains additional
 * information on the correct usage of the techniques and operating system
 * functions presented in this example.  The source and executable code of
 * this example may only be distributed in free electronic form, via bulletin
 * board or as part of a fully non-commercial and freely redistributable
 * diskette.  Both the source and executable code (including comments) must
 * be included, without modification, in any copy.  This example may not be
 * published in printed form or distributed with any commercial product.
 * However, the programming techniques and support routines set forth in
 * this example may be used in the development of original executable
 * software products for Commodore Amiga computers.
 * All other rights reserved.
 * This example is provided "as-is" and is subject to change; no warranties
 * are made.  All use is at your own risk.  No liability or responsibility
 * is assumed.
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <devices/printer.h>
#include <devices/prtbase.h>
#include <devices/prtgfx.h>

#define NUMSTARTCMD	8	/* # of cmd bytes before binary data */
#define NUMENDCMD	1	/* # of cmd bytes after binary data */
#define NUMTOTALCMD (NUMSTARTCMD + NUMENDCMD)	/* total of above */
#define NUMLFCMD	4	/* # of cmd bytes for linefeed */
#define MAXCOLORBUFS	4	/* max # of color buffers */

#define STARTLEN	16
#define PITCH		1
#define CONDENSED	2
#define LMARG		8
#define RMARG		11
#define DIREC		15

Render(ct, x, y, status)
long ct, x, y, status;
{
	extern void *AllocMem(), FreeMem();

	extern struct PrinterData *PD;
	extern struct PrinterExtendedData *PED;

	static UWORD RowSize, ColorSize, BufSize, TotalBufSize;
	static UWORD dataoffset, dpi_code;
	static UWORD colors[MAXCOLORBUFS]; /* color ptrs */
	static UWORD colorcodes[MAXCOLORBUFS]; /* printer color codes */
	static UWORD NumColorBufs; /* actually number of color buffers req. */
	/*
		00-01	\003P		set pitch (10 or 12 cpi)
		02-02	\022		set condensed fine (on or off)
		03-05	\033W\000	enlarge off
		06-08	\033ln		set left margin to n
		09-11	\033Qn		set right margin to n
		12-12	\015		carriage return
		13-15	\033U1		set uni-directional mode
	*/
	static UBYTE StartBuf[STARTLEN] =
        {0x1b,'P',0x12,0x1b,'W',0x0,0x1b,'l','n',0x1b,'Q','n',0x0d,0x1b,'U','1'};

	UBYTE *ptr, *ptrstart, *ptr2, *ptr2start, **dummy;

	int i, err;

    switch(status) {
	    case 0:  /* Master Initialization */
			/*
				ct	- pointer to IODRPReq structure.
				x	- width of printed picture in pixels.
				y	- height of printed picture in pixels.
			*/
			RowSize = x * 3;
			ColorSize = RowSize + NUMTOTALCMD;
			if (PD->pd_Preferences.PrintShade == SHADE_COLOR) {
				NumColorBufs = MAXCOLORBUFS;
				colors[0] = ColorSize * 3; /* Black */
				colors[1] = ColorSize * 0; /* Yellow */
				colors[2] = ColorSize * 1; /* Magenta */
				colors[3] = ColorSize * 2; /* Cyan */
				colorcodes[0] = 4; /* Yellow */
				colorcodes[1] = 1; /* Magenta */
				colorcodes[2] = 2; /* Cyan */
				colorcodes[3] = 0; /* Black */
			}
			else { /* grey-scale or black&white */
				NumColorBufs = 1;
				colors[0] = ColorSize * 0; /* Black */
				colorcodes[0] = 0; /* Black */
			}
			BufSize = ColorSize * NumColorBufs + NUMLFCMD;
			TotalBufSize = BufSize * 2;
			PD->pd_PrintBuf = AllocMem(TotalBufSize, MEMF_PUBLIC);
			if (PD->pd_PrintBuf == NULL) {
				err = PDERR_BUFFERMEMORY; /* no mem */
			}
			else {
				dataoffset = NUMSTARTCMD;
				/*
					This printer prints graphics within its
					text margins.  This code makes sure the
					printer is in 10 cpi and then sets the
					left and right margins to their minimum
					and maximum values (respectively).  A
					carriage return is sent so that the
					print head is at the leftmost position
					as this printer starts printing from
					the print head's position.  The printer
					is put into unidirectional mode to
					reduce wavy vertical lines.
				*/
				StartBuf[PITCH] = 'P'; /* 10 cpi */
				StartBuf[CONDENSED] = '\022'; /* off */
				/* left margin of 1 */
				StartBuf[LMARG] = 0;
				/* right margin of 80 or 136 */
				StartBuf[RMARG] = PD->pd_Preferences.
					PaperSize == W_TRACTOR ? 136 : 80;
				/* uni-directional mode */
				StartBuf[DIREC] = '1';
				err = (*(PD->pd_PWrite))(StartBuf, STARTLEN);
			}
			break;

	    case 1: /* Scale, Dither and Render */
			/*
				ct	- pointer to PrtInfo structure.
				x	- 0.
				y	- row # (0 to Height - 1).
			*/
			Transfer(ct, y, &PD->pd_PrintBuf[dataoffset], colors);
			err = PDERR_NOERR; /* all ok */
			break;

	    case 2: /* Dump Buffer to Printer */
			/*
				ct	- 0.
				x	- 0.
				y	- # of rows sent (1 to NumRows).
			*/
			/* white-space strip */
			ptrstart = &PD->pd_PrintBuf[dataoffset];
			ptr2start = ptr2 = ptrstart - NUMSTARTCMD;
			x = 0; /* flag no transfer required yet */
			for (ct=0; ct<NumColorBufs;
				ct++, ptrstart += ColorSize) {
				i = RowSize;
				ptr = ptrstart + i - 1;
				while (i > 0 && *ptr == 0) {
					i--;
					ptr--;
				}
				if (i != 0) { /* if data */
					/* convert to # of pixels */
					i = (i + 2) / 3;
					ptr = ptrstart - NUMSTARTCMD;
					*ptr++ = 27;
					*ptr++ = 'r';
					*ptr++ = colorcodes[ct]; /* color */
					*ptr++ = 27;
					*ptr++ = '*';
					*ptr++ = dpi_code;	/* density */
					*ptr++ = i & 0xff;
					*ptr++ = i >> 8;	/* size */
					i *= 3; /* back to # of bytes used */
					*(ptrstart + i) = 13; /* cr */
					i += NUMTOTALCMD;
					/* if must transfer data */
					if (x != 0) {
						/* get src start */
						ptr = ptrstart - NUMSTARTCMD;
                                                /* otherwise Lattice looses
                                                   track of the pointer.... */
                                                dummy = &ptr;
						/* xfer and update dest ptr */
						do {
							*ptr2++ = *ptr++;
						} while (--i);
					}
					else { /* no transfer required */
						/* update dest ptr */
						ptr2 += i;
					}
				}
				/* if compacted or 0 */
				if (i != RowSize + NUMTOTALCMD) {
					/* we need to transfer next time */
					x = 1;
				}
			}
			*ptr2++ = 13; /* cr */
			*ptr2++ = 27;
			*ptr2++ = 'J';
			*ptr2++ = y; /* y/180 lf */
			err = (*(PD->pd_PWrite))(ptr2start, ptr2 - ptr2start);
			if (err == PDERR_NOERR) {
				dataoffset = (dataoffset == NUMSTARTCMD ?
					BufSize : 0) + NUMSTARTCMD;
			}
			break;

	    case 3: /* Clear and Init Buffer */
			/*
				ct	- 0.
				x	- 0.
				y	- 0.
			*/
			ptr = &PD->pd_PrintBuf[dataoffset];
			i = BufSize - NUMTOTALCMD - NUMLFCMD;
			do {
				*ptr++ = 0;
			} while (--i);
			err = PDERR_NOERR; /* all ok */
			break;

	    case 4: /* Close Down */
			/*
				ct	- error code.
				x	- io_Special flag from IODRPReq.
				y	- 0.
			*/
			err = PDERR_NOERR; /* assume all ok */
			/* if user did not cancel print */
			if (ct != PDERR_CANCEL) {
				/* restore preferences pitch and margins */
				if (PD->pd_Preferences.PrintPitch == ELITE) {
					StartBuf[PITCH] = 'M'; /* 12 cpi */
				}
				else if (PD->pd_Preferences.PrintPitch == FINE) {
					StartBuf[CONDENSED] = '\017'; /* on */
				}
				StartBuf[LMARG] =
					PD->pd_Preferences.PrintLeftMargin - 1;
				StartBuf[RMARG] =
					PD->pd_Preferences.PrintRightMargin;
				StartBuf[DIREC] = '0'; /* bi-directional */
				err = (*(PD->pd_PWrite))(StartBuf, STARTLEN);
			}
			 /* wait for both buffers to empty */
			(*(PD->pd_PBothReady))();
			if (PD->pd_PrintBuf != NULL) {
				FreeMem(PD->pd_PrintBuf, TotalBufSize);
			}
			break;

		case 5:   /* Pre-Master Initialization */
			/*
				ct	- 0 or pointer to IODRPReq structure.
				x	- io_Special flag from IODRPReq.
				y	- 0.
			*/
			/*
				Kludge for weak power supplies.
				FANFOLD - use all 24 pins (default).
				SINGLE  - use only 16 pins.
			*/
			PED->ped_NumRows = PD->pd_Preferences.PaperType ==
				SINGLE ? 16 : 24;
			dpi_code = SetDensity(x & SPECIAL_DENSITYMASK);
			err = PDERR_NOERR; /* all ok */
			break;
	}
	return(err);
}
