/*   Graph.c (ProjMot)                       *
*    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        *  Libraries Used
*         This Program plots the path        *  ~~~~~~~~~~~~~~~~~
*         of a projectyle fired at           *  req.library
*         origon o, with velocity v          *  intuition.library
*         and angle Ø (theta),               *  graphics.library
*         with constant acceleration         *  mathffp.library
*         g (-9.8 m/s^2).                    *  mathtrans.library
*                                            *
*    © Copyright 1991 Christian E. Hopps
*/


/* Functions                                 * Global Variables
 * ~~~~~~~~~~~~~~~~~~~~~~~~                  * ~~~~~~~~~~~~~~~~~~
 * GLibLoad()                                * IntuitionBase
 * GLibUnload()                              * GfxBase
 * Gcalc()                                   * ReqBase
 * Fire()                                    * MathBase
 * HandleIDCMP()                             * MathTransBase
 * ReClip()                                  * Scr
 * VectorComponents();                       * Win
 * GetTime()                                 * RP
 *                                           *
*/
#include <stdio.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <proto/req.h>
#include <libraries/reqbase.h>
#include <exec/memory.h>
#include <libraries/mathffp.h>
#include "window.h"
#include "ggads.h"
#define SIGNALW  (1L << Win->UserPort->mp_SigBit)
#define SIGNALG  (1L << Gwin->UserPort->mp_SigBit)
#define CLIPx1 xy->clip->clipx1
#define CLIPy1 xy->clip->clipy1
#define CLIPx2 xy->clip->clipx2
#define CLIPy2 xy->clip->clipy2

	
extern int GLibLoad();
extern void GLibUnload();
extern int HandleIDCMP();
extern void Gcalc();
extern void Fire();
void ReClip();
struct Window *OpenWindow();
float GetTime();
void VectorComponents();

struct IntuitionBase     *IntuitionBase;     /* These libraries will be */
struct GfxBase           *GfxBase;           /* initialized by the */
struct ReqLib            *ReqBase;           /* external programg libload.o */
struct MathBase          *MathBase;
struct MathTransBase     *MathTransBase;

struct Window            *Win;               /* Window Pointer */
struct Window            *Gwin;              /* Win Pntr to Gads */
struct Screen            *Scr;               /* Screen Pointer */
struct RPort             *RP;                /* RastPort Pointer */

struct Clip                                  /* Clipping info */
{
     short clipx1;
     short clipy1;
     short clipx2;
     short clipy2;
};

struct XY                                    /* everything else info */
{
	float voy;
	float vox;
	float x;
	float y;
	short xp;
	short yp;
	BOOL clipped;
	int scale;
	struct Clip *clip;
};
char text[] = "\nThe projectile made it %ldm.  \nIt took %ld seconds.\n";

main()
{
	struct IntuiMessage *msg;
	struct XY *xy;
	struct Clip *c;
	struct GetLongStruct *GetLongStructVel, *GetLongStructAngle;
	ULONG signal, sec, micro, timeo, acctime;
	USHORT adone = FALSE;
	int success,angle_i,vel_i, class;
	float time;
	BOOL timeisacc;

     /* Open Up Everything and Allocate Memory */

	if(!(GLibLoad()))
	{
		printf("\nLibraries could not open\n");
		printf("Make sure req.library is in LIBS:\n");	
		GLibUnload();
		exit(20);
	}
	if(!(Scr = (struct Screen *)AllocMem(sizeof(struct Screen),MEMF_PUBLIC | MEMF_CLEAR)))
	{	
		printf("\ncould not allocatemem for screen\n");
		goto exit1;
	}
	if(!(xy = (struct XY *)AllocMem(sizeof(struct XY),MEMF_PUBLIC | MEMF_CLEAR)))
		{	
			printf("\ncould not allocatemem for xy\n");
			goto exit1;
		}
	if(!(c = (struct Clip *)AllocMem(sizeof(struct Clip),MEMF_PUBLIC | MEMF_CLEAR)))
		{	
			printf("\ncould not allocatemem for clip\n");
			goto exit1;
		}

	/* 	Set up clip areas based on window size at start also modify 
		NewWindowStructure1 to make window as large as screen. */

	xy->clip = c;
	GetScreenData( Scr, sizeof(struct Screen), WBENCHSCREEN, NULL );
	CLIPx2 = (NewWindowStructure1.Width = Scr->Width) - 40;
	CLIPy2 = (NewWindowStructure1.Height = Scr->Height) - 20;
	CLIPx1 = 10;
	CLIPy1 = 10;

	if(!(Win = OpenWindow(&NewWindowStructure1)))
	{
		printf("\nCould not open window\n");
		GLibUnload();
	}

	if(!(Gwin = OpenWindow(&NewWindowStructure2)))
	{
		printf("\nCould not open window\n");
		CloseWindow(Win);
		GLibUnload();
	}
	if((success = (int)AddGList(Gwin, &Gadget1, -1, -1 ,NULL)) == -1)
		goto exit;
	RefreshGList(&Gadget1, Gwin, NULL, -1);
	if(!(GetLongStructVel = (struct GetLongStruct *)AllocMem(sizeof(struct GetLongStruct),MEMF_PUBLIC | MEMF_CLEAR)))
		{
			printf("\ncould not get memory for req.struct\n");
			goto exit1;
		}
	if(!(GetLongStructAngle = (struct GetLongStruct *)AllocMem(sizeof(struct GetLongStruct),MEMF_PUBLIC | MEMF_CLEAR)))
		{
			printf("\ncould not get memory for req.struct\n");
			goto exit1;
		}


	RP = Win->RPort;                             /* Init some var. */
	vel_i=50; 
	angle_i=45; 
	xy->clipped = 0;
	SetDrMd(RP,JAM1);
	class = 0;
	xy->xp = CLIPx1;
	xy->yp = CLIPy2;
	SetAPen(RP,1);
	acctime = 1;
	timeisacc = FALSE;
	xy->scale = 1;
/* Main Loop */
/* if close gadget is clicked then adone will be set to true */

	while(!(adone))
	{
		Move(RP,CLIPx1,CLIPy2); 				/* Move to modified origin */
		if(acctime != 1) timeisacc = TRUE; 
		signal = Wait(SIGNALW | SIGNALG);

		if(signal & SIGNALG)                     /* Gadget Window has rec. */
		{                                        /* a message can only be  */
			success = HandleIDCMP((int)1,Gwin); /* a GADGETUP */
			switch(success)
			{
				case 5:                        /* velocity */
					GetLongStructVel->titlebar = "Initial Velocity(m/s)";
					GetLongStructVel->defaultval = vel_i;
					GetLongStructVel->minlimit = 0;
					GetLongStructVel->maxlimit = 100000;
					GetLongStructVel->versionnumber = REQVERSION;

					if(vel_i = GetLong(GetLongStructVel))
						if(!(vel_i = GetLongStructVel->result))
							vel_i = 50;
					break;

				case 1:                        /* angle */
 					GetLongStructAngle->titlebar = "Ø (theta)";
					GetLongStructAngle->defaultval = angle_i;
					GetLongStructAngle->minlimit = 0;
					GetLongStructAngle->maxlimit = 90;
					GetLongStructAngle->versionnumber = REQVERSION;
					if(angle_i = GetLong(GetLongStructAngle))
						if(!(angle_i = GetLongStructAngle->result))
							angle_i = 45;
					break;

				case 3:                        /* Fire! */
					WindowToBack(Gwin);
					VectorComponents(xy,angle_i,vel_i);
					CurrentTime(&timeo,&micro); 

				/*   Now we go into the secondary loop, draw motion path.*/
				/*   if left mouse button clicked, close gadget clicked, */
				/*   size is changed, or function is done, END           */

					while(SPFix(xy->y) >= 0  & 
						(!(msg = (struct IntuiMessage *)
								GetMsg(Win->UserPort))))
					{
						time = GetTime(timeo);
						if(timeisacc) 
							time = SPMul(time,SPFlt(acctime));
						Gcalc(time,xy);
						Fire(xy, RP);
					}                        /* Done with plot */

					if(msg)                  /* This is to check    */
					{                        /* if Newsize was rec. */
						class = msg->Class;	/* if so bypass handle */
						ReplyMsg(msg);      /* function and do it  */
						if(class == NEWSIZE)/* right here otherwise*/
						{                   /* forget message      */
							ReClip(Win,xy);
							SetRast(RP,0);
						}
					}
					CurrentTime(&sec,&micro);
					xy->y =SPFlt(1);         /* init y so it can pass */
					Move(RP,CLIPx1,CLIPy2);  /* while condition next  */
					xy->clipped = 0;         /* time;  reset origin   */
					SimpleRequest(&text,(SPFix(xy->x)*xy->scale),(acctime*(sec-timeo)));
					WindowToFront(Gwin);     /* and send a text req.  */
					break;
				case 6:                  /* Clear */
					SetRast(RP,0);
					break;
				case 2:                  /* Scale */
					GetLongStructVel->titlebar = "Scale (# of m/pixel)";
					GetLongStructVel->defaultval = xy->scale;
					GetLongStructVel->minlimit = 1;
					GetLongStructVel->maxlimit = 10000;
					GetLongStructVel->versionnumber = REQVERSION;
					xy->scale = GetLong(GetLongStructVel);
					xy->scale = GetLongStructVel->result;
					if(xy->scale == 0) 
						xy->scale = 1;
					SetRast(RP,0);
					break;
				case 4:                  /* Acc. Time */
					GetLongStructVel->titlebar = "Time Acceleration";
					GetLongStructVel->defaultval = acctime;
					GetLongStructVel->minlimit = 1;
					GetLongStructVel->maxlimit = 100;
					GetLongStructVel->versionnumber = REQVERSION;
					acctime = GetLong(GetLongStructVel);
					acctime = GetLongStructVel->result;
					if(acctime == 0) 
						acctime = 1;
					timeisacc = TRUE;
					
					break;
				default:
					break;
			}
		}
		if(signal & SIGNALW)                    /* Handle message from */ 
		{                                       /* the main window     */
			success = HandleIDCMP((int)0,Win);
			switch(success)
			{
				case 0:
					adone = TRUE;
					break;
				case 5:
					SetRast(RP,0);
					ReClip(Win,xy);
					break;
				case 2:
					adone = FALSE;
					break;
				defualt:
					break;
			}
		}
	}


exit1:


	if(GetLongStructAngle) 
		FreeMem(GetLongStructAngle, sizeof(struct GetLongStruct));
	if(GetLongStructVel) 
		FreeMem(GetLongStructVel, sizeof(struct GetLongStruct));
	success = RemoveGList(Gwin, &Gadget1,-1);
exit:
	if(Gwin) CloseWindow(Gwin);
	if(Win) CloseWindow(Win);	
	if(Scr) FreeMem(Scr, sizeof(struct Screen));
	if(xy)  FreeMem(xy, sizeof(struct XY)); 
	if(c) FreeMem(c,sizeof(struct Clip));
	GLibUnload();
/* All Done */
}


void ReClip(Win,xy)                               /* Set up new clip values */
struct XY *xy;
struct Window *Win;
{

	CLIPx2 = Win->Width - 40;
	CLIPy2 = Win->Height - 30;
}

void VectorComponents(xy,angle_i,vel_i)           /* Break Vector in comp.  */
struct XY *xy;
int angle_i, vel_i;
{
	float vel,cosx,siny,rangle,angle;
	vel = SPDiv(SPFlt(xy->scale),SPFlt(vel_i));
	angle = SPFlt(angle_i); /* change angle to flt */

		/* Compute Radian Conversion                        */
		/* NOTE!! there is multiple errors in commodore's	  */
		/* Libraries and devices, they incorectly state that*/
		/* the mathtrans functions are like so:             */
		/* f1 = SPDiv(f2,f3) => (f1 = f2 / f3)              */
		/* when in reality the function is equal  to:       */
		/* f1 = f3 / f2; It took a week to find that bug!:-)*/
		/* this is also true for SPSub, and I have an itchy */
		/* feeling for the rest of the functions as well,   */
		/* it doesn't realy matter for the comunitive       */
		/* functions though.                                */

	rangle = SPDiv(SPFlt((int)180), SPMul(PI,angle));
	siny = SPSin(rangle);
	cosx = SPCos(rangle);
	xy->vox = SPMul(vel , cosx); /* calc init. x vel.*/
	xy->voy = SPMul(vel , siny); /* calc inti. y vel.*/
}

float GetTime(timeo)                           /* Get the time in sec.micro */
long timeo;                                    /* return a float value      */
{
	int sec,micro;
	float m,time;

	CurrentTime(&sec,&micro);
	m = SPDiv(SPFlt(1000000),SPFlt(micro));
	time = SPAdd(SPFlt(sec - timeo), m);
	return(time);
}