/*
     plot2am.c : Plot Unix plot files on an Amiga HIRES Screen.

	 By Joel Swank April, 1988

	 */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <intuition/intuition.h>
#include <stdio.h>
/*  The header files needed for gadget definitions  */ 
#include <intuition/intuitionbase.h> 
#include <libraries/dosextens.h> 
#include <graphics/gfxbase.h> 
#include <graphics/gfx.h> 
#include <graphics/gfxmacros.h> 
#include <graphics/display.h> 

#include <graphics/text.h> 
#include <ctype.h> 

#include <functions.h> 
#include "plotscreen.h" 
#ifdef NULL
#undef NULL
#endif
#define NULL ((void *)0)

#define INTUITION_REV 1L

static struct NewWindow	New_Window = {
	0, 2,			/* Take all except the */
	XSIZE, YSIZE,	/* top two lines       */
	-1, -1,			/* Default pens */
	CLOSEWINDOW,	/* Inputs acceppeted */
	WINDOWCLOSE		/* Fairly standard window */
	| WINDOWDEPTH | WINDOWDRAG | SMART_REFRESH | BORDERLESS ,
	NULL,			/* no gadgets */
	(struct Image *) NULL,
	(UBYTE *)"Plot2Am",	/* title */
	(struct Screen *) NULL,		/* filled at startup */
	(struct BitMap *) NULL,
	0, 0, 0, 0,		/* no change sizes, doesn't matter */
	CUSTOMSCREEN
	} ;



struct	TextAttr myattr = {
    (STRPTR)("puny.font"),
    7,
    0,
    FPB_DISKFONT};
struct	TextFont *myfont = NULL;

 
/*
 * Some things that need to be shared with done.
 */
struct IntuitionBase	*IntuitionBase = NULL;
static struct Window		*Wind = NULL ;
static struct Screen		*MyScreen = NULL ;
static struct MsgPort		*CreatePort() ;
struct GfxBase *GfxBase = NULL;
struct RastPort *rp;
struct Library *DiskfontBase = NULL;
FILE *input;

/* scaling factors */

long xscale, yscale;  /* width, height of output device */
long xmult, ymult;  /* width, height on Amiga Screen */
long xoff, yoff;	  /* offset to lower left corner  */

/* linemode constants */

char *lmodestr[] = { "dotted",
                     "solid",
                     "longdashed",
                     "shortdashed",
                     "dotdashed" };

USHORT lmode[] = { 0xaaaa, 0xffff, 0xff00, 0xf0f0, 0xf2f2 };


main(argc,argv)
int argc;
char *argv[];
{

struct IntuiMessage	*msg;
int cmd, i;
long x,y, r;
long r1, r2;
long x1,y1,x2,y2;
char textbuf[100], *p;
 
/*************************************************
     Init defaults
*************************************************/

xscale = 3120;
yscale = 3120;
xmult = 550;
ymult = 400;
xoff = 0;
yoff = 0;

 
/*************************************************
     Interrogate command line 
*************************************************/

if (argc == 0) exit(1); /* no WB for now */

if (argc == 1)
	{
	fprintf(stderr,"Usage:plot2am plotfile\n");
	exit(2);
	}

while (*argv[1] == '-') 
	{
	p = (char *) &*argv[1];
	p++;		/* point to the option chars */
	switch (*p)
		{
		case 'x':		/* x size value */
			xmult = atol(++p);
			break;

		case 'y':		/* y size value */
			ymult = atol(++p);
			break;

		default:
			fprintf(stderr,"plot2am:Invalid option %s\n",argv[1]);
			exit(27);
		}
	argc--;
	argv++;
	}

if (argc == 1 || argc >2)
	{
	fprintf(stderr,"plot2am:Exactly One filename required\n");
	exit(2);
	}


if ((input = fopen(argv[1],"r")) == NULL)
	{
	fprintf(stderr,"plot2am: %s: open failed\n",argv[1]);
	exit(3);
	}

/*************************************************
     OPEN everything
*************************************************/

 
if ((IntuitionBase = (struct IntuitionBase *)
    OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
	done(21);

GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", NULL);
if (GfxBase == NULL) done(22);

DiskfontBase = (struct Library *)OpenLibrary("diskfont.library", NULL);
if (DiskfontBase == NULL) {
	fprintf(stderr,"plot2am:cannot open font library - using default font\n");
	}

if ((MyScreen = (struct Screen *) OpenScreen(&NewScreenStructure)) == NULL)
	done(23);

New_Window.Screen = MyScreen;

if ((Wind = (struct Window *) OpenWindow(&New_Window)) == NULL)
	done(25);
rp = Wind->RPort;

if (DiskfontBase != NULL) {
	if ((myfont = (struct TextFont *)OpenDiskFont(&myattr)) == NULL) {
		fprintf(stderr,"plot2am:cannot find puny font - using default\n");
	} else  SetFont(rp,myfont);
}


LoadRGB4(&(MyScreen->ViewPort),&Palette,PaletteColorCount);

 
/*************************************************
     MAIN Drawing loop
*************************************************/

while ((cmd = getc(input)) != EOF)
	{
	switch (cmd)
		{
		case 'm':	/* move x,y */
			get_xy(&x,&y);
			Move(rp,x,y);
			break;
		case 'n':	/* draw x,y */
			get_xy(&x,&y);
			Draw(rp,x,y);
			break;
		case 'p':	/* point x,y */
			get_xy(&x,&y);
			WritePixel(rp,x,y);
			break;
		case 'l':	/* line xs,ys, xe,ye */
			get_xy(&x,&y);
			Move(rp,x,y);
			get_xy(&x,&y);
			Draw(rp,x,y);
			break;
		case 'a':	/* arc xc,yc, xs,ys, xe,ye */
			get_xy(&x,&y);    /* get center */
			get_xy(&x2,&y2);  /* get end point */
			get_xy(&x1,&y1);  /* get start point */
			arc(x, y, x1, y1, x2, y2);  /* draw counterclockwise  */
			Move(rp,x1,y1);
			break;
		case 't':	/* Text string\n   */
			get_txt(textbuf);
			if (rp->cp_y == 0) break;
			Text(rp,textbuf, (long) strlen(textbuf));
			break;
		case 'c':	/* circle xc,yc, r */
			get_xy(&x,&y);
			get_int(&r);
			r1 = r*xmult/xscale;
			r2 = r*ymult/yscale;
			DrawEllipse(rp,x,y,r1,r2);
			break;
		case 'f':	/* linemode string\n   */
			get_txt(textbuf);
			for (i=0; i<5; i++)
				{
				if (0 == strcmp(textbuf,lmodestr[i]))
					{
					SetDrPt(rp,lmode[i]);
					break;
					}
				}
			break;
		case 's':	/* space xlo,ylo, xhi,yhi */
			get_int(&xoff);
			get_int(&yoff);
			get_int(&xscale);
			get_int(&yscale);
			xscale = xscale - xoff;
			yscale = yscale - yoff;
			break;
		case 'e':	/* erase */
			SetAPen(rp,0L);
			RectFill(rp,0L,0L,(long) (XSIZE-1),(long) (YSIZE-1));
			SetAPen(rp,1L);
			break;
		}
	}

 
/*************************************************
     WAIT for Close Gadget
*************************************************/

while (1)
	{
	Wait( 1L << Wind->UserPort->mp_SigBit);	/* wait on mesg */
	while(msg = (struct IntuiMessage *) GetMsg(Wind->UserPort)) {
		switch(msg->Class) {
			case CLOSEWINDOW:
				ReplyMsg(msg);
				done(0);
			}
			ReplyMsg(msg);
		}
	}
}

/*************************************************
     Parameter input routines
*************************************************/


/*
 * input a pair of 16 bit ints, scale
 * and return them as longs
 *
 */

get_xy(x,y)
register long *x, *y;
{
	get_int(x);
	*x = (*x-xoff)*xmult/xscale;
	get_int(y);
	*y = (YSIZE-1)-(*y-yoff)*ymult/yscale;
}

/*
 * input a 16 bit int and return as a long
 */

get_int(num)
long *num;
{
	register long hi, lo;
	lo = (long) getc(input);
	hi = ( (long) getc(input)) << 8;
	*num = lo + hi;
}

/*
 * input a text string delinited by newline,
 * return to buffer delimited by a null.
 */

get_txt(str)
char *str;
{
	register int cmd;
	while ((cmd = getc(input)) != '\n')
		*str++ = cmd;
	*str = '\0';
}

/*
 * done - just clean up that which is open, and then leave.
 */
done(how)
int how;
    {
    if (Wind) CloseWindow(Wind) ;
    if (MyScreen) CloseScreen(MyScreen) ;
    if (IntuitionBase) CloseLibrary(IntuitionBase) ;
    if (GfxBase) CloseLibrary(GfxBase) ;
    if (DiskfontBase) CloseLibrary(DiskfontBase) ;
	if (myfont   != NULL) CloseFont( myfont );
 
    OpenWorkBench() ;		/* As requested */
    exit(how) ;
    }

/*
 * arc and integer sqrt routines.
 * lifted from sunplot program by:

Sjoerd Mullender
Dept. of Mathematics and Computer Science
Free University
Amsterdam
Netherlands

Email: sjoerd@cs.vu.nl
If this doesn't work, try ...!seismo!mcvax!cs.vu.nl!sjoerd or
...!seismo!mcvax!vu44!sjoerd or sjoerd%cs.vu.nl@seismo.css.gov.

 *
 */

long
isqrt(n)
long n;
{
	long a, b, c;

	a = n;
	b = n;
	if (n > 1) {
		while (a > 0) {
			a = a >> 2;
			b = b >> 1;
		}
		do {
			a = b;
			c = n / b;
			b = (c + a) >> 1;
		} while ((a - c) < -1 || (a - c) > 1);
	}
	return b;
}


#define setcir(x, y, a1, b1, c1, a2, b2, c2) \
	{if (a1 * (y) - b1 * (x) >= c1 && a2 * (y) - b2 * (x) <= c2) \
	WritePixel(rp,x, y);}

arc(x, y, x1, y1, x2, y2)
long x, y, x1, y1, x2, y2;
{
	register long a1 = x1 - x, b1 = y1 - y, a2 = x2 - x, b2 = y2 - y;
	register long c1 = a1 * y - b1 * x, c2 = a2 * y - b2 * x;
	register long r2 = a1 * a1 + b1 * b1;
	register long i, sqrt;

	for (i = isqrt(r2 >> 1); i >= 0; i -= 1) {
		sqrt = isqrt(r2 - i * i);
		setcir(x + i, y + sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x + i, y - sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x - i, y + sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x - i, y - sqrt, a1, b1, c1, a2, b2, c2);
		setcir(x + sqrt, y + i, a1, b1, c1, a2, b2, c2);
		setcir(x + sqrt, y - i, a1, b1, c1, a2, b2, c2);
		setcir(x - sqrt, y + i, a1, b1, c1, a2, b2, c2);
		setcir(x - sqrt, y - i, a1, b1, c1, a2, b2, c2);
	}
}
