/*************************************************************************
*
*	FFuz.c - a Double-Precision Math Demo by David Milligan.
*
*	Copyright (C)1987 by MicroBotics, Inc. and David Milligan.
*	All rights reserved. Permission is granted to reproduce and
*	redistribute on a strictly non-profit basis provided all
*	copyright messages and source comments remain intact.
*
**************************************************************************
*		    More Fuzzy Numbers on the Amiga
*
*	   This Fuz shows a way to use direct calls to the IEEEDP math
*	functions. This way people without the Manx mi.lib & mi32.lib
*	files can compile this mess (just wait 'till you see the assembler
*	version...) and get some fuzzy idea of how to use the MC68881 on
*	Microbotics' Multi-Function Module.
*	   Fuz works off of three input variable - rot or rotation factor,
*	vx and vy which are the X & Y vectors. The values that give the
*	best results are floating point numbers of course. Use a value of
*	.1 or less for rot, vy generally likes bigger #'s like 599.9893,
*	and vx can be anything including 0 up to the 9 character limit on
*	the input buffer. - when it's started it'll plot the default values
*	I put in, and takes 20 seconds (roughly) to draw. I chose these
*	values because they're a good example of the type of numerical
*	input you should try. It's a toy. Play with it.
*
*		To compile FFuz.c with Manx, you need to link in two extra
*	libraries, midb.lib and midt.lib that I hacked together for use with
*	Manx. They stand for mathieeedoubbas.lib and mathieeedoubtrans.lib 
*	respectively, which I've gotten damned tired of typing, so if you see
*	midb or midt somewhere in my code, that's what they mean. I'm glad
*	there's a 30 character filename size limit, 'cause gawd knows what
*	weird library or function names that Dale Luck will come up with,
*	you know? I mean, have you ever looked at the function names in the
*	Layers library? I rest my case.
*		Anyway, here's the makefile for FFuz.c that you should use
*	if you don't have mi32.lib. If you do, just change -lma32 to -lmi32
*	in the Makefile.
*
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

#######################################################################
#			Makefile for FFuz.c
#	Fuz, Ffuz, Ftrans, and RedFuz are copyright (C) 1987 
#	by MicroBotics, Inc. and David Milligan. All rights reserved.
#	Permission is granted to reproduce and redistribute on a
#	strictly non-profit basis. 
#######################################################################
CFLAGS	=	+fi +L -S
LFLAGS	=	-lmidb -lmidt -lma32 -lc32
OBJ	=	FFuz.o

ffuz:		$(OBJ)
		ln -o FFuz $(OBJ) $(LFLAGS)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
*	Lattice 3.10 users can compile & link FFuz by using the script
*	files FFuz.cmd & FFuz.lnk. Have both scripts in the same directory
*	as FFuz.c and from CLI type:   Execute FFuz.cmd
*	The file mathieeedoubtrans_lib.lib used in FFuz.lnk is the Lattice
*	compatible double-precision transcendental math functions for the
*	Lattice linker, Blink. The other double-precision math functions
*	are in amiga.lib.
*

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;
;	FFuz.cmd
;
LC -cw -v FFuz
blink with FFuz.lnk

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

;
;	FFuz.lnk
;
FROM LIB:c.o+FFuz.o
TO FFuz
LIB *
LIB:mathieeedoubtrans_lib.lib,*
LIB:lcm.lib,*
LIB:lc.lib,*
LIB:amiga.lib

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
*	If you have trouble compiling my 68881 demos, I can be reached
*	via Email on the following systems. I'll gladly give you a hand.
*	I'd also be interested in seeing other programs that use the
*	MFM & 68881.
*
*		BIX	-	dmilligan
*		CI$	-	70707,2521
*		PLINK	-	Dmil
*		WELL	-	dmil
*
*			David Milligan, for MicroBotics 
*
****************************************************************************/

/*
 *   the following lines should be included in any mathchip-using
 *   program that does not use Manx's "mi" libraries.
 */

#include <libraries/midb.h>  /* route all the math functions to the	  */
#include <libraries/midt.h>  /* mathieeedoub???.library files		  */

#include <math.h>	/* this declares all the math functions as double */

long MathIeeeDoubBasBase;
long MathIeeeDoubTransBase;

double atof();		/* declare any other math functions */

/*
 *   then follows the rest of the program
 */

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

#define INTUITION	0x00000001
#define GRAPHICS	0x00000002
#define SCREEN		0x00000004
#define WINDOW		0x00000008
#define MIDB		0x00000010
#define MIDT		0x00000020

#define NS_MODE		HIRES|LACE
#define NS_TYPE		CUSTOMSCREEN
#define NS_WIDTH	640
#define NS_HEIGHT	400
#define NS_PLANES	4
#define	NW_IDCMP	MOUSEBUTTONS|GADGETDOWN|GADGETUP|CLOSEWINDOW
#define	NW_FLAGS	BORDERLESS|BACKDROP|ACTIVATE|WINDOWCLOSE
#define LINEOTYPE	12

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

#define CX	(NS_WIDTH/2)
#define CY	(NS_HEIGHT/2)
#define XTWEAK	170
#define YTWEAK	140

/*
 * Gadget definitions
 */
#define ROT	1
#define VX	2
#define VY	3
#define WHOA	4
#define GO	5
#define NUMGADS 5
#define BOOLAFLAGS	RELVERIFY|GADGIMMEDIATE
#define STRAFLAGS	RELVERIFY|GADGIMMEDIATE|STRINGCENTER
#define GADL_EDGE	5
#define GADT_EDGE	30

struct  GfxBase       *GfxBase;
struct  IntuitionBase *IntuitionBase;
struct  RastPort      *rp;
struct  ViewPort      *vp;
struct	Window	*w;
struct	Screen	*screen;
struct	IntuiMessage	*message;

UBYTE rotbuf[10] =	".02";	/* This set of values draws a nice display */
UBYTE vxbuf[10] =	"199";
UBYTE vybuf[10] =	"192";
char timebuf[25];

struct timeval t1;
struct timeval t2;

extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();


unsigned int mask = 0;
BOOL idling;
	/* A variable for everything I could think of, and a couple more */
	/* just in case it wasn't confusing enough.	*/

int from_wb,col,cnt,nx,ny,n;

double rot,vx,vy,inc,deginc,degvx,degvy,absvx,absvy,xtweak,ytweak;
double PI,DEG,sintemp,sintempvx,costemp,costempvy,vnx,vny,n1,n2;

/************************************************
 * 		Main Program 			*
 ************************************************/
main(argc)
int argc;
{
	ULONG  class;
	USHORT code;
	register struct Gadget *gad;
	register int gadgid;

	col = 1;
	inc = nx = ny = cnt = 0;

	if(argc)		/* started from CLI or Workbench? */
	  from_wb = 0;
	else
	  from_wb = -1;

	std_open();	/* open all the librarys, screens, etc. */

	xtweak = Flt(XTWEAK);
	ytweak = Flt(YTWEAK);

			/* This could've be #defined , but I did that */
			/* in the last program. Tempting fate... */
	PI = 3.14159265358979323846;
	n = 80;
	n1 = Flt(n);
	DEG = Div(PI,n1);

	rot = atof(rotbuf); /* use default values for initial plot */
	vx = atof(vxbuf);
	vy = atof(vybuf);
	SetBPen(rp, 0);
	SetAPen(rp,col);
	Move(rp,CX,CY+YTWEAK);
	idling = FALSE;

	GetSysTime(&t1);

/************************************************
 * 		Main Fuzzy Area			*
 ************************************************/

FOREVER 
  {
	if((message = (struct IntuiMessage *)GetMsg(w->UserPort)) != NULL)
	{
	class = message->Class;
	code  = message->Code;
	gad = message->IAddress;
	ReplyMsg(message);
	   switch (class)
	    {
             case CLOSEWINDOW:
		stage_left();		/* Anyone remember Snagglepuss? */
		break;
	     case GADGETDOWN:
	     case GADGETUP:
		gadgid = gad->GadgetID;
		if(class == GADGETUP)
	  	 switch (gadgid)
		 {
			case WHOA:
			   ny = YTWEAK;
			   GetSysTime(&t2);
			   showetime();
			   break;
			case GO:
			   rot = atof(rotbuf);
			   vx = atof(vxbuf);
			   vy = atof(vybuf);
			   SetRast(rp,0);
			   RefreshWindowFrame(w);
			   col = 1;
			   SetAPen(rp,col);
			   Move(rp,CX,CY+YTWEAK);
			   inc =0;
			   cnt = 0;
			   ny = 0;
			   GetSysTime(&t1);
			   idling = FALSE;
			   break;

			default:
			  break;
			}
	   default:
		break;
	    }

	}
	do_fuzzer();
  }
 stage_left();	/* main exit */
}	/* end of main */


	/*
	 * Here we are, all set to bang out fuzzy numbers & draw them in
	 * loud, garish colors. In interlace too, so that all you out 
	 * there without long persistance monitors (I've got one) get the
	 * added eyestrain of flickering teensy dots.
	 *  I've broken the math functions into individual calls stored
	 * in lots of variables to avoid extremely long lines of code.
	 * You may not like this approach. Bummer. I do.
	 */
do_fuzzer()
{
   if(ny < YTWEAK) {
	inc = Add(inc,rot);

	deginc = Mul(inc,DEG);		/* With Manx' mi libraries, we could */
	sintemp = Sin(deginc);		/* write these as normal equations   */
	costemp = Cos(deginc);		/* as in the file Fuz.c, but without */
	degvy = Mul(deginc,vy);		/* them, each operation must be      */
	costempvy = Cos(degvy);		/* specifically sent to the IEEE     */
	absvy = Abs(costempvy);		/* libraries.			     */
	vny = Mul(costemp,absvy);
	if(vx == 0) {
	   nx = Fix(Mul(sintemp,xtweak));
	} else {	
	   degvx = Mul(deginc,vx);	/* Look at the code in Fuz.c if you  */
	   sintempvx = Sin(degvx);	/* want to understand the basic math */
	   absvx = Abs(sintempvx);	/* that is being used here.  It's    */
	   vnx = Mul(sintemp,absvx);	/* much easier to read in the other  */
	   nx = Fix(Mul(vnx,xtweak));	/* format. */
	}
	ny = Fix(Mul(vny,ytweak));
	cnt ++;
	if(cnt >141) {
	   cnt = 0;
	   col++;
	   if(col == 15) col = 1;
	   SetAPen(rp,col);
	}
	Draw(rp,nx+CX,ny+CY);
	if(ny >= YTWEAK && !idling) {
	   GetSysTime(&t2);
	   showetime();
	}
   }  /* end if */
}     /* end of do_fuzzer() */

/*
 *	color values
 *		pen #	  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
 */
USHORT red[] =		{ 0, 13,11,12,13,13,14,15, 8, 4, 0, 0, 0, 0, 0, 4 };
USHORT green[] =	{ 0,  2, 3, 4, 5, 7, 9,13,11, 9, 6, 4, 2, 0, 5,10 };
USHORT blue[] =		{ 0,  2, 2, 2, 2, 1, 1, 0, 0, 0, 2, 7,10,14,15,15 };

struct TextAttr Topfont =
	{
	"topaz.font", TOPAZ_SIXTY,
	FSF_EXTENDED | FSF_ITALIC | FSF_BOLD,
	FPF_ROMFONT | FPF_PROPORTIONAL
	};
struct TextAttr Toyfont =
	{
	"topaz.font", TOPAZ_EIGHTY,
	FSF_EXTENDED,
	FPF_ROMFONT | FPF_PROPORTIONAL
	};
/*
 *	border line vectors
 */
USHORT gadvecs2[] =	{ 0,0,58,0,58,10,0,10,0,0 };
USHORT gadvecs3[] =	{ 0,0,84,0,84,12,0,12,0,0 };
USHORT timervec[] =	{0,0,200,0,200,11,0,11,0,0};

struct IntuiText timer_text =
	{ 7,0,JAM2,20,NS_HEIGHT-LINEOTYPE-13, &Toyfont, &timebuf, NULL };
struct Border timer_brdr =
	{ 5,NS_HEIGHT-LINEOTYPE-15, 1,0,JAM2, 5, timervec, NULL };

struct Border gad_brdr[NUMGADS] = 
{
	{ -2,-3, 15,0,JAM1, 5, gadvecs3, NULL },
	{ -2,-3, 13,0,JAM1, 5, gadvecs3, NULL },
	{ -2,-3, 11,0,JAM1, 5, gadvecs3, NULL },
	{ -2,-1,  5,0,JAM1, 5, gadvecs2, NULL },
	{ -2,-1, 10,0,JAM1, 5, gadvecs2, NULL }
};

struct IntuiText gad_txt[NUMGADS] =
{
	{ 7,0,JAM2,	28,-12, &Toyfont, "rot", NULL },
	{ 7,0,JAM2,	34,-12, &Toyfont, "vx", NULL },
	{ 7,0,JAM2,	34,-12, &Toyfont, "vy", NULL },
	{ 7,4,JAM2,	1,   0, &Topfont, "Whoa!", NULL },
	{ 7,9,JAM2,	1,   0, &Topfont, "Start", NULL }
};

struct StringInfo gad_info[NUMGADS-2] =
{ 
	{ rotbuf,  NULL, 0, 10, 0, 0,0,0,2,1, 0, NULL, NULL },
	{ vxbuf,   NULL, 0, 10, 0, 0,0,0,2,1, 0, NULL, NULL },
	{ vybuf,   NULL, 0, 10, 0, 0,0,0,2,1, 0, NULL, NULL }
};

struct Gadget toy_gad[NUMGADS] = 
{
	{		/*	rotation string gadget	*/
	NULL,
	GADL_EDGE,GADT_EDGE,
	80,10,
	GADGHCOMP,STRAFLAGS,STRGADGET,
	(APTR)&gad_brdr[0],NULL, &gad_txt[0],
	0, (APTR)&gad_info[0],
	ROT, NULL
	},
	{		/*	x-vector input gadget	*/
	&toy_gad[0],
	GADL_EDGE,GADT_EDGE+25,
	80,10,
	GADGHCOMP,STRAFLAGS,STRGADGET,
	(APTR)&gad_brdr[1],NULL, &gad_txt[1],
	0, (APTR)&gad_info[1],
	VX, NULL
	},
	{		/*	y-vector input gadget	*/
	&toy_gad[1],
	GADL_EDGE,GADT_EDGE+50,
	80,10,
	GADGHCOMP,STRAFLAGS,STRGADGET,
	(APTR)&gad_brdr[2],NULL, &gad_txt[2],
	0, (APTR)&gad_info[2],
	VY, NULL
	},
	{		/*	stop button	*/
	&toy_gad[2],
	GADL_EDGE+11,GADT_EDGE+65,
	58,9,
	GADGHCOMP, BOOLAFLAGS, BOOLGADGET,
	(APTR)&gad_brdr[3],NULL, &gad_txt[3],
	0, NULL,
	WHOA, NULL
	},
	{		/*	start button 	*/
	&toy_gad[3],
	GADL_EDGE+11,GADT_EDGE+80,
	58,9, 
	GADGHCOMP, BOOLAFLAGS, BOOLGADGET, 
	(APTR)&gad_brdr[4],NULL, &gad_txt[4],
	0, NULL, 
	GO, NULL
	}
};

struct NewScreen ns =
	{
	0, 0, NS_WIDTH, NS_HEIGHT,
	NS_PLANES, 0, 0,
	NS_MODE, NS_TYPE,
	&Toyfont,NULL, NULL
	};

struct NewWindow nw =
	{
	0, LINEOTYPE, NS_WIDTH, NS_HEIGHT-LINEOTYPE, 7, 0,
	NW_IDCMP,
	NW_FLAGS,
	&toy_gad[4], NULL,
	"               MicroBotics' Fuzzy Number Plotter, by Dmil",
	NULL, NULL, 0, 0, 0, 0, NS_TYPE
	};


std_open()
{
	register int i;

	if(!(IntuitionBase = (struct IntuitionBase *)
			OpenLibrary("intuition.library", 0)))
		errexit(" Can't open Intuition");

	mask |= INTUITION;

	if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0)))
		errexit(" Can't open Gfx lib");

	mask |= GRAPHICS;

	if(!(MathIeeeDoubBasBase = OpenLibrary("mathieeedoubbas.library",0)))
		errexit(" no basic ieee library\n");

	mask |= MIDB;

	if(!(MathIeeeDoubTransBase = OpenLibrary("mathieeedoubtrans.library",0)))
		errexit(" no transcendental ieee library\n");

	mask |= MIDT;

	if(!(screen = (struct Screen *)OpenScreen(&ns))) 
		errexit(" Can't open the screen");

	mask |= SCREEN;

	nw.Screen = screen;

	ShowTitle(screen,FALSE);	/* turn off the screen title bar */
	vp = &screen->ViewPort;
		
/*
 * install some loud garish color
 */
	for(i = 0; i < 16; i++)
		SetRGB4(vp,i,red[i],green[i],blue[i]);

	if(!(w = (struct Window *)OpenWindow(&nw)))
		errexit(" Can't open the window");

	mask |= WINDOW;

	rp = w->RPort;
}

errexit(str)
register UBYTE *str;
{
	if(!from_wb)		/* started from CLI, so it's safe to */
	  printf("%s\n",str);	/* printf the error message	*/

	stage_left();
}

stage_left()
{
/*
 *	use the masked flag bits to close what we opened
 */

	if (mask & WINDOW)
		CloseWindow(w);
	if (mask & SCREEN)
		CloseScreen(screen);
	if (mask & MIDT)
		CloseLibrary(MathIeeeDoubTransBase);
	if (mask & MIDB)
		CloseLibrary(MathIeeeDoubBasBase);
	if (mask & GRAPHICS)
		CloseLibrary(GfxBase);
	if (mask & INTUITION)
		CloseLibrary(IntuitionBase);
	exit();
}

showetime()
{
	if(!idling)
	   sprintf(timebuf,"%lu.%lu seconds"
		,t2.tv_secs-t1.tv_secs,t2.tv_micro-t1.tv_micro);
	   DrawBorder(rp,&timer_brdr,0L,0L);
	   PrintIText(rp,&timer_text,0L,0L);
	   idling = TRUE;
}

struct timerequest *PrepareTimer(precision)
SHORT precision;
{

	int error;
	SHORT whichunit;

	struct MsgPort *timerport;
	struct timerequest *timermsg;
	
        timerport = CreatePort(0,0);
        if (timerport == NULL) 
		return(NULL);	/* Error during CreatePort */

	timermsg = (struct timerequest *)CreateExtIO(
					timerport,sizeof(struct timerequest));
	if (timermsg == NULL)
		{
		DeletePort(timerport);
		return(NULL);	/* Error during CreateExtIO */
		}
	
	if(precision)	/* if true, use precision timer  ( under 1 second ) */
		whichunit = UNIT_MICROHZ;
	else
		whichunit = UNIT_VBLANK;

	error = OpenDevice(TIMERNAME, whichunit, timermsg, 0);
	if (error != 0)
		{
		DeleteExtIO(timermsg,sizeof(struct timerequest));
		DeletePort(timerport);
		return(NULL);	/* Error during OpenDevice */
		}
	return(timermsg);
}

int
GetSysTime(tv)
struct timeval *tv;
{
	struct timerequest *tr;
	tr = PrepareTimer(TRUE);	/* MUST use Precise timer for this */
	if(tr == 0) return(-1);		/* non zero return says error */
 
	tr->tr_node.io_Command = TR_GETSYSTIME;
	DoIO( tr );

	tv->tv_secs = tr->tr_time.tv_secs;
	tv->tv_micro = tr->tr_time.tv_micro;

	DeleteTimer(tr);
	return(0);

}

int
DeleteTimer(tr)
struct timerequest *tr;
{
	struct MsgPort *tp;

	tp = tr->tr_node.io_Message.mn_ReplyPort;
	if(tr != 0)
	{
		CloseDevice(tr);
		DeleteExtIO(tr,sizeof(struct timerequest));
	}
	if(tp != 0)
		DeletePort(tp);
	return(0);		
}
