/* MPMorph - Amiga Morphing program */
/* Copyright (C) © 1993-97 Mark John Paddock */

/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* any later version. */

/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
/* GNU General Public License for more details. */

/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

/* mpaddock@cix.compulink.co.uk */

#include "Render.h"

#ifndef __MPCLI
#include "a/Render.h"
#endif

void __regargs FindPoint(struct MyPoint *RetPoint,BOOL Everything,WORD x,WORD y);
static int   *IntVect(int ncols);
static void  MyFreeVecti(int *vectptr);
static int   **IntMatrix(int nrows,int ncols);
static void  FreeMatrixi(int **matptr);
static double **DoubleMatrix(int nrows,int ncols);
static void  FreeMatrixd(double **matptr);

#ifndef __MPCLI
extern struct Library *EGSIntuiBase	= NULL;
extern struct Library *EGSGfxBase	= NULL;
extern struct Library *EGSBase		= NULL;

/* Help nodes */
extern STRPTR context[] = {
	"Req-Progress",
	"Err-LibraryR",
	"Err-AllocVec",
	"Err-OpenPoints",
	"Err-Progress",
	"Err-FileFormat",
	"Err-Range",
	"Err-MemPointsR",
	"Err-CloseFile",
	"Err-3Points",
	"Err-OpenFile",
	"Err-ARexx",
	"Req-Really_quit",
	"Err-OldFormat",
	"Err-RLoadImage",
	"Err-RSaveImage",
	"Err-RScaleImage",
};

/* Libraries */
struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;
struct Library *LayersBase=NULL;
struct Library *GadToolsBase=NULL;
struct Library *AslBase=NULL;
struct UtilityBase *UtilityBase=NULL;
struct Library *RexxSysBase=NULL;
struct Library *AmigaGuideBase=NULL;
struct Device *TimerBase=NULL;
struct ReqToolsBase *ReqToolsBase=NULL;
struct Library *IconBase=NULL;
struct Library *DiskfontBase=NULL;

extern struct Library *MPImageBase=NULL;

extern struct List InfoList={0}; /* List of messages */

/* Help stuff */
extern AMIGAGUIDECONTEXT handle = {NULL};
extern struct NewAmigaGuide nag = {NULL};
extern ULONG ASig = 0;
#endif

/* Version string for CLI version */
#ifdef __MPCLI
extern const char Version[] = "$VER: MPRender_cli"
#else
#ifdef MY040
extern const char Version[] = "$VER: MPRender_040"
#else
#ifdef _M68060
extern const char Version[] = "$VER: MPRender_060"
#else
#ifdef _M68881
extern const char Version[] = "$VER: MPRender_881"
#else
#ifdef _M68020
extern const char Version[] = "$VER: MPRender_020"
#else
extern const char Version[] = "$VER: MPRender_000"
#endif
#endif
#endif
#endif
#endif
" 4.8 (18.3.97)";

extern BOOL Pic1_Open = FALSE;				/* 1st image open OK */
extern BOOL Pic2_Open = FALSE;				/* 2nd image open OK */

#ifndef __MPCLI
extern struct MsgPort		*WMsgPortp=NULL;		/* Message port for Picture Windows */

extern struct EI_NewWindow	EGS_NewWindow = {0};	/* EGS New window */
extern struct EI_Window		*EGS_Win=NULL;			/* EGS Window */
extern struct E_EBitMap		*EGS_BitMap=NULL;

extern void *Chain = NULL;

extern struct RexxHost *myhost = NULL;
#endif

/* some work buffers */
extern char buffer[256]="";
extern char buffer1[512]="";

extern struct Picture Pic1={0},Pic2={0};/* 1st and 2nd image */

/* List of points */
extern struct List			PointList = {0};

/* Size of image */
extern USHORT	width=0, height=0;

extern char AnimName[256]="";	/* Buffer for file name to save */

extern char *Loadscript=NULL;		/* ARexx load script */

extern struct MyPoint **Points = NULL;	/* Pointer to points */
extern struct MyPoint **PointsAlloc = NULL;	/* The actual allocated pointer */
extern struct MyPoint **PointsX = NULL;	/* Pointer to points horizontal */
extern struct MyPoint **PointsY = NULL;	/* Pointer to points vertical */

extern WORD	Depth=0;	/* Number of points to check each time */

extern UWORD Mode=0;		/* Mode = 0 use 3 closest if no others, choose 1st 3 */
					/* Mode = 1 leave points stationary, choose 1st 3 */
					/* Mode = 2 Only calculate points once */
					/* Mode = 4 choose 3 closet, always use */
					/* Mode = 8 Delaunay Triangle algorithm */
					/* Mode = 16 Binary search - NOT IN THIS VERSION */

extern LONG PointCount = 0;			/* Number of points */

extern struct MyPoint BigPoint={0};	/* Point far away */

extern char MyFileName[257]="";

/* Settings stuff */
extern char **ArgArray=NULL;
extern char **ArgArraySettings=NULL;

extern BOOL				AntiAlias=FALSE;	/* AntiAlias points */

/* Table of parameters */
extern struct Arexx Arexx = {0};

extern char 				FileName[256]="";	/* File name buffer */
extern UBYTE 				*arrayr=NULL,		/* Pointers to red,green and blue */
		  						*arrayg=NULL,
		  						*arrayb=NULL;
extern BOOL					EGS=FALSE;			/* EGS Preview */
extern UBYTE		*p[3] = {NULL,NULL,NULL};/* chunky pointers - order for OpalVision */
extern BOOL					CreateIcons=FALSE;/* Create Icons on pictures? */

extern char 					*Postscript=NULL;/* ARexx postscript */
BOOL					Integer = FALSE;

extern char *SaveFormat="ILBM24";
extern char *ModeName = NULL;
extern char *palette = NULL;
extern ULONG Colours = 16;
extern BOOL Bit12 = FALSE;
extern BOOL QuickGrey = TRUE;
extern BOOL ForceGrey = FALSE;
extern BOOL Grey = FALSE;
extern BOOL NoProgress = FALSE;
extern struct Hook *PProgressHook = NULL;

/* Close an image clearing everything down	*/
void
Close24bit(struct Picture *pic) {
	if (pic) {
		if (pic->MPi) {
			FreeMPImage(pic->MPi);
			pic->MPi = NULL;
		}
	}
}

/* Delete all the points from the list	*/
void
DeleteAllPoints(void) {
	struct MyPoint *MyPoint;
	/* Loops looking at the head every time and deletes it */
	while ((MyPoint =(struct MyPoint *)PointList.lh_Head)->MyNode.mln_Succ) {
		Remove((struct Node *)MyPoint);
		MyFreeMem(MyPoint,sizeof(struct MyPoint));
	}
	if (PointsAlloc) {
		MyFreeVec(PointsAlloc);
		PointsAlloc = NULL;
	}
	if (PointsX) {
		MyFreeVec(PointsX);
		PointsX = NULL;
	}
	if (PointsY) {
		MyFreeVec(PointsY);
		PointsY = NULL;
	}
}

/* Load some image(s) for a frame */
BOOL
LoadFrames(BOOL points,BOOL image1,BOOL image2) {
	char buffer[257];
	BOOL ok=TRUE;
#ifndef __MPCLI
	UBYTE *er,*eg,*eb;
	int i;
#endif
	if ((Single == 2) || (Single == 3)) {
		if (points) {
			AddMessage("Loading points");
   	 	DeleteAllPoints();
			sprintf(buffer,MyFileName,f+Start-1);
			ok = MyOpen(buffer,TRUE);
		}
		sprintf(buffer,Pic1.filename,f+Start-1);
	}
	else {
		strcpy(buffer,Pic1.filename);
	}
	if (ok) {
		if (image1) {
			AddMessage("Loading Image 1");
			ok = Pic1_Open = (BOOL)(Pic1.MPi=LoadMPImage(buffer,NULL,ForceGrey ? MPIF_FORCEGREY : MPIF_GREY));
			if (!ok) {
				Error("Error Loading Image\n%s","Quit",MPImageErrorMessage(),HE_RLoad);
			}
			else {
				if ((Pic1.MPi->Width != width) || (Pic1.MPi->Height != height)) {
					AddMessage("Scaling Image 1");
					if (!RescaleMPImage(Pic1.MPi,width,height)) {
						Error("Error Scaling Image 1\n%s","Quit",MPImageErrorMessage(),HE_RScale);
						ok = FALSE;
					}
				}
			}
#ifndef __MPCLI
			if (ok && EGS && !EGS_BitMap) {
				if (EGS_BitMap = E_AllocBitMap(width,1,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
					EGS_NewWindow.LeftEdge = 0;
					EGS_NewWindow.TopEdge = 20;
					EGS_NewWindow.Width = width;
					EGS_NewWindow.Height = height;
					EGS_NewWindow.MinWidth = 20;
					EGS_NewWindow.MinHeight = 20;
					EGS_NewWindow.MaxWidth = width;
					EGS_NewWindow.MaxHeight = height;
					EGS_NewWindow.Screen = NULL;
					EGS_NewWindow.Bordef.SysGadgets = EI_WINDOWSIZE | EI_WINDOWFRONT | EI_WINDOWFLIP |
																 EI_WINDOWARROWL | EI_WINDOWARROWR | EI_WINDOWARROWU | EI_WINDOWARROWD |
																 EI_WINDOWSCROLLH | EI_WINDOWSCROLLV | EI_WINDOWDRAG;
					EGS_NewWindow.FirstGadgets = NULL;
					EGS_NewWindow.Title = "MPMorph-render output";
					EGS_NewWindow.Flags = EI_GIMMEZEROZERO | EI_SUPER_BITMAP | EI_WINDOWACTIVE | EI_REPORTMOUSE | EI_QUICKSCROLL | EI_RMBTRAP;
					EGS_NewWindow.IDCMPFlags = NULL;
					EGS_NewWindow.Port = NULL;
					EGS_NewWindow.Menu = NULL;
					EGS_NewWindow.Render = NULL;
					if (EGS_Win = EI_OpenWindow(&EGS_NewWindow)) {
						EI_SetWindowTitles(EGS_Win,(UBYTE *)-1,"MPRender");
						E_ActivateEGSScreen();
						er = Pic1.MPi->Red;
						eg = Pic1.MPi->Green;
						eb = Pic1.MPi->Blue;
						for (i = 0; i<height; ++i) {
							CopyEGS(i,&er,&eg,&eb);
						}
					}
				}
			}
#endif
		}
		if (!ForceGrey) {
			if (ok && QuickGrey && ((Single == 1) || (Single = 0)) && (Pic1.MPi->GreyScale)) {
				Grey = TRUE;
			}
		}
		if (image2 && ok && ((Single == 0) || (Single == 2))) {
			AddMessage("Loading Image 2");
			/* If we loaded the 1st image then try the second */
			if (Single == 2) {
				sprintf(buffer,Pic2.filename,f+Start-1);
			}
			else {
				strcpy(buffer,Pic2.filename);
			}
			ok = Pic2_Open = (BOOL)(Pic2.MPi=LoadMPImage(buffer,NULL,ForceGrey ? MPIF_FORCEGREY : MPIF_GREY));
			if (!ok) {
				Error("Error Loading Image\n%s","Quit",MPImageErrorMessage(),HE_RLoad);
			}
			else {
				if (!ForceGrey) {
					if (QuickGrey && (Single == 0) && (Pic1.MPi->GreyScale) && (Pic2.MPi->GreyScale)) {
						Grey = TRUE;
					}
					else {
						Grey = FALSE;
					}
				}
				if ((Pic2.MPi->Width != width) || (Pic2.MPi->Height != height)) {
					AddMessage("Scaling Image 2");
					if (!RescaleMPImage(Pic2.MPi,width,height)) {
						Error("Error Scaling Image 2\n%s","Quit",MPImageErrorMessage(),HE_RScale);
						ok = FALSE;
					}
				}
			}
		}
	}
	return ok;
}

int
cmpX(struct MyPoint **A,struct MyPoint **B) {
	if ((*A)->Cx < (*B)->Cx) {
		return -1;
	}
	if ((*A)->Cx > (*B)->Cx) {
		return 1;
	}
	return 0;
}

int
cmpY(struct MyPoint **A,struct MyPoint **B) {
	if ((*A)->Cy < (*B)->Cy) {
		return -1;
	}
	if ((*A)->Cy > (*B)->Cy) {
		return 1;
	}
	return 0;
}

int
cmpDiff(struct MyPoint **A,struct MyPoint **B) {
	if ((*A)->Cdiff < (*B)->Cdiff) {
		return -1;
	}
	if ((*A)->Cdiff > (*B)->Cdiff) {
		return 1;
	}
	return 0;
}

/* nsort() was written by Dave Watson and uses the algorithm described in -
 *    Watson, D.F., 1981, Computing the n-dimensional Delaunay tessellation with 
 *          application to Voronoi polytopes: The Computer J., 24(2), p. 167-172. 
 */

#define SQ(x)				(x) * (x)
#define BIGNUM				1E37
#define EPSILON         0.00001
#define TSIZE				75                  /* temporary storage size factor*/
#define  XRANGE          10.0                /* factor (>=1) for radius of control points */
#define FILENAMELEN     32
#define AND             &&
#define OR              ||
#define EQ              ==
#define NE              !=

BOOL
GenerateTriangles(void) {
	BOOL ok = FALSE;
	BOOL flag = TRUE;
   double xx, bgs, **mxy, **wrk, **pts, **ccr;
   int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11, ii[3], 
       dm, nts, tsz, *id, **tmp, **a3s;

   if (mxy = DoubleMatrix(2, 2)) {
	   for (i0=0; i0<2; i0++) {
	  		mxy[0][i0] = - (mxy[1][i0] = BIGNUM);
	   }
	   if (wrk = DoubleMatrix(2, 3)) {
		   for (i0=0; i0<2; i0++) {
		   	for (i1=0; i1<3; i1++) {
		   		wrk[i0][i1] = -XRANGE;
		   	}
		   }
		   for (i0=0; i0<2; i0++) {
		   	wrk[i0][i0] = XRANGE * (3 * 2 - 1);
		   }
			if (pts = DoubleMatrix(PointCount + 3, 2)) {
				for (i0=0; i0<PointCount; i0++) {
			   	NewList(&(PointsX[i0]->TList));
					pts[i0][0] = PointsX[i0]->Cx;
					pts[i0][1] = PointsX[i0]->Cy;
					for (i1=0; i1<2; i1++) {
						if (mxy[0][i1] < pts[i0][i1]) {
							mxy[0][i1] = pts[i0][i1];
						}
						if (mxy[1][i1] > pts[i0][i1]) {
							mxy[1][i1] = pts[i0][i1];
						}
					}
				}
				for (bgs=0, i0=0; i0<2; i0++) {
					mxy[0][i0] -= mxy[1][i0];
			      if (bgs < mxy[0][i0]) {
			      	bgs = mxy[0][i0];
			      }
			   }
				bgs *= EPSILON;
			   for (i0=0; i0<PointCount; i0++) {
			   	for (i1=0; i1<2; i1++) {
						pts[i0][i1] += bgs * (0.5 - (double)rand() / 0x7fffffff);
					}
				}
				for (i0=0; i0<3; i0++) {
					for (i1=0; i1<2; i1++) {
						pts[PointCount+i0][i1] = mxy[1][i1] + wrk[i1][i0] * mxy[0][i1];
					}
				}
			   for (i1=1, i0=2; i0<3; i0++) {
			   	i1 *= i0;
			   }
			   tsz = TSIZE * i1;
			   if (tmp = IntMatrix(tsz + 1, 2)) {
				   i1 *= (PointCount + i1);
				   if (id = IntVect(i1)) {
					   for (i0=0; i0<i1; i0++) {
					   	id[i0] = i0;
					   }
						if (a3s = IntMatrix(i1,3)) {
						  	if (ccr = DoubleMatrix(i1,3)) {
							  	for (a3s[0][0]=PointCount, i0=1; i0<3; i0++) {
							  		a3s[0][i0] = a3s[0][i0-1] + 1;
							  	}
								for (ccr[0][2]=BIGNUM, i0=0; i0<2; i0++) {
									ccr[0][i0] = 0;
								}
							   nts = i4 = 1;
							   dm = 2 - 1;
							   for (i0=0; i0<PointCount; i0++) {
							      i1 = i7 = -1;
							      i9 = 0;
							      for (i11=0; i11<nts; i11++) {
							         i1++;
							         while (a3s[i1][0] < 0) { 
							         	i1++;
							         }
							         xx = ccr[i1][2];
							         for (i2=0; i2<2; i2++) {
							            xx -= SQ(pts[i0][i2] - ccr[i1][i2]);
										   if (xx<0) {
										   	goto Corner3;
										   }
							         }
							         i9--;
										i4--;
										id[i4] = i1;
										for (i2=0; i2<3; i2++) {
										   ii[0] = 0;
							            if (ii[0] EQ i2) {
							            	ii[0]++;
							            }
							            for (i3=1; i3<2; i3++) {
							               ii[i3] = ii[i3-1] + 1;
							               if (ii[i3] EQ i2) {
							               	ii[i3]++;
							               }
							            }
							            if (i7>dm) {
											   i8 = i7;
												for (i3=0; i3<=i8; i3++) {
												   for (i5=0; i5<2; i5++) {
												   	if (a3s[i1][ii[i5]] NE tmp[i3][i5]) {
												   		goto Corner1;
												   	}
												   }
													for (i6=0; i6<2; i6++) {
														tmp[i3][i6] = tmp[i8][i6];
													}
													i7--;
													goto Corner2;
Corner1:;
												}
											}
											if (++i7 > tsz) {
												goto returnfail;
											}
											for (i3=0; i3<2; i3++) {
												tmp[i7][i3] = a3s[i1][ii[i3]];
											}
Corner2:;
										}
								      a3s[i1][0] = -1;
Corner3:;
								   }
								   for (i1=0; i1<=i7; i1++) {
								      for (i2=0; i2<2; i2++) {
								   		for (wrk[i2][2]=0, i3=0; i3<2; i3++) {
								            wrk[i2][i3] = pts[tmp[i1][i2]][i3] - pts[i0][i3];
										   	wrk[i2][2] += wrk[i2][i3] * (pts[tmp[i1][i2]][i3] + pts[i0][i3]) / 2;
											}
										}
										xx = wrk[0][0] * wrk[1][1] - wrk[1][0] * wrk[0][1];
										ccr[id[i4]][0] = (wrk[0][2] * wrk[1][1] - wrk[1][2] * wrk[0][1]) / xx;
										ccr[id[i4]][1] = (wrk[0][0] * wrk[1][2] - wrk[1][0] * wrk[0][2]) / xx;
								      for (ccr[id[i4]][2]=0, i2=0; i2<2; i2++) {
								        	ccr[id[i4]][2] += SQ(pts[i0][i2] - ccr[id[i4]][i2]);
										   a3s[id[i4]][i2] = tmp[i1][i2];
								      }
										a3s[id[i4]][2] = i0;
										i4++;
								      i9++;
								   }
								   nts += i9;
								}
								i0 = -1;
								for (i11=0; flag && (i11<nts); i11++) {
									i0++;
								   while (a3s[i0][0] < 0) {
								   	i0++;
								   }
								   if (a3s[i0][0] < PointCount) {
										for (i1=0; i1<2; i1++) for (i2=0; i2<2; i2++)  {
								      	wrk[i1][i2] = pts[a3s[i0][i1]][i2] - pts[a3s[i0][2]][i2];
								      }
								      xx = wrk[0][0] * wrk[1][1] - wrk[0][1] * wrk[1][0];
								      if (fabs(xx) > EPSILON) {
											flag = AddTri(a3s[i0][0],a3s[i0][2],a3s[i0][1]);
								      }
								   }
								}
							   ok = flag;
returnfail:
								FreeMatrixd(ccr);
							}
							FreeMatrixi(a3s);
						}
						MyFreeVecti(id);
					}
				   FreeMatrixi(tmp);
				}
				FreeMatrixd(pts);
			}
			FreeMatrixd(wrk);
		}
		FreeMatrixd(mxy);
	}
	return ok;
}
	
static int
*IntVect(int ncols) {  
	return (int *) MyAllocVec(ncols * sizeof(int),0);
}

static void
MyFreeVecti(int *vectptr) {
	if (vectptr) {
		MyFreeVec(vectptr);
	}
}

static int
**IntMatrix(int nrows, int ncols) {
   int i0;
   int **matptr;
   if (nrows<2) nrows = 2;
   if (ncols<2) ncols = 2;
   if ((matptr = (int **) MyAllocVec(nrows * sizeof(int *),0)) EQ NULL) {
   	return NULL;
   }
   if ((matptr[0] = (int *) MyAllocVec(nrows * ncols * sizeof(int),0)) EQ NULL) {
   	MyFreeVec(matptr);
   	return NULL;
   }
   for (i0=1; i0<nrows; i0++) {
   	matptr[i0] = matptr[0] + i0 * ncols;
   }
   return matptr;
}

static void
FreeMatrixi(int **matptr) {  
	if (matptr) {
		if (matptr[0]) {
			MyFreeVec(matptr[0]);
		}
		MyFreeVec(matptr);
	}
}

static double
**DoubleMatrix(int nrows, int ncols) {
   int i0;
   double **matptr;
   if (nrows<2) nrows = 2;
   if (ncols<2) ncols = 2;
   if ((matptr = (double **) MyAllocVec(nrows * sizeof(double *),0)) EQ NULL) {
   	return NULL;
   }
   if ((matptr[0] = (double *) MyAllocVec(nrows * ncols * sizeof(double),0)) EQ NULL) {
   	MyFreeVec(matptr);
   	return NULL;
   }
   for (i0=1; i0<nrows; i0++) {
	   matptr[i0] = matptr[0] + i0 * ncols;
	}
   return matptr;
}

static void
FreeMatrixd(double **matptr) {
	if (matptr) {
		if (matptr[0]) {
		   MyFreeVec(matptr[0]);
		}
		MyFreeVec(matptr);
	}
}

void
FreeTriangles(void) {
	int i;
	struct Triangle *T;
	struct MyPoint *P;
	for (i=0; i<PointCount; i++) {
		P = PointsX[i];
		if (P) {
			if (P->TList.lh_Head) {
				while ((T =(struct Triangle *)(P->TList.lh_Head))->TNode.mln_Succ) {
					Remove((struct Node *)T);
					MyFreeVec(T);
				}
			}
		}
	}
}

BOOL AddTri(int aa,int bb,int cc) {
	struct Triangle *T1,*T2=NULL,*T3;
	if ((T1 = (struct Triangle *)MyAllocVec(sizeof (struct Triangle),0)) &&
		 (T2 = (struct Triangle *)MyAllocVec(sizeof (struct Triangle),0)) &&
		 (T3 = (struct Triangle *)MyAllocVec(sizeof (struct Triangle),0))) {
		T1->Point1 = PointsX[bb];
		T1->Point2 = PointsX[cc];
		AddTail(&(PointsX[aa]->TList),(struct Node *)T1);
		T2->Point1 = PointsX[aa];
		T2->Point2 = PointsX[cc];
		AddTail(&(PointsX[bb]->TList),(struct Node *)T2);
		T3->Point1 = PointsX[aa];
		T3->Point2 = PointsX[bb];
		AddTail(&(PointsX[cc]->TList),(struct Node *)T3);
		T1->MinX = T2->MinX = T3->MinX = min(min(min(min(min(PointsX[aa]->x,PointsX[aa]->x1),PointsX[bb]->x),PointsX[bb]->x1),PointsX[cc]->x),PointsX[cc]->x1);
		T1->MinY = T2->MinY = T3->MinY = min(min(min(min(min(PointsX[aa]->y,PointsX[aa]->y1),PointsX[bb]->y),PointsX[bb]->y1),PointsX[cc]->y),PointsX[cc]->y1);
		T1->MaxX = T2->MaxX = T3->MaxX = max(max(max(max(max(PointsX[aa]->x,PointsX[aa]->x1),PointsX[bb]->x),PointsX[bb]->x1),PointsX[cc]->x),PointsX[cc]->x1);
		T1->MaxY = T2->MaxY = T3->MaxY = max(max(max(max(max(PointsX[aa]->y,PointsX[aa]->y1),PointsX[bb]->y),PointsX[bb]->y1),PointsX[cc]->y),PointsX[cc]->y1);
		return TRUE;
	}
	if (T1) {
		MyFreeVec(T1);
	}
	if (T2) {
		MyFreeVec(T2);
	}
	return FALSE;
}


#ifndef __MPCLI
#ifndef _M68881
/* Prevent zero divide failures on 68020 version in FFP maths */
APTR oldTrapCode=NULL;
extern __stdargs ULONG trapa();
#endif
#endif

/* External for handle progress task (Future version for better
 * processing of list view! */
BOOL 	OkFlag	= TRUE;	/* Is it working ? */

/* Main program	*/
int
main(int argc,char **argv) {
 char 	*e			= NULL;	/* error message */
 struct MyPoint 	MyPoint;		/* Points to work with */
 struct MyPoint 	*MyPointp;
 BOOL 				Opened=FALSE;		/* has file been opened */
 char 				*Prescript;	/* Rexx script names */
#ifndef __MPCLI
 struct WBStartup *argmsg;		/* Workbench stuff */
 struct WBArg 		*wb_arg;
 struct Window 	*oldWindowPtr=0;	/* Redirect the system requesters */
 struct Process 	*process=0;
 struct AmigaGuideMsg *agm;	/* help stuff */
 struct timeval	time1,		/* To display time per image */
 						time2={0};
 struct timerequest tr;
 BOOL 				t2	= FALSE;	/* Set when the times calculated */
 char 				tbuffer[30];/* buffer for time message */
 ULONG				hnum = 0;	/* Help number for error */
 UBYTE				*er,*eg,*eb;/* EGS pointers */
 BPTR					progdir;
#endif
 char 				*e1=NULL;			/* The rest of the error message */
 char 				*filename;	/* file name */
 ULONG 				offset,		/* 2d to 1d array offsets */
 						offset1;
 UWORD				myx,			/* indexes for skipping */
 						myy;
 UBYTE				xr,			/* more skipping stuff */
 						xg=0,
 						xb=0;
 BOOL					Alloced=FALSE;	/* Allocated memory? */
 UWORD				xbig;
 double				xsmall;		/* Int and rest of coords */
 UWORD				ybig;
 double				ysmall;		/* y coords */
 WORD					right,down;	/* move right and down? */
 UWORD				xbig1;
 double				xsmall1;		/* Int and rest of coords */
 UWORD				ybig1;
 double				ysmall1;		/* y coords */
 WORD					right1,down1;/* move right and down? */
 double				a,bb,c,d,a1,b1,c1,d1;	/* AntiAlias stuff */
 WORD 				x,y;			/* Current coords */

 /* Set /0 trap handler */
#ifndef __MPCLI
#ifndef _M68881
 process = (struct Process *)FindTask(NULL);
 oldTrapCode = process->pr_Task.tc_TrapCode;
 process->pr_Task.tc_TrapCode = (APTR)trapa;
#endif
#endif
 /* Set up BigPoint */
 BigPoint.Cdiff = 0x7FFFFFFF;
 /* Initialise points list */
 NewList(&PointList);
#ifdef __MPCLI
 ArgArray = argv;
 if (OpenUnixInterface()) {
#else
 /* Assign MPMorph to progdir */
 if (progdir = Lock("progdir:",ACCESS_READ)) {
  AssignLock("MPMorph",progdir);
 }
 /* Try and open reqtools.library */
 ReqToolsBase = (struct ReqToolsBase *)OpenLibrary("reqtools.library",38);
 Chain = CreatePool(MEMF_ANY,PUDDLE,THRESH);
 /* Set up amigaguide (if available) */
 if (AmigaGuideBase = OpenLibrary("amigaguide.library", 33L)) {
  nag.nag_BaseName = "MPRender";
  nag.nag_Name = "MPRender.guide";
  nag.nag_ClientPort = "MPMorph-render_HELP";
  nag.nag_Context = context;
  if (handle = OpenAmigaGuideAsync(&nag, TAG_END)) {
   ASig = AmigaGuideSignal(handle);
  }
 }
 /* Try and open the timer */
 if (!OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *) &tr, 0L)) {
  TimerBase = tr.tr_node.io_Device;
 }
 /* Open all the libraries */
 if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39L)) {
  if (RexxSysBase = OpenLibrary("rexxsyslib.library",0L)) {
    if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39L)) {
     if (LayersBase = OpenLibrary("layers.library",37L)) {
      if (GadToolsBase = OpenLibrary("gadtools.library",37L)) {
       if (AslBase = OpenLibrary("asl.library",37L)) {
        if (UtilityBase = (struct UtilityBase *)OpenLibrary("utility.library",37L)) {
         if (IconBase = OpenLibrary("icon.library",37L)) {
          if (DiskfontBase = OpenLibrary("diskfont.library",36L)) {
           if (MPImageBase = OpenLibrary("MPImage.library",6L)) {
				ProgressHook.h_Entry = (HOOKFUNC)ProgressH;
            MPProgressHook(&ProgressHook);
            /* Read and process the parameters */
            MyArgArrayInit(argc,argv,"Render.Prefs","ENV:MPMorph/");
            if (MatchToolValue(MyArgString("EGS","NO",FALSE),"YES")) {
				 if ((EGSBase = OpenLibrary("egs.library",0)) &&
				  	  (EGSGfxBase = OpenLibrary("egsgfx.library", 0)) &&
					  (EGSIntuiBase = OpenLibrary("egsintui.library", 0))) {
				  EGS = TRUE;
				 }
				}
            if (MatchToolValue(MyArgString("REQTOOLS","YES",FALSE),"NO")) {
             if (ReqToolsBase) {
              CloseLibrary((struct Library *)ReqToolsBase);
              ReqToolsBase = NULL;
             }
            }
            PubScreenName = MyArgString("PUBSCREEN",NULL,FALSE);
            if (!*PubScreenName) {
            	PubScreenName = NULL;
            }
            if (MatchToolValue(MyArgString("NOPROGRESS","NO",FALSE),"YES")) {
             NoProgress = TRUE;
            }
            PProgressHook = (struct Hook *)MyArgInt("PROGRESSHOOK",0,FALSE);
            /* Open the progress window */
        	   if (!SetupScreen()  && !OpenProgressWindow()) {
        	  	 /* redirect requesters */
             process = (struct Process *)FindTask(NULL);
             oldWindowPtr = process->pr_WindowPtr;
             process->pr_WindowPtr = ProgressWnd;
        	    SetMPImageScreen(PubScreenName,0);	//MPIF_PROGRESS);
             myhost = SetupARexxHost("MPRENDER",NULL);
#endif
             /* Open the project file (CLI or WB) */
             DisableWindow();
  	    	    AddMessage("Opening points file");
             if (argc) {
 	           if (filename = ArgString(ArgArray,"FILES",NULL)) {
               Opened = MyOpen(filename,FALSE);
              }
#ifndef __MPCLI
              else {
         	   Opened = MyOpen(NULL,FALSE);
              }
             }
             else {
              argmsg = (struct WBStartup *)argv;
			     if (argmsg->sm_NumArgs > 1) {
	            wb_arg = argmsg->sm_ArgList;
   	         wb_arg++;
      	      if (wb_arg->wa_Lock) {
 	             NameFromLock(wb_arg->wa_Lock,buffer,256);
 	            }
     	         if (AddPart(buffer,wb_arg->wa_Name,256)) {
        	       Opened = MyOpen(buffer,FALSE);
               }
              }
              else {
        	      Opened = MyOpen(NULL,FALSE);
        	     }
#endif
        	    }
        	    if (Opened) {
        	     /* Get a few parameters */
        	     SaveFormat = MyArgString("SAVEFORMAT","ILBM24",FALSE);
        	     ModeName = MyArgString("MODENAME",NULL,FALSE);
        	     palette = MyArgString("PALETTE",NULL,FALSE);
        	     if (!*palette) {
        	     	palette = NULL;
        	     }
        	     Colours = MyArgInt("COLOURS",16,FALSE);
        	     Bit12 = MatchToolValue(MyArgString("12BIT","NO",FALSE),"YES");
        	     QuickGrey = MatchToolValue(MyArgString("QUICKGREY","YES",FALSE),"YES");
        	     ForceGrey = MatchToolValue(MyArgString("FORCEGREY","NO",FALSE),"YES");
        	     if (ForceGrey) {
        	      Grey = TRUE;
        	      QuickGrey = TRUE;
        	     }
              Prescript = MyArgString("PRESCRIPT","MPMorph:Rexx/Prescript.MPM",FALSE);
              Postscript = MyArgString("POSTSCRIPT","MPMorph:Rexx/Postscript.MPM",FALSE);
              Loadscript = MyArgString("LOADSCRIPT","MPMorph:Rexx/Loadscript.MPM",FALSE);
              DX = MyArgInt("DX",0,FALSE);
              DY = MyArgInt("DY",0,FALSE);
              CreateIcons = MatchToolValue(MyArgString("CREATEICONS","NO",FALSE),"YES");
              AntiAlias = MatchToolValue(MyArgString("ANTIALIAS","NO",FALSE),"YES");
#ifdef __MPCLI
              Integer = MatchToolValue(MyArgString("INTEGER","NO",FALSE),"YES");
#else
#ifdef _M68060
              Integer = MatchToolValue(MyArgString("INTEGER","NO",FALSE),"YES");
#else
#ifdef _M68040
              Integer = MatchToolValue(MyArgString("INTEGER","NO",FALSE),"YES");
#else
#ifdef _M68881
              Integer = MatchToolValue(MyArgString("INTEGER","NO",FALSE),"YES");
#else
              Integer = MatchToolValue(MyArgString("INTEGER","YES",FALSE),"YES");
#endif
#endif
#endif
#endif
              if (Integer) {
               AntiAlias = FALSE;
              }
        	     /* File has been opened */
  	    	     AddMessage("Allocating work memory");
     	    	  /* Allocate chunky and ILBM bit maps */
        	     if ((RED = MyAllocVec((width*height),MEMF_CLEAR)) &&
        	     		(ForceGrey ||
  	       	 	    ((GREEN = MyAllocVec((width*height),MEMF_CLEAR)) &&
  	       	 	     (BLUE =  MyAllocVec((width*height),MEMF_CLEAR))))) {
  	       		Alloced = TRUE;
  	       		/* Update the progress */
  	       	   EnableWindow();
  	       	   SetMaxFrame(Frames);
  	       	   SetMaxLine(height-1);
#ifndef __MPCLI
				   /* Pass to ARexx for processing */
					if (strcmp(Prescript,"OFF")) {
    	    	    AddMessage("Prescript for frame 0");
      	    	 f = 0;
      	    	 Do = 0;
					 strcpy(buffer,Prescript);
					 strcat(buffer," %ld");
					 sprintf(buffer1,buffer,&Arexx);
					 OkFlag = !SendRxMsg(buffer1,FALSE);
					 if (!OkFlag) {
					   e = (char *)-1;
					 }
#endif
					 if (Do && OkFlag) {
        	    	  OkFlag = LoadFrames(FALSE,TRUE,FALSE);
        	    	  if (!OkFlag) {
        	    	   e = (char *)-1;
        	    	  }
        	    	  else {
        	    	   memcpy(RED,Pic1.MPi->Red,width*height);
        	    	   if (!Grey) {
	        	    	   memcpy(GREEN,Pic1.MPi->Green,width*height);
   	     	    	   memcpy(BLUE,Pic1.MPi->Blue,width*height);
   	     	    	}
     	     	      OkFlag = HandleProgressIDCMP();
     	     	      if (!OkFlag) {
     	     	       e = (char *)-1;
     	     	      }
     	     	      else {
					    OkFlag = SaveFile();
         	    	 if (!OkFlag) {
         	    	  e = (char *)-1;
         	    	 }
         	    	}
        	    	  }
					 }
					}
  	     	      OkFlag = HandleProgressIDCMP();
     	     	   if (!OkFlag) {
     	     	    e = (char *)-1;
     	     	   }
					if ((Mode & MODE_ONCE) && OkFlag) {
    	    	    AddMessage("Precalculating points");
    	    	    Points = PointsAlloc;
					 for (MyPointp = (struct MyPoint *)PointList.lh_Head;
							MyPointp->MyNode.mln_Succ;
				   		MyPointp = (struct MyPoint *)MyPointp->MyNode.mln_Succ) {
		   		  MyPointp->Cx = (MyPointp->x1+MyPointp->x)>>1;
			   	  MyPointp->Cy = (MyPointp->y1+MyPointp->y)>>1;
			   	 }
			   	 SetMaxLine(height-1);
        		  	 for (y=0;
        	  	    		((y<height) && OkFlag);
        	  	     		y++) {
        	  	     /* Update progress */
        	  	     SetLine(y);
   	     	     /* Loop thru columns */
      	     	  for (x=0;
       	          x < width;
        	          x++) {
        	         /* Determine coordinates on end image(s) */
        	         FindPoint(&MyPoint,FALSE,x,y);
        	         Points += ((Mode & MODE_DELAU) ?
								 	  (Mode & MODE_STAT) ? 1 :
									  3 :
								 	  (Depth + 4));
      		  	   if (DX) {
      		  	    x++;
      		  	    for (myx = 0;
      		  	  		   (myx < DX) && (x < width);
      		  	     		x++,myx++) {
	        	        Points += ((Mode & MODE_DELAU) ?
								 	  (Mode & MODE_STAT) ? 1 :
									  3 :
								 	  (Depth + 4));
      		  	    }
      		  	    x--;
      		  	   }
        	     	  }
        	     	  /* end of line, check 'Stop' and 'Help' */
        	     	  OkFlag = HandleProgressIDCMP();
#ifndef __MPCLI
      	        if (handle) {
	      	      while (agm = GetAmigaGuideMsg(handle)) {
   	   		    ReplyAmigaGuideMsg(agm);
      		      }
      		     }
#endif
        	     	  if (DY) {
        	     	   y++;
        		  	   for (myy = 0;
        	  	           (myy < DY) && (y<height);
        	  	           y++, myy++) {
        	          Points += ((Mode & MODE_DELAU) ?
								 	  (Mode & MODE_STAT) ? 1 :
									  3 :
								 	  (Depth + 4))*width;
        	  	      }
        	  	      y--;
      		     }
      		    }
        	    	 /* not ok - already displayed an error */
        	    	 if (!OkFlag) {
        	    	  e = (char *)-1;
         	    }
         	    else {
					  if (Mode & MODE_DELAU) {
   	    	      AddMessage("Calculating triangles");
					   OkFlag = GenerateTriangles();
					   if (!OkFlag) {
                   Error("Out of memory for points","Quit",NULL,H_MemPointsR);
					   }
					  }
					 }
					}
#ifndef __MPCLI
     	    	   /* Determine start time */
     	    	   if (TimerBase) {
     	    	    GetSysTime(&time1);
     	    	   }
#endif
     	    	   /* Loop thru frames */
      	      for (f=1;
      	    	 	  (f < (Frames+1)) && OkFlag;		/* no of Frames */
        	    		  f++) {
        	    	 /* Update progress */
  	    	       AddMessage("Prescript processing");
  	    	       SetFrame(f);
        	       /* calculate default image parameters */
        	    	 rplus = gplus = bplus = rminus = gminus = bminus = 0;
					 if ((Single == 1) || (Single == 3)) {
					  move = ((Frames-f) << 10)/Frames;
					  r = g = b = 1024;
					  r2 = g2 = b2 = 0;
					  Do = 1;
					 }
					 else {
					  r = g = b = move = ((Frames-f+1) << 10)/(Frames + 1);
					  r2 = g2 = b2 = (1024 - r);
					  Do = 1;
					 }
					 /* Pass to ARexx for processing */
#ifndef __MPCLI
					 if (strcmp(Prescript,"OFF")) {
					  strcpy(buffer,Prescript);
					  strcat(buffer," %ld");
					  sprintf(buffer1,buffer,&Arexx);
					  OkFlag = !SendRxMsg(buffer1,FALSE);
					  if (!OkFlag) {
					   e = (char *)-1;
					  }
					 }
#endif
        	       if (OkFlag && Do && ((!Pic1_Open) || (Single == 2) || (Single == 3))) {
                 if (Pic2_Open) {
 	               Close24bit(&Pic2);
 	               Pic2_Open = FALSE;
 	              }
	              if (Pic1_Open) {
	               Close24bit(&Pic1);
	               Pic1_Open = FALSE;
	              }
     	     	     OkFlag = HandleProgressIDCMP();
     	     	     if (!OkFlag) {
     	     	      e = (char *)-1;
     	     	     }
     	     	     else {
        	    	   OkFlag = LoadFrames(TRUE,TRUE,TRUE);
        	    	   if (!OkFlag) {
        	    	    e = (char *)-1;
        	    	   }
        	    	  }
        	    	 }
        	    	 else {	/* Version 2.4 - Open frame 2 if not yet open */
     	     	     OkFlag = HandleProgressIDCMP();
     	     	     if (!OkFlag) {
     	     	      e = (char *)-1;
     	     	     }
     	     	     else {
        	    	   if (OkFlag && Do && !Pic2_Open && (Single == 0)) {
        	    	    OkFlag = LoadFrames(FALSE,FALSE,TRUE);
        	    	    if (!ForceGrey && Grey) {
        	    	     MyFreeVec(BLUE);
        	    	     BLUE = NULL;
        	    	     MyFreeVec(GREEN);
        	    	     GREEN = NULL;
        	    	    }
        	    	   }
        	    	  }
        	    	 }
					 if ((PointCount < 3) && OkFlag) {
					  Error("Must have at least 3 points","Quit",NULL,H_3Points);
					  OkFlag = FALSE;
					 }
					 if (Do && OkFlag) {
#ifndef __MPCLI
        	    	  /* If we have calculated time per image the display it, update other gadgets */
        	    	  if (t2) {
        	    	   sprintf(tbuffer,"%ld.%02ld Seconds for last image",time2.tv_secs,time2.tv_micro/10000);
   	    	      AddMessage(tbuffer);
        	    	  }
        	    	  else {
#endif
   	    	      AddMessage("Rendering image");
#ifndef __MPCLI
      	    	  }
      	    	  if (TimerBase) {
      	    	   GetSysTime(&time1);
      	    	  }
#endif
					  /* We want to do this image so calculate coordinates in this image */
					  if ((Single == 1) || (Single == 3)) {
					   for (MyPointp = (struct MyPoint *)PointList.lh_Head;
							MyPointp->MyNode.mln_Succ;
				   		MyPointp = (struct MyPoint *)MyPointp->MyNode.mln_Succ) {
		   		    MyPointp->Cx = (MyPointp->x1*(1024-move)+MyPointp->x*move)>>10;
			   	    MyPointp->Cy = (MyPointp->y1*(1024-move)+MyPointp->y*move)>>10;
		      	   }
		      	  }
		      	  else {
					   for (MyPointp = (struct MyPoint *)PointList.lh_Head;
					 		MyPointp->MyNode.mln_Succ;
				    		MyPointp = (struct MyPoint *)MyPointp->MyNode.mln_Succ) {
		   		  	 MyPointp->Cx = (MyPointp->x1*(1024-move)+MyPointp->x*move)>>10;
			   	    MyPointp->Cy = (MyPointp->y1*(1024-move)+MyPointp->y*move)>>10;
		      	   }
		      	  }
					  if ((Mode & MODE_DELAU) && (!(Mode & MODE_ONCE))) {
   	    	      AddMessage("Calculating triangles");
					   OkFlag = GenerateTriangles();
					   if (!OkFlag) {
                   Error("Out of memory for points","Quit",NULL,H_MemPointsR);
					   }
					  }
		      	  /* Initialise chunky pointers */
#ifndef __MPCLI
	        	     er =
#endif
	        	  		arrayr=RED;
	        	     if (Grey) {
#ifndef __MPCLI
	   	     	   eg =
#endif
	   	     	    arrayg = RED;
#ifndef __MPCLI
   	   	  	   eb =
#endif
   	   	  	    arrayb = RED;
   	   	  	  }
   	   	  	  else {
#ifndef __MPCLI
	   	     	   eg =
#endif
	   	     	    arrayg = GREEN;
#ifndef __MPCLI
   	   	  	   eb =
#endif
   	   	  	    arrayb = BLUE;
   	   	  	  }
      	  	     Points = PointsAlloc;
      	  	     SetMaxLine(height-1);
      	  	     /* loop thru lines */
        		  	  for (y=0;
        	  	      (y<height) && OkFlag;
        	  	      y++) {
        	  	      /* Update progress */
        	  	      SetLine(y);
   	     	     	/* Loop thru columns */
      	     	   for (x=0;
       	           x < width;
        	           x++) {
        	          /* Determine coordinates on end image(s) */
        	          FindPoint(&MyPoint,TRUE,x,y);
        	          if (Mode & MODE_ONCE) {
        	           Points += ((Mode & MODE_DELAU) ?
								 	    (Mode & MODE_STAT) ? 1 :
									    3 :
								 	    (Depth + 4));
	        	       }
        	          if (AntiAlias) {
        	           /* Horrible AntiAlias stuff */
        	           xbig = (UWORD)(MyPoint.xd + 0.5);
        	           xsmall = MyPoint.xd - (double)xbig;
        	           if (xsmall > 0) {
        	            right = 1;
        	           }
        	           else {
        	            xsmall = -xsmall;
        	            right = -1;
        	           }
        	           ybig = (UWORD)(MyPoint.yd + 0.5);
        	           ysmall = MyPoint.yd - (double)ybig;
        	           if (ysmall > 0) {
        	            down = width;
        	           }
        	           else {
        	            ysmall = -ysmall;
        	            down = -(WORD)width;
        	           }
     	              offset = ybig*width+xbig;
     	              a = 1.0 + (xsmall * ysmall) - xsmall - ysmall;
     	              bb = xsmall * (1.0 - ysmall);
     	              c = ysmall * (1.0 - xsmall);
     	              d = xsmall * ysmall;
        	           if ((Single != 1) && (Single != 3)) {
         	         xbig1 = (UWORD)(MyPoint.x1d + 0.5);
        	            xsmall1 = MyPoint.x1d - (double)xbig1;
        	            if (xsmall1 > 0) {
        	             right1 = 1;
        	            }
        	            else {
        	             xsmall1 = -xsmall1;
        	             right1 = -1;
        	            }
        	            ybig1 = (UWORD)(MyPoint.y1d + 0.5);
        	            ysmall1 = MyPoint.y1d - (double)ybig1;
        	            if (ysmall1 > 0) {
        	             down1 = width;
        	            }
        	            else {
        	             ysmall1 = -ysmall1;
        	             down1 = -(WORD)width;
        	            }
     	               offset1 = ybig1*width+xbig1;
     	               a1 = 1.0 + (xsmall1 * ysmall1) - xsmall1 - ysmall1;
     	               b1 = xsmall1 * (1.0 - ysmall1);
     	               c1 = ysmall1 * (1.0 - xsmall1);
     	               d1 = xsmall1 * ysmall1;
			            (*arrayr) = min(max((((ULONG)
														((((double)  Pic1.MPi->Red[offset])*a + ((double)  Pic1.MPi->Red[offset+right])*bb+
			            							 ((double)  Pic1.MPi->Red[offset+down])*c+((double)  Pic1.MPi->Red[offset+down+right])*d)*((double)r) +
														(((double)  Pic2.MPi->Red[offset1])*a1 + ((double)  Pic2.MPi->Red[offset1+right1])*b1+
			            							 ((double)  Pic2.MPi->Red[offset1+down1])*c1+((double)  Pic2.MPi->Red[offset1+down1+right1])*d1)*((double)r2))
			            							)>>10) + rplus - rminus,0),255);
			            if (!Grey) {
 			             (*arrayg) = min(max((((ULONG)
														 ((((double)Pic1.MPi->Green[offset])*a + ((double)Pic1.MPi->Green[offset+right])*bb+
			            							  ((double)Pic1.MPi->Green[offset+down])*c+((double)Pic1.MPi->Green[offset+down+right])*d)*((double)g) +
														 (((double)Pic2.MPi->Green[offset1])*a1 + ((double)Pic2.MPi->Green[offset1+right1])*b1+
			            							  ((double)Pic2.MPi->Green[offset1+down1])*c1+((double)Pic2.MPi->Green[offset1+down1+right1])*d1)*((double)g2))
			            							 )>>10) + gplus - gminus,0),255);
			             (*arrayb) = min(max((((ULONG)
														 ((((double) Pic1.MPi->Blue[offset])*a + ((double) Pic1.MPi->Blue[offset+right])*bb+
			            							  ((double) Pic1.MPi->Blue[offset+down])*c+((double) Pic1.MPi->Blue[offset+down+right])*d)*((double)b) +
														 (((double) Pic2.MPi->Blue[offset1])*a1 + ((double) Pic2.MPi->Blue[offset1+right1])*b1+
			            							  ((double) Pic2.MPi->Blue[offset1+down1])*c1+((double) Pic2.MPi->Blue[offset1+down1+right1])*d1)*((double)b2))
			            							 )>>10) + bplus - bminus,0),255);
			            }
        	           }
        	           else {
			            (*arrayr) = min(max(((ULONG)
														(((((double)Pic1.MPi->Red[offset])*a + ((double)Pic1.MPi->Red[offset+right])*bb+
			            							 ((double)Pic1.MPi->Red[offset+down])*c+((double)Pic1.MPi->Red[offset+down+right])*d)
			            							)*((double)r))>>10) + rplus - rminus,0),255);
			            if (!Grey) {
      	  	   	    (*arrayg) = min(max(((ULONG)
			             							 (((((double)Pic1.MPi->Green[offset])*a + ((double)Pic1.MPi->Green[offset+1])*bb+
			            							  ((double)Pic1.MPi->Green[offset+down])*c+((double)Pic1.MPi->Green[offset+down+right])*d)
      	  	   	   							 )*((double)g))>>10) + gplus - gminus,0),255);
		      	  	    (*arrayb) = min(max(((ULONG)
														 (((((double)Pic1.MPi->Blue[offset])*a + ((double)Pic1.MPi->Blue[offset+1])*bb+
			            							  ((double)Pic1.MPi->Blue[offset+down])*c+((double)Pic1.MPi->Blue[offset+down+right])*d)
		      	  	   							 )*((double)b))>>10) + bplus - bminus,0),255);
		      	  	   }
        	           }
        	          }
        	          else {
        	           /* Calculate new colours (without AntiAlias) */
     	              offset = MyPoint.y*width+MyPoint.x;
        	           if ((Single == 1) || (Single == 3)) {
			            (*arrayr) = min(max(((Pic1.MPi->Red[offset]*r)>>10) + rplus - rminus,0),255);
			            if (!Grey) {
      	  	   	    (*arrayg) = min(max(((Pic1.MPi->Green[offset]*g)>>10) + gplus - gminus,0),255);
		      	  	    (*arrayb) = min(max(((Pic1.MPi->Blue[offset]*b)>>10) + bplus - bminus,0),255);
		      	  	   }
      		  	     }
      		  	     else {
      	            offset1 = MyPoint.y1*width+MyPoint.x1;
			            (*arrayr) = min(max((((Pic2.MPi->Red[offset1]*r2) +
   	   		  	    				 (Pic1.MPi->Red[offset]*r))>>10) + rplus - rminus,0),255);
   	   		  	   if (!Grey) {
      	  	   	    (*arrayg) = min(max((((Pic2.MPi->Green[offset1]*g2) +
        		        		 		  	  (Pic1.MPi->Green[offset]*g))>>10) + gplus - gminus,0),255);
		      	  	    (*arrayb) = min(max((((Pic2.MPi->Blue[offset1]*b2) +
      		  		    				  (Pic1.MPi->Blue[offset]*b))>>10) + bplus - bminus,0),255);
      		  		   }
      		  	     }
      		  	    }
      		  	    /* If we are skipping columns then copy colour forward */
      		  	    if (DX) {
     		  	        xr = *arrayr;
     		  	        if (!Grey) {
      		  	      xg = *arrayg;
      		  	      xb = *arrayb;
      		  	     }
      		  	     x++;
      		  	     for (myx = 0;
      		  	     		 (myx < DX) && (x < width);
      		  	     		 x++,myx++) {
        	  	         if (Mode & MODE_ONCE) {
	        	          Points += ((Mode & MODE_DELAU) ?
								 	  (Mode & MODE_STAT) ? 1 :
									  3 :
								 	  (Depth + 4));
		        	      }
 		        	      arrayr++;
      		  	      *arrayr = xr;
      		  	      if (!Grey) {
         	   	    arrayg++;
      		  	       *arrayg = xg;
      		  	       arrayb++;
      		  	       *arrayb = xb;
      		  	      }
      		  	     }
      		  	     x--;
      		  	    }
      		  	    /* next column (if not already there) */
      		  	    if (x < width) {
		        	     arrayr++;
		        	     if (!Grey) {
         	   	   arrayg++;
      		  	      arrayb++;
      		  	     }
      		  	    }
        	     	   }
        	     	   /* end of line, check 'Stop' and 'Help' */
        	     	   OkFlag = HandleProgressIDCMP();
#ifndef __MPCLI
      	         if (handle) {
	      	       while (agm = GetAmigaGuideMsg(handle)) {
   	   		     ReplyAmigaGuideMsg(agm);
      		       }
      		      }
        	     	   if (EGS_Win) {
        	     	    CopyEGS(y,&er,&eg,&eb);
        	     	   }
#endif
        	     	   /* if skipping lines then copy previous line */
        	     	   if (DY) {
        	     	    y++;
        		  	    for (myy = 0;
        	  	            (myy < DY) && (y<height);
        	  	            y++, myy++) {
        	  	        memcpy(arrayr, arrayr - width, width);
        	  	        arrayr += width;
        	  	        if (!Grey) {
        	  	         memcpy(arrayg, arrayg - width, width);
        	  	         arrayg += width;
        	  	         memcpy(arrayb, arrayb - width, width);
        	  	         arrayb += width;
        	  	        }
#ifndef __MPCLI
	        	     	  if (EGS_Win) {
   		     	      CopyEGS(y,&er,&eg,&eb);
        		     	  }
#endif
        	  	        if (Mode & MODE_ONCE) {
	        	         Points += ((Mode & MODE_DELAU) ?
								 	  (Mode & MODE_STAT) ? 1 :
									  3 :
								 	  (Depth + 4))*width;
	        	        }
        	  	       }
        	  	       y--;
        	  	      }
        	    	  }
        	    	  if ((Mode & MODE_DELAU) && (!(Mode & MODE_ONCE))) {
					   FreeTriangles();
                 }
        	    	  /* not ok - already displayed an error */
        	    	  if (!OkFlag) {
        	    	   e = (char *)-1;
         	     }
        	    	  else {
        	    	   /* Save image */
					   OkFlag = SaveFile();
#ifndef __MPCLI

					   /* Caclulate time (if we have not already) */
          	    	if (TimerBase) {
     	          	 GetSysTime(&time2);
     	          	 t2 = TRUE;
     	          	 SubTime(&time2,&time1);
     	    		   }
#endif
     	    		   /* Not ok - already displayed error message */
				 	   if (!OkFlag) {
					    e = (char *)-1;
					   }
	  	 			  }
		          }
		         }
		         if (OkFlag && ((Single == 0) || (Single == 2))) {
 				    /* Pass to ARexx for processing */
#ifndef __MPCLI
 					 if (strcmp(Prescript,"OFF")) {
    	    	     AddMessage("Prescript for last frame");
      	    	  f = Frames+1;
      	    	  Do = 0;
					  strcpy(buffer,Prescript);
					  strcat(buffer," %ld");
					  sprintf(buffer1,buffer,&Arexx);
					  OkFlag = !SendRxMsg(buffer1,FALSE);
					  if (!OkFlag) {
					   e = (char *)-1;
					  }
#endif					  
        	        if (OkFlag && Do && ((!Pic2_Open) || (Single == 2))) {
                  if (Pic2_Open) {
 	                Close24bit(&Pic2);
 	                Pic2_Open = FALSE;
 	               }
	               if (Pic1_Open) {
	                Close24bit(&Pic1);
	                Pic1_Open = FALSE;
	               }
     	     	      OkFlag = HandleProgressIDCMP();
     	     	      if (!OkFlag) {
     	     	       e = (char *)-1;
     	     	      }
     	     	      else {
        	    	    OkFlag = LoadFrames(FALSE,FALSE,TRUE);
        	    	    if (!OkFlag) {
        	    	     e = (char *)-1;
        	    	    }
        	    	   }
        	    	  }
        	    	  if (OkFlag && Do) {
    	    	      AddMessage("Saving last frame");
        	    	   memcpy(RED,Pic2.MPi->Red,width*height);
        	    	   if (!Grey) {
	        	    	   memcpy(GREEN,Pic2.MPi->Green,width*height);
   	     	    	   memcpy(BLUE,Pic2.MPi->Blue,width*height);
   	     	    	}
					   OkFlag = SaveFile();
         	    	if (!OkFlag) {
         	    	 e = (char *)-1;
         	    	}
        	    	  }
#ifndef __MPCLI
					 }
#endif
					}
		        }
  	    	     AddMessage("Cleaning up");
     	    	  if ((Mode & MODE_DELAU) && (Mode & MODE_ONCE)) {
				   FreeTriangles();
              }
  	    	     DeleteAllPoints();
  	    	     if (RED) MyFreeVec(RED);
  	    	     if (GREEN) MyFreeVec(GREEN);
	           if (BLUE) MyFreeVec(BLUE);
		        if (!Alloced && !e) {
		         e = "Error AllocVec for output";
		         e1 = NULL;
#ifndef __MPCLI
		         hnum = H_AllocVec;
#endif
		        }
#ifdef __MPCLI
				 }
				 else {
				  UnixError("Error opening interface",NULL);
				 }
				 CloseUnixInterface();
#else
		       }
		       else {
		        e = (char *)-1;
		       }
#endif
		       if (OkFlag) {
		        e = (char *)-1;
		       }
#ifndef __MPCLI
             if (myhost) {
              CloseDownARexxHost(myhost);
             }
#endif
		       if (!e) {
 		        e = "Error Opening points file";
		        e1 = NULL;
#ifndef __MPCLI
		        hnum = H_OpenPoints;
#endif
		       }
		       if (Pic2_Open) {
 	           Close24bit(&Pic2);
 	           Pic2_Open = FALSE;
 	          }
	          if (Pic1_Open) {
	           Close24bit(&Pic1);
	           Pic1_Open = FALSE;
	          }
#ifndef __MPCLI
			    /* reset requesters */
	          process->pr_WindowPtr = oldWindowPtr;
	         }
	         else {
	          e = "Error opening progress window";
	          e1 = NULL;
	          hnum = H_Progress;
	         }
	         /* close down everything */
	         CloseProgressWindow();
	         CloseDownScreen();
			   MyArgArrayDone();
            if (EGS) {
				 if (EGS_Win) {
				  EI_CloseWindow(EGS_Win);
				 }
				 if (EGS_BitMap) {
				  E_DisposeBitMap(EGS_BitMap);
				 }
				}
				if (EGSIntuiBase) {
				 CloseLibrary(EGSIntuiBase);
				}
				if (EGSGfxBase) {
				 CloseLibrary(EGSGfxBase);
				}
				if (EGSBase) {
				 CloseLibrary(EGSBase);
				}
				CloseLibrary(MPImageBase);
			  }
           if (!e) {
            e = "Unable to Open %s";
            e1 = "MPImage.library(0)";
            hnum = H_Library;
           }
           CloseLibrary(DiskfontBase);
          }
          if (!e) {
           e = "Unable to Open %s";
           e1 = "diskfont.library(36)";
           hnum = H_Library;
          }
          CloseLibrary(IconBase);
         }
         if (!e) {
          e = "Unable to Open %s";
          e1 = "icon.library(37)";
          hnum = H_Library;
         }
         CloseLibrary((struct Library *)UtilityBase);
        }
        if (!e) {
         e = "Unable to Open %s";
         e1= "utility.library(37)";
         hnum = H_Library;
        }
        CloseLibrary((struct Library *)AslBase);
       }
       if (!e) {
        e = "Unable to Open %s";
        e1 = "asl.library(37)";
        hnum = H_Library;
       }
       CloseLibrary((struct Library *)GadToolsBase);
      }
      if (!e) {
       e = "Unable to Open %s";
       e1 = "gadtools.library(37)";
       hnum = H_Library;
      }
      CloseLibrary((struct Library *)LayersBase);
     }
     if (!e) {
      e = "Unable to Open %s";
      e1 = "layers.library(37)";
      hnum = H_Library;
     }
     CloseLibrary((struct Library *)GfxBase);
    }
    if (!e) {
     e = "Unable to Open %s";
     e1 = "graphics.library(39)";
     hnum = H_Library;
    }
    CloseLibrary((struct Library *)RexxSysBase);
  }
  if (!e) {
   e = "Unable to Open %s";
   e1 = "rexxsyslib.library(0)";
   hnum = H_Library;
  }
#endif
  /* Display an error message */
  if (e != (char *)-1) {
   Error(e,"Quit",e1,hnum);
  }
#ifndef __MPCLI
 }
 if (TimerBase) {
  CloseDevice((struct IORequest *) &tr);
 }
 if (AmigaGuideBase) {
  if (handle) {
   while (agm = GetAmigaGuideMsg(handle)) {
    ReplyAmigaGuideMsg(agm);
   }
 	CloseAmigaGuide(handle);
  }
  CloseLibrary((struct Library *)AmigaGuideBase);
 }
 if (Chain) {
  DeletePool(Chain);
 }
 if (ReqToolsBase) {
  CloseLibrary((struct Library *)ReqToolsBase);
 }
 if (IntuitionBase) {
  CloseLibrary((struct Library *)IntuitionBase);
 }
#endif
#ifndef __MPCLI
#ifndef _M68881
 process->pr_Task.tc_TrapCode = (APTR)oldTrapCode;
#endif
#endif
 return 0;
}

/* Open a file
 * Returns	: TRUE if ok
 * filename	: name of file, or NULL for requester
 */
BOOL
MyOpen(char *filename,BOOL JustPoints) {
#ifndef __MPCLI
	char dirname[257];
#endif
	char *ifilename=NULL;
	BOOL ok=TRUE;
	FILE *fh;
	char buffer[257];
	LONG w=0,h=0;
	LONG xx,x1,yy,y1;
	UWORD				i;				/* General index */

	struct MyPoint *MyPoint;
	/* If filename supplied then use it otherwise use file requester */
	if (filename) {
		ifilename = filename;
	}
#ifndef __MPCLI
	else {
		struct FileRequester *filereq;	/* For file requester */
		if (filereq = (struct FileRequester *)AllocAslRequest(ASL_FileRequest,NULL)) {
			if (AslRequestTags((APTR) filereq,
						ASLFR_TitleText,(Tag) "MPRender - Pick project",
						ASLFR_RejectIcons, TRUE,
						ASLFR_PositiveText, (Tag) "Render",
						TAG_DONE)) {
				strncpy(dirname,filereq->fr_Drawer,256);
				if (AddPart(dirname,filereq->fr_File,256)) {
					ifilename=dirname;
				}
			}
     	   FreeAslRequest(filereq);
		}
	}
#endif
	/* If user did not cancel */
	if (ifilename) {
#ifndef __MPCLI
		OpenNewArgs(ifilename);		/* Load new parameters */
#endif
		/* Open file and skip the WB displayable names */
		if (fh=fopen(ifilename,"r")) {
			fgets(buffer,256,fh);
			if (JustPoints && strcmp(buffer,"TSMorph 2.0\n")) {
				Error("Invalid file format\nLine '%s'","Quit",buffer,H_FileFormat);
				ok = FALSE;
			}
			else {
				if (!JustPoints) {
					Pic1.filename[0]=0;
					Pic2.filename[0]=0;
					/* Keep file name */
					strcpy(MyFileName,ifilename);
					strcat(MyFileName,".%03ld");
					if (strcmp(buffer,"TSMorph 1.2\n")) {
						Error("Assuming version 1.0 file format","OK",NULL,HE_OldFormat);
					}
					else {
						fgets(buffer,256,fh);
					}
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					strcpy(Pic1.filename,buffer);
					fgets(buffer,256,fh);
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					strcpy(Pic2.filename,buffer);
					/* Get file name, set progress and try and load image */
					fgets(buffer,256,fh);
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					if (buffer[0]) {
						strcpy(Pic1.filename,buffer);
					}
					fgets(buffer,256,fh);
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					if (buffer[0]) {
						strcpy(Pic2.filename,buffer);
					}
					/* Loaded both so get anim name */
					fgets(AnimName,256,fh);
					if (strlen(AnimName)) {
						AnimName[strlen(AnimName)-1]=0;
					}
					/* Read and validate general information */
					fgets(buffer,256,fh);
					if (ok && (sscanf(buffer,"w=%ld,h=%ld,Frames=%ld,Single=%ld,Start=%ld",&w,&h,&Frames,&Single,&Start) != 5)) {
						Error("Invalid file format\nLine '%s'","Quit",buffer,H_FileFormat);
						ok = FALSE;
					}
					else {
						width = w;
						height = h;
					}
				}
			}
			if (ok) {
				PointCount = 0;
				/* Read and store all the points */
				while (ok &&
						fgets(buffer,256,fh) &&
						(sscanf(buffer,"x=%ld,y=%ld,x1=%ld,y1=%ld",&xx,&yy,&x1,&y1) == 4)) {
					if ((xx<0)||(xx>(width-1)) ||
						 (yy<0)||(yy>(height-1))) {
						Error("Point out of range\nLine '%s'","Quit",buffer,H_Range);
						ok = FALSE;
					}
					if (MyPoint = MyAllocMem(sizeof(struct MyPoint),MEMF_CLEAR)) {
						MyPoint->x = xx;
						MyPoint->y = yy;
						MyPoint->x1 = x1;
						MyPoint->y1 = y1;
						AddTail(&PointList,(struct Node *)MyPoint);
						++PointCount;
					}
					else {
						ok = FALSE;
					}
				}
			}
         Depth = MyArgInt("DEPTH",2,FALSE);
         Depth = min(Depth,20);
         Mode = MyArgInt("MODE",0,FALSE);
			if (Mode & MODE_DELAU) {
				Depth = 0;
				Mode &= ~MODE_CLOSEST;
			}
         if ((Single == 2) || (Single == 3)) {
         	Mode &= ~MODE_ONCE;						/* Irrelevant for anims */
         }
			if (ok) {
				if ((PointsAlloc = MyAllocVec(
						((Mode & MODE_DELAU) ?
					 	 (Mode & MODE_STAT) ? 1 :
					 	 3 :
					 	 (Depth + 4))
						*sizeof(struct MyPoint *) *		/* + 1 = NumPoints */
										((Mode & MODE_ONCE)?width*height:1),MEMF_CLEAR)) &&
					 (PointsX = MyAllocVec((max(PointCount,23) + 3)*sizeof(struct MyPoint *),MEMF_CLEAR)) &&
					 (PointsY = MyAllocVec((max(PointCount,23) + 3)*sizeof(struct MyPoint *),MEMF_CLEAR))) {
					/* Set up x and y order */
					Points = PointsAlloc;
					i = 0;
				   for (MyPoint = (struct MyPoint *)PointList.lh_Head;
						  MyPoint->MyNode.mln_Succ;
			   		  MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
						PointsX[i] = MyPoint;
						PointsY[i] = MyPoint;
						++i;
					}
				}
				else {
					Error("Out of memory for points","Quit",NULL,H_MemPointsR);
					ok = FALSE;
				}
			}
			/* Close file and cleanup */
			if (fclose(fh)) {
				if (ok) {
					Error("Error closing file '%s'","Quit",ifilename,H_CloseFile);
					ok = FALSE;
				}
			}
		}
		else {
			Error("Error opening file '%s'","Quit",ifilename,H_Open);
			ok = FALSE;
		}
	}
	else {
		ok = FALSE;
	}
	return ok;
}
