/* Automatically generated by
	VMPluginCodeGenerator VMMaker.oscog-eem.2480 uuid: bb3ffda7-8241-4dea-b886-d656e474b6c1
   from
	ScratchPlugin VMMaker.oscog-eem.2480 uuid: bb3ffda7-8241-4dea-b886-d656e474b6c1
 */
static char __buildInfo[] = "ScratchPlugin VMMaker.oscog-eem.2480 uuid: bb3ffda7-8241-4dea-b886-d656e474b6c1 " __DATE__ ;



#include "config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
#include "sqConfig.h"			/* Configuration options */
#include "sqVirtualMachine.h"	/*  The virtual machine proxy definition */
#include "sqPlatformSpecific.h"	/* Platform specific definitions */

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
# undef EXPORT
# define EXPORT(returnType) static returnType
#endif

#include "ScratchPlugin.h"
#include "sqMemoryAccess.h"


/*** Function Prototypes ***/
static sqInt bitmapatputHsv(unsigned int *bitmap, sqInt i, sqInt hue, sqInt saturation, sqInt brightness);
static double * checkedFloatPtrOf(sqInt oop);
static unsigned int * checkedUnsignedIntPtrOf(sqInt oop);
EXPORT(const char*) getModuleName(void);
static sqInt hueFromRGBminmax(sqInt r, sqInt g, sqInt b, sqInt min, sqInt max);
static sqInt interpolatedFromxywidthheight(unsigned int *bitmap, sqInt xFixed, sqInt yFixed, sqInt w, sqInt h);
static sqInt interpolateandfrac(sqInt pix1, sqInt pix2, sqInt frac2);
EXPORT(sqInt) primClose(void);
EXPORT(sqInt) primGetOption(void);
EXPORT(sqInt) primIsPortOpen(void);
EXPORT(sqInt) primitiveBlur(void);
EXPORT(sqInt) primitiveBrightnessShift(void);
EXPORT(sqInt) primitiveCondenseSound(void);
EXPORT(sqInt) primitiveDoubleSize(void);
EXPORT(sqInt) primitiveExtractChannel(void);
EXPORT(sqInt) primitiveFisheye(void);
EXPORT(sqInt) primitiveGetFolderPath(void);
EXPORT(sqInt) primitiveHalfSizeAverage(void);
EXPORT(sqInt) primitiveHalfSizeDiagonal(void);
EXPORT(sqInt) primitiveHueShift(void);
EXPORT(sqInt) primitiveInterpolate(void);
EXPORT(sqInt) primitiveIsHidden(void);
EXPORT(sqInt) primitiveOpenURL(void);
EXPORT(sqInt) primitiveSaturationShift(void);
EXPORT(sqInt) primitiveScale(void);
EXPORT(sqInt) primitiveSetUnicodePasteBuffer(void);
EXPORT(sqInt) primitiveSetWindowTitle(void);
EXPORT(sqInt) primitiveShortToLongPath(void);
EXPORT(sqInt) primitiveWaterRipples1(void);
EXPORT(sqInt) primitiveWhirl(void);
EXPORT(sqInt) primOpenPortNamed(void);
EXPORT(sqInt) primPortCount(void);
EXPORT(sqInt) primPortName(void);
EXPORT(sqInt) primRead(void);
EXPORT(sqInt) primSetOption(void);
EXPORT(sqInt) primWrite(void);
EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);


/*** Variables ***/

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*classString)(void);
static sqInt (*failed)(void);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
static sqInt (*isBytes)(sqInt oop);
static sqInt (*isWords)(sqInt oop);
static sqInt (*isWordsOrBytes)(sqInt oop);
static sqInt (*methodReturnInteger)(sqInt integer);
static sqInt (*pop)(sqInt nItems);
static sqInt (*popthenPush)(sqInt nItems, sqInt oop);
static sqInt (*pushBool)(sqInt trueOrFalse);
static sqInt (*pushInteger)(sqInt integerValue);
static sqInt (*stSizeOf)(sqInt oop);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*success)(sqInt aBoolean);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern sqInt booleanValueOf(sqInt obj);
extern sqInt classString(void);
extern sqInt failed(void);
extern void * firstIndexableField(sqInt oop);
extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
extern sqInt isBytes(sqInt oop);
extern sqInt isWords(sqInt oop);
extern sqInt isWordsOrBytes(sqInt oop);
extern sqInt methodReturnInteger(sqInt integer);
extern sqInt pop(sqInt nItems);
extern sqInt popthenPush(sqInt nItems, sqInt oop);
extern sqInt pushBool(sqInt trueOrFalse);
extern sqInt pushInteger(sqInt integerValue);
extern sqInt stSizeOf(sqInt oop);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt success(sqInt aBoolean);
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"ScratchPlugin VMMaker.oscog-eem.2480 (i)"
#else
	"ScratchPlugin VMMaker.oscog-eem.2480 (e)"
#endif
;


	/* ScratchPlugin>>#bitmap:at:putH:s:v: */
static sqInt
bitmapatputHsv(unsigned int *bitmap, sqInt i, sqInt hue, sqInt saturation, sqInt brightness)
{
    sqInt hF;
    sqInt hI;
    sqInt outPix;
    sqInt p;
    sqInt q;
    sqInt t;
    sqInt v;

	outPix = 0;

	/* integer part of hue (0..5) */
	hI = hue / 60;

	/* fractional part ofhue */
	hF = hue % 60;
	p = (1000 - saturation) * brightness;
	q = (1000 - ((saturation * hF) / 60)) * brightness;
	t = (1000 - ((saturation * (60 - hF)) / 60)) * brightness;
	v = (brightness * 1000) / 3922;
	p = p / 3922;
	q = q / 3922;
	t = t / 3922;
	if (0 == hI) {
		outPix = ((((usqInt) v << 16)) + (((usqInt) t << 8))) + p;
	}
	if (1 == hI) {
		outPix = ((((usqInt) q << 16)) + (((usqInt) v << 8))) + p;
	}
	if (2 == hI) {
		outPix = ((((usqInt) p << 16)) + (((usqInt) v << 8))) + t;
	}
	if (3 == hI) {
		outPix = ((((usqInt) p << 16)) + (((usqInt) q << 8))) + v;
	}
	if (4 == hI) {
		outPix = ((((usqInt) t << 16)) + (((usqInt) p << 8))) + v;
	}
	if (5 == hI) {
		outPix = ((((usqInt) v << 16)) + (((usqInt) p << 8))) + q;
	}
	if (outPix == 0) {
		outPix = 1;
	}
	bitmap[i] = outPix;
	return 0;
}


/*	Return an unsigned int pointer to the first indexable word of oop, which
	must be a words object.
 */

	/* ScratchPlugin>>#checkedFloatPtrOf: */
static double *
checkedFloatPtrOf(sqInt oop)
{
	success(isWordsOrBytes(oop));
	if (failed()) {
		return 0;
	}
	return ((double *) (firstIndexableField(oop)));
}


/*	Return an unsigned int pointer to the first indexable word of oop, which
	must be a words object.
 */

	/* ScratchPlugin>>#checkedUnsignedIntPtrOf: */
static unsigned int *
checkedUnsignedIntPtrOf(sqInt oop)
{
	success(isWords(oop));
	if (failed()) {
		return 0;
	}
	return ((unsigned int *) (firstIndexableField(oop)));
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

	/* InterpreterPlugin>>#getModuleName */
EXPORT(const char*)
getModuleName(void)
{
	return moduleName;
}


/*	Answer the hue, an angle between 0 and 360. */

	/* ScratchPlugin>>#hueFromR:G:B:min:max: */
static sqInt
hueFromRGBminmax(sqInt r, sqInt g, sqInt b, sqInt min, sqInt max)
{
    sqInt result;
    sqInt span;

	span = max - min;
	if (span == 0) {
		return 0;
	}
	if (r == max) {
		result = (60 * (g - b)) / span;
	}
	else {
		if (g == max) {
			result = 120 + ((60 * (b - r)) / span);
		}
		else {
			result = 240 + ((60 * (r - g)) / span);
		}
	}
	if (result < 0) {
		return result + 360;
	}
	return result;
}


/*	Answer the interpolated pixel value from the given bitmap at the given
	point. The x and y coordinates are fixed-point integers with 10 bits of
	fraction (i.e. they were multiplied by 1024, then truncated). If the given
	point is right on an edge, answer the nearest edge pixel value. If it is
	entirely outside of the image, answer 0 (transparent).
 */

	/* ScratchPlugin>>#interpolatedFrom:x:y:width:height: */
static sqInt
interpolatedFromxywidthheight(unsigned int *bitmap, sqInt xFixed, sqInt yFixed, sqInt w, sqInt h)
{
    sqInt b;
    sqInt b1;
    sqInt b2;
    sqInt bottomPix;
    sqInt frac1;
    sqInt frac11;
    sqInt frac12;
    sqInt g;
    sqInt g1;
    sqInt g2;
    sqInt index;
    sqInt pix2;
    sqInt pix21;
    sqInt r;
    sqInt r1;
    sqInt r2;
    sqInt result;
    sqInt result1;
    sqInt result2;
    sqInt topPix;
    sqInt x;
    sqInt xFrac;
    sqInt y;
    sqInt yFrac;

	x = ((usqInt) xFixed >> 10);
	if ((x < -1)
	 || (x >= w)) {
		return 0;
	}
	y = ((usqInt) yFixed >> 10);
	if ((y < -1)
	 || (y >= h)) {
		return 0;
	}
	xFrac = xFixed & 0x3FF;
	if (x == -1) {
		x = 0;
		xFrac = 0;
	}
	if (x == (w - 1)) {
		xFrac = 0;
	}
	yFrac = yFixed & 0x3FF;
	if (y == -1) {
		y = 0;
		yFrac = 0;
	}
	if (y == (h - 1)) {
		yFrac = 0;
	}

	/* for squeak: + 1 */
	index = (y * w) + x;
	topPix = (bitmap[index]) & 0xFFFFFF;
	if (xFrac > 0) {
		/* begin interpolate:and:frac: */
		pix2 = (bitmap[index + 1]) & 0xFFFFFF;
		if (topPix == 0) {
			topPix = pix2;
			goto l1;
		}
		if (pix2 == 0) {
			topPix = topPix;
			goto l1;
		}
		frac1 = 1024 - xFrac;
		r = ((frac1 * ((((usqInt) topPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 16)) & 0xFF))) / 1024;
		g = ((frac1 * ((((usqInt) topPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 8)) & 0xFF))) / 1024;
		b = ((frac1 * (topPix & 0xFF)) + (xFrac * (pix2 & 0xFF))) / 1024;
		result = ((((usqInt) r << 16)) + (((usqInt) g << 8))) + b;
		if (result == 0) {
			result = 1;
		}
		topPix = result;
	l1:	/* end interpolate:and:frac: */;
	}
	if (yFrac == 0) {
		return topPix;
	}

	/* for squeak: + 1 */
	index = ((y + 1) * w) + x;
	bottomPix = (bitmap[index]) & 0xFFFFFF;
	if (xFrac > 0) {
		/* begin interpolate:and:frac: */
		pix21 = (bitmap[index + 1]) & 0xFFFFFF;
		if (bottomPix == 0) {
			bottomPix = pix21;
			goto l2;
		}
		if (pix21 == 0) {
			bottomPix = bottomPix;
			goto l2;
		}
		frac11 = 1024 - xFrac;
		r1 = ((frac11 * ((((usqInt) bottomPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 16)) & 0xFF))) / 1024;
		g1 = ((frac11 * ((((usqInt) bottomPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 8)) & 0xFF))) / 1024;
		b1 = ((frac11 * (bottomPix & 0xFF)) + (xFrac * (pix21 & 0xFF))) / 1024;
		result1 = ((((usqInt) r1 << 16)) + (((usqInt) g1 << 8))) + b1;
		if (result1 == 0) {
			result1 = 1;
		}
		bottomPix = result1;
	l2:	/* end interpolate:and:frac: */;
	}
	/* begin interpolate:and:frac: */
	if (topPix == 0) {
		return bottomPix;
	}
	if (bottomPix == 0) {
		return topPix;
	}
	frac12 = 1024 - yFrac;
	r2 = ((frac12 * ((((usqInt) topPix >> 16)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 16)) & 0xFF))) / 1024;
	g2 = ((frac12 * ((((usqInt) topPix >> 8)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 8)) & 0xFF))) / 1024;
	b2 = ((frac12 * (topPix & 0xFF)) + (yFrac * (bottomPix & 0xFF))) / 1024;
	result2 = ((((usqInt) r2 << 16)) + (((usqInt) g2 << 8))) + b2;
	if (result2 == 0) {
		result2 = 1;
	}
	return result2;
}


/*	Answer the interpolated pixel value between the given two pixel values. If
	either pixel is zero (transparent) answer the other pixel. If both pixels
	are transparent, answer transparent. The fraction is between 0 and 1023,
	out of a total range of 1024.
 */

	/* ScratchPlugin>>#interpolate:and:frac: */
static sqInt
interpolateandfrac(sqInt pix1, sqInt pix2, sqInt frac2)
{
    sqInt b;
    sqInt frac1;
    sqInt g;
    sqInt r;
    sqInt result;

	if (pix1 == 0) {
		return pix2;
	}
	if (pix2 == 0) {
		return pix1;
	}
	frac1 = 1024 - frac2;
	r = ((frac1 * ((((usqInt) pix1 >> 16)) & 0xFF)) + (frac2 * ((((usqInt) pix2 >> 16)) & 0xFF))) / 1024;
	g = ((frac1 * ((((usqInt) pix1 >> 8)) & 0xFF)) + (frac2 * ((((usqInt) pix2 >> 8)) & 0xFF))) / 1024;
	b = ((frac1 * (pix1 & 0xFF)) + (frac2 * (pix2 & 0xFF))) / 1024;
	result = ((((usqInt) r << 16)) + (((usqInt) g << 8))) + b;
	if (result == 0) {
		result = 1;
	}
	return result;
}


/*	Close the given serial port. */

	/* ScratchPlugin>>#primClose */
EXPORT(sqInt)
primClose(void)
{
    sqInt portNum;

	portNum = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	SerialPortClose(portNum);
	pop(1);
	return 0;
}


/*	Return the given option value for the given serial port. */

	/* ScratchPlugin>>#primGetOption */
EXPORT(sqInt)
primGetOption(void)
{
    sqInt attrNum;
    sqInt portNum;
    sqInt result;

	portNum = stackIntegerValue(1);
	attrNum = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	result = SerialPortGetOption(portNum, attrNum);
	if (result == -1) {
		success(0);
		return 0;
	}
	pop(3);
	pushInteger(result);
	return 0;
}


/*	Answer the true if the given port is open. */

	/* ScratchPlugin>>#primIsPortOpen */
EXPORT(sqInt)
primIsPortOpen(void)
{
    sqInt portNum;
    sqInt result;

	portNum = stackIntegerValue(0);
	if (failed()) {
		return 0;
	}
	result = SerialPortIsOpen(portNum);
	pop(2);
	pushBool(result != 0);
	return 0;
}

	/* ScratchPlugin>>#primitiveBlur */
EXPORT(sqInt)
primitiveBlur(void)
{
    sqInt bTotal;
    sqInt dX;
    sqInt dY;
    sqInt gTotal;
    sqInt height;
    unsigned int *in;
    sqInt inOop;
    sqInt n;
    unsigned int *out;
    sqInt outOop;
    sqInt outPix;
    unsigned int pix;
    sqInt rTotal;
    sqInt sz;
    sqInt width;
    sqInt x;
    sqInt y;

	inOop = stackValue(2);
	outOop = stackValue(1);
	width = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	height = sz / width;
	for (y = 1; y <= (height - 2); y += 1) {
		for (x = 1; x <= (width - 2); x += 1) {
			n = (rTotal = (gTotal = (bTotal = 0)));
			for (dY = -1; dY <= 1; dY += 1) {
				for (dX = -1; dX <= 1; dX += 1) {

					/* add 1 when testing in Squeak */
					pix = (in[((y + dY) * width) + (x + dX)]) & 0xFFFFFF;
					if (!(pix == 0)) {

						/* skip transparent pixels */
						rTotal += (((usqInt) pix >> 16)) & 0xFF;
						gTotal += (((usqInt) pix >> 8)) & 0xFF;
						bTotal += pix & 0xFF;
						n += 1;
					}
				}
			}
			if (n == 0) {
				outPix = 0;
			}
			else {
				outPix = ((((usqInt) (rTotal / n) << 16)) + (((usqInt) (gTotal / n) << 8))) + (bTotal / n);
			}
			out[(y * width) + x] = outPix;
		}
	}
	pop(3);
	return 0;
}

	/* ScratchPlugin>>#primitiveBrightnessShift */
EXPORT(sqInt)
primitiveBrightnessShift(void)
{
    unsigned int b;
    sqInt brightness;
    sqInt g;
    sqInt hF;
    sqInt hI;
    sqInt hue;
    sqInt i;
    unsigned int *in;
    sqInt inOop;
    sqInt max;
    sqInt min;
    unsigned int *out;
    sqInt outOop;
    sqInt outPix;
    sqInt p;
    unsigned int pix;
    sqInt q;
    sqInt r;
    sqInt result;
    sqInt saturation;
    sqInt shift;
    sqInt span;
    sqInt sz;
    sqInt t;
    sqInt v;

	outPix = 0;
	inOop = stackValue(2);
	outOop = stackValue(1);
	shift = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l3;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l3:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l4;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l4:	/* end checkedUnsignedIntPtrOf: */;
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	for (i = 0; i < sz; i += 1) {
		pix = (in[i]) & 0xFFFFFF;
		if (!(pix == 0)) {

			/* skip pixel values of 0 (transparent) */
			r = (((usqInt) pix >> 16)) & 0xFF;
			g = (((usqInt) pix >> 8)) & 0xFF;

			/* find min and max color components */
			b = pix & 0xFF;
			max = (min = r);
			if (g > max) {
				max = g;
			}
			if (b > max) {
				max = b;
			}
			if (g < min) {
				min = g;
			}
			if (b < min) {
				min = b;
			}
			/* begin hueFromR:G:B:min:max: */
			span = max - min;
			if (span == 0) {
				hue = 0;
				goto l1;
			}
			if (r == max) {
				result = (60 * (g - b)) / span;
			}
			else {
				if (g == max) {
					result = 120 + ((60 * (b - r)) / span);
				}
				else {
					result = 240 + ((60 * (r - g)) / span);
				}
			}
			if (result < 0) {
				hue = result + 360;
				goto l1;
			}
			hue = result;
	l1:	/* end hueFromR:G:B:min:max: */;
			if (max == 0) {
				saturation = 0;
			}
			else {
				saturation = ((max - min) * 1000) / max;
			}

			/* compute new brigthness */
			brightness = (max * 1000) / 0xFF;
			brightness += shift * 10;
			if (brightness > 1000) {
				brightness = 1000;
			}
			if (brightness < 0) {
				brightness = 0;
			}
			/* begin bitmap:at:putH:s:v: */

			/* integer part of hue (0..5) */
			hI = hue / 60;

			/* fractional part ofhue */
			hF = hue % 60;
			p = (1000 - saturation) * brightness;
			q = (1000 - ((saturation * hF) / 60)) * brightness;
			t = (1000 - ((saturation * (60 - hF)) / 60)) * brightness;
			v = (brightness * 1000) / 3922;
			p = p / 3922;
			q = q / 3922;
			t = t / 3922;
			if (0 == hI) {
				outPix = ((((usqInt) v << 16)) + (((usqInt) t << 8))) + p;
			}
			if (1 == hI) {
				outPix = ((((usqInt) q << 16)) + (((usqInt) v << 8))) + p;
			}
			if (2 == hI) {
				outPix = ((((usqInt) p << 16)) + (((usqInt) v << 8))) + t;
			}
			if (3 == hI) {
				outPix = ((((usqInt) p << 16)) + (((usqInt) q << 8))) + v;
			}
			if (4 == hI) {
				outPix = ((((usqInt) t << 16)) + (((usqInt) p << 8))) + v;
			}
			if (5 == hI) {
				outPix = ((((usqInt) v << 16)) + (((usqInt) p << 8))) + q;
			}
			if (outPix == 0) {
				outPix = 1;
			}
			out[i] = outPix;
		}
	}
	pop(3);
	return 0;
}

	/* ScratchPlugin>>#primitiveCondenseSound */
EXPORT(sqInt)
primitiveCondenseSound(void)
{
    sqInt count;
    short *dst;
    sqInt dstOop;
    sqInt factor;
    sqInt i;
    sqInt j;
    sqInt max;
    short *src;
    sqInt srcOop;
    sqInt sz;
    sqInt v;

	srcOop = stackValue(2);
	dstOop = stackValue(1);
	factor = stackIntegerValue(0);
	success(isWords(srcOop));
	success(isWords(dstOop));
	count = (2 * (stSizeOf(srcOop))) / factor;
	sz = 2 * (stSizeOf(dstOop));
	success(sz >= count);
	if (failed()) {
		return null;
	}
	src = ((short *) (firstIndexableField(srcOop)));
	dst = ((short *) (firstIndexableField(dstOop)));
	for (i = 1; i <= count; i += 1) {
		max = 0;
		for (j = 1; j <= factor; j += 1) {
			v = *src++;
			if (v < 0) {
				v = 0 - v;
			}
			if (v > max) {
				max = v;
			}
		}
		*dst++ = max;
	}
	pop(3);
	return 0;
}

	/* ScratchPlugin>>#primitiveDoubleSize */
EXPORT(sqInt)
primitiveDoubleSize(void)
{
    sqInt baseIndex;
    sqInt dstX;
    sqInt dstY;
    sqInt i;
    int *in;
    sqInt inH;
    sqInt inOop;
    sqInt inW;
    int *out;
    sqInt outH;
    sqInt outOop;
    sqInt outW;
    int pix;
    sqInt x;
    sqInt y;

	inOop = stackValue(7);
	inW = stackIntegerValue(6);
	inH = stackIntegerValue(5);
	outOop = stackValue(4);
	outW = stackIntegerValue(3);
	outH = stackIntegerValue(2);
	dstX = stackIntegerValue(1);
	dstY = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = ((unsigned int *) 0);
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = ((unsigned int *) 0);
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	success((dstX + (2 * inW)) < outW);
	success((dstY + (2 * inH)) < outH);
	if (failed()) {
		return null;
	}
	for (y = 0; y < inH; y += 1) {
		baseIndex = ((dstY + (2 * y)) * outW) + dstX;
		for (x = 0; x < inW; x += 1) {
			pix = in[x + (y * inW)];
			i = baseIndex + (2 * x);
			out[i] = pix;
			out[i + 1] = pix;
			out[i + outW] = pix;
			out[(i + outW) + 1] = pix;
		}
	}
	pop(8);
	return 0;
}

	/* ScratchPlugin>>#primitiveExtractChannel */
EXPORT(sqInt)
primitiveExtractChannel(void)
{
    short *dst;
    sqInt dstOop;
    sqInt i;
    sqInt rightFlag;
    short *src;
    sqInt srcOop;
    sqInt sz;

	srcOop = stackValue(2);
	dstOop = stackValue(1);
	rightFlag = booleanValueOf(stackValue(0));
	success(isWords(srcOop));
	success(isWords(dstOop));
	sz = stSizeOf(srcOop);
	success((stSizeOf(dstOop)) >= (sz / 2));
	if (failed()) {
		return null;
	}
	src = ((short *) (firstIndexableField(srcOop)));
	dst = ((short *) (firstIndexableField(dstOop)));
	if (rightFlag) {
		src++;
	}
	for (i = 1; i <= sz; i += 1) {
		*dst++ = *src; src += 2;
	}
	pop(3);
	return 0;
}

	/* ScratchPlugin>>#primitiveFisheye */
EXPORT(sqInt)
primitiveFisheye(void)
{
    double ang;
    sqInt b;
    sqInt b1;
    sqInt b2;
    sqInt bottomPix;
    sqInt centerX;
    sqInt centerY;
    double dx;
    double dy;
    sqInt frac1;
    sqInt frac11;
    sqInt frac12;
    sqInt g;
    sqInt g1;
    sqInt g2;
    sqInt height;
    unsigned int *in;
    sqInt index;
    sqInt inOop;
    unsigned int *out;
    sqInt outOop;
    sqInt pix;
    sqInt pix2;
    sqInt pix21;
    sqInt power;
    double r;
    sqInt r1;
    sqInt r2;
    sqInt r3;
    sqInt result;
    sqInt result1;
    sqInt result2;
    double scaledPower;
    sqInt srcX;
    sqInt srcY;
    sqInt sz;
    sqInt topPix;
    sqInt width;
    sqInt x;
    sqInt x1;
    sqInt xFrac;
    sqInt y;
    sqInt y1;
    sqInt yFrac;

	inOop = stackValue(3);
	outOop = stackValue(2);
	width = stackIntegerValue(1);
	power = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	height = sz / width;
	centerX = width / 2;
	centerY = height / 2;
	height = sz / width;
	centerX = width / 2;
	centerY = height / 2;
	scaledPower = power / 100.0;
	for (x = 0; x < width; x += 1) {
		for (y = 0; y < height; y += 1) {
			dx = (x - centerX) / (((double) centerX ));
			dy = (y - centerY) / (((double) centerY ));
			r = pow((sqrt((dx * dx) + (dy * dy))),scaledPower);
			if (r <= 1.0) {
				ang = atan2(dy,dx);
				srcX = ((sqInt)(1024 * (centerX + ((r * (cos(ang))) * centerX))));
				srcY = ((sqInt)(1024 * (centerY + ((r * (sin(ang))) * centerY))));
			}
			else {
				srcX = 1024 * x;
				srcY = 1024 * y;
			}
			/* begin interpolatedFrom:x:y:width:height: */
			x1 = ((usqInt) srcX >> 10);
			if ((x1 < -1)
			 || (x1 >= width)) {
				pix = 0;
				goto l5;
			}
			y1 = ((usqInt) srcY >> 10);
			if ((y1 < -1)
			 || (y1 >= height)) {
				pix = 0;
				goto l5;
			}
			xFrac = srcX & 0x3FF;
			if (x1 == -1) {
				x1 = 0;
				xFrac = 0;
			}
			if (x1 == (width - 1)) {
				xFrac = 0;
			}
			yFrac = srcY & 0x3FF;
			if (y1 == -1) {
				y1 = 0;
				yFrac = 0;
			}
			if (y1 == (height - 1)) {
				yFrac = 0;
			}

			/* for squeak: + 1 */
			index = (y1 * width) + x1;
			topPix = (in[index]) & 0xFFFFFF;
			if (xFrac > 0) {
				/* begin interpolate:and:frac: */
				pix2 = (in[index + 1]) & 0xFFFFFF;
				if (topPix == 0) {
					topPix = pix2;
					goto l3;
				}
				if (pix2 == 0) {
					topPix = topPix;
					goto l3;
				}
				frac1 = 1024 - xFrac;
				r3 = ((frac1 * ((((usqInt) topPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 16)) & 0xFF))) / 1024;
				g = ((frac1 * ((((usqInt) topPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 8)) & 0xFF))) / 1024;
				b = ((frac1 * (topPix & 0xFF)) + (xFrac * (pix2 & 0xFF))) / 1024;
				result = ((((usqInt) r3 << 16)) + (((usqInt) g << 8))) + b;
				if (result == 0) {
					result = 1;
				}
				topPix = result;
	l3:	/* end interpolate:and:frac: */;
			}
			if (yFrac == 0) {
				pix = topPix;
				goto l5;
			}

			/* for squeak: + 1 */
			index = ((y1 + 1) * width) + x1;
			bottomPix = (in[index]) & 0xFFFFFF;
			if (xFrac > 0) {
				/* begin interpolate:and:frac: */
				pix21 = (in[index + 1]) & 0xFFFFFF;
				if (bottomPix == 0) {
					bottomPix = pix21;
					goto l4;
				}
				if (pix21 == 0) {
					bottomPix = bottomPix;
					goto l4;
				}
				frac11 = 1024 - xFrac;
				r1 = ((frac11 * ((((usqInt) bottomPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 16)) & 0xFF))) / 1024;
				g1 = ((frac11 * ((((usqInt) bottomPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 8)) & 0xFF))) / 1024;
				b1 = ((frac11 * (bottomPix & 0xFF)) + (xFrac * (pix21 & 0xFF))) / 1024;
				result1 = ((((usqInt) r1 << 16)) + (((usqInt) g1 << 8))) + b1;
				if (result1 == 0) {
					result1 = 1;
				}
				bottomPix = result1;
	l4:	/* end interpolate:and:frac: */;
			}
			/* begin interpolate:and:frac: */
			if (topPix == 0) {
				pix = bottomPix;
				goto l5;
			}
			if (bottomPix == 0) {
				pix = topPix;
				goto l5;
			}
			frac12 = 1024 - yFrac;
			r2 = ((frac12 * ((((usqInt) topPix >> 16)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 16)) & 0xFF))) / 1024;
			g2 = ((frac12 * ((((usqInt) topPix >> 8)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 8)) & 0xFF))) / 1024;
			b2 = ((frac12 * (topPix & 0xFF)) + (yFrac * (bottomPix & 0xFF))) / 1024;
			result2 = ((((usqInt) r2 << 16)) + (((usqInt) g2 << 8))) + b2;
			if (result2 == 0) {
				result2 = 1;
			}
			pix = result2;
	l5:	/* end interpolatedFrom:x:y:width:height: */;
			out[(y * width) + x] = pix;
		}
	}
	pop(4);
	return 0;
}


/*	Get the path for the special folder with given ID. Fail if the folder ID
	is out of range.
 */

	/* ScratchPlugin>>#primitiveGetFolderPath */
EXPORT(sqInt)
primitiveGetFolderPath(void)
{
    sqInt count;
    char* dst;
    sqInt folderID;
    sqInt i;
    char nameStr[2000];
    sqInt resultOop;

	folderID = stackIntegerValue(0);
	if (failed()) {
		return 0;
	}
	GetFolderPathForID(folderID, nameStr, 2000);
	count = strlen(nameStr);
	resultOop = instantiateClassindexableSize(classString(), count);
	dst = ((char *) (firstIndexableField(resultOop)));
	for (i = 0; i < count; i += 1) {
		dst[i] = (nameStr[i]);
	}
	popthenPush(2, resultOop);
	return 0;
}

	/* ScratchPlugin>>#primitiveHalfSizeAverage */
EXPORT(sqInt)
primitiveHalfSizeAverage(void)
{
    int b;
    sqInt dstH;
    sqInt dstIndex;
    sqInt dstW;
    sqInt dstX;
    sqInt dstY;
    int g;
    int *in;
    sqInt inH;
    sqInt inW;
    sqInt oop;
    sqInt oop1;
    int *out;
    sqInt outH;
    sqInt outW;
    int pixel;
    int r;
    sqInt srcIndex;
    sqInt srcX;
    sqInt srcY;
    sqInt x;
    sqInt y;

	/* begin checkedUnsignedIntPtrOf: */
	oop = stackValue(11);
	success(isWords(oop));
	if (failed()) {
		in = ((unsigned int *) 0);
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(oop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	inW = stackIntegerValue(10);
	inH = stackIntegerValue(9);
	/* begin checkedUnsignedIntPtrOf: */
	oop1 = stackValue(8);
	success(isWords(oop1));
	if (failed()) {
		out = ((unsigned int *) 0);
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(oop1)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	outW = stackIntegerValue(7);
	outH = stackIntegerValue(6);
	srcX = stackIntegerValue(5);
	srcY = stackIntegerValue(4);
	dstX = stackIntegerValue(3);
	dstY = stackIntegerValue(2);
	dstW = stackIntegerValue(1);
	dstH = stackIntegerValue(0);
	success((srcX >= 0) && (srcY >= 0));
	success((srcX + (2 * dstW)) <= inW);
	success((srcY + (2 * dstH)) <= inH);
	success((dstX >= 0) && (dstY >= 0));
	success((dstX + dstW) <= outW);
	success((dstY + dstH) <= outH);
	if (failed()) {
		return null;
	}
	for (y = 0; y < dstH; y += 1) {
		srcIndex = (inW * (srcY + (2 * y))) + srcX;
		dstIndex = (outW * (dstY + y)) + dstX;
		for (x = 0; x < dstW; x += 1) {
			pixel = in[srcIndex];
			r = pixel & 0xFF0000;
			g = pixel & 0xFF00;
			b = pixel & 0xFF;
			pixel = in[srcIndex + 1];
			r += pixel & 0xFF0000;
			g += pixel & 0xFF00;
			b += pixel & 0xFF;
			pixel = in[srcIndex + inW];
			r += pixel & 0xFF0000;
			g += pixel & 0xFF00;
			b += pixel & 0xFF;
			pixel = in[(srcIndex + inW) + 1];
			r += pixel & 0xFF0000;
			g += pixel & 0xFF00;

			/* store combined RGB into target bitmap */
			b += pixel & 0xFF;
			out[dstIndex] = (((((usqInt) r >> 2)) & 0xFF0000) | (((((usqInt) g >> 2)) & 0xFF00) | (((usqInt) b >> 2))));
			srcIndex += 2;
			dstIndex += 1;
		}
	}
	pop(12);
	return 0;
}

	/* ScratchPlugin>>#primitiveHalfSizeDiagonal */
EXPORT(sqInt)
primitiveHalfSizeDiagonal(void)
{
    sqInt b;
    sqInt dstH;
    sqInt dstIndex;
    sqInt dstW;
    sqInt dstX;
    sqInt dstY;
    sqInt g;
    int *in;
    sqInt inH;
    sqInt inW;
    sqInt oop;
    sqInt oop1;
    int *out;
    sqInt outH;
    sqInt outW;
    int p1;
    int p2;
    sqInt r;
    sqInt srcIndex;
    sqInt srcX;
    sqInt srcY;
    sqInt x;
    sqInt y;

	/* begin checkedUnsignedIntPtrOf: */
	oop = stackValue(11);
	success(isWords(oop));
	if (failed()) {
		in = ((unsigned int *) 0);
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(oop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	inW = stackIntegerValue(10);
	inH = stackIntegerValue(9);
	/* begin checkedUnsignedIntPtrOf: */
	oop1 = stackValue(8);
	success(isWords(oop1));
	if (failed()) {
		out = ((unsigned int *) 0);
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(oop1)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	outW = stackIntegerValue(7);
	outH = stackIntegerValue(6);
	srcX = stackIntegerValue(5);
	srcY = stackIntegerValue(4);
	dstX = stackIntegerValue(3);
	dstY = stackIntegerValue(2);
	dstW = stackIntegerValue(1);
	dstH = stackIntegerValue(0);
	success((srcX >= 0) && (srcY >= 0));
	success((srcX + (2 * dstW)) <= inW);
	success((srcY + (2 * dstH)) <= inH);
	success((dstX >= 0) && (dstY >= 0));
	success((dstX + dstW) <= outW);
	success((dstY + dstH) <= outH);
	if (failed()) {
		return null;
	}
	for (y = 0; y < dstH; y += 1) {
		srcIndex = (inW * (srcY + (2 * y))) + srcX;
		dstIndex = (outW * (dstY + y)) + dstX;
		for (x = 0; x < dstW; x += 1) {
			p1 = in[srcIndex];
			p2 = in[(srcIndex + inW) + 1];
			r = (((usqInt) ((p1 & 0xFF0000) + (p2 & 0xFF0000)) >> 1)) & 0xFF0000;
			g = (((usqInt) ((p1 & 0xFF00) + (p2 & 0xFF00)) >> 1)) & 0xFF00;

			/* store combined RGB into target bitmap */
			b = ((usqInt) ((p1 & 0xFF) + (p2 & 0xFF)) >> 1);
			out[dstIndex] = (r | (g | b));
			srcIndex += 2;
			dstIndex += 1;
		}
	}
	pop(12);
	return 0;
}

	/* ScratchPlugin>>#primitiveHueShift */
EXPORT(sqInt)
primitiveHueShift(void)
{
    unsigned int b;
    sqInt brightness;
    sqInt g;
    sqInt hF;
    sqInt hI;
    sqInt hue;
    sqInt i;
    unsigned int *in;
    sqInt inOop;
    sqInt max;
    sqInt min;
    unsigned int *out;
    sqInt outOop;
    sqInt outPix;
    sqInt p;
    unsigned int pix;
    sqInt q;
    sqInt r;
    sqInt result;
    sqInt saturation;
    sqInt shift;
    sqInt span;
    sqInt sz;
    sqInt t;
    sqInt v;

	outPix = 0;
	inOop = stackValue(2);
	outOop = stackValue(1);
	shift = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l3;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l3:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l4;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l4:	/* end checkedUnsignedIntPtrOf: */;
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	for (i = 0; i < sz; i += 1) {
		pix = (in[i]) & 0xFFFFFF;
		if (!(pix == 0)) {

			/* skip pixel values of 0 (transparent) */
			r = (((usqInt) pix >> 16)) & 0xFF;
			g = (((usqInt) pix >> 8)) & 0xFF;

			/* find min and max color components */
			b = pix & 0xFF;
			max = (min = r);
			if (g > max) {
				max = g;
			}
			if (b > max) {
				max = b;
			}
			if (g < min) {
				min = g;
			}
			if (b < min) {
				min = b;
			}
			brightness = (max * 1000) / 0xFF;
			if (max == 0) {
				saturation = 0;
			}
			else {
				saturation = ((max - min) * 1000) / max;
			}
			if (brightness < 110) {

				/* force black to a very dark, saturated gray */
				brightness = 110;
				saturation = 1000;
			}
			if (saturation < 90) {
				saturation = 90;
			}
			if ((brightness == 110) || (saturation == 90)) {

				/* tint all blacks and grays the same */
				hue = 0;
			}
			else {
				/* begin hueFromR:G:B:min:max: */
				span = max - min;
				if (span == 0) {
					hue = 0;
					goto l1;
				}
				if (r == max) {
					result = (60 * (g - b)) / span;
				}
				else {
					if (g == max) {
						result = 120 + ((60 * (b - r)) / span);
					}
					else {
						result = 240 + ((60 * (r - g)) / span);
					}
				}
				if (result < 0) {
					hue = result + 360;
					goto l1;
				}
				hue = result;
	l1:	/* end hueFromR:G:B:min:max: */;
			}

			/* compute new hue */
			hue = ((hue + shift) + 360000000) % 360;
			/* begin bitmap:at:putH:s:v: */

			/* integer part of hue (0..5) */
			hI = hue / 60;

			/* fractional part ofhue */
			hF = hue % 60;
			p = (1000 - saturation) * brightness;
			q = (1000 - ((saturation * hF) / 60)) * brightness;
			t = (1000 - ((saturation * (60 - hF)) / 60)) * brightness;
			v = (brightness * 1000) / 3922;
			p = p / 3922;
			q = q / 3922;
			t = t / 3922;
			if (0 == hI) {
				outPix = ((((usqInt) v << 16)) + (((usqInt) t << 8))) + p;
			}
			if (1 == hI) {
				outPix = ((((usqInt) q << 16)) + (((usqInt) v << 8))) + p;
			}
			if (2 == hI) {
				outPix = ((((usqInt) p << 16)) + (((usqInt) v << 8))) + t;
			}
			if (3 == hI) {
				outPix = ((((usqInt) p << 16)) + (((usqInt) q << 8))) + v;
			}
			if (4 == hI) {
				outPix = ((((usqInt) t << 16)) + (((usqInt) p << 8))) + v;
			}
			if (5 == hI) {
				outPix = ((((usqInt) v << 16)) + (((usqInt) p << 8))) + q;
			}
			if (outPix == 0) {
				outPix = 1;
			}
			out[i] = outPix;
		}
	}
	pop(3);
	return 0;
}

	/* ScratchPlugin>>#primitiveInterpolate */
EXPORT(sqInt)
primitiveInterpolate(void)
{
    sqInt b;
    sqInt b1;
    sqInt b2;
    sqInt bottomPix;
    sqInt frac1;
    sqInt frac11;
    sqInt frac12;
    sqInt g;
    sqInt g1;
    sqInt g2;
    unsigned int *in;
    sqInt index;
    sqInt inOop;
    sqInt pix2;
    sqInt pix21;
    sqInt r;
    sqInt r1;
    sqInt r2;
    sqInt result;
    sqInt result1;
    sqInt result2;
    sqInt result3;
    sqInt sz;
    sqInt topPix;
    sqInt width;
    sqInt x;
    sqInt xFixed;
    sqInt xFrac;
    sqInt y;
    sqInt yFixed;
    sqInt yFrac;

	inOop = stackValue(3);
	width = stackIntegerValue(2);
	xFixed = stackIntegerValue(1);
	yFixed = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	if (failed()) {
		return null;
	}
	/* begin interpolatedFrom:x:y:width:height: */
	x = ((usqInt) xFixed >> 10);
	if ((x < -1)
	 || (x >= width)) {
		result = 0;
		goto l4;
	}
	y = ((usqInt) yFixed >> 10);
	if ((y < -1)
	 || (y >= (sz / width))) {
		result = 0;
		goto l4;
	}
	xFrac = xFixed & 0x3FF;
	if (x == -1) {
		x = 0;
		xFrac = 0;
	}
	if (x == (width - 1)) {
		xFrac = 0;
	}
	yFrac = yFixed & 0x3FF;
	if (y == -1) {
		y = 0;
		yFrac = 0;
	}
	if (y == ((sz / width) - 1)) {
		yFrac = 0;
	}

	/* for squeak: + 1 */
	index = (y * width) + x;
	topPix = (in[index]) & 0xFFFFFF;
	if (xFrac > 0) {
		/* begin interpolate:and:frac: */
		pix2 = (in[index + 1]) & 0xFFFFFF;
		if (topPix == 0) {
			topPix = pix2;
			goto l3;
		}
		if (pix2 == 0) {
			topPix = topPix;
			goto l3;
		}
		frac1 = 1024 - xFrac;
		r = ((frac1 * ((((usqInt) topPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 16)) & 0xFF))) / 1024;
		g = ((frac1 * ((((usqInt) topPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 8)) & 0xFF))) / 1024;
		b = ((frac1 * (topPix & 0xFF)) + (xFrac * (pix2 & 0xFF))) / 1024;
		result3 = ((((usqInt) r << 16)) + (((usqInt) g << 8))) + b;
		if (result3 == 0) {
			result3 = 1;
		}
		topPix = result3;
	l3:	/* end interpolate:and:frac: */;
	}
	if (yFrac == 0) {
		result = topPix;
		goto l4;
	}

	/* for squeak: + 1 */
	index = ((y + 1) * width) + x;
	bottomPix = (in[index]) & 0xFFFFFF;
	if (xFrac > 0) {
		/* begin interpolate:and:frac: */
		pix21 = (in[index + 1]) & 0xFFFFFF;
		if (bottomPix == 0) {
			bottomPix = pix21;
			goto l2;
		}
		if (pix21 == 0) {
			bottomPix = bottomPix;
			goto l2;
		}
		frac11 = 1024 - xFrac;
		r1 = ((frac11 * ((((usqInt) bottomPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 16)) & 0xFF))) / 1024;
		g1 = ((frac11 * ((((usqInt) bottomPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 8)) & 0xFF))) / 1024;
		b1 = ((frac11 * (bottomPix & 0xFF)) + (xFrac * (pix21 & 0xFF))) / 1024;
		result1 = ((((usqInt) r1 << 16)) + (((usqInt) g1 << 8))) + b1;
		if (result1 == 0) {
			result1 = 1;
		}
		bottomPix = result1;
	l2:	/* end interpolate:and:frac: */;
	}
	/* begin interpolate:and:frac: */
	if (topPix == 0) {
		result = bottomPix;
		goto l4;
	}
	if (bottomPix == 0) {
		result = topPix;
		goto l4;
	}
	frac12 = 1024 - yFrac;
	r2 = ((frac12 * ((((usqInt) topPix >> 16)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 16)) & 0xFF))) / 1024;
	g2 = ((frac12 * ((((usqInt) topPix >> 8)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 8)) & 0xFF))) / 1024;
	b2 = ((frac12 * (topPix & 0xFF)) + (yFrac * (bottomPix & 0xFF))) / 1024;
	result2 = ((((usqInt) r2 << 16)) + (((usqInt) g2 << 8))) + b2;
	if (result2 == 0) {
		result2 = 1;
	}
	result = result2;
	l4:	/* end interpolatedFrom:x:y:width:height: */;
	pop(5);
	pushInteger(result);
	return 0;
}


/*	Answer true if the file or folder with the given path should be hidden
	from the user. On Windows, this is the value of the 'hidden' file
	property. 
 */

	/* ScratchPlugin>>#primitiveIsHidden */
EXPORT(sqInt)
primitiveIsHidden(void)
{
    sqInt count;
    char fullPath[1000];
    sqInt i;
    sqInt pathOop;
    sqInt result;
    char *src;

	pathOop = stackValue(0);
	success(isBytes(pathOop));
	if (failed()) {
		return 0;
	}
	src = ((char *) (firstIndexableField(pathOop)));
	count = stSizeOf(pathOop);
	if (count >= 1000) {
		success(0);
		return 0;
	}
	for (i = 0; i < count; i += 1) {
		fullPath[i] = (src[i]);
	}
	fullPath[count] = 0;
	result = IsFileOrFolderHidden(fullPath);
	pop(2);
	pushBool(result != 0);
	return 0;
}


/*	Open a web browser on the given URL. */

	/* ScratchPlugin>>#primitiveOpenURL */
EXPORT(sqInt)
primitiveOpenURL(void)
{
    sqInt count;
    sqInt i;
    char *src;
    sqInt urlOop;
    char urlStr[2000];

	urlOop = stackValue(0);
	success(isBytes(urlOop));
	if (failed()) {
		return 0;
	}
	src = ((char *) (firstIndexableField(urlOop)));
	count = stSizeOf(urlOop);
	if (count >= 2000) {
		success(0);
		return 0;
	}
	for (i = 0; i < count; i += 1) {
		urlStr[i] = (src[i]);
	}
	urlStr[count] = 0;
	OpenURL(urlStr);
	pop(1);
	return 0;
}

	/* ScratchPlugin>>#primitiveSaturationShift */
EXPORT(sqInt)
primitiveSaturationShift(void)
{
    unsigned int b;
    sqInt brightness;
    sqInt g;
    sqInt hF;
    sqInt hI;
    sqInt hue;
    sqInt i;
    unsigned int *in;
    sqInt inOop;
    sqInt max;
    sqInt min;
    unsigned int *out;
    sqInt outOop;
    sqInt outPix;
    sqInt p;
    unsigned int pix;
    sqInt q;
    sqInt r;
    sqInt result;
    sqInt saturation;
    sqInt shift;
    sqInt span;
    sqInt sz;
    sqInt t;
    sqInt v;

	outPix = 0;
	inOop = stackValue(2);
	outOop = stackValue(1);
	shift = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l3;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l3:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l4;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l4:	/* end checkedUnsignedIntPtrOf: */;
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	for (i = 0; i < sz; i += 1) {
		pix = (in[i]) & 0xFFFFFF;
		if (!(pix < 2)) {

			/* skip pixel values of 0 (transparent) and 1 (black) */
			r = (((usqInt) pix >> 16)) & 0xFF;
			g = (((usqInt) pix >> 8)) & 0xFF;

			/* find min and max color components */
			b = pix & 0xFF;
			max = (min = r);
			if (g > max) {
				max = g;
			}
			if (b > max) {
				max = b;
			}
			if (g < min) {
				min = g;
			}
			if (b < min) {
				min = b;
			}
			brightness = (max * 1000) / 0xFF;
			if (max == 0) {
				saturation = 0;
			}
			else {
				saturation = ((max - min) * 1000) / max;
			}
			if (saturation > 0) {

				/* do nothing if pixel is unsaturated (gray) */
				/* begin hueFromR:G:B:min:max: */
				span = max - min;
				if (span == 0) {
					hue = 0;
					goto l1;
				}
				if (r == max) {
					result = (60 * (g - b)) / span;
				}
				else {
					if (g == max) {
						result = 120 + ((60 * (b - r)) / span);
					}
					else {
						result = 240 + ((60 * (r - g)) / span);
					}
				}
				if (result < 0) {
					hue = result + 360;
					goto l1;
				}
				hue = result;
	l1:	/* end hueFromR:G:B:min:max: */;
				saturation += shift * 10;
				if (saturation > 1000) {
					saturation = 1000;
				}
				if (saturation < 0) {
					saturation = 0;
				}
				/* begin bitmap:at:putH:s:v: */

				/* integer part of hue (0..5) */
				hI = hue / 60;

				/* fractional part ofhue */
				hF = hue % 60;
				p = (1000 - saturation) * brightness;
				q = (1000 - ((saturation * hF) / 60)) * brightness;
				t = (1000 - ((saturation * (60 - hF)) / 60)) * brightness;
				v = (brightness * 1000) / 3922;
				p = p / 3922;
				q = q / 3922;
				t = t / 3922;
				if (0 == hI) {
					outPix = ((((usqInt) v << 16)) + (((usqInt) t << 8))) + p;
				}
				if (1 == hI) {
					outPix = ((((usqInt) q << 16)) + (((usqInt) v << 8))) + p;
				}
				if (2 == hI) {
					outPix = ((((usqInt) p << 16)) + (((usqInt) v << 8))) + t;
				}
				if (3 == hI) {
					outPix = ((((usqInt) p << 16)) + (((usqInt) q << 8))) + v;
				}
				if (4 == hI) {
					outPix = ((((usqInt) t << 16)) + (((usqInt) p << 8))) + v;
				}
				if (5 == hI) {
					outPix = ((((usqInt) v << 16)) + (((usqInt) p << 8))) + q;
				}
				if (outPix == 0) {
					outPix = 1;
				}
				out[i] = outPix;
			}
		}
	}
	pop(3);
	return 0;
}


/*	Scale using bilinear interpolation. */
/*	This version isn't really able to do much with full ARGB based images; the
	A channel will be ignored and only fully transparent pixels will be
	treated as transparent. The output pixel will be either fully transparent
	or fully opaque.
 */

	/* ScratchPlugin>>#primitiveScale */
EXPORT(sqInt)
primitiveScale(void)
{
    int *in;
    sqInt inH;
    sqInt inOop;
    sqInt inW;
    sqInt inX;
    sqInt inY;
    int *out;
    sqInt outH;
    sqInt outOop;
    sqInt outPix;
    sqInt outW;
    sqInt outX;
    sqInt outY;
    int p1;
    int p2;
    int p3;
    int p4;
    sqInt t;
    sqInt tWeight;
    sqInt w1;
    sqInt w2;
    sqInt w3;
    sqInt w4;
    sqInt xIncr;
    sqInt yIncr;

	inOop = stackValue(5);
	inW = stackIntegerValue(4);
	inH = stackIntegerValue(3);
	outOop = stackValue(2);
	outW = stackIntegerValue(1);
	outH = stackIntegerValue(0);
	success((stSizeOf(inOop)) == (inW * inH));
	success((stSizeOf(outOop)) == (outW * outH));
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = ((unsigned int *) 0);
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = ((unsigned int *) 0);
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	if (failed()) {
		return null;
	}

	/* source x and y, scaled by 1024 */
	inX = (inY = 0);

	/* source x increment, scaled by 1024 */
	xIncr = (inW * 1024) / outW;

	/* source y increment, scaled by 1024 */
	yIncr = (inH * 1024) / outH;
	for (outY = 0; outY < outH; outY += 1) {
		inX = 0;
		for (outX = 0; outX < outW; outX += 1) {

			/* compute weights, scaled by 2^20 */
			w1 = (1024 - (inX & 0x3FF)) * (1024 - (inY & 0x3FF));
			w2 = (inX & 0x3FF) * (1024 - (inY & 0x3FF));
			w3 = (1024 - (inX & 0x3FF)) * (inY & 0x3FF);

			/* get source pixels */
			w4 = (inX & 0x3FF) * (inY & 0x3FF);
			t = ((((usqInt) inY) >> 10) * inW) + (((usqInt) inX) >> 10);
			p1 = in[t];
			if ((((usqInt) inX) >> 10) < (inW - 1)) {
				p2 = in[t + 1];
			}
			else {
				p2 = p1;
			}
			if ((((usqInt) inY) >> 10) < (inH - 1)) {
				t += inW;
			}
			p3 = in[t];
			if ((((usqInt) inX) >> 10) < (inW - 1)) {
				p4 = in[t + 1];
			}
			else {
				p4 = p3;
			}
			tWeight = 0;
			if (p1 == 0) {
				p1 = p2;
				tWeight += w1;
			}
			if (p2 == 0) {
				p2 = p1;
				tWeight += w2;
			}
			if (p3 == 0) {
				p3 = p4;
				tWeight += w3;
			}
			if (p4 == 0) {
				p4 = p3;
				tWeight += w4;
			}
			if (p1 == 0) {
				p1 = p3;
				p2 = p4;
			}
			if (p3 == 0) {
				p3 = p1;
				p4 = p2;
			}
			outPix = 0;
			if (tWeight < 500000) {

				/* compute an (opaque) output pixel if less than 50% transparent */
				t = (((w1 * ((((usqInt) p1) >> 16) & 0xFF)) + (w2 * ((((usqInt) p2) >> 16) & 0xFF))) + (w3 * ((((usqInt) p3) >> 16) & 0xFF))) + (w4 * ((((usqInt) p4) >> 16) & 0xFF));
				outPix = ((sqInt)((usqInt)(((((usqInt) t) >> 20) & 0xFF)) << 16));
				t = (((w1 * ((((usqInt) p1) >> 8) & 0xFF)) + (w2 * ((((usqInt) p2) >> 8) & 0xFF))) + (w3 * ((((usqInt) p3) >> 8) & 0xFF))) + (w4 * ((((usqInt) p4) >> 8) & 0xFF));
				outPix = outPix | (((sqInt)((usqInt)(((((usqInt) t) >> 20) & 0xFF)) << 8)));
				t = (((w1 * (p1 & 0xFF)) + (w2 * (p2 & 0xFF))) + (w3 * (p3 & 0xFF))) + (w4 * (p4 & 0xFF));

				/* If the result is black, remember to make it Squeak-standard-fake-black */
				outPix = outPix | ((((usqInt) t) >> 20) & 0xFF);
				if (outPix == 0) {
					outPix = 1;
				}
				outPix = outPix | 0xFF000000U;
			}
			out[(outY * outW) + outX] = outPix;
			inX += xIncr;
		}
		inY += yIncr;
	}
	pop(6);
	return 0;
}


/*	Set the Mac OS X Unicode paste buffer. */

	/* ScratchPlugin>>#primitiveSetUnicodePasteBuffer */
EXPORT(sqInt)
primitiveSetUnicodePasteBuffer(void)
{
    sqInt count;
    sqInt strOop;
    short *utf16;

	strOop = stackValue(0);
	success(isBytes(strOop));
	if (failed()) {
		return 0;
	}
	utf16 = ((short *) (firstIndexableField(strOop)));
	count = stSizeOf(strOop);
	SetUnicodePasteBuffer(utf16, count);
	pop(1);
	return 0;
}


/*	Set the title of the Scratch window. */

	/* ScratchPlugin>>#primitiveSetWindowTitle */
EXPORT(sqInt)
primitiveSetWindowTitle(void)
{
    sqInt count;
    sqInt i;
    char *src;
    sqInt titleOop;
    char titleStr[1000];

	titleOop = stackValue(0);
	success(isBytes(titleOop));
	if (failed()) {
		return 0;
	}
	src = ((char *) (firstIndexableField(titleOop)));
	count = stSizeOf(titleOop);
	if (count >= 1000) {
		success(0);
		return 0;
	}
	for (i = 0; i < count; i += 1) {
		titleStr[i] = (src[i]);
	}
	titleStr[count] = 0;
	SetScratchWindowTitle(titleStr);
	pop(1);
	return 0;
}


/*	On Windows, convert a short file/path name into a long one. Fail on other
	platforms. 
 */

	/* ScratchPlugin>>#primitiveShortToLongPath */
EXPORT(sqInt)
primitiveShortToLongPath(void)
{
    sqInt count;
    sqInt i;
    char longPath[1000];
    char *ptr;
    sqInt result;
    sqInt resultOop;
    char shortPath[1000];
    sqInt shortPathOop;

	shortPathOop = stackValue(0);
	if (!(isBytes(shortPathOop))) {
		success(0);
		return 0;
	}
	ptr = ((char *) (firstIndexableField(shortPathOop)));
	count = stSizeOf(shortPathOop);
	if (count >= 1000) {
		success(0);
		return 0;
	}
	for (i = 0; i < count; i += 1) {
		shortPath[i] = (ptr[i]);
	}
	shortPath[count] = 0;
	result = WinShortToLongPath(shortPath, longPath, 1000);
	if (result == -1) {
		success(0);
		return 0;
	}
	count = strlen(longPath);
	resultOop = instantiateClassindexableSize(classString(), count);
	ptr = ((char *) (firstIndexableField(resultOop)));
	for (i = 0; i < count; i += 1) {
		ptr[i] = (longPath[i]);
	}
	popthenPush(2, resultOop);
	return 0;
}

	/* ScratchPlugin>>#primitiveWaterRipples1 */
EXPORT(sqInt)
primitiveWaterRipples1(void)
{
    sqInt aArOop;
    double *aArray;
    sqInt allPix;
    sqInt bArOop;
    double *bArray;
    sqInt blops;
    sqInt d;
    double dist;
    sqInt dx;
    double dx2;
    sqInt dy;
    double dy2;
    sqInt f;
    sqInt g;
    sqInt h;
    sqInt height;
    sqInt i;
    unsigned int *in;
    sqInt inOop;
    sqInt j;
    sqInt newLoc;
    unsigned int *out;
    sqInt outOop;
    unsigned int pix;
    sqInt power;
    sqInt q;
    int ripply;
    sqInt t;
    sqInt t1;
    double temp;
    sqInt val;
    sqInt val2;
    sqInt width;
    sqInt x;
    sqInt y;

	inOop = stackValue(5);
	outOop = stackValue(4);
	width = stackIntegerValue(3);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	allPix = stSizeOf(inOop);
	ripply = stackIntegerValue(2);
	aArOop = stackValue(1);
	bArOop = stackValue(0);
	/* begin checkedFloatPtrOf: */
	success(isWordsOrBytes(aArOop));
	if (failed()) {
		aArray = 0;
		goto l3;
	}
	aArray = ((double *) (firstIndexableField(aArOop)));
	l3:	/* end checkedFloatPtrOf: */;
	/* begin checkedFloatPtrOf: */
	success(isWordsOrBytes(bArOop));
	if (failed()) {
		bArray = 0;
		goto l4;
	}
	bArray = ((double *) (firstIndexableField(bArOop)));
	l4:	/* end checkedFloatPtrOf: */;
	success((stSizeOf(outOop)) == allPix);
	if (failed()) {
		return null;
	}
	height = allPix / width;
	t1 = rand();
	blops = (t1 % ripply) - 1;
	for (t = 0; t < (blops / 2); t += 1) {
		t1 = rand();
		x = t1 % width;
		t1 = rand();
		y = t1 % height;
		t1 = rand();
		power = t1 % 8;
		for (g = -4; g <= 4; g += 1) {
			for (h = -4; h <= 4; h += 1) {
				dist = ((double) ((g * g) + (h * h)) );
				if ((dist < 25)
				 && (dist > 0)) {
					dx = ((sqInt)(x + g));
					dy = ((sqInt)(y + h));
					if ((dx > 0)
					 && ((dy > 0)
					 && ((dy < height)
					 && (dx < width)))) {
						aArray[(dy * width) + dx] = (power * (((double) ((((double) 1.0 )) - (dist / (((double) 25.0 )))) )));
					}
				}
			}
		}
	}
	for (f = 1; f <= (width - 2); f += 1) {
		for (d = 1; d <= (height - 2); d += 1) {
			val = (d * width) + f;
			aArray[val] = ((((((((((bArray[val + 1]) + (bArray[val - 1])) + (bArray[val + width])) + (bArray[val - width])) + ((bArray[(val - 1) - width]) / 2)) + ((bArray[(val - 1) + width]) / 2)) + ((bArray[(val + 1) - width]) / 2)) + ((bArray[(val + 1) + width]) / 2)) / 4) - (aArray[val]));
			aArray[val] = ((aArray[val]) * (((double) 0.9 )));
		}
	}
	for (q = 0; q <= (width * height); q += 1) {
		temp = bArray[q];
		bArray[q] = (aArray[q]);
		aArray[q] = temp;
	}
	for (j = 0; j < height; j += 1) {
		for (i = 0; i < width; i += 1) {
			if ((i > 1)
			 && ((i < (width - 1))
			 && ((j > 1)
			 && (j < (height - 1))))) {
				val2 = (j * width) + i;
				dx2 = ((double) ((((aArray[val2]) - (aArray[val2 - 1])) + ((aArray[val2 + 1]) - (aArray[val2]))) * 64) );
				dy2 = ((double) ((((aArray[val2]) - (aArray[val2 - width])) + ((aArray[val2 + width]) - (aArray[val2]))) / 64) );
				if (dx2 < -2) {
					dx2 = -2;
				}
				if (dx2 > 2) {
					dx2 = 2;
				}
				if (dy2 < -2) {
					dy2 = -2;
				}
				if (dy2 > 2) {
					dy2 = 2;
				}
				newLoc = ((sqInt)(((j + dy2) * width) + (i + dx2)));
				if ((newLoc < (width * height))
				 && (newLoc >= 0)) {
					pix = in[newLoc];
				}
				else {
					pix = in[i + (j * width)];
				}
			}
			else {
				pix = in[i + (j * width)];
			}
			out[i + (j * width)] = pix;
		}
	}
	pop(6);
	return 0;
}

	/* ScratchPlugin>>#primitiveWhirl */
EXPORT(sqInt)
primitiveWhirl(void)
{
    double ang;
    sqInt b;
    sqInt b1;
    sqInt b2;
    sqInt bottomPix;
    sqInt centerX;
    sqInt centerY;
    double cosa;
    double d;
    sqInt degrees;
    double dx;
    double dy;
    double factor;
    sqInt frac1;
    sqInt frac11;
    sqInt frac12;
    sqInt g;
    sqInt g1;
    sqInt g2;
    sqInt height;
    unsigned int *in;
    sqInt index;
    sqInt inOop;
    unsigned int *out;
    sqInt outOop;
    sqInt pix;
    sqInt pix2;
    sqInt pix21;
    sqInt r;
    sqInt r1;
    sqInt r2;
    sqInt radius;
    double radiusSquared;
    sqInt result;
    sqInt result1;
    sqInt result2;
    double scaleX;
    double scaleY;
    double sina;
    sqInt sz;
    sqInt topPix;
    double whirlRadians;
    sqInt width;
    sqInt x;
    sqInt x1;
    sqInt xFixed;
    sqInt xFrac;
    sqInt y;
    sqInt y1;
    sqInt yFixed;
    sqInt yFrac;

	inOop = stackValue(3);
	outOop = stackValue(2);
	width = stackIntegerValue(1);
	degrees = stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(inOop));
	if (failed()) {
		in = 0;
		goto l1;
	}
	in = ((unsigned int *) (firstIndexableField(inOop)));
	l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	success(isWords(outOop));
	if (failed()) {
		out = 0;
		goto l2;
	}
	out = ((unsigned int *) (firstIndexableField(outOop)));
	l2:	/* end checkedUnsignedIntPtrOf: */;
	sz = stSizeOf(inOop);
	success((stSizeOf(outOop)) == sz);
	if (failed()) {
		return null;
	}
	height = sz / width;
	centerX = width / 2;
	centerY = height / 2;
	if (centerX < centerY) {
		radius = centerX;
		scaleX = (((double) centerY )) / centerX;
		scaleY = 1.0;
	}
	else {
		radius = centerY;
		scaleX = 1.0;
		if (centerY < centerX) {
			scaleY = (((double) centerX )) / centerY;
		}
		else {
			scaleY = 1.0;
		}
	}
	whirlRadians = (-3.141592653589793 * degrees) / 180.0;
	radiusSquared = ((double) (radius * radius) );
	for (x = 0; x < width; x += 1) {
		for (y = 0; y < height; y += 1) {
			dx = scaleX * (((double) (x - centerX) ));
			dy = scaleY * (((double) (y - centerY) ));
			d = (dx * dx) + (dy * dy);
			if (d < radiusSquared) {

				/* inside the whirl circle */
				factor = 1.0 - ((sqrt(d)) / radius);
				ang = whirlRadians * (factor * factor);
				sina = sin(ang);
				cosa = cos(ang);
				/* begin interpolatedFrom:x:y:width:height: */
				xFixed = ((sqInt)(1024.0 * ((((cosa * dx) - (sina * dy)) / scaleX) + centerX)));
				yFixed = ((sqInt)(1024.0 * ((((sina * dx) + (cosa * dy)) / scaleY) + centerY)));
				x1 = ((usqInt) xFixed >> 10);
				if ((x1 < -1)
				 || (x1 >= width)) {
					pix = 0;
					goto l5;
				}
				y1 = ((usqInt) yFixed >> 10);
				if ((y1 < -1)
				 || (y1 >= height)) {
					pix = 0;
					goto l5;
				}
				xFrac = xFixed & 0x3FF;
				if (x1 == -1) {
					x1 = 0;
					xFrac = 0;
				}
				if (x1 == (width - 1)) {
					xFrac = 0;
				}
				yFrac = yFixed & 0x3FF;
				if (y1 == -1) {
					y1 = 0;
					yFrac = 0;
				}
				if (y1 == (height - 1)) {
					yFrac = 0;
				}

				/* for squeak: + 1 */
				index = (y1 * width) + x1;
				topPix = (in[index]) & 0xFFFFFF;
				if (xFrac > 0) {
					/* begin interpolate:and:frac: */
					pix2 = (in[index + 1]) & 0xFFFFFF;
					if (topPix == 0) {
						topPix = pix2;
						goto l3;
					}
					if (pix2 == 0) {
						topPix = topPix;
						goto l3;
					}
					frac1 = 1024 - xFrac;
					r = ((frac1 * ((((usqInt) topPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 16)) & 0xFF))) / 1024;
					g = ((frac1 * ((((usqInt) topPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix2 >> 8)) & 0xFF))) / 1024;
					b = ((frac1 * (topPix & 0xFF)) + (xFrac * (pix2 & 0xFF))) / 1024;
					result = ((((usqInt) r << 16)) + (((usqInt) g << 8))) + b;
					if (result == 0) {
						result = 1;
					}
					topPix = result;
	l3:	/* end interpolate:and:frac: */;
				}
				if (yFrac == 0) {
					pix = topPix;
					goto l5;
				}

				/* for squeak: + 1 */
				index = ((y1 + 1) * width) + x1;
				bottomPix = (in[index]) & 0xFFFFFF;
				if (xFrac > 0) {
					/* begin interpolate:and:frac: */
					pix21 = (in[index + 1]) & 0xFFFFFF;
					if (bottomPix == 0) {
						bottomPix = pix21;
						goto l4;
					}
					if (pix21 == 0) {
						bottomPix = bottomPix;
						goto l4;
					}
					frac11 = 1024 - xFrac;
					r1 = ((frac11 * ((((usqInt) bottomPix >> 16)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 16)) & 0xFF))) / 1024;
					g1 = ((frac11 * ((((usqInt) bottomPix >> 8)) & 0xFF)) + (xFrac * ((((usqInt) pix21 >> 8)) & 0xFF))) / 1024;
					b1 = ((frac11 * (bottomPix & 0xFF)) + (xFrac * (pix21 & 0xFF))) / 1024;
					result1 = ((((usqInt) r1 << 16)) + (((usqInt) g1 << 8))) + b1;
					if (result1 == 0) {
						result1 = 1;
					}
					bottomPix = result1;
	l4:	/* end interpolate:and:frac: */;
				}
				/* begin interpolate:and:frac: */
				if (topPix == 0) {
					pix = bottomPix;
					goto l5;
				}
				if (bottomPix == 0) {
					pix = topPix;
					goto l5;
				}
				frac12 = 1024 - yFrac;
				r2 = ((frac12 * ((((usqInt) topPix >> 16)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 16)) & 0xFF))) / 1024;
				g2 = ((frac12 * ((((usqInt) topPix >> 8)) & 0xFF)) + (yFrac * ((((usqInt) bottomPix >> 8)) & 0xFF))) / 1024;
				b2 = ((frac12 * (topPix & 0xFF)) + (yFrac * (bottomPix & 0xFF))) / 1024;
				result2 = ((((usqInt) r2 << 16)) + (((usqInt) g2 << 8))) + b2;
				if (result2 == 0) {
					result2 = 1;
				}
				pix = result2;
	l5:	/* end interpolatedFrom:x:y:width:height: */;
				out[(width * y) + x] = pix;
			}
		}
	}
	pop(4);
	return 0;
}


/*	Open the port with the given name and baud rate. */

	/* ScratchPlugin>>#primOpenPortNamed */
EXPORT(sqInt)
primOpenPortNamed(void)
{
    sqInt baudRate;
    sqInt count;
    sqInt i;
    sqInt nameOop;
    char nameStr[1000];
    sqInt portNum;
    char *src;

	nameOop = stackValue(1);
	baudRate = stackIntegerValue(0);
	success(isBytes(nameOop));
	if (failed()) {
		return 0;
	}
	src = ((char *) (firstIndexableField(nameOop)));
	count = stSizeOf(nameOop);
	for (i = 0; i < count; i += 1) {
		nameStr[i] = (src[i]);
	}
	nameStr[count] = 0;
	portNum = SerialPortOpenPortNamed(nameStr, baudRate);
	if (portNum == -1) {
		success(0);
		return 0;
	}
	return methodReturnInteger(portNum);
}


/*	Answer the number of serial ports. */

	/* ScratchPlugin>>#primPortCount */
EXPORT(sqInt)
primPortCount(void)
{
    sqInt result;

	result = SerialPortCount();
	if (result == -1) {
		success(0);
		return 0;
	}
	return methodReturnInteger(result);
}


/*	Get the name for the port with the given number. Fail if the port number
	is greater than the number of available ports. Port numbering starts with
	1. 
 */

	/* ScratchPlugin>>#primPortName */
EXPORT(sqInt)
primPortName(void)
{
    sqInt count;
    char* dst;
    sqInt i;
    char nameStr[1000];
    sqInt portIndex;
    sqInt resultOop;

	portIndex = stackIntegerValue(0);
	if (failed()) {
		return 0;
	}
	SerialPortName(portIndex, nameStr, 1000);
	count = strlen(nameStr);
	if (count == 0) {
		success(0);
		return 0;
	}
	resultOop = instantiateClassindexableSize(classString(), count);
	dst = ((char *) (firstIndexableField(resultOop)));
	for (i = 0; i < count; i += 1) {
		dst[i] = (nameStr[i]);
	}
	popthenPush(2, resultOop);
	return 0;
}


/*	Read data from the given serial port into the given buffer (a ByteArray or
	String). Answer the number of bytes read.
 */

	/* ScratchPlugin>>#primRead */
EXPORT(sqInt)
primRead(void)
{
    sqInt bufOop;
    sqInt bytesRead;
    sqInt portNum;

	portNum = stackIntegerValue(1);
	bufOop = stackValue(0);
	success(isBytes(bufOop));
	if (failed()) {
		return 0;
	}
	bytesRead = SerialPortRead(portNum, ((char *) (firstIndexableField(bufOop))), stSizeOf(bufOop));
	pop(3);
	pushInteger(bytesRead);
	return 0;
}


/*	Return the given option value for the given serial port. */

	/* ScratchPlugin>>#primSetOption */
EXPORT(sqInt)
primSetOption(void)
{
    sqInt attrNum;
    sqInt attrValue;
    sqInt portNum;
    sqInt result;

	portNum = stackIntegerValue(2);
	attrNum = stackIntegerValue(1);
	attrValue = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	result = SerialPortSetOption(portNum, attrNum, attrValue);
	if (result == -1) {
		success(0);
		return 0;
	}
	pop(3);
	return 0;
}


/*	Write data to the given serial port from the given buffer (a ByteArray or
	String). Answer the number of bytes written.
 */

	/* ScratchPlugin>>#primWrite */
EXPORT(sqInt)
primWrite(void)
{
    sqInt bufOop;
    sqInt bytesWritten;
    sqInt portNum;

	portNum = stackIntegerValue(1);
	bufOop = stackValue(0);
	success(isBytes(bufOop));
	if (failed()) {
		return 0;
	}
	bytesWritten = SerialPortWrite(portNum, ((char *) (firstIndexableField(bufOop))), stSizeOf(bufOop));
	pop(3);
	pushInteger(bytesWritten);
	return 0;
}


/*	Note: This is coded so that it can be run in Squeak. */

	/* InterpreterPlugin>>#setInterpreter: */
EXPORT(sqInt)
setInterpreter(struct VirtualMachine *anInterpreter)
{
    sqInt ok;

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		booleanValueOf = interpreterProxy->booleanValueOf;
		classString = interpreterProxy->classString;
		failed = interpreterProxy->failed;
		firstIndexableField = interpreterProxy->firstIndexableField;
		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
		isBytes = interpreterProxy->isBytes;
		isWords = interpreterProxy->isWords;
		isWordsOrBytes = interpreterProxy->isWordsOrBytes;
		methodReturnInteger = interpreterProxy->methodReturnInteger;
		pop = interpreterProxy->pop;
		popthenPush = interpreterProxy->popthenPush;
		pushBool = interpreterProxy->pushBool;
		pushInteger = interpreterProxy->pushInteger;
		stSizeOf = interpreterProxy->stSizeOf;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackValue = interpreterProxy->stackValue;
		success = interpreterProxy->success;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}


#ifdef SQUEAK_BUILTIN_PLUGIN

static char _m[] = "ScratchPlugin";
void* ScratchPlugin_exports[][3] = {
	{(void*)_m, "getModuleName", (void*)getModuleName},
	{(void*)_m, "primClose\000\000", (void*)primClose},
	{(void*)_m, "primGetOption\000\000", (void*)primGetOption},
	{(void*)_m, "primIsPortOpen\000\000", (void*)primIsPortOpen},
	{(void*)_m, "primitiveBlur\000\000", (void*)primitiveBlur},
	{(void*)_m, "primitiveBrightnessShift\000\000", (void*)primitiveBrightnessShift},
	{(void*)_m, "primitiveCondenseSound\000\000", (void*)primitiveCondenseSound},
	{(void*)_m, "primitiveDoubleSize\000\000", (void*)primitiveDoubleSize},
	{(void*)_m, "primitiveExtractChannel\000\000", (void*)primitiveExtractChannel},
	{(void*)_m, "primitiveFisheye\000\000", (void*)primitiveFisheye},
	{(void*)_m, "primitiveGetFolderPath\000\000", (void*)primitiveGetFolderPath},
	{(void*)_m, "primitiveHalfSizeAverage\000\000", (void*)primitiveHalfSizeAverage},
	{(void*)_m, "primitiveHalfSizeDiagonal\000\000", (void*)primitiveHalfSizeDiagonal},
	{(void*)_m, "primitiveHueShift\000\000", (void*)primitiveHueShift},
	{(void*)_m, "primitiveInterpolate\000\000", (void*)primitiveInterpolate},
	{(void*)_m, "primitiveIsHidden\000\000", (void*)primitiveIsHidden},
	{(void*)_m, "primitiveOpenURL\000\000", (void*)primitiveOpenURL},
	{(void*)_m, "primitiveSaturationShift\000\000", (void*)primitiveSaturationShift},
	{(void*)_m, "primitiveScale\000\000", (void*)primitiveScale},
	{(void*)_m, "primitiveSetUnicodePasteBuffer\000\000", (void*)primitiveSetUnicodePasteBuffer},
	{(void*)_m, "primitiveSetWindowTitle\000\000", (void*)primitiveSetWindowTitle},
	{(void*)_m, "primitiveShortToLongPath\000\000", (void*)primitiveShortToLongPath},
	{(void*)_m, "primitiveWaterRipples1\000\000", (void*)primitiveWaterRipples1},
	{(void*)_m, "primitiveWhirl\000\000", (void*)primitiveWhirl},
	{(void*)_m, "primOpenPortNamed\000\000", (void*)primOpenPortNamed},
	{(void*)_m, "primPortCount\000\377", (void*)primPortCount},
	{(void*)_m, "primPortName\000\000", (void*)primPortName},
	{(void*)_m, "primRead\000\000", (void*)primRead},
	{(void*)_m, "primSetOption\000\000", (void*)primSetOption},
	{(void*)_m, "primWrite\000\000", (void*)primWrite},
	{(void*)_m, "setInterpreter", (void*)setInterpreter},
	{NULL, NULL, NULL}
};

#else /* ifdef SQ_BUILTIN_PLUGIN */

signed char primCloseAccessorDepth = 0;
signed char primGetOptionAccessorDepth = 0;
signed char primIsPortOpenAccessorDepth = 0;
signed char primitiveBlurAccessorDepth = 0;
signed char primitiveBrightnessShiftAccessorDepth = 0;
signed char primitiveCondenseSoundAccessorDepth = 0;
signed char primitiveDoubleSizeAccessorDepth = 0;
signed char primitiveExtractChannelAccessorDepth = 0;
signed char primitiveFisheyeAccessorDepth = 0;
signed char primitiveGetFolderPathAccessorDepth = 0;
signed char primitiveHalfSizeAverageAccessorDepth = 0;
signed char primitiveHalfSizeDiagonalAccessorDepth = 0;
signed char primitiveHueShiftAccessorDepth = 0;
signed char primitiveInterpolateAccessorDepth = 0;
signed char primitiveIsHiddenAccessorDepth = 0;
signed char primitiveOpenURLAccessorDepth = 0;
signed char primitiveSaturationShiftAccessorDepth = 0;
signed char primitiveScaleAccessorDepth = 0;
signed char primitiveSetUnicodePasteBufferAccessorDepth = 0;
signed char primitiveSetWindowTitleAccessorDepth = 0;
signed char primitiveShortToLongPathAccessorDepth = 0;
signed char primitiveWaterRipples1AccessorDepth = 0;
signed char primitiveWhirlAccessorDepth = 0;
signed char primOpenPortNamedAccessorDepth = 0;
signed char primPortNameAccessorDepth = 0;
signed char primReadAccessorDepth = 0;
signed char primSetOptionAccessorDepth = 0;
signed char primWriteAccessorDepth = 0;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
