/*	sMOVIE.c	by:-	Martin J. Round.
						17 Naseby Drive,
						Halesowen,
						West Mids.
						B63 1HJ
						England.
						
						Tel: (voice) 021-550-0014
						
						or contact me (Martin Round)
						on the Plug 'Ole BB:  021-472-0256
						
						16-Oct-89
*/

#include "sMOVIE.h"

/*	Declarations for CBACK	*/
extern BPTR _Backstdout;		/*	std output when run in background	*/
long _BackGroundIO = 1;			/*	Flag to tell it we want to do I/O	*/
long _stack = 4000;				/*	Amount of stack space task needs	*/
char *_procname = "sMOVIE";		/*	The name of the task to create		*/
long _priority = 1;				/*	The priority to run us at			*/

struct NewWindow HelloWindow = {

	220,85,200,30, 		/* position and size						*/
	2,3,  				/* pens 									*/
	NULL,				/* IDCMPFlags								*/
	ACTIVATE |
	NOCAREREFRESH,		/* flags									*/
	NULL,				/* no special gadgets						*/
	NULL,				/* no special checkmark 					*/
	"  sMOVIE",
	NULL,				/* pointer to screen						*/
	NULL,				/* no bitmap								*/
	0,0,				/* minimum sizes							*/
	200,30, 			/* maximum sizes							*/
	WBENCHSCREEN,		/* type of screen							*/
	};

struct Window *window, *OpenWindow();

/*	If priority is the standard 0 then when run from the CLI, the command
	line prompt is put up before we can output our banner.
	This looks messy - hence priority of 1.
*/

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

struct DosLibrary *DosBase;
struct Library *DiskfontBase;

struct TextFont *tf[MAXFONTS+1], *font, *defaultfont;

struct TextAttr ta;

struct View *oldview;	/* for saving the original view.		*/
struct View v;
struct RasInfo ri;
struct ViewPort vp;
struct BitMap b;
struct RastPort rp; 	/* the stuctures for the view to be created */

extern struct ColorMap *GetColorMap();

extern void argread (int, char **, int);

extern void smoothtext (char *, short, short, BYTE, BYTE, struct TextFont *);

extern void smoothlines (short, short, short, BYTE, BYTE,);

extern int mousemonitor (void);

extern int initmousemonitor (void);

extern void removemousemonitor (void);

extern void message (UBYTE *);

extern void print (char *);

extern int Min (int, int);

extern void free_memory (int);

extern void on_sprite (void);

extern void off_sprite (void);

void resize (short,short,short,short,short);

char *txptr, *txstart,fontname[MAXFONTS][MAXFONTNAMELENGTH];

char line[MAXLINE + 1],buff[MAXLINE * 2];

int pointsize[MAXFONTS],fonts,textsiz,cmdsiz,maxfontheight,bitmapheight;

int height,width,maxheight,maxwidth,maxdepth,centring,ind,tab,ypos,delay;

int no_text_or_lines,normal;

BYTE apen,bpen;

short *cmdptr,*cmdstart;

char esc;

/*	following stuff is needed by mousemonitor()	*/

int abort_prog;

extern MOUSE_INFO mouseinfo;

/*	following stuff so we can work from CLI or WorkBench	*/

int runningfromcli;

#define MAXARGS 32

void _main(cmd)  /*	Using _main() and cback.o avoids the stupid console
					window opening when we are run from the Workbench	*/
char *cmd;

{
	int argc = 0;
	char *argv[MAXARGS];

	int i,j;
	short spacing;

	/*	This code fragment gets argc and argv as if from main()		*/
	if (cmd && *cmd) {
		argv[argc] = strtok(cmd,", \n");
		while(argv[argc])
			argv[++argc] = strtok(NULL,", \n");
		}

	runningfromcli = (argc == 0 ? 0 : 1);
	
	window = NULL;

	if (runningfromcli) {	/*	Output my banner.	*/
		print("\n\2330;33msMOVIE 1.0\2330m  by\t\2331mMartin Round.\2330m\n");
		print("\t\t17, Naseby Drive, Halesowen, West Mids.\n");
		print("\t\tB63 1HJ  England.  Contact me through\n");
		print("\t\tthe Plug 'Ole B.B.  (021-472-0256).\n\n");
		}
	
	
	if((IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library",0)) == NULL) {
			exit(0L);
			}

	if ((DosBase = (struct DosLibrary *)
		OpenLibrary("dos.library",0)) == NULL) {
			message("Couldn't open dos.library'.");
			free_memory(1);
			exit(0L);
			}

	if ((GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library",0)) == NULL) {
			message("Couldn't open graphics.library'.");
			free_memory(2);
			exit(0L);
			}

	if (!runningfromcli) {	/*	Give Workbenchers something to see.	*/
		if ((window = OpenWindow(&HelloWindow)) == NULL) {
			message("Couldn't open Window.");
			free_memory(3);
			exit(0);
			}

		SetAPen(window->RPort,3);
		SetDrMd(window->RPort,JAM1);
		RectFill(window->RPort,2,11,197,28);
		SetAPen(window->RPort,2);
		Move(window->RPort,35,23);
		Text(window->RPort,"Patience...",11);
		}

	/*  open default font	*/
	ta.ta_Style = 0;
	ta.ta_Flags = FPF_ROMFONT;
	ta.ta_Name = DEFAULTFONTNAME;
	ta.ta_YSize = DEFAULTFONTHEIGHT;

	if ((defaultfont = (struct TextFont *) OpenFont(&ta)) == NULL) {
		message("Couldn't open default font.");
		free_memory(3);
		exit(0L);
		}

	tf[0] = defaultfont;
	
	fonts = textsiz = cmdsiz = 0;

	height = maxheight = 0;

	maxdepth = 1;

	maxwidth = 0;
	
	/*  need this in case user tries to centre without first sizing	*/
	width = GfxBase->NormalDisplayColumns;
	
	centring = 0;

	tab = DEFAULTTABSIZE;
	
	ind = 0;

	font = defaultfont;

	maxfontheight = defaultfont->tf_YSize;

	esc = DEFAULT_ESC_CHAR;	/*	set defaults before 1st pass		*/
	
	no_text_or_lines = 1;	/*	this gets cleared if any are found	*/
	
	argread(argc, argv, 0);		/*	read file(s) for 1st time		*/
	
	if (runningfromcli) {
		if (fonts) {
			print("FONTS REQUIRED:-\n");
			for(i=0; i<fonts; i++) {
				sprintf(buff,"%2d:%16s %d\n",
					i+1, fontname[i], pointsize[i]);
				print(buff);
				}
			print ("\n");
			}
		}
		
	if (fonts) {
		if((DiskfontBase = (struct Library *)
			OpenLibrary("diskfont.library",0)) == NULL) {
				message("Couldn't open 'diskfont.library'.");
				free_memory(4);
				exit(0L);
				}
		}
	else
		DiskfontBase = NULL;

	ta.ta_Style = 0;
	ta.ta_Flags = FPF_ROMFONT | FPF_DISKFONT;

	for (i=0; i<fonts; i++) {
		strcpy(line,fontname[i]);
		strcat(line,".font");
		ta.ta_Name = line;
		ta.ta_YSize = pointsize[i];

		if ((tf[i] = (struct TextFont *)OpenDiskFont(&ta)) == NULL) {
			sprintf(buff,"Can't open Font: %20s %2d  Using default.",
				ta.ta_Name, ta.ta_YSize);	
			message(buff);
			tf[i] = defaultfont;
			}

		if (tf[i]->tf_YSize > maxfontheight)
			maxfontheight = tf[i]->tf_YSize;

		}

	if (no_text_or_lines) {
		message("Nothing to display!");
		free_memory(5);
		exit(0L);
		}

	if (textsiz == 0)
		textsiz = 1;	/*  this kludge allows scripts without text
							to be run (otherwise getmem returns NULL)	*/

	if ((txstart = getmem(textsiz)) == NULL) {
		message("Couldn't get memory for text.");
		free_memory(5);
		exit(0L);
		}

	if ((cmdstart =
		(short *)getmem(cmdsiz * sizeof(short))) == NULL) {
		message("Couldn't get memory for commands.");
		free_memory(6);
		exit(0L);
		}

	/*	get a rastport for centring up text	*/
	InitBitMap(&b,1,640,50);
	b.Planes[0] = (PLANEPTR)AllocRaster(640,50);
	if(b.Planes[0] == NULL) {
		message("Couldn't get centring bitmap.");
		free_memory(7);
		exit(0L);
		}
	InitRastPort(&rp);
	rp.BitMap = &b;

	/*  pass 2  */

	centring = 0;

	tab = DEFAULTTABSIZE;
	
	ind = 0;

	font = defaultfont;

	esc = DEFAULT_ESC_CHAR;	/*	reset defaults before 2nd pass	*/

	cmdptr = cmdstart;
	txptr = txstart;

	argread(argc, argv, 1);		/*	read file(s) a 2nd (and final) time	*/

	FreeRaster(b.Planes[0],640,50);
	
	if(!runningfromcli)
		CloseWindow(window);
		
	window = NULL;

/*
{
	short *p;
	int i;
	for (p=cmdstart,i=0; i<cmdsiz; i++) {
		sprintf(buff,"%4d",(int) *p++);
		print(buff);
		}
		
}
*/
	if (maxheight < MIN_HEIGHT)
		maxheight = GfxBase->NormalDisplayRows;

	if (maxwidth < MIN_WIDTH)
		maxwidth = GfxBase->NormalDisplayColumns;

	bitmapheight = 2 * maxheight + 3 * (maxfontheight - 1) + 6;

	oldview = GfxBase->ActiView; /* save current view to restore later */

	InitView(&v);		/* initialize view */
	InitVPort(&vp); 	/* initialise view port */
	v.ViewPort = &vp;	/* link view into viewport */

	/* init bit maps (for rasinfo ) */
	InitBitMap(&b,maxdepth,maxwidth,bitmapheight);

	/* init RasInfo */
	ri.BitMap = &b;
	ri.RxOffset = 0;	
	ri.RyOffset = 0;
	ri.Next = NULL;

	/* init ViewPort */
	vp.DWidth = Min(GfxBase->NormalDisplayColumns,maxwidth);
	vp.DHeight = Min(GfxBase->NormalDisplayRows,maxheight);
	vp.RasInfo = &ri;
	vp.Modes = HIRES;
	if((vp.ColorMap = GetColorMap(2 << maxdepth)) == NULL) {
		message("Couldn't get memory for ColourMap.");
		free_memory(8);
		exit(0L);
		}

	/* allocate space for bitmap */
	for(i=0; i<maxdepth; i++) {
		b.Planes[i] = (PLANEPTR)AllocRaster(maxwidth,bitmapheight);
		if(b.Planes[i] == NULL) {
			message("Couldn't get memory for bitmap.");
			maxdepth = i;
			free_memory(10);
			exit(0L);
			}
		}

	/* open a RastPort to alow use of text and drawing routines */
	InitRastPort(&rp);
	rp.BitMap = &b;

	SetRast(&rp,0); /* clear the bitmap */
	
	if (initmousemonitor()) {
		message("Couldn't initialise mouse monitor.");
		free_memory(10);
		exit(0L);
		}
		
	abort_prog = 0;

	width = vp.DWidth;
	height = vp.DHeight;
	txptr = txstart;
	cmdptr = cmdstart;
	ypos = height + 6;
	apen = 1;
	bpen = 0;
	SetRGB4(&vp,0,DEFAULTBACKGROUNDCOLOUR);
	SetRGB4(&vp,1,DEFAULTPENCOLOUR);
	font = defaultfont;
	delay = DEFAULTDELAY;
	spacing = DEFAULTSPACING;
	normal = 1;					/*	causes 'press mouse button' message	*/

	SetTaskPri(FindTask(NULL),21);	/*	now run at high priority		*/
	
	WaitTOF();
	
	off_sprite();	/*	kill intuition cursor	*/

	while (!abort_prog && cmdptr - cmdstart < cmdsiz) {
		switch (*cmdptr++) {

			case 1: 	/*  text			*/
				smoothtext(txptr,*cmdptr++,*cmdptr++,apen,bpen,font);
				smoothlines(spacing,0,0,bpen,bpen);
				txptr += *(cmdptr-2);
				continue;

			case 2: 	/*  lines			*/
				smoothlines(*cmdptr++,*cmdptr++,*cmdptr++,apen,bpen);
				continue;

			case 3: 	/*  pen colours 	*/
				apen = *cmdptr++;
				bpen = *cmdptr++;
				break;

			case 4: 	/*  change font 	*/
				font = tf[*cmdptr++];
				break;

			case 5: 	/*  delay			*/
				for (j=0; j< *cmdptr; j++) {
					if (abort_prog = mousemonitor()) break;
					WaitTOF();
					}
				++cmdptr;
				continue;

			case 6: 	/*  scroll speed	*/
				delay = *cmdptr++;
				if (delay)
					SetTaskPri(FindTask(NULL),21);
				else
					SetTaskPri(FindTask(NULL),20);

				break;

			case 7: 	/*  clr 			*/
				SetRast(&rp,bpen);
				ri.RyOffset = 0;
				ypos = height + 6;
				MakeVPort(&v, v.ViewPort);
				MrgCop(&v);
				LoadView(&v);
				break;

			case 9: 	/*  change spacing  */
				spacing = *cmdptr++;
				break;

			case 10:	/*  change pallette */
				WaitBOVP(&vp);
				SetRGB4(&vp,*cmdptr++,*cmdptr++,*cmdptr++,*cmdptr++);
				break;

			case 11:	/*	change size		*/
				vp.Modes = 0;
				if (*cmdptr++)
					vp.Modes = HIRES;

				resize
					(*cmdptr++,*cmdptr++,*cmdptr++,*cmdptr++,*cmdptr++);

				break;

			case 12:	/*	smooth sizing  	*/
				{
				short ow,oh,ox,oy,oxo,w,h,x,y,xo;
				
				int delay;
				
				register int i,steps,old;
				
				ow = vp.DWidth;
				oh = vp.DHeight;
				ox = vp.DxOffset;
				oy = vp.DyOffset;
				oxo = ri.RxOffset;
				
				steps = *cmdptr++;
				delay = *cmdptr++;
				w = *cmdptr++;
				h = *cmdptr++;
				x = *cmdptr++;
				y = *cmdptr++;
				xo = *cmdptr++;
				
				for (i=1; i<=steps; i++) {
					old = steps-i;
					resize(	(short) ((ow  * old + w  * i)/steps),
							(short) ((oh  * old + h  * i)/steps),
							(short) ((ox  * old + x  * i)/steps),
							(short) ((oy  * old + y  * i)/steps),
							(short) ((oxo * old + xo * i)/steps) );
					if (abort_prog = mousemonitor()) break;
					for (j=0; j< delay; j++) {
						if (abort_prog = mousemonitor()) break;
						WaitTOF();
						}
					}
				}
				
				break;

			case 13:	/*	default sizes	*/
				vp.Modes = HIRES;
				resize(
					GfxBase->NormalDisplayColumns,GfxBase->NormalDisplayRows,
					0,0,0);
					
				break;
			
			case 14:	/*	restart			*/
				txptr = txstart;
				cmdptr = cmdstart;
				
				continue;

			default:
				sprintf(buff,"Error %d\n",*(cmdptr-1));
				print(buff);
				mouseinfo.button = -1;	/*	force abort	*/
				break;

			}	/*  switch  */
			
		abort_prog = mousemonitor();
		
		}	/*while */

	if (!abort_prog  && normal) {
		delay = 0;
		smoothlines(2,0,0,0,0);
		smoothlines(2,0,0,1,1);
		smoothlines(2,0,0,0,0);
		smoothtext("Press either Mouse button.",26,0,1,0,defaultfont);
		smoothlines(5,0,0,0,0);
		for(j=0; j<50; j++)
			WaitTOF();
		mouseinfo.button = 0;	/*	stops accidental pausing at end	*/
		while (!mouseinfo.button)
			WaitTOF();
		}

	SetTaskPri(FindTask(NULL),0);	/*	give other tasks a chance!		*/
	
	on_sprite();				/*	come back pointer - we need you!	*/

	LoadView(oldview);  		/* put back the old view				*/
	
	removemousemonitor();

	free_memory(10);
	
	exit(0L);

}	/*  end of main */

void resize(w,h,x,y,xo)

short w;	/*	width	*/
short h;	/*	height	*/
short x;	/*	x posn of view on screen	*/
short y;	/*	y posn of view on screen	*/
short xo;	/*	x offset into bitmap for view	*/
{
	vp.DWidth = width = w;

	height = h;

	if (vp.DHeight >= height)	/*	getting smaller	or same	*/
		ypos -= (vp.DHeight - height);

	else if (ri.RyOffset >= (height - vp.DHeight))
		ri.RyOffset = ri.RyOffset - height + vp.DHeight;

	else {	/*	must clear	*/
		ypos = height + 6;
		ri.RyOffset = 0;
		SetRast(&rp,bpen);
		}

	vp.DHeight = height;
	vp.DxOffset = x;
	vp.DyOffset = y;				/*  *****NOTE*****  */
									/*  Value in range  */
									/*  11 - 48 causes  */
									/*  \F/L\I/C\K/E\R  */
									/*  	WHY???  	*/

	ri.RxOffset = xo;
	MakeVPort(&v, v.ViewPort);
	MrgCop(&v);
	WaitTOF();
	LoadView(&v);
	normal=1;
	if (ri.RxOffset || width < 250 ) normal=0;
}
