/* Automatically generated from Squeak on #(4 April 2004 12:15:29 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
#include "b3d.h"
#include "b3d.h"

/* 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 ***/
#define AmbientPart 0
#define DiffusePart 4
#define EmissionAlpha 15
#define EmissionBlue 14
#define EmissionGreen 13
#define EmissionRed 12
#define FlagAmbientPart 256
#define FlagAttenuated 4
#define FlagDiffusePart 512
#define FlagDirectional 2
#define FlagHasSpot 8
#define FlagM44Identity 1
#define FlagM44NoPerspective 2
#define FlagM44NoTranslation 4
#define FlagPositional 1
#define FlagSpecularPart 1024
#define InAllMask 1365
#define InBackBit 1024
#define InBottomBit 64
#define InFrontBit 256
#define InLeftBit 1
#define InRightBit 4
#define InTopBit 16
#define MaterialShininess 16
#define MaterialSize 17
#define OutAllMask 2730
#define OutBackBit 2048
#define OutBottomBit 128
#define OutFrontBit 512
#define OutLeftBit 2
#define OutRightBit 8
#define OutTopBit 32
#define PrimLightAttenuationConstant 18
#define PrimLightAttenuationLinear 19
#define PrimLightAttenuationSquared 20
#define PrimLightDirection 15
#define PrimLightDirectionX 15
#define PrimLightDirectionY 16
#define PrimLightDirectionZ 17
#define PrimLightFlags 21
#define PrimLightPositionX 12
#define PrimLightPositionY 13
#define PrimLightPositionZ 14
#define PrimLightSize 32
#define PrimTypeMax 6
#define PrimVertexSize 16
#define PrimVtxClipFlags 13
#define PrimVtxColor32 12
#define PrimVtxNormal 3
#define PrimVtxNormalX 3
#define PrimVtxNormalY 4
#define PrimVtxNormalZ 5
#define PrimVtxPosition 0
#define PrimVtxPositionX 0
#define PrimVtxPositionY 1
#define PrimVtxPositionZ 2
#define PrimVtxRasterPosW 11
#define PrimVtxRasterPosX 8
#define PrimVtxRasterPosY 9
#define PrimVtxRasterPosZ 10
#define PrimVtxTexCoordU 6
#define PrimVtxTexCoordV 7
#define PrimVtxTexCoords 6
#define SpecularPart 8
#define SpotLightDeltaCos 24
#define SpotLightExponent 25
#define SpotLightMinCos 22
#define VBTrackAmbient 1
#define VBTrackDiffuse 2
#define VBTrackEmission 8
#define VBTrackSpecular 4
#define VBTwoSidedLighting 64
#define VBUseLocalViewer 128
#define VBVtxHasNormals 16

/*** Variables ***/
static char bbPluginName[256] = "BitBltPlugin";
static int copyBitsFn;

#ifdef SQUEAK_BUILTIN_PLUGIN
extern
#endif
struct VirtualMachine* interpreterProxy;
static double l2vDirection[3];
static double l2vDistance;
static double l2vSpecDir[3];
static int lightFlags;
static double lightScale;
static float* litVertex;
static int loadBBFn;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"Squeak3D 4 April 2004 (i)"
#else
	"Squeak3D 4 April 2004 (e)"
#endif
;
static float* primLight;
static float* primMaterial;
static B3DRasterizerState state;
static int vbFlags;
static B3DPrimitiveViewport viewport;
static double vtxInColor[4];
static double vtxOutColor[4];

/*** Function Prototypes ***/
static int addPartfromtrackFlagscale(float *lightPart, float *materialPart, int vbTrackFlag, double scale);
static int analyzeMatrix3x3Length(float *m);
static int analyzeMatrix(float *m);
#pragma export on
EXPORT(int) b3dClipPolygon(void);
EXPORT(int) b3dComputeMinIndexZ(void);
EXPORT(int) b3dComputeMinZ(void);
EXPORT(int) b3dDetermineClipFlags(void);
EXPORT(int) b3dInitPrimitiveObject(void);
EXPORT(int) b3dInitializeRasterizerState(void);
EXPORT(int) b3dInplaceHouseHolderInvert(void);
EXPORT(int) b3dLoadIndexArray(void);
EXPORT(int) b3dLoadVertexBuffer(void);
EXPORT(int) b3dMapVertexBuffer(void);
EXPORT(int) b3dOrthoNormInverseMatrix(void);
EXPORT(int) b3dPrimitiveNextClippedTriangle(void);
EXPORT(int) b3dPrimitiveObjectSize(void);
EXPORT(int) b3dPrimitiveTextureSize(void);
EXPORT(int) b3dRasterizerVersion(void);
EXPORT(int) b3dShadeVertexBuffer(void);
EXPORT(int) b3dShaderVersion(void);
EXPORT(int) b3dStartRasterizer(void);
EXPORT(int) b3dTransformDirection(void);
EXPORT(int) b3dTransformMatrixWithInto(void);
EXPORT(int) b3dTransformPoint(void);
EXPORT(int) b3dTransformPrimitiveNormal(void);
EXPORT(int) b3dTransformPrimitivePosition(void);
EXPORT(int) b3dTransformPrimitiveRasterPosition(void);
EXPORT(int) b3dTransformVertexBuffer(void);
EXPORT(int) b3dTransformerVersion(void);
EXPORT(int) b3dTransposeMatrix(void);
#pragma export off
static double backClipValueFromto(int last, int next);
static double bottomClipValueFromto(int last, int next);
static int clipPolygoncountwithmask(int *vtxArray, int vtxCount, int *tempVtxArray, int outMask);
static int clipPolygonBackFromtocount(int *buf1, int *buf2, int n);
static int clipPolygonBottomFromtocount(int *buf1, int *buf2, int n);
static int clipPolygonFrontFromtocount(int *buf1, int *buf2, int n);
static int clipPolygonLeftFromtocount(int *buf1, int *buf2, int n);
static int clipPolygonRightFromtocount(int *buf1, int *buf2, int n);
static int clipPolygonTopFromtocount(int *buf1, int *buf2, int n);
static int computeAttenuation(void);
static int computeDirection(void);
static int computeSpecularDirection(void);
static double computeSpotFactor(void);
static int determineClipFlagscount(void *vtxArray, int count);
static double dotProductOfFloatwithDouble(float * v1, double *v2);
static void* fetchLightSourceofObject(int index, int anArray);
static double frontClipValueFromto(int last, int next);
#pragma export on
EXPORT(const char*) getModuleName(void);
#pragma export off
static int halt(void);
#pragma export on
EXPORT(int) initialiseModule(void);
#pragma export off
static int interpolateFromtoatinto(float *last, float *next, double t, float *out);
static double inverseLengthOfDouble(double * aVector);
static double inverseLengthOfFloat(float * aVector);
static double leftClipValueFromto(int last, int next);
static int loadObjectsFrom(int stackIndex);
static int loadPrimitiveLightSource(void);
static int loadPrimitiveVertex(void);
static int loadRasterizerState(int stackIndex);
static int loadTextureinto(int textureOop, B3DTexture *destPtr);
static int loadTexturesFrom(int stackIndex);
static int loadViewportFrom(int stackIndex);
static int mapVBofSizeinto(void *vtxArray, int vtxCount, int boxArray);
#pragma export on
EXPORT(int) moduleUnloaded(char * aModuleName);
#pragma export off
static int msg(char *s);
#pragma export on
EXPORT(int) primitiveSetBitBltPlugin(void);
#pragma export off
static double processIndexedofSizeidxArrayidxSize(float *vtxArray, int vtxSize, int *idxArray, int idxSize);
static int processIndexedIDXofSizeidxArrayidxSize(float *vtxArray, int vtxSize, int *idxArray, int idxSize);
static double processNonIndexedofSize(float *vtxArray, int vtxSize);
static int processNonIndexedIDXofSize(float *vtxArray, int vtxSize);
static double rightClipValueFromto(int last, int next);
#pragma export on
EXPORT(int) setInterpreter(struct VirtualMachine* anInterpreter);
#pragma export off
static int shadeVertex(void);
static int stackLightArrayValue(int stackIndex);
static void * stackMaterialValue(int stackIndex);
static void* stackMatrix(int index);
static void* stackPrimitiveIndexArrayofSizevalidateforVertexSize(int stackIndex, int nItems, int aBool, int maxIndex);
static void* stackPrimitiveVertex(int index);
static void* stackPrimitiveVertexArrayofSize(int index, int nItems);
static int storeObjectsInto(int stackIndex);
static int storePrimitiveVertex(void);
static double topClipValueFromto(int last, int next);
static int transformMatrixwithinto(float *src, float *arg, float *dst);
static int transformPrimitiveNormalbyrescale(float *pVertex, float *matrix, int rescale);
static int transformPrimitivePositionby(float *pVertex, float *matrix);
static int transformPrimitivePositionFastby(float *pVertex, float *matrix);
static int transformPrimitivePositionFasterby(float *pVertex, float *matrix);
static int transformPrimitiveRasterPositionby(float *pVertex, float *matrix);
static int transformVBcountbyandflags(float *vtxArray, int vtxCount, float *modelViewMatrix, float *projectionMatrix, int flags);
static void* vbLoadArraysize(int oop, int count);


/*	Add the given light part to the output color, scaled by the given scale factor.

	If the given flag is set in vbFlags then load the part from the primitive vertex */

static int addPartfromtrackFlagscale(float *lightPart, float *materialPart, int vbTrackFlag, double scale) {
    double gPart;
    double aPart;
    double rPart;
    double bPart;

	if (vbFlags & vbTrackFlag) {
		rPart = ((vtxInColor[0]) * (lightPart[0])) * scale;
		gPart = ((vtxInColor[1]) * (lightPart[1])) * scale;
		bPart = ((vtxInColor[2]) * (lightPart[2])) * scale;
		aPart = ((vtxInColor[3]) * (lightPart[3])) * scale;
	} else {
		rPart = ((materialPart[0]) * (lightPart[0])) * scale;
		gPart = ((materialPart[1]) * (lightPart[1])) * scale;
		bPart = ((materialPart[2]) * (lightPart[2])) * scale;
		aPart = ((materialPart[3]) * (lightPart[3])) * scale;
	}
	vtxOutColor[0] = ((vtxOutColor[0]) + rPart);
	vtxOutColor[1] = ((vtxOutColor[1]) + gPart);
	vtxOutColor[2] = ((vtxOutColor[2]) + bPart);
	vtxOutColor[3] = ((vtxOutColor[3]) + aPart);
}


/*	Check if the matrix scales normals to non-unit length. */

static int analyzeMatrix3x3Length(float *m) {
    double det;

	det = (((((((m[0]) * (m[5])) * (m[10])) - (((m[2]) * (m[5])) * (m[8]))) + (((m[4]) * (m[9])) * (m[2]))) - (((m[6]) * (m[9])) * (m[0]))) + (((m[8]) * (m[1])) * (m[6]))) - (((m[10]) * (m[1])) * (m[4]));
	return (det < 0.99) || (det > 1.01);
}


/*	Analyze the matrix and return the appropriate flags */

static int analyzeMatrix(float *m) {
    int flags;

	flags = 0;
	if (((m[12]) == 0.0) && (((m[13]) == 0.0) && (((m[14]) == 0.0) && ((m[15]) == 1.0)))) {

		/* Check translation */

		flags = flags | FlagM44NoPerspective;
		if (((m[3]) == 0.0) && (((m[7]) == 0.0) && ((m[11]) == 0.0))) {

			/* Check for identity */

			flags = flags | FlagM44NoTranslation;
			if (((m[0]) == 1.0) && (((m[5]) == 1.0) && (((m[10]) == 1.0) && (((m[1]) == 0.0) && (((m[2]) == 0.0) && (((m[4]) == 0.0) && (((m[6]) == 0.0) && (((m[8]) == 0.0) && ((m[9]) == 0.0))))))))) {
				flags = flags | FlagM44Identity;
			}
		}
	}
	return flags;
}


/*	Primitive. Clip the polygon given in the vertexArray using the temporary vertex array which is assumed to have sufficient size. */

EXPORT(int) b3dClipPolygon(void) {
    int *tempVtxArray;
    int count;
    int outMask;
    int vtxCount;
    int *vtxArray;

	if (!((interpreterProxy->methodArgumentCount()) == 4)) {
		return interpreterProxy->primitiveFail();
	}
	outMask = interpreterProxy->stackIntegerValue(0);
	vtxCount = interpreterProxy->stackIntegerValue(2);
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxCount + 4);
	tempVtxArray = stackPrimitiveVertexArrayofSize(1, vtxCount + 4);
	if ((vtxArray == null) || ((tempVtxArray == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	vtxArray -= PrimVertexSize;
	tempVtxArray -= PrimVertexSize;
	count = clipPolygoncountwithmask(vtxArray, vtxCount, tempVtxArray, outMask);
	interpreterProxy->pop(5);
	interpreterProxy->pushInteger(count);
}


/*	Primitive. Compute and return the index for the minimal z value of all objects in the vertex buffer. */

EXPORT(int) b3dComputeMinIndexZ(void) {
    int vtxSize;
    int primType;
    int idxSize;
    int minIndex;
    int *idxArray;
    float *vtxArray;

	if (!((interpreterProxy->methodArgumentCount()) == 5)) {
		return interpreterProxy->primitiveFail();
	}
	idxSize = interpreterProxy->stackIntegerValue(0);
	vtxSize = interpreterProxy->stackIntegerValue(2);
	primType = interpreterProxy->stackIntegerValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxSize);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxSize, 1, vtxSize);
	if ((vtxArray == null) || ((idxArray == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	if ((primType < 1) || (primType > 6)) {
		return interpreterProxy->primitiveFail();
	}
	if (primType <= 3) {
		minIndex = processNonIndexedIDXofSize(vtxArray, vtxSize);
	} else {
		minIndex = processIndexedIDXofSizeidxArrayidxSize(vtxArray, vtxSize, idxArray, idxSize);
	}
	if (!(interpreterProxy->failed())) {
		interpreterProxy->pop(6);
		interpreterProxy->pushInteger(minIndex);
	}
}


/*	Primitive. Compute and return the minimal z value of all objects in the vertex buffer. */

EXPORT(int) b3dComputeMinZ(void) {
    int vtxSize;
    int primType;
    int idxSize;
    double minZ;
    int *idxArray;
    float *vtxArray;

	if (!((interpreterProxy->methodArgumentCount()) == 5)) {
		return interpreterProxy->primitiveFail();
	}
	idxSize = interpreterProxy->stackIntegerValue(0);
	vtxSize = interpreterProxy->stackIntegerValue(2);
	primType = interpreterProxy->stackIntegerValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxSize);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxSize, 1, vtxSize);
	if ((vtxArray == null) || ((idxArray == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	if ((primType < 1) || (primType > 6)) {
		return interpreterProxy->primitiveFail();
	}
	if (primType <= 3) {
		minZ = processNonIndexedofSize(vtxArray, vtxSize);
	} else {
		minZ = processIndexedofSizeidxArrayidxSize(vtxArray, vtxSize, idxArray, idxSize);
	}
	if (!(interpreterProxy->failed())) {
		interpreterProxy->pop(6);
		interpreterProxy->pushFloat(minZ);
	}
}


/*	Primitive. Determine the clipping flags for all vertices. */

EXPORT(int) b3dDetermineClipFlags(void) {
    int vtxCount;
    void *vtxArray;
    int result;

	if (!((interpreterProxy->methodArgumentCount()) == 2)) {
		return interpreterProxy->primitiveFail();
	}
	vtxCount = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(1, vtxCount);
	if ((vtxArray == null) || (interpreterProxy->failed())) {
		return interpreterProxy->primitiveFail();
	}
	result = determineClipFlagscount(vtxArray, vtxCount);
	if (!(interpreterProxy->failed())) {
		interpreterProxy->pop(3);
		interpreterProxy->pushInteger(result);
	}
}

EXPORT(int) b3dInitPrimitiveObject(void) {
    int vtxSize;
    int textureIndex;
    int primSize;
    int idxSize;
    void *primObj;
    int *idxArray;
    int *vtxArray;
    int primitive;
    int primOop;

	if (!((interpreterProxy->methodArgumentCount()) == 8)) {
		return interpreterProxy->primitiveFail();
	}
	textureIndex = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	loadViewportFrom(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxSize = interpreterProxy->stackIntegerValue(4);
	vtxArray = stackPrimitiveVertexArrayofSize(5, vtxSize);
	if (vtxArray == null) {
		return interpreterProxy->primitiveFail();
	}
	idxSize = interpreterProxy->stackIntegerValue(2);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(3, idxSize, 1, vtxSize);
	if (idxArray == null) {
		return interpreterProxy->primitiveFail();
	}
	primitive = interpreterProxy->stackIntegerValue(6);
	if ((primitive < 1) || (primitive > PrimTypeMax)) {
		return interpreterProxy->primitiveFail();
	}
	if (!((primitive == 3) || ((primitive == 5) || (primitive == 6)))) {
		return interpreterProxy->primitiveFail();
	}
	primOop = interpreterProxy->stackObjectValue(7);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(interpreterProxy->isWords(primOop))) {
		return interpreterProxy->primitiveFail();
	}
	primObj = interpreterProxy->firstIndexableField(primOop);

	/* Do the work */

	primSize = interpreterProxy->byteSizeOf(primOop);
	if (primitive == 3) {
		if (b3dAddPolygonObject((void*) primObj, primSize, B3D_FACE_RGB, textureIndex, (B3DPrimitiveVertex*) vtxArray, vtxSize, &viewport) != B3D_NO_ERROR) {
			return interpreterProxy->primitiveFail();
		}
	}
	if (primitive == 5) {
		if (b3dAddIndexedTriangleObject((void*) primObj, primSize, B3D_FACE_RGB, textureIndex, (B3DPrimitiveVertex*) vtxArray, vtxSize, (B3DInputFace*) idxArray, idxSize / 3, &viewport) != B3D_NO_ERROR) {
			return interpreterProxy->primitiveFail();
		}
	}
	if (primitive == 6) {
		if (b3dAddIndexedQuadObject((void*) primObj, primSize, B3D_FACE_RGB, textureIndex, (B3DPrimitiveVertex*) vtxArray, vtxSize, (B3DInputQuad*) idxArray, idxSize / 4, &viewport) != B3D_NO_ERROR) {
			return interpreterProxy->primitiveFail();
		}
	}
	interpreterProxy->pop(9);
	interpreterProxy->push(primOop);
}


/*	Primitive. Initialize the primitive level objects of the given rasterizer. */

EXPORT(int) b3dInitializeRasterizerState(void) {
    int objOop;
    int stateOop;
    void *obj;
    int objLen;

	if (!((interpreterProxy->methodArgumentCount()) == 0)) {
		return interpreterProxy->primitiveFail();
	}
	stateOop = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->isPointers(stateOop)) && ((interpreterProxy->slotSizeOf(stateOop)) >= 7))) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(0, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeFaceAllocator(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(1, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeEdgeAllocator(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(2, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeAttrAllocator(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(3, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeAET(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(4, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeEdgeList(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
	objOop = interpreterProxy->fetchPointerofObject(5, stateOop);
	if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
		return interpreterProxy->primitiveFail();
	}
	objLen = interpreterProxy->byteSizeOf(objOop);
	obj = interpreterProxy->firstIndexableField(objOop);
	if (b3dInitializeFillList(obj, objLen) != B3D_NO_ERROR) {
		return interpreterProxy->primitiveFail();
	}
}


/*	Primitive. Perform an inplace house holder matrix inversion */

EXPORT(int) b3dInplaceHouseHolderInvert(void) {
    double sum;
    double beta;
    int k;
    int j;
    double d[4][4];
    int i;
    double s;
    float *rcvr;
    double x[4][4] = { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} };
    double m[4][4];
    int r;
    double sigma;

	;
	rcvr = stackMatrix(0);
	for (i = 0; i <= 3; i += 1) {
		for (j = 0; j <= 3; j += 1) {
			(m[i])[j] = (rcvr[(i * 4) + j]);
		}
	}
	for (j = 0; j <= 3; j += 1) {
		sigma = 0.0;
		for (i = j; i <= 3; i += 1) {
			sigma += ((m[i])[j]) * ((m[i])[j]);
		}
		if (sigma < 1.0e-10) {
			return interpreterProxy->primitiveFail();
		}
		if (((m[j])[j]) < 0.0) {
			s = sqrt(sigma);
		} else {
			s = 0.0 - (sqrt(sigma));
		}
		for (r = 0; r <= 3; r += 1) {
			(d[j])[r] = s;
		}
		beta = 1.0 / ((s * ((m[j])[j])) - sigma);
		(m[j])[j] = (((m[j])[j]) - s);
		for (k = (j + 1); k <= 3; k += 1) {
			sum = 0.0;
			for (i = j; i <= 3; i += 1) {
				sum += ((m[i])[j]) * ((m[i])[k]);
			}
			sum = sum * beta;
			for (i = j; i <= 3; i += 1) {
				(m[i])[k] = (((m[i])[k]) + (((m[i])[j]) * sum));
			}
		}
		for (r = 0; r <= 3; r += 1) {
			sum = 0.0;
			for (i = j; i <= 3; i += 1) {
				sum += ((x[i])[r]) * ((m[i])[j]);
			}
			sum = sum * beta;
			for (i = j; i <= 3; i += 1) {
				(x[i])[r] = (((x[i])[r]) + (sum * ((m[i])[j])));
			}
		}
	}
	for (r = 0; r <= 3; r += 1) {
		for (i = 3; i >= 0; i += -1) {
			for (j = (i + 1); j <= 3; j += 1) {
				(x[i])[r] = (((x[i])[r]) - (((x[j])[r]) * ((m[i])[j])));
			}
			(x[i])[r] = (((x[i])[r]) / ((d[i])[r]));
		}
	}
	for (i = 0; i <= 3; i += 1) {
		for (j = 0; j <= 3; j += 1) {
			rcvr[(i * 4) + j] = (((float) ((x[i])[j])));
		}
	}
}


/*	Primitive. Load the given index array into the receiver.

	NOTE: dstStart is a zero-based index. */

EXPORT(int) b3dLoadIndexArray(void) {
    int dstSize;
    int vtxOffset;
    int count;
    int i;
    int dstArray;
    int idx;
    int *srcPtr;
    int maxValue;
    int srcArray;
    int dstStart;
    int *dstPtr;

	vtxOffset = interpreterProxy->stackIntegerValue(0);
	maxValue = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(2);
	srcArray = interpreterProxy->stackObjectValue(3);
	dstStart = interpreterProxy->stackIntegerValue(4);
	dstArray = interpreterProxy->stackObjectValue(5);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(interpreterProxy->isWords(srcArray))) {
		return interpreterProxy->primitiveFail();
	}
	if ((interpreterProxy->slotSizeOf(srcArray)) < count) {
		return interpreterProxy->primitiveFail();
	}

	/* Check dstArray */

	srcPtr = ((int*) (interpreterProxy->firstIndexableField(srcArray)));

	/* Check if there is enough room left in dstArray */

	dstSize = interpreterProxy->slotSizeOf(dstArray);
	if ((dstStart + count) > dstSize) {
		return interpreterProxy->primitiveFail();
	}

	/* Do the actual work */

	dstPtr = ((int *) (interpreterProxy->firstIndexableField(dstArray)));
	for (i = 0; i <= (count - 1); i += 1) {
		idx = srcPtr[i];
		if ((idx < 1) || (idx > maxValue)) {
			return interpreterProxy->primitiveFail();
		}
		dstPtr[dstStart + i] = (idx + vtxOffset);
	}
	interpreterProxy->pop(7);
	interpreterProxy->pushInteger(count);
}


/*	Primitive. Load the data into the given vertex buffer.

	NOTE: dstStart is a zero-based index. */

EXPORT(int) b3dLoadVertexBuffer(void) {
    int *defaultColor;
    int *colorPtr;
    int count;
    int *texPtr;
    int *defaultTexCoords;
    int *vtxPtr;
    int i;
    int *defaultVtx;
    int *defaultNormal;
    int *normalPtr;
    int *pVtx;
    int dstStart;
    int *dstPtr;

	defaultVtx = stackPrimitiveVertex(0);
	count = interpreterProxy->stackIntegerValue(1);
	texPtr = vbLoadArraysize(interpreterProxy->stackObjectValue(2), 2 * count);
	colorPtr = vbLoadArraysize(interpreterProxy->stackObjectValue(3), count);
	normalPtr = vbLoadArraysize(interpreterProxy->stackObjectValue(4), 3 * count);
	vtxPtr = vbLoadArraysize(interpreterProxy->stackObjectValue(5), 3 * count);
	dstStart = interpreterProxy->stackIntegerValue(6);

	/* Check for all problems above */

	dstPtr = stackPrimitiveVertexArrayofSize(7, dstStart + count);
	if ((dstPtr == null) || ((defaultVtx == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	if (normalPtr == null) {
		defaultNormal = defaultVtx + PrimVtxNormal;
	} else {
		defaultNormal = normalPtr;
	}
	if (texPtr == null) {
		defaultTexCoords = defaultVtx + PrimVtxTexCoords;
	} else {
		defaultTexCoords = texPtr;
	}
	if (colorPtr == null) {
		defaultColor = defaultVtx + PrimVtxColor32;
	} else {
		defaultColor = colorPtr;
	}
	pVtx = dstPtr + (dstStart * PrimVertexSize);
	for (i = 0; i <= (count - 1); i += 1) {
		pVtx[PrimVtxPositionX] = (vtxPtr[0]);
		pVtx[PrimVtxPositionY] = (vtxPtr[1]);
		pVtx[PrimVtxPositionZ] = (vtxPtr[2]);
		pVtx[PrimVtxNormalX] = (defaultNormal[0]);
		pVtx[PrimVtxNormalY] = (defaultNormal[1]);
		pVtx[PrimVtxNormalZ] = (defaultNormal[2]);
		pVtx[PrimVtxColor32] = (defaultColor[0]);
		pVtx[PrimVtxTexCoordU] = (defaultTexCoords[0]);
		pVtx[PrimVtxTexCoordV] = (defaultTexCoords[1]);
		pVtx += PrimVertexSize;
		vtxPtr += 3;
		if (!(normalPtr == null)) {
			defaultNormal += 3;
		}
		if (!(colorPtr == null)) {
			defaultColor += 1;
		}
		if (!(texPtr == null)) {
			defaultTexCoords += 2;
		}
	}
	interpreterProxy->pop(9);
	interpreterProxy->pushInteger(count);
}


/*	Primitive. Determine the bounds for all vertices in the vertex buffer. */

EXPORT(int) b3dMapVertexBuffer(void) {
    int vtxCount;
    void *vtxArray;
    int boxArray;

	if (!((interpreterProxy->methodArgumentCount()) == 3)) {
		return interpreterProxy->primitiveFail();
	}
	boxArray = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(((interpreterProxy->fetchClassOf(boxArray)) == (interpreterProxy->classArray())) && ((interpreterProxy->slotSizeOf(boxArray)) == 4))) {
		return interpreterProxy->primitiveFail();
	}
	vtxCount = interpreterProxy->stackIntegerValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(2, vtxCount);
	if ((vtxArray == null) || (interpreterProxy->failed())) {
		return interpreterProxy->primitiveFail();
	}
	mapVBofSizeinto(vtxArray, vtxCount, boxArray);
	if (!(interpreterProxy->failed())) {
		interpreterProxy->pop(3);
	}
}

EXPORT(int) b3dOrthoNormInverseMatrix(void) {
    double rz;
    int dstOop;
    double z;
    double ry;
    double y;
    double rx;
    float *dst;
    double x;
    int srcOop;
    float *src;

	if (!((interpreterProxy->methodArgumentCount()) == 0)) {
		return interpreterProxy->primitiveFail();
	}
	srcOop = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->isWords(srcOop)) && ((interpreterProxy->slotSizeOf(srcOop)) == 16))) {
		return interpreterProxy->primitiveFail();
	}

	/* reload srcOop in case of GC */

	dstOop = interpreterProxy->clone(srcOop);
	srcOop = interpreterProxy->stackObjectValue(0);
	src = interpreterProxy->firstIndexableField(srcOop);

	/* Transpose upper 3x3 matrix */
	/* dst at: 0 put: (src at: 0). */

	dst = interpreterProxy->firstIndexableField(dstOop);
	dst[1] = (src[4]);
	dst[2] = (src[8]);
	dst[4] = (src[1]);
	dst[6] = (src[9]);
	dst[8] = (src[2]);
	dst[9] = (src[6]);
	x = src[3];
	y = src[7];
	z = src[11];
	rx = ((x * (dst[0])) + (y * (dst[1]))) + (z * (dst[2]));
	ry = ((x * (dst[4])) + (y * (dst[5]))) + (z * (dst[6]));
	rz = ((x * (dst[8])) + (y * (dst[9]))) + (z * (dst[10]));
	dst[3] = (((float) (0.0 - rx)));
	dst[7] = (((float) (0.0 - ry)));
	dst[11] = (((float) (0.0 - rz)));
	interpreterProxy->pop(1);
	interpreterProxy->push(dstOop);
}


/*	Primitive. Return the next clipped triangle from the vertex buffer and return its index. */

EXPORT(int) b3dPrimitiveNextClippedTriangle(void) {
    int firstIndex;
    int idx3;
    int idx2;
    int i;
    int idxCount;
    int idx1;
    int vtxCount;
    int *idxArray;
    int *vtxArray;
    int triMask;

	if (!((interpreterProxy->methodArgumentCount()) == 5)) {
		return interpreterProxy->primitiveFail();
	}
	idxCount = interpreterProxy->stackIntegerValue(0);
	vtxCount = interpreterProxy->stackIntegerValue(2);
	firstIndex = interpreterProxy->stackIntegerValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxCount);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxCount, 1, vtxCount);
	if ((vtxArray == null) || ((idxArray == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	idxArray -= 1;
	vtxArray -= PrimVertexSize;
	for (i = firstIndex; i <= idxCount; i += 3) {
		idx1 = idxArray[i];
		idx2 = idxArray[i + 1];
		idx3 = idxArray[i + 2];
		if (!((idx1 == 0) || ((idx2 == 0) || (idx3 == 0)))) {

			/* Check if tri is completely inside */

			triMask = (vtxArray[(idx1 * PrimVertexSize) + PrimVtxClipFlags]) & ((vtxArray[(idx2 * PrimVertexSize) + PrimVtxClipFlags]) & (vtxArray[(idx3 * PrimVertexSize) + PrimVtxClipFlags]));
			if (!((InAllMask & triMask) == InAllMask)) {
				if (triMask & OutAllMask) {
					idxArray[i] = 0;
					idxArray[i + 1] = 0;
					idxArray[i + 2] = 0;
				} else {
					interpreterProxy->pop(6);
					interpreterProxy->pushInteger(i);
					return null;
				}
			}
		}
	}
	interpreterProxy->pop(6);
	interpreterProxy->pushInteger(0);
}


/*	Primitive. Return the minimal number of words needed for a primitive object. */

EXPORT(int) b3dPrimitiveObjectSize(void) {
    int objSize;

	objSize = (((int) (sizeof(B3DPrimitiveObject) + sizeof(B3DPrimitiveVertex)) >> 2)) + 1;
	interpreterProxy->pop(1);
	interpreterProxy->pushInteger(objSize);
}


/*	Primitive. Return the minimal number of words needed for a primitive object. */

EXPORT(int) b3dPrimitiveTextureSize(void) {
    int objSize;

	objSize = (((int) (sizeof(B3DTexture)) >> 2)) + 1;
	interpreterProxy->pop(1);
	interpreterProxy->pushInteger(objSize);
}


/*	Primitive. Return the version of the rasterizer. */

EXPORT(int) b3dRasterizerVersion(void) {
	interpreterProxy->pop(1);
	interpreterProxy->pushInteger(1);
}


/*	Primitive. Shade all the vertices in the vertex buffer using the given array of primitive light sources. Return true on success. */

EXPORT(int) b3dShadeVertexBuffer(void) {
    int i;
    int lightCount;
    int lightArray;
    int j;
    int vtxCount;
    float *vtxArray;
    int a;
    int r;
    int b;
    int g;
    int lightOop;
    int rgba;

	vbFlags = interpreterProxy->stackIntegerValue(0);
	primMaterial = stackMaterialValue(1);
	lightArray = stackLightArrayValue(2);
	vtxCount = interpreterProxy->stackIntegerValue(3);
	vtxArray = stackPrimitiveVertexArrayofSize(4, vtxCount);
	if ((vtxArray == null) || ((primMaterial == null) || (interpreterProxy->failed()))) {
		return interpreterProxy->primitiveFail();
	}
	litVertex = vtxArray;

	/* Go over all vertices */

	lightCount = interpreterProxy->slotSizeOf(lightArray);
	for (i = 1; i <= vtxCount; i += 1) {
		/* begin loadPrimitiveVertex */
		rgba = (((int*) litVertex))[PrimVtxColor32];
		vtxInColor[2] = ((rgba & 255) * (1.0 / 255.0));
		rgba = ((unsigned) rgba) >> 8;
		vtxInColor[1] = ((rgba & 255) * (1.0 / 255.0));
		rgba = ((unsigned) rgba) >> 8;
		vtxInColor[0] = ((rgba & 255) * (1.0 / 255.0));
		rgba = ((unsigned) rgba) >> 8;
		vtxInColor[3] = ((rgba & 255) * (1.0 / 255.0));
		if (vbFlags & VBTrackEmission) {
			vtxOutColor[0] = ((vtxInColor[0]) + (primMaterial[EmissionRed]));
			vtxOutColor[1] = ((vtxInColor[1]) + (primMaterial[EmissionGreen]));
			vtxOutColor[2] = ((vtxInColor[2]) + (primMaterial[EmissionBlue]));
			vtxOutColor[3] = ((vtxInColor[3]) + (primMaterial[EmissionAlpha]));
		} else {
			vtxOutColor[0] = (primMaterial[EmissionRed]);
			vtxOutColor[1] = (primMaterial[EmissionGreen]);
			vtxOutColor[2] = (primMaterial[EmissionBlue]);
			vtxOutColor[3] = (primMaterial[EmissionAlpha]);
		}
		for (j = 0; j <= (lightCount - 1); j += 1) {
			/* begin fetchLightSource:ofObject: */
			lightOop = interpreterProxy->fetchPointerofObject(j, lightArray);
			primLight = interpreterProxy->firstIndexableField(lightOop);
			/* begin loadPrimitiveLightSource */
			lightFlags = (((int*) primLight))[PrimLightFlags];
			shadeVertex();
		}
		/* begin storePrimitiveVertex */
		r = ((int) ((vtxOutColor[0]) * 255) );
		r = (((((r < 255) ? r : 255)) < 0) ? 0 : (((r < 255) ? r : 255)));
		g = ((int) ((vtxOutColor[1]) * 255) );
		g = (((((g < 255) ? g : 255)) < 0) ? 0 : (((g < 255) ? g : 255)));
		b = ((int) ((vtxOutColor[2]) * 255) );
		b = (((((b < 255) ? b : 255)) < 0) ? 0 : (((b < 255) ? b : 255)));
		a = ((int) ((vtxOutColor[3]) * 255) );
		a = (((((a < 255) ? a : 255)) < 0) ? 0 : (((a < 255) ? a : 255)));
		(((int*) litVertex))[PrimVtxColor32] = (b + ((g + ((r + (a << 8)) << 8)) << 8));
		litVertex += PrimVertexSize;
	}
	interpreterProxy->pop(6);
	interpreterProxy->pushBool(1);
}


/*	Return the current shader version. */

EXPORT(int) b3dShaderVersion(void) {
	interpreterProxy->pop(1);
	interpreterProxy->pushInteger(1);
}


/*	Primitive. Start the rasterizer. */

EXPORT(int) b3dStartRasterizer(void) {
    int errCode;

	if (!((interpreterProxy->methodArgumentCount()) == 3)) {
		return interpreterProxy->primitiveFail();
	}
	if (!(loadRasterizerState(2))) {
		return interpreterProxy->primitiveFail();
	}
	loadTexturesFrom(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	loadObjectsFrom(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	errCode = b3dMainLoop(&state, B3D_NO_ERROR);
	storeObjectsInto(1);
	interpreterProxy->pop(4);
	interpreterProxy->pushInteger(errCode);
}

EXPORT(int) b3dTransformDirection(void) {
    double rz;
    double z;
    double ry;
    int v3Oop;
    double y;
    double rx;
    float *vertex;
    double x;
    float *matrix;

	if (!((interpreterProxy->methodArgumentCount()) == 1)) {
		return interpreterProxy->primitiveFail();
	}
	v3Oop = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->isWords(v3Oop)) && ((interpreterProxy->slotSizeOf(v3Oop)) == 3))) {
		return interpreterProxy->primitiveFail();
	}
	vertex = interpreterProxy->firstIndexableField(v3Oop);
	matrix = stackMatrix(1);
	if (matrix == null) {
		return interpreterProxy->primitiveFail();
	}
	x = vertex[0];
	y = vertex[1];
	z = vertex[2];
	rx = ((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]));
	ry = ((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]));
	rz = ((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]));
	v3Oop = interpreterProxy->clone(v3Oop);
	vertex = interpreterProxy->firstIndexableField(v3Oop);
	vertex[0] = (((float) rx));
	vertex[1] = (((float) ry));
	vertex[2] = (((float) rz));
	interpreterProxy->pop(2);
	interpreterProxy->push(v3Oop);
}


/*	Transform two matrices into the third */

EXPORT(int) b3dTransformMatrixWithInto(void) {
    float *m2;
    float *m1;
    float *m3;

	m3 = stackMatrix(0);
	m2 = stackMatrix(1);
	m1 = stackMatrix(2);
	if (((m1 == null) || (m2 == null)) || (m3 == null)) {
		return interpreterProxy->primitiveFail();
	}
	if (m2 == m3) {
		return interpreterProxy->primitiveFail();
	}
	transformMatrixwithinto(m1, m2, m3);
	interpreterProxy->pop(3);
}

EXPORT(int) b3dTransformPoint(void) {
    double rz;
    double z;
    double ry;
    int v3Oop;
    double y;
    double rx;
    float *vertex;
    double x;
    double rw;
    float *matrix;

	if (!((interpreterProxy->methodArgumentCount()) == 1)) {
		return interpreterProxy->primitiveFail();
	}
	v3Oop = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->isWords(v3Oop)) && ((interpreterProxy->slotSizeOf(v3Oop)) == 3))) {
		return interpreterProxy->primitiveFail();
	}
	vertex = interpreterProxy->firstIndexableField(v3Oop);
	matrix = stackMatrix(1);
	if (matrix == null) {
		return interpreterProxy->primitiveFail();
	}
	x = vertex[0];
	y = vertex[1];
	z = vertex[2];
	rx = (((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]))) + (matrix[3]);
	ry = (((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]))) + (matrix[7]);
	rz = (((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]))) + (matrix[11]);
	rw = (((x * (matrix[12])) + (y * (matrix[13]))) + (z * (matrix[14]))) + (matrix[15]);
	v3Oop = interpreterProxy->clone(v3Oop);
	vertex = interpreterProxy->firstIndexableField(v3Oop);
	if (rw == 1.0) {
		vertex[0] = (((float) rx));
		vertex[1] = (((float) ry));
		vertex[2] = (((float) rz));
	} else {
		if (rw == 0.0) {
			rw = 0.0;
		} else {
			rw = 1.0 / rw;
		}
		vertex[0] = (((float) (rx * rw)));
		vertex[1] = (((float) (ry * rw)));
		vertex[2] = (((float) (rz * rw)));
	}
	interpreterProxy->pop(2);
	interpreterProxy->push(v3Oop);
}


/*	Transform the normal of the given primitive vertex using the argument matrix and rescale the normal if necessary. */

EXPORT(int) b3dTransformPrimitiveNormal(void) {
    float *pVertex;
    int rescale;
    float *matrix;

	rescale = interpreterProxy->stackValue(0);
	if (!(rescale == (interpreterProxy->nilObject()))) {
		rescale = interpreterProxy->booleanValueOf(rescale);
	}
	matrix = stackMatrix(1);
	pVertex = stackPrimitiveVertex(2);
	if ((matrix == null) || (pVertex == null)) {
		return interpreterProxy->primitiveFail();
	}
	if ((rescale != 1) && (rescale != 0)) {
		rescale = analyzeMatrix3x3Length(matrix);
	}
	transformPrimitiveNormalbyrescale(pVertex, matrix, rescale);
	interpreterProxy->pop(3);
}


/*	Transform the position of the given primitive vertex the given matrix

	and store the result back inplace. */

EXPORT(int) b3dTransformPrimitivePosition(void) {
    float *pVertex;
    float *matrix;

	matrix = stackMatrix(0);
	pVertex = stackPrimitiveVertex(1);
	if ((matrix == null) || (pVertex == null)) {
		return interpreterProxy->primitiveFail();
	}
	transformPrimitivePositionby(pVertex, matrix);
	interpreterProxy->pop(2);
}


/*	Transform the position of the given primitive vertex the given matrix

	and store the result in homogenous coordinates at rasterPos. */

EXPORT(int) b3dTransformPrimitiveRasterPosition(void) {
    float *pVertex;
    float *matrix;

	matrix = stackMatrix(0);
	pVertex = stackPrimitiveVertex(1);
	if ((matrix == null) || (pVertex == null)) {
		return interpreterProxy->primitiveFail();
	}
	transformPrimitiveRasterPositionby(pVertex, matrix);
	interpreterProxy->pop(2);
}


/*	Transform an entire vertex buffer using the supplied modelview and projection matrix. */

EXPORT(int) b3dTransformVertexBuffer(void) {
    float *modelViewMatrix;
    int flags;
    float *projectionMatrix;
    int vtxCount;
    float *vtxArray;

	flags = interpreterProxy->stackIntegerValue(0);
	projectionMatrix = stackMatrix(1);
	modelViewMatrix = stackMatrix(2);
	vtxCount = interpreterProxy->stackIntegerValue(3);
	vtxArray = stackPrimitiveVertexArrayofSize(4, vtxCount);
	if (((projectionMatrix == null) || (modelViewMatrix == null)) || (vtxArray == null)) {
		return interpreterProxy->primitiveFail();
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	transformVBcountbyandflags(vtxArray, vtxCount, modelViewMatrix, projectionMatrix, flags);
	interpreterProxy->pop(5);
}


/*	Return the current version of the transformer */

EXPORT(int) b3dTransformerVersion(void) {
	interpreterProxy->pop(1);
	interpreterProxy->pushInteger(1);
}

EXPORT(int) b3dTransposeMatrix(void) {
    int dstOop;
    float *dst;
    int srcOop;
    float *src;

	if (!((interpreterProxy->methodArgumentCount()) == 0)) {
		return interpreterProxy->primitiveFail();
	}
	srcOop = interpreterProxy->stackObjectValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->isWords(srcOop)) && ((interpreterProxy->slotSizeOf(srcOop)) == 16))) {
		return interpreterProxy->primitiveFail();
	}

	/* reload srcOop in case of GC */

	dstOop = interpreterProxy->clone(srcOop);
	srcOop = interpreterProxy->stackObjectValue(0);
	src = interpreterProxy->firstIndexableField(srcOop);

	/* dst at: 0 put: (src at: 0). */

	dst = interpreterProxy->firstIndexableField(dstOop);
	dst[1] = (src[4]);
	dst[2] = (src[8]);
	dst[3] = (src[12]);
	dst[4] = (src[1]);
	dst[6] = (src[9]);
	dst[7] = (src[13]);
	dst[8] = (src[2]);
	dst[9] = (src[6]);
	dst[11] = (src[14]);
	dst[12] = (src[3]);
	dst[13] = (src[7]);
	dst[14] = (src[11]);
	interpreterProxy->pop(1);
	interpreterProxy->push(dstOop);
}

static double backClipValueFromto(int last, int next) {
	return (((((float *) last))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosZ])));
}

static double bottomClipValueFromto(int last, int next) {
	return (0.0 - (((((float *) last))[PrimVtxRasterPosY]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosY])));
}

static int clipPolygoncountwithmask(int *vtxArray, int vtxCount, int *tempVtxArray, int outMask) {
    int count;

	if (outMask == OutLeftBit) {
		return clipPolygonLeftFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	if (outMask == OutRightBit) {
		return clipPolygonRightFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	if (outMask == OutTopBit) {
		return clipPolygonTopFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	if (outMask == OutBottomBit) {
		return clipPolygonBottomFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	if (outMask == OutFrontBit) {
		return clipPolygonFrontFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	if (outMask == OutBackBit) {
		return clipPolygonBackFromtocount(tempVtxArray, vtxArray, vtxCount);
	}
	count = vtxCount;
	count = clipPolygonLeftFromtocount(vtxArray, tempVtxArray, count);
	if (count == 0) {
		return 0;
	}
	count = clipPolygonRightFromtocount(tempVtxArray, vtxArray, count);
	if (count == 0) {
		return 0;
	}
	count = clipPolygonTopFromtocount(vtxArray, tempVtxArray, count);
	if (count == 0) {
		return 0;
	}
	count = clipPolygonBottomFromtocount(tempVtxArray, vtxArray, count);
	if (count == 0) {
		return 0;
	}
	count = clipPolygonFrontFromtocount(vtxArray, tempVtxArray, count);
	if (count == 0) {
		return 0;
	}
	count = clipPolygonBackFromtocount(tempVtxArray, vtxArray, count);
	return count;
}

static int clipPolygonBackFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InBackBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InBackBit;
		if (!(inLast == inNext)) {
			t = (((((float *) last))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosZ])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

static int clipPolygonBottomFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InBottomBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InBottomBit;
		if (!(inLast == inNext)) {
			t = (0.0 - (((((float *) last))[PrimVtxRasterPosY]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosY])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

static int clipPolygonFrontFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InFrontBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InFrontBit;
		if (!(inLast == inNext)) {
			t = (0.0 - (((((float *) last))[PrimVtxRasterPosZ]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosZ])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

static int clipPolygonLeftFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InLeftBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InLeftBit;
		if (!(inLast == inNext)) {
			t = (0.0 - (((((float *) last))[PrimVtxRasterPosX]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosX])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

static int clipPolygonRightFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InRightBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InRightBit;
		if (!(inLast == inNext)) {
			t = (((((float *) last))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosX])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

static int clipPolygonTopFromtocount(int *buf1, int *buf2, int n) {
    int *last;
    int *next;
    int inLast;
    int j;
    double t;
    int outIndex;
    int i;
    int inNext;

	outIndex = 0;
	last = buf1 + (n * PrimVertexSize);
	next = buf1 + PrimVertexSize;
	inLast = (last[PrimVtxClipFlags]) & InTopBit;
	for (i = 1; i <= n; i += 1) {
		inNext = (next[PrimVtxClipFlags]) & InTopBit;
		if (!(inLast == inNext)) {
			t = (((((float *) last))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosY])));
			outIndex += 1;
			interpolateFromtoatinto(((float *) last), ((float *) next), t, ((float*) (buf2 + (outIndex * PrimVertexSize))));
		}
		if (inNext) {
			outIndex += 1;
			for (j = 0; j <= (PrimVertexSize - 1); j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}


/*	Compute the attenuation for the current light and vertex */

static int computeAttenuation(void) {
	lightScale = 1.0;
	if (lightFlags & FlagAttenuated) {
		lightScale = 1.0 / ((primLight[PrimLightAttenuationConstant]) + (l2vDistance * ((primLight[PrimLightAttenuationLinear]) + (l2vDistance * (primLight[PrimLightAttenuationSquared])))));
	}
}


/*	Compute the direction for the current light and vertex */

static int computeDirection(void) {
    double scale;

	if (lightFlags & FlagPositional) {
		l2vDirection[0] = ((litVertex[PrimVtxPositionX]) - (primLight[PrimLightPositionX]));
		l2vDirection[1] = ((litVertex[PrimVtxPositionY]) - (primLight[PrimLightPositionY]));
		l2vDirection[2] = ((litVertex[PrimVtxPositionZ]) - (primLight[PrimLightPositionZ]));
		l2vDistance = (((l2vDirection[0]) * (l2vDirection[0])) + ((l2vDirection[1]) * (l2vDirection[1]))) + ((l2vDirection[2]) * (l2vDirection[2]));
		if (!((l2vDistance == 0.0) || (l2vDistance == 1.0))) {
			l2vDistance = sqrt(l2vDistance);
			scale = -1.0 / l2vDistance;
		}
		l2vDirection[0] = ((l2vDirection[0]) * scale);
		l2vDirection[1] = ((l2vDirection[1]) * scale);
		l2vDirection[2] = ((l2vDirection[2]) * scale);
	} else {
		if (lightFlags & FlagDirectional) {
			l2vDirection[0] = (primLight[PrimLightDirectionX]);
			l2vDirection[1] = (primLight[PrimLightDirectionY]);
			l2vDirection[2] = (primLight[PrimLightDirectionZ]);
		}
	}
}


/*	Computes

		l2vSpecDir _ l2vSpecDir - vtx position safelyNormalized.

	 */

static int computeSpecularDirection(void) {
    double scale;

	scale = inverseLengthOfFloat(litVertex + PrimVtxPosition);
	l2vSpecDir[0] = ((l2vSpecDir[0]) - ((litVertex[PrimVtxPositionX]) * scale));
	l2vSpecDir[1] = ((l2vSpecDir[1]) - ((litVertex[PrimVtxPositionY]) * scale));
	l2vSpecDir[2] = ((l2vSpecDir[2]) - ((litVertex[PrimVtxPositionZ]) * scale));
}


/*	Compute the spot factor for a spot light */

static double computeSpotFactor(void) {
    double deltaCos;
    double cosAngle;
    double minCos;

	cosAngle = dotProductOfFloatwithDouble(primLight + PrimLightDirection, l2vDirection);
	cosAngle = 0.0 - cosAngle;
	minCos = primLight[SpotLightMinCos];
	if (cosAngle < minCos) {
		return 0.0;
	}
	deltaCos = primLight[SpotLightDeltaCos];
	if (deltaCos <= 1.0e-5) {
		return 1.0;
	}
	cosAngle = (cosAngle - minCos) / deltaCos;
	return pow(cosAngle,(primLight[SpotLightExponent]));
}

static int determineClipFlagscount(void *vtxArray, int count) {
    double z;
    float *vtxPtr;
    double w2;
    double y;
    int fullMask;
    int i;
    int flags;
    double x;
    double w;

	vtxPtr = ((float *) vtxArray);
	fullMask = InAllMask + OutAllMask;
	for (i = 1; i <= count; i += 1) {
		w = vtxPtr[PrimVtxRasterPosW];
		w2 = 0.0 - w;
		flags = 0;
		x = vtxPtr[PrimVtxRasterPosX];
		if (x >= w2) {
			flags = flags | InLeftBit;
		} else {
			flags = flags | OutLeftBit;
		}
		if (x <= w) {
			flags = flags | InRightBit;
		} else {
			flags = flags | OutRightBit;
		}
		y = vtxPtr[PrimVtxRasterPosY];
		if (y >= w2) {
			flags = flags | InBottomBit;
		} else {
			flags = flags | OutBottomBit;
		}
		if (y <= w) {
			flags = flags | InTopBit;
		} else {
			flags = flags | OutTopBit;
		}
		z = vtxPtr[PrimVtxRasterPosZ];
		if (z >= w2) {
			flags = flags | InFrontBit;
		} else {
			flags = flags | OutFrontBit;
		}
		if (z <= w) {
			flags = flags | InBackBit;
		} else {
			flags = flags | OutBackBit;
		}
		fullMask = fullMask & flags;
		(((int *) vtxPtr))[PrimVtxClipFlags] = flags;
		vtxPtr += PrimVertexSize;
	}
	return fullMask;
}

static double dotProductOfFloatwithDouble(float * v1, double *v2) {
	return (((v1[0]) * (v2[0])) + ((v1[1]) * (v2[1]))) + ((v1[2]) * (v2[2]));
}


/*	Fetch the primitive light source from the given array.

	Note: No checks are done within here - that happened in stackLightArrayValue: */

static void* fetchLightSourceofObject(int index, int anArray) {
    int lightOop;

	lightOop = interpreterProxy->fetchPointerofObject(index, anArray);
	return interpreterProxy->firstIndexableField(lightOop);
}

static double frontClipValueFromto(int last, int next) {
	return (0.0 - (((((float *) last))[PrimVtxRasterPosZ]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosZ])));
}


/*	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) {
	;
}

EXPORT(int) initialiseModule(void) {
	loadBBFn = interpreterProxy->ioLoadFunctionFrom("loadBitBltFrom", bbPluginName);
	copyBitsFn = interpreterProxy->ioLoadFunctionFrom("copyBitsFromtoat", bbPluginName);
	return (loadBBFn != 0) && (copyBitsFn != 0);
}


/*	Interpolate the primitive vertices last/next at the parameter t */

static int interpolateFromtoatinto(float *last, float *next, double t, float *out) {
    unsigned int nextValue;
    double z;
    unsigned int lastValue;
    unsigned int rgbaNext;
    unsigned int newValue;
    double y;
    double w2;
    double delta;
    double x;
    unsigned int rgbaLast;
    double w;
    int flags;

	delta = (next[PrimVtxRasterPosX]) - (last[PrimVtxRasterPosX]);
	x = (last[PrimVtxRasterPosX]) + (delta * t);
	out[PrimVtxRasterPosX] = (((float) x));
	delta = (next[PrimVtxRasterPosY]) - (last[PrimVtxRasterPosY]);
	y = (last[PrimVtxRasterPosY]) + (delta * t);
	out[PrimVtxRasterPosY] = (((float) y));
	delta = (next[PrimVtxRasterPosZ]) - (last[PrimVtxRasterPosZ]);
	z = (last[PrimVtxRasterPosZ]) + (delta * t);
	out[PrimVtxRasterPosZ] = (((float) z));
	delta = (next[PrimVtxRasterPosW]) - (last[PrimVtxRasterPosW]);
	w = (last[PrimVtxRasterPosW]) + (delta * t);
	out[PrimVtxRasterPosW] = (((float) w));
	w2 = 0.0 - w;
	flags = 0;
	if (x >= w2) {
		flags = flags | InLeftBit;
	} else {
		flags = flags | OutLeftBit;
	}
	if (x <= w) {
		flags = flags | InRightBit;
	} else {
		flags = flags | OutRightBit;
	}
	if (y >= w2) {
		flags = flags | InBottomBit;
	} else {
		flags = flags | OutBottomBit;
	}
	if (y <= w) {
		flags = flags | InTopBit;
	} else {
		flags = flags | OutTopBit;
	}
	if (z >= w2) {
		flags = flags | InFrontBit;
	} else {
		flags = flags | OutFrontBit;
	}
	if (z <= w) {
		flags = flags | InBackBit;
	} else {
		flags = flags | OutBackBit;
	}
	(((int *) out))[PrimVtxClipFlags] = flags;
	rgbaLast = (((unsigned int *) last))[PrimVtxColor32];
	lastValue = rgbaLast & 255;
	rgbaLast = ((unsigned) rgbaLast) >> 8;
	rgbaNext = (((unsigned int *) next))[PrimVtxColor32];
	nextValue = rgbaNext & 255;
	rgbaNext = ((unsigned) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue = ((int) (lastValue + delta) );
	lastValue = rgbaLast & 255;
	rgbaLast = ((unsigned) rgbaLast) >> 8;
	nextValue = rgbaNext & 255;
	rgbaNext = ((unsigned) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += (((int) (lastValue + delta) )) << 8;
	lastValue = rgbaLast & 255;
	rgbaLast = ((unsigned) rgbaLast) >> 8;
	nextValue = rgbaNext & 255;
	rgbaNext = ((unsigned) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += (((int) (lastValue + delta) )) << 16;
	lastValue = rgbaLast & 255;
	nextValue = rgbaNext & 255;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += (((int) (lastValue + delta) )) << 24;
	(((unsigned int*) out))[PrimVtxColor32] = newValue;
	delta = (next[PrimVtxTexCoordU]) - (last[PrimVtxTexCoordU]);
	out[PrimVtxTexCoordU] = (((float) ((last[PrimVtxTexCoordU]) + (delta * t))));
	delta = (next[PrimVtxTexCoordV]) - (last[PrimVtxTexCoordV]);
	out[PrimVtxTexCoordV] = (((float) ((last[PrimVtxTexCoordV]) + (delta * t))));
}

static double inverseLengthOfDouble(double * aVector) {
    double scale;

	scale = (((aVector[0]) * (aVector[0])) + ((aVector[1]) * (aVector[1]))) + ((aVector[2]) * (aVector[2]));
	if ((scale == 0.0) || (scale == 1.0)) {
		return scale;
	}
	return 1.0 / (sqrt(scale));
}

static double inverseLengthOfFloat(float * aVector) {
    double scale;

	scale = (((aVector[0]) * (aVector[0])) + ((aVector[1]) * (aVector[1]))) + ((aVector[2]) * (aVector[2]));
	if ((scale == 0.0) || (scale == 1.0)) {
		return scale;
	}
	return 1.0 / (sqrt(scale));
}

static double leftClipValueFromto(int last, int next) {
	return (0.0 - (((((float *) last))[PrimVtxRasterPosX]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosX])));
}

static int loadObjectsFrom(int stackIndex) {
    B3DPrimitiveObject *objPtr;
    int arrayOop;
    int arraySize;
    int objOop;
    int i;
    B3DPrimitiveObject **objArray;

	arrayOop = interpreterProxy->stackObjectValue(stackIndex);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->fetchClassOf(arrayOop)) == (interpreterProxy->classArray()))) {
		return interpreterProxy->primitiveFail();
	}
	arraySize = interpreterProxy->slotSizeOf(arrayOop);
	if (arraySize > (state.nObjects)) {
		return interpreterProxy->primitiveFail();
	}
	objArray = state.objects;
	for (i = 0; i <= (arraySize - 1); i += 1) {
		objOop = interpreterProxy->fetchPointerofObject(i, arrayOop);
		if (((objOop & 1)) || (!(interpreterProxy->isWords(objOop)))) {
			return interpreterProxy->primitiveFail();
		}
		objPtr = ((B3DPrimitiveObject*) (interpreterProxy->firstIndexableField(objOop)));
		if (objPtr->magic != B3D_PRIMITIVE_OBJECT_MAGIC) {
			return interpreterProxy->primitiveFail();
		}
		objPtr->__oop__ = objOop;
		objArray[i] = objPtr;
	}
}

static int loadPrimitiveLightSource(void) {
	lightFlags = (((int*) primLight))[PrimLightFlags];
}


/*	Load the necessary values from the current primitive vertex */

static int loadPrimitiveVertex(void) {
    int rgba;

	rgba = (((int*) litVertex))[PrimVtxColor32];
	vtxInColor[2] = ((rgba & 255) * (1.0 / 255.0));
	rgba = ((unsigned) rgba) >> 8;
	vtxInColor[1] = ((rgba & 255) * (1.0 / 255.0));
	rgba = ((unsigned) rgba) >> 8;
	vtxInColor[0] = ((rgba & 255) * (1.0 / 255.0));
	rgba = ((unsigned) rgba) >> 8;
	vtxInColor[3] = ((rgba & 255) * (1.0 / 255.0));
}


/*	Load the rasterizer state from the given stack index. */

static int loadRasterizerState(int stackIndex) {
    void *objPtr;
    int stateOop;
    int obj;
    int objLen;

	if ((copyBitsFn == 0) || (loadBBFn == 0)) {
		if (!(initialiseModule())) {
			return 0;
		}
	}
	stateOop = interpreterProxy->stackObjectValue(stackIndex);
	if (interpreterProxy->failed()) {
		return 0;
	}
	if (!((interpreterProxy->isPointers(stateOop)) && ((interpreterProxy->slotSizeOf(stateOop)) >= 10))) {
		return 0;
	}
	obj = interpreterProxy->fetchPointerofObject(0, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.faceAlloc = objPtr;
	obj = interpreterProxy->fetchPointerofObject(1, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.edgeAlloc = objPtr;
	obj = interpreterProxy->fetchPointerofObject(2, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.attrAlloc = objPtr;
	obj = interpreterProxy->fetchPointerofObject(3, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.aet = objPtr;
	obj = interpreterProxy->fetchPointerofObject(4, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.addedEdges = objPtr;
	obj = interpreterProxy->fetchPointerofObject(5, stateOop);
	if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
		return 0;
	}
	objPtr = interpreterProxy->firstIndexableField(obj);
	state.fillList = objPtr;
	obj = interpreterProxy->fetchPointerofObject(6, stateOop);
	if (obj == (interpreterProxy->nilObject())) {
		state.nObjects = 0;
		state.objects = NULL;
	} else {
		if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
			return 0;
		}
		objLen = interpreterProxy->slotSizeOf(obj);
		objPtr = interpreterProxy->firstIndexableField(obj);
		state.objects = (B3DPrimitiveObject **)objPtr;
		state.nObjects = objLen;
	}
	obj = interpreterProxy->fetchPointerofObject(7, stateOop);
	if (obj == (interpreterProxy->nilObject())) {
		state.nTextures = 0;
		state.textures = NULL;
	} else {
		if (((obj & 1)) || (!(interpreterProxy->isWords(obj)))) {
			return 0;
		}
		objLen = interpreterProxy->byteSizeOf(obj);
		objPtr = interpreterProxy->firstIndexableField(obj);
		state.textures = (B3DTexture *)objPtr;
		state.nTextures = objLen / sizeof(B3DTexture);
	}
	obj = interpreterProxy->fetchPointerofObject(8, stateOop);
	if (obj == (interpreterProxy->nilObject())) {
		state.spanSize = 0;
		state.spanBuffer = NULL;
	} else {
		if (!((interpreterProxy->fetchClassOf(obj)) == (interpreterProxy->classBitmap()))) {
			return 0;
		}
		objLen = interpreterProxy->slotSizeOf(obj);
		objPtr = interpreterProxy->firstIndexableField(obj);
		state.spanBuffer = (unsigned int *)objPtr;
		state.spanSize = objLen;
	}
	obj = interpreterProxy->fetchPointerofObject(9, stateOop);
	if (obj == (interpreterProxy->nilObject())) {
		state.spanDrawer = NULL;
	} else {
		if (!(((int (*) (int))loadBBFn)(obj))) {
			return 0;
		}
		state.spanDrawer = (b3dDrawBufferFunction) copyBitsFn;
	}
	return !(interpreterProxy->failed());
}


/*	Note: This still uses the old-style textures */

static int loadTextureinto(int textureOop, B3DTexture *destPtr) {
    int texWrap;
    int formWidth;
    int formBits;
    int texEnvMode;
    void *bitsPtr;
    int formDepth;
    int formHeight;
    int texInterpolate;
    int form;

	form = textureOop;
	if (!(interpreterProxy->isPointers(form))) {
		return 0;
	}
	if ((interpreterProxy->slotSizeOf(form)) < 8) {
		return 0;
	}
	formBits = interpreterProxy->fetchPointerofObject(0, form);
	formWidth = interpreterProxy->fetchIntegerofObject(1, form);
	formHeight = interpreterProxy->fetchIntegerofObject(2, form);
	formDepth = interpreterProxy->fetchIntegerofObject(3, form);
	texWrap = interpreterProxy->booleanValueOf(interpreterProxy->fetchPointerofObject(5, form));
	texInterpolate = interpreterProxy->booleanValueOf(interpreterProxy->fetchPointerofObject(6, form));
	texEnvMode = interpreterProxy->fetchIntegerofObject(7, form);
	if (interpreterProxy->failed()) {
		return 0;
	}
	if ((formWidth < 1) || ((formHeight < 1) || (formDepth != 32))) {
		return 0;
	}
	if (!((interpreterProxy->fetchClassOf(formBits)) == (interpreterProxy->classBitmap()))) {
		return 0;
	}
	if (!((interpreterProxy->byteSizeOf(formBits)) == ((formWidth * formHeight) * 4))) {
		return 0;
	}
	if ((texEnvMode < 0) || (texEnvMode > 1)) {
		return 0;
	}

	/* Set the texture parameters */

	bitsPtr = interpreterProxy->firstIndexableField(formBits);
	return b3dLoadTexture(destPtr, formWidth, formHeight, formDepth, (unsigned int*) bitsPtr, 0, NULL) == B3D_NO_ERROR;
}

static int loadTexturesFrom(int stackIndex) {
    B3DTexture *destPtr;
    int arrayOop;
    int n;
    int i;
    int textureOop;

	arrayOop = interpreterProxy->stackObjectValue(stackIndex);
	if (!((interpreterProxy->fetchClassOf(arrayOop)) == (interpreterProxy->classArray()))) {
		return interpreterProxy->primitiveFail();
	}
	n = interpreterProxy->slotSizeOf(arrayOop);
	n = ((n < (state.nTextures)) ? n : (state.nTextures));
	for (i = 0; i <= (n - 1); i += 1) {
		destPtr = state.textures + i;
		textureOop = interpreterProxy->fetchPointerofObject(i, arrayOop);
		if (!(loadTextureinto(textureOop, destPtr))) {
			return interpreterProxy->primitiveFail();
		}
	}
	return 0;
}


/*	Load the viewport from the given stack index */

static int loadViewportFrom(int stackIndex) {
    int oop;
    int p1;
    int x1;
    int x0;
    int y1;
    int y0;
    int p2;

	oop = interpreterProxy->stackObjectValue(stackIndex);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(interpreterProxy->isPointers(oop))) {
		return interpreterProxy->primitiveFail();
	}
	if ((interpreterProxy->slotSizeOf(oop)) < 2) {
		return interpreterProxy->primitiveFail();
	}
	p1 = interpreterProxy->fetchPointerofObject(0, oop);
	p2 = interpreterProxy->fetchPointerofObject(1, oop);
	if (!((interpreterProxy->fetchClassOf(p1)) == (interpreterProxy->classPoint()))) {
		return interpreterProxy->primitiveFail();
	}
	if (!((interpreterProxy->fetchClassOf(p2)) == (interpreterProxy->classPoint()))) {
		return interpreterProxy->primitiveFail();
	}
	x0 = interpreterProxy->fetchIntegerofObject(0, p1);
	y0 = interpreterProxy->fetchIntegerofObject(1, p1);
	x1 = interpreterProxy->fetchIntegerofObject(0, p2);
	y1 = interpreterProxy->fetchIntegerofObject(1, p2);
	if (interpreterProxy->failed()) {
		return null;
	}
	viewport.x0 = x0;
	viewport.y0 = y0;
	viewport.x1 = x1;
	viewport.y1 = y1;
	return 0;
}

static int mapVBofSizeinto(void *vtxArray, int vtxCount, int boxArray) {
    double right;
    double left;
    int oop;
    float *vtxPtr;
    double y;
    int i;
    int flags;
    double x;
    double bottom;
    double top;
    double w;
    int floatOop;

	vtxPtr = ((float *) vtxArray);
	for (i = 1; i <= vtxCount; i += 1) {
		flags = (((int *) vtxPtr))[PrimVtxClipFlags];
		w = vtxPtr[PrimVtxRasterPosW];
		if (!(w == 0.0)) {
			w = 1.0 / w;
		}
		if ((flags & OutLeftBit) != 0) {
			x = -1.0;
		} else {
			if ((flags & OutRightBit) != 0) {
				x = 1.0;
			} else {
				x = (vtxPtr[PrimVtxRasterPosX]) * w;
			}
		}
		if ((flags & OutTopBit) != 0) {
			y = -1.0;
		} else {
			if ((flags & OutBottomBit) != 0) {
				y = 1.0;
			} else {
				y = (vtxPtr[PrimVtxRasterPosY]) * w;
			}
		}
		if (i == 1) {
			left = right = x;
			top = bottom = y;
		}
		if (x < left) {
			left = x;
		}
		if (x > right) {
			right = x;
		}
		if (y < top) {
			top = y;
		}
		if (y > bottom) {
			bottom = y;
		}
		vtxPtr += PrimVertexSize;
	}
	oop = boxArray;
	interpreterProxy->pushRemappableOop(oop);
	floatOop = interpreterProxy->floatObjectOf(left);
	oop = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(0, oop, floatOop);
	interpreterProxy->pushRemappableOop(oop);
	floatOop = interpreterProxy->floatObjectOf(top);
	oop = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(1, oop, floatOop);
	interpreterProxy->pushRemappableOop(oop);
	floatOop = interpreterProxy->floatObjectOf(right);
	oop = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(2, oop, floatOop);
	interpreterProxy->pushRemappableOop(oop);
	floatOop = interpreterProxy->floatObjectOf(bottom);
	oop = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(3, oop, floatOop);
}


/*	The module with the given name was just unloaded.

	Make sure we have no dangling references. */

EXPORT(int) moduleUnloaded(char * aModuleName) {
	if ((strcmp(aModuleName, bbPluginName)) == 0) {
		loadBBFn = 0;
		copyBitsFn = 0;
	}
}

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


/*	Primitive. Set the BitBlt plugin to use. */

EXPORT(int) primitiveSetBitBltPlugin(void) {
    char *ptr;
    int length;
    int pluginName;
    int i;
    int needReload;


	/* Must be string to work */

	pluginName = interpreterProxy->stackValue(0);
	if (!(interpreterProxy->isBytes(pluginName))) {
		return interpreterProxy->primitiveFail();
	}
	length = interpreterProxy->byteSizeOf(pluginName);
	if (length >= 256) {
		return interpreterProxy->primitiveFail();
	}
	ptr = interpreterProxy->firstIndexableField(pluginName);
	needReload = 0;
	for (i = 0; i <= (length - 1); i += 1) {
		if (!((bbPluginName[i]) == (ptr[i]))) {
			bbPluginName[i] = (ptr[i]);
			needReload = 1;
		}
	}
	if (!((bbPluginName[length]) == 0)) {
		bbPluginName[length] = 0;
		needReload = 1;
	}
	if (needReload) {
		if (!(initialiseModule())) {
			return interpreterProxy->primitiveFail();
		}
	}
	interpreterProxy->pop(1);
}

static double processIndexedofSizeidxArrayidxSize(float *vtxArray, int vtxSize, int *idxArray, int idxSize) {
    double zValue;
    float *vtxPtr;
    int i;
    double minZ;
    double wValue;
    int index;

	minZ = 10.0;
	for (i = 1; i <= idxSize; i += 1) {
		index = idxArray[i];
		if (index > 0) {
			vtxPtr = vtxArray + ((index - 1) * PrimVertexSize);
			zValue = vtxPtr[PrimVtxRasterPosZ];
			wValue = vtxPtr[PrimVtxRasterPosW];
			if (!(wValue == 0.0)) {
				zValue = zValue / wValue;
			}
			if (zValue < minZ) {
				minZ = zValue;
			}
		}
	}
	return minZ;
}

static int processIndexedIDXofSizeidxArrayidxSize(float *vtxArray, int vtxSize, int *idxArray, int idxSize) {
    double zValue;
    float *vtxPtr;
    int minIndex;
    int i;
    double minZ;
    double wValue;
    int index;

	minZ = 10.0;
	minIndex = 0;
	for (i = 1; i <= idxSize; i += 1) {
		index = idxArray[i];
		if (index > 0) {
			vtxPtr = vtxArray + ((index - 1) * PrimVertexSize);
			zValue = vtxPtr[PrimVtxRasterPosZ];
			wValue = vtxPtr[PrimVtxRasterPosW];
			if (!(wValue == 0.0)) {
				zValue = zValue / wValue;
			}
			if ((minIndex == 0) || (zValue < minZ)) {
				minIndex = i;
				minZ = zValue;
			}
		}
	}
	return minIndex;
}

static double processNonIndexedofSize(float *vtxArray, int vtxSize) {
    double zValue;
    float *vtxPtr;
    int i;
    double minZ;
    double wValue;

	minZ = 10.0;
	vtxPtr = vtxArray;
	for (i = 1; i <= vtxSize; i += 1) {
		zValue = vtxPtr[PrimVtxRasterPosZ];
		wValue = vtxPtr[PrimVtxRasterPosW];
		if (!(wValue == 0.0)) {
			zValue = zValue / wValue;
		}
		if (zValue < minZ) {
			minZ = zValue;
		}
	}
	return minZ;
}

static int processNonIndexedIDXofSize(float *vtxArray, int vtxSize) {
    double zValue;
    float *vtxPtr;
    int minIndex;
    int i;
    double minZ;
    double wValue;

	minZ = 10.0;
	minIndex = 0;
	vtxPtr = vtxArray;
	for (i = 1; i <= vtxSize; i += 1) {
		zValue = vtxPtr[PrimVtxRasterPosZ];
		wValue = vtxPtr[PrimVtxRasterPosW];
		if (!(wValue == 0.0)) {
			zValue = zValue / wValue;
		}
		if ((minIndex == 0) || (zValue < minZ)) {
			minIndex = i;
			minZ = zValue;
		}
	}
	return minIndex;
}

static double rightClipValueFromto(int last, int next) {
	return (((((float *) last))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosX])));
}


/*	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;
}

static int shadeVertex(void) {
    double specularFactor;
    double cosAngle;

	computeDirection();
	/* begin computeAttenuation */
	lightScale = 1.0;
	if (lightFlags & FlagAttenuated) {
		lightScale = 1.0 / ((primLight[PrimLightAttenuationConstant]) + (l2vDistance * ((primLight[PrimLightAttenuationLinear]) + (l2vDistance * (primLight[PrimLightAttenuationSquared])))));
	}
	if (lightFlags & FlagHasSpot) {
		lightScale = lightScale * (computeSpotFactor());
	}
	if (lightScale > 0.001) {
		if (lightFlags & FlagAmbientPart) {
			addPartfromtrackFlagscale(primLight + AmbientPart, primMaterial + AmbientPart, VBTrackAmbient, lightScale);
		}
		if (lightFlags & FlagDiffusePart) {

			/* For one-sided lighting negate cosAngle if necessary */

			cosAngle = dotProductOfFloatwithDouble(litVertex + PrimVtxNormal, l2vDirection);
			if (((vbFlags & VBTwoSidedLighting) == 0) && (cosAngle < 0.0)) {
				cosAngle = 0.0 - cosAngle;
			}
			if (cosAngle > 0.0) {
				addPartfromtrackFlagscale(primLight + DiffusePart, primMaterial + DiffusePart, VBTrackDiffuse, lightScale * cosAngle);
			}
		}
	}
	if ((lightFlags & FlagSpecularPart) && ((primMaterial[MaterialShininess]) > 0.0)) {
		l2vSpecDir[0] = (l2vDirection[0]);
		l2vSpecDir[1] = (l2vDirection[1]);
		l2vSpecDir[2] = (l2vDirection[2]);
		if (vbFlags & VBUseLocalViewer) {
			computeSpecularDirection();
		} else {
			l2vSpecDir[2] = ((l2vSpecDir[2]) - 1.0);
		}
		cosAngle = dotProductOfFloatwithDouble(litVertex + PrimVtxNormal, l2vSpecDir);
		if (cosAngle > 0.0) {

			/* cosAngle should be somewhere between 0 and 1.

			If not, then the vertex normal was not normalized */

			cosAngle = cosAngle * (inverseLengthOfDouble(l2vSpecDir));
			if (cosAngle > 1.0) {
				specularFactor = pow(cosAngle,(primMaterial[MaterialShininess]));
			} else {
				if (cosAngle == 0.0) {
					specularFactor = 1.0;
				} else {
					specularFactor = pow(cosAngle,(primMaterial[MaterialShininess]));
				}
			}
			addPartfromtrackFlagscale(primLight + SpecularPart, primMaterial + SpecularPart, VBTrackSpecular, specularFactor);
		}
	}
}


/*	Load an Array of B3DPrimitiveLights from the given stack index */

static int stackLightArrayValue(int stackIndex) {
    int oop;
    int i;
    int array;
    int arraySize;

	array = interpreterProxy->stackObjectValue(stackIndex);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!((interpreterProxy->fetchClassOf(array)) == (interpreterProxy->classArray()))) {
		return interpreterProxy->primitiveFail();
	}
	arraySize = interpreterProxy->slotSizeOf(array);
	for (i = 0; i <= (arraySize - 1); i += 1) {
		oop = interpreterProxy->fetchPointerofObject(i, array);
		if ((oop & 1)) {
			return interpreterProxy->primitiveFail();
		}
		if (!((interpreterProxy->isWords(oop)) && ((interpreterProxy->slotSizeOf(oop)) == PrimLightSize))) {
			return interpreterProxy->primitiveFail();
		}
	}
	return array;
}


/*	Load a B3DMaterial from the given stack index */

static void * stackMaterialValue(int stackIndex) {
    int oop;

	oop = interpreterProxy->stackObjectValue(stackIndex);
	if (interpreterProxy->failed()) {
		return null;
	}
	if ((interpreterProxy->isWords(oop)) && ((interpreterProxy->slotSizeOf(oop)) == MaterialSize)) {
		return interpreterProxy->firstIndexableField(oop);
	}
	return null;
}


/*	Load a 4x4 transformation matrix from the interpreter stack.

	Return a pointer to the matrix data if successful, nil otherwise. */

static void* stackMatrix(int index) {
    int oop;

	oop = interpreterProxy->stackObjectValue(index);
	if (oop == null) {
		return null;
	}
	if ((interpreterProxy->isWords(oop)) && ((interpreterProxy->slotSizeOf(oop)) == 16)) {
		return interpreterProxy->firstIndexableField(oop);
	}
	return null;
}


/*	Load a primitive index array from the interpreter stack.

	If aBool is true then check that all the indexes are in the range (1,maxIndex).

	Return a pointer to the index data if successful, nil otherwise. */

static void* stackPrimitiveIndexArrayofSizevalidateforVertexSize(int stackIndex, int nItems, int aBool, int maxIndex) {
    int oop;
    int *idxPtr;
    int i;
    int index;
    int oopSize;

	oop = interpreterProxy->stackObjectValue(stackIndex);
	if (oop == null) {
		return null;
	}
	if (!(interpreterProxy->isWords(oop))) {
		return null;
	}
	oopSize = interpreterProxy->slotSizeOf(oop);
	if (oopSize < nItems) {
		return null;
	}
	idxPtr = ((int *) (interpreterProxy->firstIndexableField(oop)));
	if (aBool) {
		for (i = 0; i <= (nItems - 1); i += 1) {
			index = idxPtr[i];
			if ((index < 0) || (index > maxIndex)) {
				return null;
			}
		}
	}
	return idxPtr;
}


/*	Load a primitive vertex from the interpreter stack.

	Return a pointer to the vertex data if successful, nil otherwise. */

static void* stackPrimitiveVertex(int index) {
    int oop;

	oop = interpreterProxy->stackObjectValue(index);
	if (oop == null) {
		return null;
	}
	if ((interpreterProxy->isWords(oop)) && ((interpreterProxy->slotSizeOf(oop)) == PrimVertexSize)) {
		return interpreterProxy->firstIndexableField(oop);
	}
	return null;
}


/*	Load a primitive vertex array from the interpreter stack.

	Return a pointer to the vertex data if successful, nil otherwise. */

static void* stackPrimitiveVertexArrayofSize(int index, int nItems) {
    int oop;
    int oopSize;

	oop = interpreterProxy->stackObjectValue(index);
	if (oop == null) {
		return null;
	}
	if (interpreterProxy->isWords(oop)) {
		oopSize = interpreterProxy->slotSizeOf(oop);
		if (((oopSize >= nItems) * PrimVertexSize) && ((oopSize % PrimVertexSize) == 0)) {
			return interpreterProxy->firstIndexableField(oop);
		}
	}
	return null;
}

static int storeObjectsInto(int stackIndex) {
    int arrayOop;
    int arraySize;
    int objOop;
    int i;

	arrayOop = interpreterProxy->stackObjectValue(stackIndex);
	arraySize = state.nObjects;
	for (i = 0; i <= (arraySize - 1); i += 1) {
		objOop = state.objects[i]->__oop__;
		interpreterProxy->storePointerofObjectwithValue(i, arrayOop, objOop);
	}
}


/*	Store the computed output color back into the current primitive vertex.

	Clamp the r,g,b,a part to be in the range 0-255. */

static int storePrimitiveVertex(void) {
    int a;
    int r;
    int b;
    int g;

	r = ((int) ((vtxOutColor[0]) * 255) );
	r = (((((r < 255) ? r : 255)) < 0) ? 0 : (((r < 255) ? r : 255)));
	g = ((int) ((vtxOutColor[1]) * 255) );
	g = (((((g < 255) ? g : 255)) < 0) ? 0 : (((g < 255) ? g : 255)));
	b = ((int) ((vtxOutColor[2]) * 255) );
	b = (((((b < 255) ? b : 255)) < 0) ? 0 : (((b < 255) ? b : 255)));
	a = ((int) ((vtxOutColor[3]) * 255) );

	/* The following is equal to b + (g << 8) + (r << 16) + (a << 24) */

	a = (((((a < 255) ? a : 255)) < 0) ? 0 : (((a < 255) ? a : 255)));
	(((int*) litVertex))[PrimVtxColor32] = (b + ((g + ((r + (a << 8)) << 8)) << 8));
}

static double topClipValueFromto(int last, int next) {
	return (((((float *) last))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosY])));
}


/*	Transform src with arg into dst.

	It is allowed that src == dst but not arg == dst */

static int transformMatrixwithinto(float *src, float *arg, float *dst) {
    float c4;
    float c3;
    float c2;
    float *m3;
    int i;
    float c1;
    float *m2;
    float *m1;

	m1 = ((float *) src);
	m2 = ((float *) arg);
	m3 = ((float *) dst);
	for (i = 0; i <= 3; i += 1) {
		c1 = ((((m1[0]) * (m2[0])) + ((m1[1]) * (m2[4]))) + ((m1[2]) * (m2[8]))) + ((m1[3]) * (m2[12]));
		c2 = ((((m1[0]) * (m2[1])) + ((m1[1]) * (m2[5]))) + ((m1[2]) * (m2[9]))) + ((m1[3]) * (m2[13]));
		c3 = ((((m1[0]) * (m2[2])) + ((m1[1]) * (m2[6]))) + ((m1[2]) * (m2[10]))) + ((m1[3]) * (m2[14]));

		/* Store result */

		c4 = ((((m1[0]) * (m2[3])) + ((m1[1]) * (m2[7]))) + ((m1[2]) * (m2[11]))) + ((m1[3]) * (m2[15]));
		m3[0] = c1;
		m3[1] = c2;
		m3[2] = c3;
		m3[3] = c4;
		m1 += 4;
		m3 += 4;
	}
}


/*	Transform the normal of the given primitive vertex */

static int transformPrimitiveNormalbyrescale(float *pVertex, float *matrix, int rescale) {
    double rz;
    double z;
    double ry;
    double dot;
    double y;
    double rx;
    double x;

	x = pVertex[PrimVtxNormalX];
	y = pVertex[PrimVtxNormalY];
	z = pVertex[PrimVtxNormalZ];
	rx = ((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]));
	ry = ((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]));
	rz = ((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]));
	if (rescale) {
		dot = ((rx * rx) + (ry * ry)) + (rz * rz);
		if (dot < 1.0e-20) {
			rx = ry = rz = 0.0;
		} else {
			if (!(dot == 1.0)) {
				dot = 1.0 / (sqrt(dot));
				rx = rx * dot;
				ry = ry * dot;
				rz = rz * dot;
			}
		}
	}
	pVertex[PrimVtxNormalX] = (((float) rx));
	pVertex[PrimVtxNormalY] = (((float) ry));
	pVertex[PrimVtxNormalZ] = (((float) rz));
}


/*	Transform the normal of the given primitive vertex */

static int transformPrimitivePositionby(float *pVertex, float *matrix) {
    double rz;
    double z;
    double ry;
    double y;
    double rx;
    double x;
    double rw;

	x = pVertex[PrimVtxPositionX];
	y = pVertex[PrimVtxPositionY];
	z = pVertex[PrimVtxPositionZ];
	rx = (((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]))) + (matrix[3]);
	ry = (((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]))) + (matrix[7]);
	rz = (((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]))) + (matrix[11]);
	rw = (((x * (matrix[12])) + (y * (matrix[13]))) + (z * (matrix[14]))) + (matrix[15]);
	if (rw == 1.0) {
		pVertex[PrimVtxPositionX] = (((float) rx));
		pVertex[PrimVtxPositionY] = (((float) ry));
		pVertex[PrimVtxPositionZ] = (((float) rz));
	} else {
		if (rw == 0.0) {
			rw = 0.0;
		} else {
			rw = 1.0 / rw;
		}
		pVertex[PrimVtxPositionX] = (((float) (rx * rw)));
		pVertex[PrimVtxPositionY] = (((float) (ry * rw)));
		pVertex[PrimVtxPositionZ] = (((float) (rz * rw)));
	}
}


/*	Transform the position of the given primitive vertex assuming that 

	matrix a41 = a42 = a43 = 0.0 and a44 = 1.0 */

static int transformPrimitivePositionFastby(float *pVertex, float *matrix) {
    double rz;
    double z;
    double ry;
    double y;
    double rx;
    double x;

	x = pVertex[PrimVtxPositionX];
	y = pVertex[PrimVtxPositionY];
	z = pVertex[PrimVtxPositionZ];
	rx = (((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]))) + (matrix[3]);
	ry = (((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]))) + (matrix[7]);
	rz = (((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]))) + (matrix[11]);
	pVertex[PrimVtxPositionX] = (((float) rx));
	pVertex[PrimVtxPositionY] = (((float) ry));
	pVertex[PrimVtxPositionZ] = (((float) rz));
}


/*	Transform the position of the given primitive vertex assuming that 

	matrix a14 = a24 = a34 = a41 = a42 = a43 = 0.0 and a44 = 1.0 */

static int transformPrimitivePositionFasterby(float *pVertex, float *matrix) {
    double rz;
    double z;
    double ry;
    double y;
    double rx;
    double x;

	x = pVertex[PrimVtxPositionX];
	y = pVertex[PrimVtxPositionY];
	z = pVertex[PrimVtxPositionZ];
	rx = ((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]));
	ry = ((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]));
	rz = ((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]));
	pVertex[PrimVtxPositionX] = (((float) rx));
	pVertex[PrimVtxPositionY] = (((float) ry));
	pVertex[PrimVtxPositionZ] = (((float) rz));
}


/*	Transform the normal of the given primitive vertex */

static int transformPrimitiveRasterPositionby(float *pVertex, float *matrix) {
    double rz;
    double z;
    double ry;
    double y;
    double rx;
    double x;
    double rw;

	x = pVertex[PrimVtxPositionX];
	y = pVertex[PrimVtxPositionY];
	z = pVertex[PrimVtxPositionZ];
	rx = (((x * (matrix[0])) + (y * (matrix[1]))) + (z * (matrix[2]))) + (matrix[3]);
	ry = (((x * (matrix[4])) + (y * (matrix[5]))) + (z * (matrix[6]))) + (matrix[7]);
	rz = (((x * (matrix[8])) + (y * (matrix[9]))) + (z * (matrix[10]))) + (matrix[11]);
	rw = (((x * (matrix[12])) + (y * (matrix[13]))) + (z * (matrix[14]))) + (matrix[15]);
	pVertex[PrimVtxRasterPosX] = (((float) rx));
	pVertex[PrimVtxRasterPosY] = (((float) ry));
	pVertex[PrimVtxRasterPosZ] = (((float) rz));
	pVertex[PrimVtxRasterPosW] = (((float) rw));
}


/*	Transform the entire vertex array by the given matrices */
/*	TODO: Check the actual trade-offs between vtxCount and analyzing */

static int transformVBcountbyandflags(float *vtxArray, int vtxCount, float *modelViewMatrix, float *projectionMatrix, int flags) {
    int prFlags;
    int hasNormals;
    int rescale;
    int mvFlags;
    int i;
    float *pVertex;

	mvFlags = analyzeMatrix(modelViewMatrix);
	prFlags = analyzeMatrix(projectionMatrix);
	pVertex = ((float *) vtxArray);

	/* Check if we have to rescale the normals */

	hasNormals = flags & VBVtxHasNormals;
	if (hasNormals) {
		if (mvFlags & FlagM44Identity) {
			rescale = 0;
		} else {
			rescale = analyzeMatrix3x3Length(modelViewMatrix);
		}
	}
	if ((mvFlags & FlagM44NoPerspective) && (prFlags == 0)) {
		if ((mvFlags == FlagM44NoTranslation) == 0) {
			for (i = 1; i <= vtxCount; i += 1) {
				if (hasNormals) {
					transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
				}
				transformPrimitivePositionFastby(pVertex, modelViewMatrix);
				transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
				pVertex += PrimVertexSize;
			}
		} else {
			for (i = 1; i <= vtxCount; i += 1) {
				if (hasNormals) {
					transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
				}
				transformPrimitivePositionFasterby(pVertex, modelViewMatrix);
				transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
				pVertex += PrimVertexSize;
			}
		}
		return null;
	}
	if ((mvFlags & prFlags) & FlagM44Identity) {
		for (i = 1; i <= vtxCount; i += 1) {
			pVertex[PrimVtxRasterPosX] = (pVertex[PrimVtxPositionX]);
			pVertex[PrimVtxRasterPosY] = (pVertex[PrimVtxPositionY]);
			pVertex[PrimVtxRasterPosZ] = (pVertex[PrimVtxPositionZ]);
			pVertex[PrimVtxRasterPosW] = 1.0;
			pVertex += PrimVertexSize;
		}
		return null;
	}
	if (mvFlags & FlagM44Identity) {
		for (i = 1; i <= vtxCount; i += 1) {
			transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
			pVertex += PrimVertexSize;
		}
		return null;
	}
	if (prFlags & FlagM44Identity) {
		for (i = 1; i <= vtxCount; i += 1) {
			if (hasNormals) {
				transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
			}
			if (mvFlags == (FlagM44NoPerspective + FlagM44NoPerspective)) {
				transformPrimitivePositionFasterby(pVertex, modelViewMatrix);
			} else {
				if (mvFlags == FlagM44NoPerspective) {
					transformPrimitivePositionFastby(pVertex, modelViewMatrix);
				} else {
					transformPrimitivePositionby(pVertex, modelViewMatrix);
				}
			}
			pVertex[PrimVtxRasterPosX] = (pVertex[PrimVtxPositionX]);
			pVertex[PrimVtxRasterPosY] = (pVertex[PrimVtxPositionY]);
			pVertex[PrimVtxRasterPosZ] = (pVertex[PrimVtxPositionZ]);
			pVertex[PrimVtxRasterPosW] = 1.0;
			pVertex += PrimVertexSize;
		}
		return null;
	}
	for (i = 1; i <= vtxCount; i += 1) {
		if (hasNormals) {
			transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
		}
		transformPrimitivePositionby(pVertex, modelViewMatrix);
		transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
		pVertex += PrimVertexSize;
	}
}


/*	Load the word based array of size count from the given oop */

static void* vbLoadArraysize(int oop, int count) {
	if (oop == null) {
		interpreterProxy->primitiveFail();
		return null;
	}
	if (oop == (interpreterProxy->nilObject())) {
		return null;
	}
	if (!(interpreterProxy->isWords(oop))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	if (!((interpreterProxy->slotSizeOf(oop)) == count)) {
		interpreterProxy->primitiveFail();
		return null;
	}
	return interpreterProxy->firstIndexableField(oop);
}


#ifdef SQUEAK_BUILTIN_PLUGIN


void* Squeak3D_exports[][3] = {
	{"Squeak3D", "b3dTransformPrimitiveNormal", (void*)b3dTransformPrimitiveNormal},
	{"Squeak3D", "primitiveSetBitBltPlugin", (void*)primitiveSetBitBltPlugin},
	{"Squeak3D", "b3dTransformMatrixWithInto", (void*)b3dTransformMatrixWithInto},
	{"Squeak3D", "b3dTransformVertexBuffer", (void*)b3dTransformVertexBuffer},
	{"Squeak3D", "b3dRasterizerVersion", (void*)b3dRasterizerVersion},
	{"Squeak3D", "b3dLoadVertexBuffer", (void*)b3dLoadVertexBuffer},
	{"Squeak3D", "b3dTransformPrimitivePosition", (void*)b3dTransformPrimitivePosition},
	{"Squeak3D", "initialiseModule", (void*)initialiseModule},
	{"Squeak3D", "b3dPrimitiveTextureSize", (void*)b3dPrimitiveTextureSize},
	{"Squeak3D", "b3dTransformPoint", (void*)b3dTransformPoint},
	{"Squeak3D", "b3dTransformPrimitiveRasterPosition", (void*)b3dTransformPrimitiveRasterPosition},
	{"Squeak3D", "b3dStartRasterizer", (void*)b3dStartRasterizer},
	{"Squeak3D", "b3dInitializeRasterizerState", (void*)b3dInitializeRasterizerState},
	{"Squeak3D", "b3dComputeMinIndexZ", (void*)b3dComputeMinIndexZ},
	{"Squeak3D", "b3dPrimitiveNextClippedTriangle", (void*)b3dPrimitiveNextClippedTriangle},
	{"Squeak3D", "setInterpreter", (void*)setInterpreter},
	{"Squeak3D", "b3dMapVertexBuffer", (void*)b3dMapVertexBuffer},
	{"Squeak3D", "getModuleName", (void*)getModuleName},
	{"Squeak3D", "b3dClipPolygon", (void*)b3dClipPolygon},
	{"Squeak3D", "b3dTransformDirection", (void*)b3dTransformDirection},
	{"Squeak3D", "b3dShaderVersion", (void*)b3dShaderVersion},
	{"Squeak3D", "b3dShadeVertexBuffer", (void*)b3dShadeVertexBuffer},
	{"Squeak3D", "b3dLoadIndexArray", (void*)b3dLoadIndexArray},
	{"Squeak3D", "b3dTransformerVersion", (void*)b3dTransformerVersion},
	{"Squeak3D", "b3dDetermineClipFlags", (void*)b3dDetermineClipFlags},
	{"Squeak3D", "b3dPrimitiveObjectSize", (void*)b3dPrimitiveObjectSize},
	{"Squeak3D", "b3dTransposeMatrix", (void*)b3dTransposeMatrix},
	{"Squeak3D", "b3dComputeMinZ", (void*)b3dComputeMinZ},
	{"Squeak3D", "b3dInplaceHouseHolderInvert", (void*)b3dInplaceHouseHolderInvert},
	{"Squeak3D", "moduleUnloaded", (void*)moduleUnloaded},
	{"Squeak3D", "b3dOrthoNormInverseMatrix", (void*)b3dOrthoNormInverseMatrix},
	{"Squeak3D", "b3dInitPrimitiveObject", (void*)b3dInitPrimitiveObject},
	{NULL, NULL, NULL}
};


#endif /* ifdef SQ_BUILTIN_PLUGIN */

