/*********************************************************************
 * Fraktales Sechseck mit Ausgabe auf einem Epson kompatiblen Drucker
 *********************************************************************
 * Autor: Rainer Umbach, Schulweg 6, 3501 Espenau 2, Januar 1990 
 *********************************************************************
 * Aztec C lauffaehige Version
 * compilieren: cc name +l
 * linken: ln name -lm -lc32
 *********************************************************************/

#include <stdio.h>
#include <exec/types.h>
#include <devices/parallel.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

#define scale 10000

/*********************************************************************
 * Definitionen mit struct
 *********************************************************************/

struct GfxBase			*GfxBase;			/* Zeiger auf GfxBase	*/
struct IntuitionBase	*IntuitionBase;		/* Zeiger auf IntBase	*/
struct Screen			*InterlaceScreen;	/* Zeiger auf Screen	*/
struct Window			*GraphWindow;		/* Zeiger auf Window	*/
struct RastPort			*InterlaceRastPort;	/* RPort des Windows	*/
struct MsgPort			*parallelPort;		/* Drucker-MsgPort		*/
struct IOExtPar			IOparallel;			/* IORequest-Struktur	*/
											/* fuer parallel.device	*/

struct NewScreen Interlace =
{ 0, 0, 952, 1010, 1, 0, 1, HIRES | LACE,
  CUSTOMSCREEN | SCREENBEHIND, NULL, (UBYTE *) "Fraktal", NULL, NULL,};	

struct NewWindow Graph =
{ 8, 12, 936, 992, 0, 1, NULL, SMART_REFRESH | BORDERLESS | BACKDROP,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, CUSTOMSCREEN,};

/*********************************************************************
 * Definitionen der Steuercodes fuer Star LC-10 		(ueber par:)
 *********************************************************************/

UBYTE	NLQ_ein[3]	= { 27, 'x', 1         };	/* NLQ Modus an			*/
UBYTE   NLQ_dlh[3]	= { 27, '%', 1         };	/* Download-Ram an		*/
UBYTE	NLQ_def[5]	= { 27, '&', 0, 33, 33 };	/* NLQ-Definition		*/
UBYTE	NLQ_ret[1]	= { 10                 };	/* linefeed				*/
UBYTE	NLQ_res[2]	= { 27, '@'            };	/* Druckerreset			*/
UBYTE	NLQ_zab[3]	= { 27, 'A', 8         };	/* neuer Zeilenabstand	*/
UBYTE	NLQ_sza[5]	= { 27, ':', 0,  0,  0 };	/* Standardchr. ins Ram	*/
UBYTE   NLQ_zei[79];							/* NLQ Zeichenkette		*/

/*********************************************************************
 * Hauptprogramm
 *********************************************************************/

main()
{
	int 	n;					/* Zaehlvariable						*/

	long	xeck[6],yeck[6];	/* Variablen fuer Fraktal				*/
	long	x,y,vx,vy,rnd,i;
	float	ran();

	for(n=32;n<=110;n++)		/* NLQ-Zeichenkette	definieren			*/
		NLQ_zei[n-32]=n;
	open1084();					/* Bildschirme & Libraries oeffnen		*/

	ScreenToFront(InterlaceScreen);

	xeck[0]=-467*scale;yeck[0]=   0*scale;
	xeck[1]=-233*scale;yeck[1]=-486*scale;
	xeck[2]= 233*scale;yeck[2]=-486*scale;
	xeck[3]= 467*scale;yeck[3]=   0*scale;
	xeck[4]= 233*scale;yeck[4]= 486*scale;
	xeck[5]=-233*scale;yeck[5]= 486*scale;
	x=-467*scale;
	y=   0*scale;

	for(i=0;i<=1000000;i++)
	{
		rnd=(int)(ran()*5.99);
		vx=xeck[rnd]-x;
		vy=yeck[rnd]-y;
		x=x+2*vx/3;
		y=y+2*vy/3;

		WritePixel(InterlaceRastPort,(x/scale)+467,-(y/scale)+495);
	}

	Hardcopy();

	close1084();
}


/*********************************************************************
 * open1084()
 *********************************************************************
 * Diese Funktion oeffnet den Interlacescreen, das Window, sowie die
 * intuition.library und graphics.library. OpenLibrary() ist eine
 * Exec-Lib.-Fkt., OpenScreen() und OpenWindow() werden von der
 * Intuition-Library gestellt. Cannot_open() s.u.
 *********************************************************************/

open1084()
{
	void			*OpenLibrary();
	struct Window	*OpenWindow();
	struct Screen	*OpenScreen();

	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library",0L)))
		{printf("Cannot open Intuition.Librrary\n");Cannot_open();}

	if (!(GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library",0L)))
		{printf("Cannot open Graphics.Library\n");Cannot_open();}

	if (!(InterlaceScreen = (struct Screen *)
		OpenScreen(&Interlace)))
		{printf("Cannot open Interlace Screen\n");Cannot_open();}
	
	Graph.Screen = InterlaceScreen; /* Dem neuen Window wird gesagt,	*/
									/* auf welchem Screen es erscheinen */
									/* soll. Wichtig: erst nach 		*/
									/* OpenScreen, da sonst `Interlace	*/
									/* Screen` nicht def. ist (!!!!)	*/

	if (!(GraphWindow = (struct Window *)
		OpenWindow(&Graph)))
		{printf("Cannot open Graph Window\n");Cannot_open();}

	InterlaceRastPort = GraphWindow->RPort;	/* Der RPort des Interlace-	*/
											/* windows wird zugewiesen.	*/
											/* Erst nach OpenWindow (!)	*/	
}

/*********************************************************************
 * Cannot_open()
 *********************************************************************
 * Escape-Funktion, wird angesprungen, wenn eine Library oder ein
 * Device nicht geoeffnet werden konnte.
 *********************************************************************/

Cannot_open()
{
	close1084();
	exit(FALSE);
}


/*********************************************************************
 * close1084()
 *********************************************************************
 * Hier wird alles unter open1084() geoeffnete wieder geschlossen,
 * falls es richtig geoeffnet wurde. CloseWindow() und CloseScreen()
 * sind aus der Intuition-Library, CloseLibrary() ist aus Exec-Lib.
 *********************************************************************/

close1084()
{
	if (GraphWindow)		CloseWindow(GraphWindow);
	if (InterlaceScreen)	CloseScreen(InterlaceScreen);
	if (GfxBase)			CloseLibrary(GfxBase);
	if (IntuitionBase)		CloseLibrary(IntuitionBase);
}

/*********************************************************************
 * Hardcopy()
 *********************************************************************
 * Diese Funktion gibt den Inhalt des Interlace-Windows als NLQ-
 * Zeichen auf dem Star LC-10 (Epson kompatibel) aus.
 * Zustand der DIP-Schalter  | * *****| | * *| <- EIN (hinten)
 * beim Star LC-10:          |* *     | |* * | <- AUS (vorne )
 * Zum Nachvollziehen des Algorithmus` siehe Handbuch Star LC-10.
 * ReadPixel() ist aus der Graphics-Lib. und gibt den Farbwert des
 * Pixel an der Stelle x/y in einem bestimmten RPort zurueck.
 *********************************************************************/

Hardcopy()
{
	register int	Zeile, x, y;	/* Spalten- & Zeilenzaehlvariablen	*/
	UBYTE			bytestr[2][936],/* Bit-Muster von zwei Zeilen		*/
					printerchar[47];/* NLQ-Defintions-String			*/

	openStar();						/* parallel.device oeffnen			*/
	printerchar[0] = 128;			/* Unterlaenge & Proportionalschr.	*/
	for(x=1;x<=46;x++)				/* NLQ-Defintions-String vorbe-		*/
		printerchar[x] = 0;			/* reiten (x nur als Zaehlvariable)	*/

	for(Zeile=0;Zeile<=61;Zeile++)	/* Die Interlace-Zeilen werden		*/
	{								/* durchgesehen.					*/
		for(x=0;x<936;x++)			/* Je 2 Zeilen à 8 Pixel werden ge-	*/
		{							/* meinsam gescannt und	in 			*/
			bytestr[0][x] = 0;		/* bytestr[] gespeichert.			*/
			bytestr[1][x] = 0;
			for(y=15;y>=0;y--)
				if(0 !=  ReadPixel(InterlaceRastPort,x,y+Zeile*16))
					bytestr[y & 1][x] += 1 << (15-y)/2;
		}
		for(x=0;x<936;x+=12)
		{
			for(y=0;y<=11;y++)		/* (y nur als Zaehlvariable)		*/
			{
				printerchar[ 1+y*2] = bytestr[0][x+y];
				printerchar[24+y*2] = bytestr[1][x+y];
			}
			NLQ_def[3] = x/12 + 33;
			NLQ_def[4] = x/12 + 33;
			writeStar(&NLQ_def[0],5);
			writeStar(&printerchar[0],47);	
		}
		writeStar(&NLQ_zei[0],79);
		writeStar(&NLQ_ret[0],1);
		writeStar(&NLQ_def[0],5);		/* 79. Definition der NLQ`s,	*/
		writeStar(&printerchar[0],47);	/* sonst Fehler (!?!?!?!?!?!?!)	*/
	}
	closeStar();					/* parallel.device schliessen		*/
}

/*********************************************************************
 * openStar()
 *********************************************************************
 * Hier wird das parallel.device geoeffnet und der Drucker initiali-
 * siert. OpenDevice() ist aus der Exec-Library und CreatePort() ist 
 * eine Exec-Support-Routine. Cannot_open() s.o.
 *********************************************************************/
 
openStar()
{
	struct MsgPort	*CreatePort();

	/* parallel.device oeffnen, bei Fehler: Ende	*/
		if((OpenDevice("parallel.device", 0, &IOparallel, 0)) != 0)
			{printf("Cannot open parallel.device\n");Cannot_open();}

	/* MsgPort def. und an IOExtPar uebergegen		*/
		parallelPort = CreatePort("parallel.device",0);
		IOparallel.IOPar.io_Message.mn_ReplyPort = parallelPort;

	/* Star LC-10 fuer NLQ-Ausdruck vorbereiten		*/
		writeStar(&NLQ_res[0],2);
		writeStar(&NLQ_ein[0],3);
		writeStar(&NLQ_dlh[0],3);
		writeStar(&NLQ_sza[0],5);
		writeStar(&NLQ_zab[0],3);
}

/*********************************************************************
 * writeStar(Daten, Laenge)		Text & Textlaenge
 *********************************************************************
 * Diese Funktion gibt einen Text auf dem Drucker aus. IOExtPar ist
 * die IORequest-Struktur fuer die Ausgabe ueber par:. DoIO() ist
 * eine Funktionen der Exec-Library.
 *********************************************************************/

writeStar(Daten, Laenge)
UBYTE *Daten;
LONG Laenge;
{
	/* Daten in IOExtPar schreiben					*/
		IOparallel.IOPar.io_Data = (APTR)Daten;
		IOparallel.IOPar.io_Length = Laenge;
		IOparallel.IOPar.io_Command = CMD_WRITE;

	/* Daten in IOExtPar auf par: ausgeben			*/
		if((DoIO(&IOparallel)) != 0)
			printf("parallel.device write error");
}

/*********************************************************************
 * closeStar()
 *********************************************************************
 * Diese Funktion schliesst das parallel.device und fuehrt vorher
 * noch einen Drucker-Reset durch. CloseDevice() und DeletePort()
 * sind Exec-Support-Routinen.
 *********************************************************************/

closeStar()
{	
	writeStar(&NLQ_res[0],2);	/* Star LC-10 Reset	*/

	CloseDevice(&IOparallel);	/* parallel.device	*/
	DeletePort(parallelPort);	/* schliessen		*/
}
