/* Automatically generated from Squeak on #(4 April 2004 12:15:56 pm) */

#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. */
/*  The virtual machine proxy definition */
#include "sqVirtualMachine.h"
/* Configuration options */
#include "sqConfig.h"
/* Platform specific definitions */
#include "sqPlatformSpecific.h"

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

/* memory access macros */
#define byteAt(i) (*((unsigned char *) (i)))
#define byteAtput(i, val) (*((unsigned char *) (i)) = val)
#define longAt(i) (*((int *) (i)))
#define longAtput(i, val) (*((int *) (i)) = val)


/*** Constants ***/

/*** Variables ***/

#ifdef SQUEAK_BUILTIN_PLUGIN
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"StarSqueakPlugin 4 April 2004 (i)"
#else
	"StarSqueakPlugin 4 April 2004 (e)"
#endif
;

/*** Function Prototypes ***/
static unsigned int * checkedUnsignedIntPtrOf(int oop);
#pragma export on
EXPORT(const char*) getModuleName(void);
#pragma export off
static int halt(void);
static int msg(char *s);
#pragma export on
EXPORT(int) primitiveDiffuseFromToWidthHeightDelta(void);
EXPORT(int) primitiveEvaporateRate(void);
EXPORT(int) primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift(void);
EXPORT(int) setInterpreter(struct VirtualMachine* anInterpreter);
#pragma export off


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

static unsigned int * checkedUnsignedIntPtrOf(int oop) {
	interpreterProxy->success(interpreterProxy->isWords(oop));
	if (interpreterProxy->failed()) {
		return 0;
	}
	return ((unsigned int *) (interpreterProxy->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! */

EXPORT(const char*) getModuleName(void) {
	return moduleName;
}

static int halt(void) {
	;
}

static int msg(char *s) {
	fprintf(stderr, "\n%s: %s", moduleName, s);
}


/*	Diffuse the integer values of the source patch variable Bitmap into the output Bitmap. Each cell of the output is the average of the NxN area around it in the source, where N = (2 * delta) + 1. */

EXPORT(int) primitiveDiffuseFromToWidthHeightDelta(void) {
    int dstOop;
    int sum;
    int endX;
    int area;
    unsigned int * dst;
    int x;
    int srcOop;
    int rowStart;
    int startX;
    int width;
    int height;
    int endY;
    int x2;
    int y;
    int y2;
    int delta;
    int startY;
    unsigned int * src;

	srcOop = interpreterProxy->stackValue(4);
	dstOop = interpreterProxy->stackValue(3);
	width = interpreterProxy->stackIntegerValue(2);
	height = interpreterProxy->stackIntegerValue(1);
	delta = interpreterProxy->stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	interpreterProxy->success(interpreterProxy->isWords(srcOop));
	if (interpreterProxy->failed()) {
		src = 0;
		goto l1;
	}
	src = ((unsigned int *) (interpreterProxy->firstIndexableField(srcOop)));
l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	interpreterProxy->success(interpreterProxy->isWords(dstOop));
	if (interpreterProxy->failed()) {
		dst = 0;
		goto l2;
	}
	dst = ((unsigned int *) (interpreterProxy->firstIndexableField(dstOop)));
l2:	/* end checkedUnsignedIntPtrOf: */;
	interpreterProxy->success((interpreterProxy->stSizeOf(srcOop)) == (interpreterProxy->stSizeOf(dstOop)));
	interpreterProxy->success((interpreterProxy->stSizeOf(srcOop)) == (width * height));
	if (interpreterProxy->failed()) {
		return null;
	}
	area = ((2 * delta) + 1) * ((2 * delta) + 1);
	for (y = 0; y <= (height - 1); y += 1) {
		startY = y - delta;
		if (startY < 0) {
			startY = 0;
		}
		endY = y + delta;
		if (endY >= height) {
			endY = height - 1;
		}
		for (x = 0; x <= (width - 1); x += 1) {
			startX = x - delta;
			if (startX < 0) {
				startX = 0;
			}
			endX = x + delta;
			if (endX >= width) {
				endX = width - 1;
			}
			sum = 0;
			for (y2 = startY; y2 <= endY; y2 += 1) {
				rowStart = y2 * width;
				for (x2 = startX; x2 <= endX; x2 += 1) {
					sum += src[rowStart + x2];
				}
			}
			dst[(y * width) + x] = (sum / area);
		}
	}
	interpreterProxy->pop(5);
}


/*	Evaporate the integer values of the source Bitmap at the given rate. The rate is an integer between 0 and 1024, where 1024 is a scale factor of 1.0 (i.e., no evaporation). */

EXPORT(int) primitiveEvaporateRate(void) {
    int i;
    unsigned int * patchVar;
    int rate;
    int sz;
    int patchVarOop;

	patchVarOop = interpreterProxy->stackValue(1);
	rate = interpreterProxy->stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	interpreterProxy->success(interpreterProxy->isWords(patchVarOop));
	if (interpreterProxy->failed()) {
		patchVar = 0;
		goto l1;
	}
	patchVar = ((unsigned int *) (interpreterProxy->firstIndexableField(patchVarOop)));
l1:	/* end checkedUnsignedIntPtrOf: */;
	sz = interpreterProxy->stSizeOf(patchVarOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	for (i = 0; i <= (sz - 1); i += 1) {
		patchVar[i] = (((unsigned) ((patchVar[i]) * rate)) >> 10);
	}
	interpreterProxy->pop(2);
}

EXPORT(int) primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift(void) {
    int dstOop;
    int dstIndex;
    int patchSize;
    unsigned int * dst;
    int x;
    int shiftAmount;
    int srcOop;
    int rowStart;
    int level;
    int rgbMult;
    int offset;
    int srcIndex;
    int pixel;
    int y;
    int rgbFlags;
    int h;
    unsigned int * src;
    int w;

	srcOop = interpreterProxy->stackValue(6);
	dstOop = interpreterProxy->stackValue(5);
	w = interpreterProxy->stackIntegerValue(4);
	h = interpreterProxy->stackIntegerValue(3);
	patchSize = interpreterProxy->stackIntegerValue(2);
	rgbFlags = interpreterProxy->stackIntegerValue(1);
	shiftAmount = interpreterProxy->stackIntegerValue(0);
	/* begin checkedUnsignedIntPtrOf: */
	interpreterProxy->success(interpreterProxy->isWords(srcOop));
	if (interpreterProxy->failed()) {
		src = 0;
		goto l1;
	}
	src = ((unsigned int *) (interpreterProxy->firstIndexableField(srcOop)));
l1:	/* end checkedUnsignedIntPtrOf: */;
	/* begin checkedUnsignedIntPtrOf: */
	interpreterProxy->success(interpreterProxy->isWords(dstOop));
	if (interpreterProxy->failed()) {
		dst = 0;
		goto l2;
	}
	dst = ((unsigned int *) (interpreterProxy->firstIndexableField(dstOop)));
l2:	/* end checkedUnsignedIntPtrOf: */;
	interpreterProxy->success((interpreterProxy->stSizeOf(dstOop)) == (w * h));
	interpreterProxy->success((interpreterProxy->stSizeOf(dstOop)) == (((interpreterProxy->stSizeOf(srcOop)) * patchSize) * patchSize));
	if (interpreterProxy->failed()) {
		return null;
	}
	rgbMult = 0;
	if ((rgbFlags & 4) > 0) {
		rgbMult += 65536;
	}
	if ((rgbFlags & 2) > 0) {
		rgbMult += 256;
	}
	if ((rgbFlags & 1) > 0) {
		rgbMult += 1;
	}
	srcIndex = -1;
	for (y = 0; y <= ((h / patchSize) - 1); y += 1) {
		for (x = 0; x <= ((w / patchSize) - 1); x += 1) {
			level = ((shiftAmount < 0) ? ((unsigned) (src[srcIndex += 1]) >> -shiftAmount) : ((unsigned) (src[srcIndex += 1]) << shiftAmount));
			if (level > 255) {
				level = 255;
			}
			if (level <= 0) {

				/* non-transparent black */

				pixel = 1;
			} else {
				pixel = level * rgbMult;
			}
			offset = ((y * w) + x) * patchSize;
			for (rowStart = offset; rowStart <= (offset + ((patchSize - 1) * w)); rowStart += w) {
				for (dstIndex = rowStart; dstIndex <= ((rowStart + patchSize) - 1); dstIndex += 1) {
					dst[dstIndex] = pixel;
				}
			}
		}
	}
	interpreterProxy->pop(7);
}


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

EXPORT(int) setInterpreter(struct VirtualMachine* anInterpreter) {
    int ok;

	interpreterProxy = anInterpreter;
	ok = interpreterProxy->majorVersion() == VM_PROXY_MAJOR;
	if (ok == 0) {
		return 0;
	}
	ok = interpreterProxy->minorVersion() >= VM_PROXY_MINOR;
	return ok;
}


#ifdef SQUEAK_BUILTIN_PLUGIN


void* StarSqueakPlugin_exports[][3] = {
	{"StarSqueakPlugin", "primitiveDiffuseFromToWidthHeightDelta", (void*)primitiveDiffuseFromToWidthHeightDelta},
	{"StarSqueakPlugin", "primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift", (void*)primitiveMapFromToWidthHeightPatchSizeRgbFlagsShift},
	{"StarSqueakPlugin", "getModuleName", (void*)getModuleName},
	{"StarSqueakPlugin", "primitiveEvaporateRate", (void*)primitiveEvaporateRate},
	{"StarSqueakPlugin", "setInterpreter", (void*)setInterpreter},
	{NULL, NULL, NULL}
};


#endif /* ifdef SQ_BUILTIN_PLUGIN */

