// MPImage - Amiga Image Conversion
// Copyright (C) © 1996 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.

// mark@topic.demon.co.uk
// mpaddock@cix.compulink.co.uk

#include "mpimage.h"

BOOL __asm __saveds RescaleMPImage(register __a0 struct MPImage *MPi,register __d0 UWORD x,
												register __d1 UWORD y);

static void RescaleXY(UBYTE *in,UWORD w,UWORD h,UBYTE *out,UWORD x,UWORD y,UBYTE *temp);
static void SmoothX(UBYTE *in,UBYTE *out,UWORD w,UWORD x,UWORD y);
static void SmoothY(UBYTE *in,UBYTE *out,UWORD h,UWORD x,UWORD y);
static void SmoothXY(UBYTE *in,UBYTE *out,UWORD w,UWORD h,UWORD x,UWORD y);
static void RescaleXYRGB(UBYTE *inr,UBYTE *ing,UBYTE *inb,UWORD w,UWORD h,UBYTE *outr,UBYTE *outg,UBYTE *outb,
			UWORD x,UWORD y,UBYTE *tr,UBYTE *tg,UBYTE *tb);

/****** MPImage.library/RescaleMPImage **************************************
*
*   NAME   
*  RescaleMPImage -- Scales an image created by LoadMPImage() (V3)
*
*   SYNOPSIS
*  error = RescaleMPImage(MPi, x, y)
*  D0                     A0   D0 D1
*
*  BOOL RescaleMPImage(struct MPImage *, UWORD, UWORD);
*
*   FUNCTION
*  Scales an Image loaded by LoadMPImage() to new width and height.
*
*   INPUTS
*  MPi - Image loaded by LoadMPImage
*  x   - New width of image
*  y   - New height of image
*
*   RESULT
*  error - 1 for success, 0 for failure.
*          Use MPImageErrorMessage() to get error.
*
*   EXAMPLE
*
*   NOTES
*  Rescaling of bitmaps is done using BitMapScale().
*  Other rescaling is done using custom code with smoothing.
*
*  If this function fails then the MPImage is no longer usable and
*  FreeMPImage() should be called to free it.
*
*  Version 4.3 is faster for RGB.
*
*   BUGS
*  Bitmaps may not scale smoothly.
*  The rescaling of EGS images is not efficent.
*
*   SEE ALSO
*  LoadMPImage(),MPImageErrorMessage(),FreeMPImage(),
*  graphics.library/BitMapScale().
*
*****************************************************************************
*
*/
BOOL __asm __saveds
RescaleMPImage(register __a0 struct MPImage *MPi,register __d0 UWORD x,
												register __d1 UWORD y) {
	UBYTE *msg;
	if (!SetupScreen()) {
		OpenProgressWindow();
	}
	if (MPi->BitMap) {
		// Normal BitMap
		struct BitMap *bitmap;
		if (!(bitmap = AllocBitMap(x,y, MPi->BitMap->Depth,BMF_DISPLAYABLE,MPi->BitMap))) {
			msg = "Can't Allocate BitMap";
		}
		else {
			struct BitScaleArgs BitScaleArgs;
			AddMessage("Scaling BitMap");
			BitScaleArgs.bsa_SrcX 			= 0;
			BitScaleArgs.bsa_SrcY 			= 0;
			BitScaleArgs.bsa_SrcWidth 		= MPi->Width;
			BitScaleArgs.bsa_SrcHeight 	= MPi->Height;
			BitScaleArgs.bsa_DestX 			= 0;
			BitScaleArgs.bsa_DestY 			= 0;
			BitScaleArgs.bsa_DestWidth 	= x;
			BitScaleArgs.bsa_DestHeight	= y;
			BitScaleArgs.bsa_XSrcFactor	= MPi->Width;
			BitScaleArgs.bsa_XDestFactor	= x;
			BitScaleArgs.bsa_YSrcFactor 	= MPi->Height;
			BitScaleArgs.bsa_YDestFactor	= y;
			BitScaleArgs.bsa_SrcBitMap 	= MPi->BitMap;
			BitScaleArgs.bsa_DestBitMap	= bitmap;
			BitScaleArgs.bsa_Flags 		= 0;
			BitMapScale(&BitScaleArgs);
			if (MPi->Object) {	// Dispose object (frees bit map as well...)
				DisposeDTObject(MPi->Object);
				MPi->Object = NULL;
			}
			else {
				FreeBitMap(MPi->BitMap);
			}
			MPi->BitMap = bitmap;
			MPi->Width = x;
			MPi->Height = y;
			CloseProgressWindow();
			CloseDownScreen();
			return TRUE;
		}
	}
	else {
		if (MPi->EGS_BitMap) {
			// EGS BitMap
			UBYTE *red,*green=NULL,*blue=NULL,*plane;
			UBYTE *r,*g=NULL,*b=NULL,*t=NULL,*t1,*t2;
			UBYTE *rr,*gg,*bb;
			UWORD i,j;
			AddMessage("Scaling EGS BitMap");
			if (!(EGSBase = OpenLibrary((char *)"egs.library",0))) {
				msg = "Can't open egs.library";
				strcpy(ErrorMessage,msg);
				CloseProgressWindow();
				CloseDownScreen();
				return FALSE;
			}
			if ((red = AllocVec((int)MPi->Width*MPi->Height,0)) &&
			    (green = AllocVec((int)MPi->Width*MPi->Height,0)) &&
			    (blue = AllocVec((int)MPi->Width*MPi->Height,0))) {
				plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
				rr = red;
				gg = green;
				bb = blue;
				AddMessage("Converting EGS to Chunky");
				SetMax(MPi->Height);
				for (i = 0; i<MPi->Height; i++) {
					SetCur(i);
					for (j = 0; j<MPi->Width; j++) {
						*rr++ = *plane++;
						*gg++ = *plane++;
						*bb++ = *plane++;
						plane++;
					}
					plane += (MPi->EGS_BitMap->BytesPerRow - (4*MPi->Width));
				}
				E_DisposeBitMap(MPi->EGS_BitMap);
				MPi->EGS_BitMap = NULL;
				if ((r = AllocVec((int)x*y,0)) &&
				    (g = AllocVec((int)x*y,0)) &&
				    (b = AllocVec((int)x*y,0)) &&
				    (t = AllocVec((int)x*y,0))) {
				   AddMessage("Scaling RGB");
				   if ((t1 = AllocVec((int)x*y,0)) &&
				    	 (t2 = AllocVec((int)x*y,0))) {
						RescaleXYRGB(red,green,blue,MPi->Width,MPi->Height,r,g,b,x,y,t,t1,t2);
						FreeVec(t1);
						FreeVec(t2);
					}
					else {
						if (t1) {
							FreeVec(t1);
						}
						RescaleXY(red,MPi->Width,MPi->Height,r,x,y,t);
						RescaleXY(green,MPi->Width,MPi->Height,g,x,y,t);
						RescaleXY(blue,MPi->Width,MPi->Height,b,x,y,t);
					}
					FreeVec(red);
					red = NULL;
					FreeVec(green);
					green = NULL;
					FreeVec(blue);
					blue = NULL;
					if (MPi->EGS_BitMap = E_AllocBitMap(x,y,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
						plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
						rr = r;
						gg = g;
						bb = b;
						AddMessage("Converting to EGS BitMap");
						SetMax(y);
						for (i = 0; i<y; i++) {
							SetCur(j);
							for (j = 0; j<x; j++) {
								*plane++ = *rr++;
								*plane++ = *gg++;
								*plane++ = *bb++;
								plane++;
							}
							plane += (MPi->EGS_BitMap->BytesPerRow - (4*x));
						}
						MPi->Width = x;
						MPi->Height = y;
						FreeVec(r);
						FreeVec(g);
						FreeVec(b);
						FreeVec(t);
						CloseProgressWindow();
						CloseDownScreen();
						return TRUE;
					}
					else {	// E_AllocBitMap
						msg = "Can't Allocate EGS BitMap";
					}
				}
				else {	// AllocVec red,green,blue
					msg = "Out of memory";
				}
				if (r) FreeVec(r);
				if (g) FreeVec(g);
				if (b) FreeVec(b);
				if (t) FreeVec(t);
			}
			else {	// AllocVec red,green,blue
				msg = "Out of memory";
			}
			if (red) FreeVec(red);
			if (green) FreeVec(green);
			if (blue) FreeVec(blue);
			CloseLibrary(EGSBase);
		}
		else {
			// RGB || Grey
			if (MPi->GreyScale) {
				UBYTE *red,*t;
				if ((red = AllocVec((int)x*y,0)) &&
					 (t = AllocVec((int)x*y,0))) {
					AddMessage("Scaling Grey");
					RescaleXY(MPi->Red,MPi->Width,MPi->Height,red,x,y,t);
					FreeVec(MPi->Red);
					FreeVec(t);
					MPi->Width = x;
					MPi->Height = y;
					MPi->Red = red;
					MPi->Green = red;
					MPi->Blue = red;
					CloseProgressWindow();
					CloseDownScreen();
					return TRUE;
				}
				else {	// AllocVec red,green,blue
					msg = "Out of memory";
					if (red) {
						FreeVec(red);
					}
				}
			}
			else {
				UBYTE *red,*green=NULL,*blue=NULL,*t,*t1,*t2;
				if ((red = AllocVec((int)x*y,0)) &&
				    (green = AllocVec((int)x*y,0)) &&
				    (blue = AllocVec((int)x*y,0)) &&
				    (t = AllocVec((int)x*y,0))) {
				   AddMessage("Scaling RGB");
				   if ((t1 = AllocVec((int)x*y,0)) &&
				    	 (t2 = AllocVec((int)x*y,0))) {
						RescaleXYRGB(MPi->Red,MPi->Green,MPi->Blue,MPi->Width,MPi->Height,red,green,blue,x,y,t,t1,t2);
						FreeVec(t1);
						FreeVec(t2);
					}
					else {
						if (t1) {
							FreeVec(t1);
						}
						RescaleXY(MPi->Red,MPi->Width,MPi->Height,red,x,y,t);
						RescaleXY(MPi->Green,MPi->Width,MPi->Height,green,x,y,t);
						RescaleXY(MPi->Blue,MPi->Width,MPi->Height,blue,x,y,t);
					}
					FreeVec(MPi->Red);
					FreeVec(MPi->Green);
					FreeVec(MPi->Blue);
					FreeVec(t);
					MPi->Width = x;
					MPi->Height = y;
					MPi->Red = red;
					MPi->Green = green;
					MPi->Blue = blue;
					CloseProgressWindow();
					CloseDownScreen();
					return TRUE;
				}
				else {	// AllocVec red,green,blue
					msg = "Out of memory";
				}
				if (red) FreeVec(red);
				if (green) FreeVec(green);
				if (blue) FreeVec(blue);
			}
		}
	}
	strcpy(ErrorMessage,msg);
	CloseProgressWindow();
	CloseDownScreen();
	return FALSE;
}

/* in = chunky in
 * w  = old width
 * h  = old height
 * out= chunky out
 * x  = new width
 * y  = new height
 * t  = Temp buffer
 */
static void
RescaleXY(UBYTE *in,UWORD w,UWORD h,UBYTE *out,UWORD x,UWORD y,UBYTE *t) {
	float xfact,yfact;

	xfact = ((float)w)/x;
	yfact = ((float)h)/y;

	if (x == w) {
		if (y == h) {
			AddMessage("Copying");
			memcpy(out,in,w*h);
			return;
		}
		if (y < h) {
			// x == w, y < h
			UWORD j;
			UBYTE *op = out;
			float tf=0.0, bf;
			float yf = 0.0;
			UWORD ys=0,ye;

			AddMessage("Scaling <Y");
			SetMax(y);
			for (j=0; j<y; j++) {
				UWORD i;
				UBYTE *tin;

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				bf = yf - ye;
				if (ys > 0) {
					tin = in + ((ys-1) * w);
				}
				else {
					tin = in + (ys * w);
				}

				for (i=0; i<x; i++) {
					float newf=0.0;
					UWORD l;
					UBYTE *tint = tin;

					if (ys > 0) {
						newf += tint[i] * tf;
						tint += w;
					}
					for (l = ys; l < ye; l++) {
						newf += tint[i];
						tint += w;
					}
					if (ye < h) {
						newf += tint[i] * bf;
					}
					*op++ = newf/yfact;
				}
				ys = ye + 1;
				tf = ys - yf;
			}
			return;
		}
		{
			// x == w, y > h
			UWORD j;
			UWORD ys=0,ye;
			float yf=0.0;
			UBYTE *op = t;
			UBYTE *tin;
			UWORD i;

			AddMessage("Scaling >Y");
			SetMax(y);
			for (j=1; j<y; j++) {

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				tin = in + (ys * w);

				if (ys == ye) {
					for (i=0; i<x; i++) {
						*op++ = *tin++;
					}
				}
				else {
					float tf,bf;

					bf = yf - floor(yf);
					tf = yfact - bf;
					for (i=0; i<x; i++) {
						*op++ = ((*tin * tf) + (tin[w] * bf)) / yfact;
						tin++;
					}
					ys = ye;
				}
			}
			tin = in + ((h-1) * w);
			for (i=0; i<x; i++) {
				*op++ = *tin++;
			}
			SmoothY(t,out,h,x,y);
			return;
		}
	}
	// x != w
	if (x < w) {
		// x < w
		if (y == h) {
			// x < w, y == h
			UWORD j;
			UBYTE *op = out;
			UBYTE *tin = in;

			AddMessage("Scaling <X");
			SetMax(y);
			for (j=0; j<y; j++) {
				float xf = 0.0;
				float lf=0.0,rf;
				UWORD xs=0,xe;
				UWORD i;

				SetCur(j);
				for (i=0; i<x; i++) {
					float newf=0.0;
					UWORD k;

					xf += xfact;
					xe = (UWORD)xf;
					rf = xf - xe;

					if (xs > 0) {
						newf += tin[xs-1] * lf;
					}
					for (k = xs; k < xe; k++) {
						newf += tin[k];
					}
					if (xe < w) {
						newf += tin[xe] * rf;
					}
					*op++ = newf/xfact;
					xs = xe + 1;
					lf = xs - xf;
				}
				tin += w;
			}
			return;
		}
		if (y < h) {
			// x < w, y < h
			UWORD j;
			float divf;
			UBYTE *op = out;
			float tf=0.0, bf;
			float yf = 0.0;
			UWORD ys=0,ye;

			divf = xfact * yfact;

			AddMessage("Scaling <X/<Y");
			SetMax(y);
			for (j=0; j<y; j++) {
				float xf = 0.0;
				float lf=0.0,rf;
				UWORD xs=0,xe;
				UWORD i;

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				bf = yf - ye;

				for (i=0; i<x; i++) {
					float newf=0.0;
					UBYTE *tin;
					UWORD l;

					xf += xfact;
					xe = (UWORD)xf;
					rf = xf - xe;

					if (ys > 0) {
						UWORD k;
						tin = in + ((ys-1) * w);
						if (xs > 0) {
							newf += tin[xs-1] * lf * tf;
						}
						for (k = xs; k < xe; k++) {
							newf += tin[k] * tf;
						}
						if (xe < w) {
							newf += tin[xe] * rf * tf;
						}
						tin += w;
					}
					else {
						tin = in + (ys * w);
					}
					for (l = ys; l < ye; l++) {
						UWORD k;
						if (xs > 0) {
							newf += tin[xs-1] * lf;
						}
						for (k = xs; k < xe; k++) {
							newf += tin[k];
						}
						if (xe < w) {
							newf += tin[xe] * rf;
						}
						tin += w;
					}
					if (ye < h) {
						UWORD k;
						newf += tin[xs-1] * lf * bf;
						for (k = xs; k < xe; k++) {
							newf += tin[k] * bf;
						}
						if (xe < w) {
							newf += tin[xe] * rf * bf;
						}
					}
					*op++ = newf/divf;
					xs = xe + 1;
					lf = xs - xf;
				}
				ys = ye + 1;
				tf = ys - yf;
			}
			return;
		}
		{
			// x < w, y > h
			UWORD j;
			UWORD ys=0,ye;
			float yf=0.0;
			UBYTE *op = t;
			UBYTE *tin;
			UWORD i;
			float divf = xfact * yfact;
			UWORD xs,xe;
			float xf;
			float lf,rf;

			AddMessage("Scaling <X/>Y");
			SetMax(y);
			for (j=1; j<y; j++) {

				SetCur(j);
				xf = 0.0;
				lf = 0.0;
				xs = 0;
				yf += yfact;
				ye = (UWORD)yf;
				tin = in + (ys * w);

				if (ys == ye) {
					for (i=0; i<x; i++) {
						float newf=0.0;
						UWORD k;

						xf += xfact;
						xe = (UWORD)xf;
						rf = xf - xe;

						if (xs > 0) {
							newf += tin[xs-1] * lf;
						}
						for (k = xs; k < xe; k++) {
							newf += tin[k];
						}
						if (xe < w) {
							newf += tin[xe] * rf;
						}
						*op++ = newf/xfact;
						xs = xe + 1;
						lf = xs - xf;
					}
				}
				else {
					float tf,bf;
					UWORD k;

					bf = yf - floor(yf);
					tf = yfact - bf;

					for (i=0; i<x; i++) {
						float newf=0.0;

						xf += xfact;
						xe = (UWORD)xf;
						rf = xf - xe;

						if (xs > 0) {
							newf += ((tin[xs-1] * tf) + (tin[xs-1+w] * bf)) * lf;
						}
						for (k = xs; k < xe; k++) {
							newf += (tin[k] * tf) + (tin[k+w] * bf);
						}
						if (xe < w) {
							newf += ((tin[xe] * tf) + (tin[xe+w] * bf)) * rf;
						}
						*op++ = newf/divf;
						xs = xe + 1;
						lf = xs - xf;
					}
					ys = ye;
				}
			}
			tin = in + ((h-1) * w);
			xs = 0;
			lf = 0.0;
			xf = 0.0;
			for (i=0; i<x; i++) {
				float newf=0.0;
				UWORD k;

				xf += xfact;
				xe = (UWORD)xf;
				rf = xf - xe;

				if (xs > 0) {
					newf += tin[xs-1] * lf;
				}
				for (k = xs; k < xe; k++) {
					newf += tin[k];
				}
				if (xe < w) {
					newf += tin[xe] * rf;
				}
				*op++ = newf/xfact;
				xs = xe + 1;
				lf = xs - xf;
			}
			SmoothY(t,out,h,x,y);
			return;
		}
	}
	// x > w
 	if (y == h) {
		// x > w, y == h
		UWORD j;
		UBYTE *op = t;
		UBYTE *tin = in;
		UWORD i;
		UBYTE *tint;

		AddMessage("Scaling >X");
		SetMax(y);
		for (j=0; j<y; j++) {
			UWORD xs=0,xe;
			float xf=0.0;

			SetCur(j);
			tint = tin;
			for (i=1; i<x; i++) {
				xf += xfact;
				xe = (UWORD)xf;
				if (xs == xe) {
					*op++ = *tint;
				}
				else {
					float lf,rf;

					rf = xf - floor(xf);
					lf = xfact - rf;
					*op++ = ((*tint * lf) + (tint[1] * rf)) / xfact;
					tint++;
					xs = xe;
				}
			}
			*op++ = *tint;
			tin += w;
		}
		SmoothX(t,out,w,x,y);
		return;
	}
	if (y > h) {
		// x > w, y > h
		UWORD j;
		UWORD ys=0,ye;
		float yf=0.0;
		UBYTE *op = t;
		UBYTE *tin;
		UWORD i;
		float divf = xfact * yfact;
		UWORD xs,xe;
		float xf;

		AddMessage("Scaling >X/>Y");
		SetMax(y);
		for (j=1; j<y; j++) {

			SetCur(j);
			xs=0;
			xf=0.0;
			yf += yfact;
			ye = (UWORD)yf;
			tin = in + (ys * w);

			if (ys == ye) {
				for (i=1; i<x; i++) {
					xf += xfact;
					xe = (UWORD)xf;
					if (xs == xe) {
						*op++ = *tin;
					}
					else {
						float lf,rf;

						rf = xf - floor(xf);
						lf = xfact - rf;
						*op++ = ((*tin * lf) + (tin[1] * rf)) / xfact;
						tin++;
						xs = xe;
					}
				}
				*op++ = *tin;
			}
			else {
				float tf,bf;

				bf = yf - floor(yf);
				tf = yfact - bf;
				for (i=1; i<x; i++) {
					xf += xfact;
					xe = (UWORD)xf;
					if (xs == xe) {
						*op++ = ((*tin * tf) + (tin[w] * bf)) / yfact;
					}
					else {
						float lf,rf;

						rf = xf - floor(xf);
						lf = xfact - rf;
						*op++ = ((*tin * lf * tf) + (tin[1] * rf * tf) +
									(tin[w] * lf * bf) + (tin[w+1] * rf * bf)) / divf;
						tin++;
						xs = xe;
					}
				}
				*op++ = *tin;
				ys = ye;
			}
		}
		tin = in + ((h-1) * w);
		xf = 0.0;
		xs = 0;
		for (i=1; i<x; i++) {
			xf += xfact;
			xe = (UWORD)xf;
			if (xs == xe) {
				*op++ = *tin;
			}
			else {
				float lf,rf;

				rf = xf - floor(xf);
				lf = xfact - rf;
				*op++ = ((*tin * lf) + (tin[1] * rf)) / xfact;
				tin++;
				xs = xe;
			}
		}
		*op = *tin;
		SmoothXY(t,out,w,h,x,y);
		return;
	}
	{
		// x > w, y < h
		UWORD j;
		UBYTE *op = t;
		float tf=0.0, bf;
		float yf = 0.0;
		UWORD ys=0,ye;
		UBYTE *tin;
		float divf = xfact * yfact;

		AddMessage("Scaling >X/<Y");
		SetMax(y);
		for (j=0; j<y; j++) {
			UWORD i;
			UBYTE *tint;
			float newf;
			UWORD l;
			UWORD xs=0,xe;
			float xf=0.0;

			SetCur(j);
			yf += yfact;
			ye = (UWORD)yf;
			bf = yf - ye;
			if (ys > 0) {
				tin = in + ((ys-1) * w);
			}
			else {
				tin = in + (ys * w);
			}

			for (i=1; i<x; i++) {
				newf=0.0;
				xf += xfact;
				xe = (UWORD)xf;
				tint = tin;

				if (xs == xe) {
					if (ys > 0) {
						newf += tint[xs] * tf;
						tint += w;
					}
					for (l = ys; l < ye; l++) {
						newf += tint[xs];
						tint += w;
					}
					if (ye < h) {
						newf += tint[xs] * bf;
					}
					*op++ = newf/yfact;
				}
				else {
					float lf,rf;

					rf = xf - floor(xf);
					lf = xfact - rf;
					if (ys > 0) {
						newf += ((tint[xs] * lf) + (tint[xe] * rf)) * tf;
						tint += w;
					}
					for (l = ys; l < ye; l++) {
						newf += ((tint[xs] * lf) + (tint[xe] * rf));
						tint += w;
					}
					if (ye < h) {
						newf += ((tint[xs] * lf) + (tint[xe] * rf)) * bf;
					}
					*op++ = newf/divf;
					xs = xe;
				}
			}
			tint = tin;
			newf = 0.0;
			if (ys > 0) {
				newf += tint[w-1] * tf;
				tint += w;
			}
			for (l = ys; l < ye; l++) {
				newf += tint[w-1];
				tint += w;
			}
			if (ye < h) {
				newf += tint[w-1] * bf;
			}
			*op++ = newf/yfact;
			ys = ye + 1;
			tf = ys - yf;
		}
		SmoothX(t,out,w,x,y);
		return;
	}
}

static void
SmoothX(UBYTE *in,UBYTE *out,UWORD w,UWORD x,UWORD y) {
	int t;
	int i,j;
	UBYTE *p,*o;

	AddMessage("Smoothing X");
	t = x/w;
	if (t < 2) {	// less than 2 times size
		AddMessage("Copying");
		memcpy(out,in,x*y);
		return;
	}
	if (t < 3) {	// less than 3 times the size
		p = in;
		o = out;
		AddMessage("<3 Times");
		SetMax(y);
		for (j = 0; j < y; ++j) {
			SetCur(j);
			for (i = 1; i < x; ++i) {	// Skip first column
				*o++ = (*p + p[1])>>1;
				++p;
			}
			*o++ = *p++;
		}
		return;
	}	// >= 3 times size
	p = in;
	o = out;
	AddMessage(">=3 Times");
	SetMax(y);
	for (j = 0; j < y; ++j) {
		SetCur(j);
		*o++ = *p;
		for (i = 2; i < x; ++i) {	// Skip first and last columns
			*o++ = (*p + p[1] + p[2])/3;
			++p;
		}
		++p;
		*o++ = *p++;
	}
}

static void
SmoothY(UBYTE *in,UBYTE *out,UWORD h,UWORD x,UWORD y) {
	int t;
	int i,j;
	UBYTE *p,*p1,*p2,*o;

	AddMessage("Smoothing Y");
	t = y/h;
	if (t < 2) {
		AddMessage("Copying");
		memcpy(out,in,x*y);
		return;
	}
	if (t < 3) {
		p = in;
		p1 = in;
		o = out;
		
		for (i = 0; i < x; ++i) {
			*o++ = *p++;
		}
		AddMessage("<3 Times");
		SetMax(y);
		for (j = 1; j < y; ++j) {	// Skip first row
			SetCur(j);
			for (i = 0; i < x; ++i) {
				*o++ = (*p++ + *p1++)>>1;
			}
		}
		return;
	}
	p1 = in;
	p = in;
	p2 = in + x + x;
	o = out;
	for (i = 0; i < x; ++i) {
		*o++ = *p++;
	}
	AddMessage(">=3 Times");
	SetMax(y);
	for (j = 2; j < y; ++j) {	// Skip first and last rows
		SetCur(j);
		for (i = 0; i < x; ++i) {
			*o++ = (*p++ + *p1++ + *p2++)/3;
		}
	}
	for (i = 0; i < x; ++i) {
		*o++ = *p++;
	}
}

static void
SmoothXY(UBYTE *in,UBYTE *out,UWORD w,UWORD h,UWORD x,UWORD y) {
	int tx,ty;
	int i,j;
	UBYTE *p,*p1,*p2,*o;

	AddMessage("Smoothing X/Y");
	tx = x/w;

	ty = y/h;

	if ((tx < 2) && (ty < 2)) {
		AddMessage("Copying");
		memcpy(out,in,x*y);
		return;
	}

	if (ty < 2) {	// No y smooth required
		SmoothX(in,out,w,x,y);
		return;
	}

	if (tx < 2) {	// No x smooth required
		SmoothY(in,out,h,x,y);
		return;
	}

	if (tx < 3) {
		if (ty < 3) {
			p = in;
			p1 = in;
			o = out;
			*o++ = *p;
			for (i = 1; i < x; ++i) {
				*o++ = (*p + p[1])>>1;
				++p;
			}
			++p;
			AddMessage("X<3 Y<3 Times");
			SetMax(y);
			for (j = 1; j < y; ++j) {
				SetCur(j);
				*o++ = (*p + *p1)>>1;
				for (i = 1; i < x; ++i) {
					*o++ = (*p + p[1] + *p1 + p1[1])>>2;
					++p;
					++p1;
				}
				++p;
				++p1;
			}
			return;
		} // tx < 3 ty >=3
		p1 = in;
		p = in;
		p2 = in + x + x;
		o = out;

		*o++ = *p;
		for (i = 1; i < x; ++i) {
			*o++ = (*p + p[1])>>1;
			++p;
		}
		++p;
		AddMessage("X<3 Y>=3 Times");
		SetMax(y);
		for (j = 2; j < y; ++j) {
			SetCur(j);
			*o++ = (*p + *p1 + *p2)/3;
			for (i = 1; i < x; ++i) {
				*o++ = (*p + p[1] + *p1 + p1[1] + *p2 + p2[1])/6;
				++p;
				++p1;
				++p2;
			}
			++p;
			++p1;
			++p2;
		}
		*o++ = *p;
		for (i = 1; i < x; ++i) {
			*o++ = (*p + p[1])>>1;
			++p;
		}
		return;
	} // tx >= 3
	if (ty < 3) {
		p1 = in;
		p = in;
		o = out;
		*o++ = *p;
		for (i = 2; i < x; ++i) {	// Skip first and last columns
			*o++ = (*p + p[1] + p[2])/3;
			++p;
		}
		++p;
		*o++ = *p++;
		AddMessage("X>=3 Y<3 Times");
		SetMax(y);
		for (j = 1; j < y; ++j) {
			SetCur(j);
			*o++ = (*p + *p1)>>1;
			for (i = 2; i < x; ++i) {
				*o++ = (*p + p[1] + p[2] + *p1 + p1[1] + p1[2])/6;
				++p;
				++p1;
			}
			++p1;
			++p;

			*o++ = (*p++ + *p1++)>>1;
		}
		return;
	}	// tx >= 3, ty >= 3
	p1 = in;
	p = in;
	p2 = in + x + x;
	o = out;

	*o++ = *p;
	for (i = 2; i < x; ++i) {	// Skip first and last columns
		*o++ = (*p + p[1] + p[2])/3;
		++p;
	}
	++p;
	*o++ = *p++;

	AddMessage("X>=3 Y>=3 Times");
	SetMax(y);
	for (j = 2; j < y; ++j) {
		SetCur(j);
		*o++ = (*p + *p1 + *p2)/3;
		for (i = 2; i < x; ++i) {
			*o++ = (*p + p[1] + p[2] + *p1 + p1[1] + p1[2] + *p2 + p2[1] + p2[2])/9;
			++p;
			++p1;
			++p2;
		}
		++p1;
		++p;
		++p2;

		*o++ = (*p++ + *p1++ + *p2++)/3;
	}
	*o++ = *p;
	for (i = 2; i < x; ++i) {	// Skip first and last columns
		*o++ = (*p + p[1] + p[2])/3;
		++p;
	}
	*o = *p;
}

/* inr = chunky in r
 * ing = chunky in g
 * inb = chunky in b
 * w  = old width
 * h  = old height
 * outr= chunky out r
 * outg= chunky out g
 * outb= chunky out b
 * x  = new width
 * y  = new height
 * tr  = Temp buffer r
 * tg  = Temp buffer g
 * tb  = Temp buffer b
 */
static
void
RescaleXYRGB(UBYTE *inr,UBYTE *ing,UBYTE *inb,UWORD w,UWORD h,UBYTE *outr,UBYTE *outg,UBYTE *outb,
			UWORD x,UWORD y,UBYTE *tr,UBYTE *tg,UBYTE *tb) {
	float xfact,yfact;

	xfact = ((float)w)/x;
	yfact = ((float)h)/y;

	if (x == w) {
		if (y == h) {
			AddMessage("Copying");
			memcpy(outr,inr,w*h);
			memcpy(outg,ing,w*h);
			memcpy(outb,inb,w*h);
			return;
		}
		if (y < h) {
			// x == w, y < h
			UWORD j;
			UBYTE *opr = outr;
			UBYTE *opg = outg;
			UBYTE *opb = outb;
			float tf=0.0, bf;
			float yf = 0.0;
			UWORD ys=0,ye;

			AddMessage("Scaling <Y");
			SetMax(y);
			for (j=0; j<y; j++) {
				UWORD i;
				UBYTE *tinr;
				UBYTE *ting;
				UBYTE *tinb;

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				bf = yf - ye;
				if (ys > 0) {
					tinr = inr + ((ys-1) * w);
					ting = ing + ((ys-1) * w);
					tinb = inb + ((ys-1) * w);
				}
				else {
					tinr = inr + (ys * w);
					ting = ing + (ys * w);
					tinb = inb + (ys * w);
				}

				for (i=0; i<x; i++) {
					float newfr=0.0;
					float newfg=0.0;
					float newfb=0.0;
					UWORD l;
					UBYTE *tintr = tinr;
					UBYTE *tintg = ting;
					UBYTE *tintb = tinb;

					if (ys > 0) {
						newfr += tintr[i] * tf;
						tintr += w;
						newfg += tintg[i] * tf;
						tintg += w;
						newfb += tintb[i] * tf;
						tintb += w;
					}
					for (l = ys; l < ye; l++) {
						newfr += tintr[i];
						tintr += w;
						newfg += tintg[i];
						tintg += w;
						newfb += tintb[i];
						tintb += w;
					}
					if (ye < h) {
						newfr += tintr[i] * bf;
						newfg += tintg[i] * bf;
						newfb += tintb[i] * bf;
					}
					*opr++ = newfr/yfact;
					*opg++ = newfg/yfact;
					*opb++ = newfb/yfact;
				}
				ys = ye + 1;
				tf = ys - yf;
			}
			return;
		}
		{
			// x == w, y > h
			UWORD j;
			UWORD ys=0,ye;
			float yf=0.0;
			UBYTE *opr = tr;
			UBYTE *tinr;
			UBYTE *opg = tg;
			UBYTE *ting;
			UBYTE *opb = tb;
			UBYTE *tinb;
			UWORD i;

			AddMessage("Scaling >Y");
			SetMax(y);
			for (j=1; j<y; j++) {

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				tinr = inr + (ys * w);
				ting = ing + (ys * w);
				tinb = inb + (ys * w);

				if (ys == ye) {
					for (i=0; i<x; i++) {
						*opr++ = *tinr++;
						*opg++ = *ting++;
						*opb++ = *tinb++;
					}
				}
				else {
					float tf,bf;

					bf = yf - floor(yf);
					tf = yfact - bf;
					for (i=0; i<x; i++) {
						*opr++ = ((*tinr * tf) + (tinr[w] * bf)) / yfact;
						tinr++;
						*opg++ = ((*ting * tf) + (ting[w] * bf)) / yfact;
						ting++;
						*opb++ = ((*tinb * tf) + (tinb[w] * bf)) / yfact;
						tinb++;
					}
					ys = ye;
				}
			}
			tinr = inr + ((h-1) * w);
			ting = ing + ((h-1) * w);
			tinb = inb + ((h-1) * w);
			for (i=0; i<x; i++) {
				*opr++ = *tinr++;
				*opg++ = *ting++;
				*opb++ = *tinb++;
			}
			SmoothY(tr,outr,h,x,y);
			SmoothY(tg,outg,h,x,y);
			SmoothY(tb,outb,h,x,y);
			return;
		}
	}
	// x != w
	if (x < w) {
		// x < w
		if (y == h) {
			// x < w, y == h
			UWORD j;
			UBYTE *opr = outr;
			UBYTE *tinr = inr;
			UBYTE *opg = outg;
			UBYTE *ting = ing;
			UBYTE *opb = outb;
			UBYTE *tinb = inb;

			AddMessage("Scaling <X");
			SetMax(y);
			for (j=0; j<y; j++) {
				float xf = 0.0;
				float lf=0.0,rf;
				UWORD xs=0,xe;
				UWORD i;

				SetCur(j);
				for (i=0; i<x; i++) {
					float newfr=0.0;
					float newfg=0.0;
					float newfb=0.0;
					UWORD k;

					xf += xfact;
					xe = (UWORD)xf;
					rf = xf - xe;

					if (xs > 0) {
						newfr += tinr[xs-1] * lf;
						newfg += ting[xs-1] * lf;
						newfb += tinb[xs-1] * lf;
					}
					for (k = xs; k < xe; k++) {
						newfr += tinr[k];
						newfg += ting[k];
						newfb += tinb[k];
					}
					if (xe < w) {
						newfr += tinr[xe] * rf;
						newfg += ting[xe] * rf;
						newfb += tinb[xe] * rf;
					}
					*opr++ = newfr/xfact;
					*opg++ = newfg/xfact;
					*opb++ = newfb/xfact;
					xs = xe + 1;
					lf = xs - xf;
				}
				tinr += w;
				ting += w;
				tinb += w;
			}
			return;
		}
		if (y < h) {
			// x < w, y < h
			UWORD j;
			float divf;
			UBYTE *opr = outr;
			UBYTE *opg = outg;
			UBYTE *opb = outb;
			float tf=0.0, bf;
			float yf = 0.0;
			UWORD ys=0,ye;

			divf = xfact * yfact;

			AddMessage("Scaling <X/<Y");
			SetMax(y);
			for (j=0; j<y; j++) {
				float xf = 0.0;
				float lf=0.0,rf;
				UWORD xs=0,xe;
				UWORD i;

				SetCur(j);
				yf += yfact;
				ye = (UWORD)yf;
				bf = yf - ye;

				for (i=0; i<x; i++) {
					float newfr=0.0;
					UBYTE *tinr;
					float newfg=0.0;
					UBYTE *ting;
					float newfb=0.0;
					UBYTE *tinb;
					UWORD l;

					xf += xfact;
					xe = (UWORD)xf;
					rf = xf - xe;

					if (ys > 0) {
						UWORD k;
						tinr = inr + ((ys-1) * w);
						ting = ing + ((ys-1) * w);
						tinb = inb + ((ys-1) * w);
						if (xs > 0) {
							newfr += tinr[xs-1] * lf * tf;
							newfg += ting[xs-1] * lf * tf;
							newfb += tinb[xs-1] * lf * tf;
						}
						for (k = xs; k < xe; k++) {
							newfr += tinr[k] * tf;
							newfg += ting[k] * tf;
							newfb += tinb[k] * tf;
						}
						if (xe < w) {
							newfr += tinr[xe] * rf * tf;
							newfg += ting[xe] * rf * tf;
							newfb += tinb[xe] * rf * tf;
						}
						tinr += w;
						ting += w;
						tinb += w;
					}
					else {
						tinr = inr + (ys * w);
						ting = ing + (ys * w);
						tinb = inb + (ys * w);
					}
					for (l = ys; l < ye; l++) {
						UWORD k;
						if (xs > 0) {
							newfr += tinr[xs-1] * lf;
							newfg += ting[xs-1] * lf;
							newfb += tinb[xs-1] * lf;
						}
						for (k = xs; k < xe; k++) {
							newfr += tinr[k];
							newfg += ting[k];
							newfb += tinb[k];
						}
						if (xe < w) {
							newfr += tinr[xe] * rf;
							newfg += ting[xe] * rf;
							newfb += tinb[xe] * rf;
						}
						tinr += w;
						ting += w;
						tinb += w;
					}
					if (ye < h) {
						UWORD k;
						newfr += tinr[xs-1] * lf * bf;
						newfg += ting[xs-1] * lf * bf;
						newfb += tinb[xs-1] * lf * bf;
						for (k = xs; k < xe; k++) {
							newfr += tinr[k] * bf;
							newfg += ting[k] * bf;
							newfb += tinb[k] * bf;
						}
						if (xe < w) {
							newfr += tinr[xe] * rf * bf;
							newfg += ting[xe] * rf * bf;
							newfb += tinb[xe] * rf * bf;
						}
					}
					*opr++ = newfr/divf;
					*opg++ = newfg/divf;
					*opb++ = newfb/divf;
					xs = xe + 1;
					lf = xs - xf;
				}
				ys = ye + 1;
				tf = ys - yf;
			}
			return;
		}
		{
			// x < w, y > h
			UWORD j;
			UWORD ys=0,ye;
			float yf=0.0;
			UBYTE *opr = tr;
			UBYTE *tinr;
			UBYTE *opg = tg;
			UBYTE *ting;
			UBYTE *opb = tb;
			UBYTE *tinb;
			UWORD i;
			float divf = xfact * yfact;
			UWORD xs,xe;
			float xf;
			float lf,rf;

			AddMessage("Scaling <X/>Y");
			SetMax(y);
			for (j=1; j<y; j++) {

				SetCur(j);
				xf = 0.0;
				lf = 0.0;
				xs = 0;
				yf += yfact;
				ye = (UWORD)yf;
				tinr = inr + (ys * w);
				ting = ing + (ys * w);
				tinb = inb + (ys * w);

				if (ys == ye) {
					for (i=0; i<x; i++) {
						float newfr=0.0;
						float newfg=0.0;
						float newfb=0.0;
						UWORD k;

						xf += xfact;
						xe = (UWORD)xf;
						rf = xf - xe;

						if (xs > 0) {
							newfr += tinr[xs-1] * lf;
							newfg += ting[xs-1] * lf;
							newfb += tinb[xs-1] * lf;
						}
						for (k = xs; k < xe; k++) {
							newfr += tinr[k];
							newfg += ting[k];
							newfb += tinb[k];
						}
						if (xe < w) {
							newfr += tinr[xe] * rf;
							newfg += ting[xe] * rf;
							newfb += tinb[xe] * rf;
						}
						*opr++ = newfr/xfact;
						*opg++ = newfg/xfact;
						*opb++ = newfb/xfact;
						xs = xe + 1;
						lf = xs - xf;
					}
				}
				else {
					float tf,bf;
					UWORD k;

					bf = yf - floor(yf);
					tf = yfact - bf;

					for (i=0; i<x; i++) {
						float newfr=0.0;
						float newfg=0.0;
						float newfb=0.0;

						xf += xfact;
						xe = (UWORD)xf;
						rf = xf - xe;

						if (xs > 0) {
							newfr += ((tinr[xs-1] * tf) + (tinr[xs-1+w] * bf)) * lf;
							newfg += ((ting[xs-1] * tf) + (ting[xs-1+w] * bf)) * lf;
							newfb += ((tinb[xs-1] * tf) + (tinb[xs-1+w] * bf)) * lf;
						}
						for (k = xs; k < xe; k++) {
							newfr += (tinr[k] * tf) + (tinr[k+w] * bf);
							newfg += (ting[k] * tf) + (ting[k+w] * bf);
							newfb += (tinb[k] * tf) + (tinb[k+w] * bf);
						}
						if (xe < w) {
							newfr += ((tinr[xe] * tf) + (tinr[xe+w] * bf)) * rf;
							newfg += ((ting[xe] * tf) + (ting[xe+w] * bf)) * rf;
							newfb += ((tinb[xe] * tf) + (tinb[xe+w] * bf)) * rf;
						}
						*opr++ = newfr/divf;
						*opg++ = newfg/divf;
						*opb++ = newfb/divf;
						xs = xe + 1;
						lf = xs - xf;
					}
					ys = ye;
				}
			}
			tinr = inr + ((h-1) * w);
			ting = ing + ((h-1) * w);
			tinb = inb + ((h-1) * w);
			xs = 0;
			lf = 0.0;
			xf = 0.0;
			for (i=0; i<x; i++) {
				float newfr=0.0;
				float newfg=0.0;
				float newfb=0.0;
				UWORD k;

				xf += xfact;
				xe = (UWORD)xf;
				rf = xf - xe;

				if (xs > 0) {
					newfr += tinr[xs-1] * lf;
					newfg += ting[xs-1] * lf;
					newfb += tinb[xs-1] * lf;
				}
				for (k = xs; k < xe; k++) {
					newfr += tinr[k];
					newfg += ting[k];
					newfb += tinb[k];
				}
				if (xe < w) {
					newfr += tinr[xe] * rf;
					newfg += ting[xe] * rf;
					newfb += tinb[xe] * rf;
				}
				*opr++ = newfr/xfact;
				*opg++ = newfg/xfact;
				*opb++ = newfb/xfact;
				xs = xe + 1;
				lf = xs - xf;
			}
			SmoothY(tr,outr,h,x,y);
			SmoothY(tg,outg,h,x,y);
			SmoothY(tb,outb,h,x,y);
			return;
		}
	}
	// x > w
 	if (y == h) {
		// x > w, y == h
		UWORD j;
		UBYTE *opr = tr;
		UBYTE *tinr = inr;
		UBYTE *opg = tg;
		UBYTE *ting = ing;
		UBYTE *opb = tb;
		UBYTE *tinb = inb;
		UWORD i;
		UBYTE *tintr;
		UBYTE *tintg;
		UBYTE *tintb;

		AddMessage("Scaling >X");
		SetMax(y);
		for (j=0; j<y; j++) {
			UWORD xs=0,xe;
			float xf=0.0;

			SetCur(j);
			tintr = tinr;
			tintg = ting;
			tintb = tinb;
			for (i=1; i<x; i++) {
				xf += xfact;
				xe = (UWORD)xf;
				if (xs == xe) {
					*opr++ = *tintr;
					*opg++ = *tintg;
					*opb++ = *tintb;
				}
				else {
					float lf,rf;

					rf = xf - floor(xf);
					lf = xfact - rf;
					*opr++ = ((*tintr * lf) + (tintr[1] * rf)) / xfact;
					*opg++ = ((*tintg * lf) + (tintg[1] * rf)) / xfact;
					*opb++ = ((*tintb * lf) + (tintb[1] * rf)) / xfact;
					tintr++;
					tintg++;
					tintb++;
					xs = xe;
				}
			}
			*opr++ = *tintr;
			tinr += w;
			*opg++ = *tintg;
			ting += w;
			*opb++ = *tintb;
			tinb += w;
		}
		SmoothX(tr,outr,w,x,y);
		SmoothX(tg,outg,w,x,y);
		SmoothX(tb,outb,w,x,y);
		return;
	}
	if (y > h) {
		// x > w, y > h
		UWORD j;
		UWORD ys=0,ye;
		float yf=0.0;
		UBYTE *opr = tr;
		UBYTE *tinr;
		UBYTE *opg = tg;
		UBYTE *ting;
		UBYTE *opb = tb;
		UBYTE *tinb;
		UWORD i;
		float divf = xfact * yfact;
		UWORD xs,xe;
		float xf;

		AddMessage("Scaling >X/>Y");
		SetMax(y);
		for (j=1; j<y; j++) {

			SetCur(j);
			xs=0;
			xf=0.0;
			yf += yfact;
			ye = (UWORD)yf;
			tinr = inr + (ys * w);
			ting = ing + (ys * w);
			tinb = inb + (ys * w);

			if (ys == ye) {
				for (i=1; i<x; i++) {
					xf += xfact;
					xe = (UWORD)xf;
					if (xs == xe) {
						*opr++ = *tinr;
						*opg++ = *ting;
						*opb++ = *tinb;
					}
					else {
						float lf,rf;

						rf = xf - floor(xf);
						lf = xfact - rf;
						*opr++ = ((*tinr * lf) + (tinr[1] * rf)) / xfact;
						tinr++;
						*opg++ = ((*ting * lf) + (ting[1] * rf)) / xfact;
						ting++;
						*opb++ = ((*tinb * lf) + (tinb[1] * rf)) / xfact;
						tinb++;
						xs = xe;
					}
				}
				*opr++ = *tinr;
				*opg++ = *ting;
				*opb++ = *tinb;
			}
			else {
				float tf,bf;

				bf = yf - floor(yf);
				tf = yfact - bf;
				for (i=1; i<x; i++) {
					xf += xfact;
					xe = (UWORD)xf;
					if (xs == xe) {
						*opr++ = ((*tinr * tf) + (tinr[w] * bf)) / yfact;
						*opg++ = ((*ting * tf) + (ting[w] * bf)) / yfact;
						*opb++ = ((*tinb * tf) + (tinb[w] * bf)) / yfact;
					}
					else {
						float lf,rf;

						rf = xf - floor(xf);
						lf = xfact - rf;
						*opr++ = ((*tinr * lf * tf) + (tinr[1] * rf * tf) +
									(tinr[w] * lf * bf) + (tinr[w+1] * rf * bf)) / divf;
						tinr++;
						*opg++ = ((*ting * lf * tf) + (ting[1] * rf * tf) +
									(ting[w] * lf * bf) + (ting[w+1] * rf * bf)) / divf;
						ting++;
						*opb++ = ((*tinb * lf * tf) + (tinb[1] * rf * tf) +
									(tinb[w] * lf * bf) + (tinb[w+1] * rf * bf)) / divf;
						tinb++;
						xs = xe;
					}
				}
				*opr++ = *tinr;
				*opg++ = *ting;
				*opb++ = *tinb;
				ys = ye;
			}
		}
		tinr = inr + ((h-1) * w);
		ting = ing + ((h-1) * w);
		tinb = inb + ((h-1) * w);
		xf = 0.0;
		xs = 0;
		for (i=1; i<x; i++) {
			xf += xfact;
			xe = (UWORD)xf;
			if (xs == xe) {
				*opr++ = *tinr;
				*opg++ = *ting;
				*opb++ = *tinb;
			}
			else {
				float lf,rf;

				rf = xf - floor(xf);
				lf = xfact - rf;
				*opr++ = ((*tinr * lf) + (tinr[1] * rf)) / xfact;
				tinr++;
				*opg++ = ((*ting * lf) + (ting[1] * rf)) / xfact;
				ting++;
				*opb++ = ((*tinb * lf) + (tinb[1] * rf)) / xfact;
				tinb++;
				xs = xe;
			}
		}
		*opr = *tinr;
		*opg = *ting;
		*opb = *tinb;
		SmoothXY(tr,outr,w,h,x,y);
		SmoothXY(tg,outg,w,h,x,y);
		SmoothXY(tb,outb,w,h,x,y);
		return;
	}
	{
		// x > w, y < h
		UWORD j;
		UBYTE *opr = tr;
		UBYTE *opg = tg;
		UBYTE *opb = tb;
		float tf=0.0, bf;
		float yf = 0.0;
		UWORD ys=0,ye;
		UBYTE *tinr;
		UBYTE *ting;
		UBYTE *tinb;
		float divf = xfact * yfact;

		AddMessage("Scaling >X/<Y");
		SetMax(y);
		for (j=0; j<y; j++) {
			UWORD i;
			UBYTE *tintr;
			float newfr;
			UBYTE *tintg;
			float newfg;
			UBYTE *tintb;
			float newfb;
			UWORD l;
			UWORD xs=0,xe;
			float xf=0.0;

			SetCur(j);
			yf += yfact;
			ye = (UWORD)yf;
			bf = yf - ye;
			if (ys > 0) {
				tinr = inr + ((ys-1) * w);
				ting = ing + ((ys-1) * w);
				tinb = inb + ((ys-1) * w);
			}
			else {
				tinr = inr + (ys * w);
				ting = ing + (ys * w);
				tinb = inb + (ys * w);
			}

			for (i=1; i<x; i++) {
				newfr=0.0;
				newfg=0.0;
				newfb=0.0;
				xf += xfact;
				xe = (UWORD)xf;
				tintr = tinr;
				tintg = ting;
				tintb = tinb;

				if (xs == xe) {
					if (ys > 0) {
						newfr += tintr[xs] * tf;
						tintr += w;
						newfg += tintg[xs] * tf;
						tintg += w;
						newfb += tintb[xs] * tf;
						tintb += w;
					}
					for (l = ys; l < ye; l++) {
						newfr += tintr[xs];
						tintr += w;
						newfg += tintg[xs];
						tintg += w;
						newfb += tintb[xs];
						tintb += w;
					}
					if (ye < h) {
						newfr += tintr[xs] * bf;
						newfg += tintg[xs] * bf;
						newfb += tintb[xs] * bf;
					}
					*opr++ = newfr/yfact;
					*opg++ = newfg/yfact;
					*opb++ = newfb/yfact;
				}
				else {
					float lf,rf;

					rf = xf - floor(xf);
					lf = xfact - rf;
					if (ys > 0) {
						newfr += ((tintr[xs] * lf) + (tintr[xe] * rf)) * tf;
						tintr += w;
						newfg += ((tintg[xs] * lf) + (tintg[xe] * rf)) * tf;
						tintg += w;
						newfb += ((tintb[xs] * lf) + (tintb[xe] * rf)) * tf;
						tintb += w;
					}
					for (l = ys; l < ye; l++) {
						newfr += ((tintr[xs] * lf) + (tintr[xe] * rf));
						tintr += w;
						newfg += ((tintg[xs] * lf) + (tintg[xe] * rf));
						tintg += w;
						newfb += ((tintb[xs] * lf) + (tintb[xe] * rf));
						tintb += w;
					}
					if (ye < h) {
						newfr += ((tintr[xs] * lf) + (tintr[xe] * rf)) * bf;
						newfg += ((tintg[xs] * lf) + (tintg[xe] * rf)) * bf;
						newfb += ((tintb[xs] * lf) + (tintb[xe] * rf)) * bf;
					}
					*opr++ = newfr/divf;
					*opg++ = newfg/divf;
					*opb++ = newfb/divf;
					xs = xe;
				}
			}
			tintr = tinr;
			newfr = 0.0;
			tintg = ting;
			newfg = 0.0;
			tintb = tinb;
			newfb = 0.0;
			if (ys > 0) {
				newfr += tintr[w-1] * tf;
				tintr += w;
				newfg += tintg[w-1] * tf;
				tintg += w;
				newfb += tintb[w-1] * tf;
				tintb += w;
			}
			for (l = ys; l < ye; l++) {
				newfr += tintr[w-1];
				tintr += w;
				newfg += tintg[w-1];
				tintg += w;
				newfb += tintb[w-1];
				tintb += w;
			}
			if (ye < h) {
				newfr += tintr[w-1] * bf;
				newfg += tintg[w-1] * bf;
				newfb += tintb[w-1] * bf;
			}
			*opr++ = newfr/yfact;
			*opg++ = newfg/yfact;
			*opb++ = newfb/yfact;
			ys = ye + 1;
			tf = ys - yf;
		}
		SmoothX(tr,outr,w,x,y);
		SmoothX(tg,outg,w,x,y);
		SmoothX(tb,outb,w,x,y);
		return;
	}
}
