/* Automatically generated by
	VMPluginCodeGenerator VMMaker.oscog-eem.2484 uuid: 63db7375-cf0b-4a19-86d9-9e4a4da68117
   from
	B3DEnginePlugin Balloon3D-Plugins-eem.15 uuid: d694149b-363b-4754-aa4a-7ef0cb2c5eab
 */
static char __buildInfo[] = "B3DEnginePlugin Balloon3D-Plugins-eem.15 uuid: d694149b-363b-4754-aa4a-7ef0cb2c5eab " __DATE__ ;



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

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

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

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

#include "b3d.h"
#include "sqMemoryAccess.h"


/*** Constants ***/
#define AmbientPart 0
#define DiffusePart 4
#define EmissionAlpha 15
#define EmissionBlue 14
#define EmissionGreen 13
#define EmissionRed 12
#define FlagAmbientPart 0x100
#define FlagAttenuated 4
#define FlagDiffusePart 0x200
#define FlagDirectional 2
#define FlagHasSpot 8
#define FlagM44Identity 1
#define FlagM44NoPerspective 2
#define FlagM44NoTranslation 4
#define FlagPositional 1
#define FlagSpecularPart 0x400
#define InAllMask 0x555
#define InBackBit 0x400
#define InBottomBit 64
#define InFrontBit 0x100
#define InLeftBit 1
#define InRightBit 4
#define InTopBit 16
#define MaterialShininess 16
#define MaterialSize 17
#define OutAllMask 0xAAA
#define OutBackBit 0x800
#define OutBottomBit 128
#define OutFrontBit 0x200
#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 PrimVtxTexCoords 6
#define PrimVtxTexCoordU 6
#define PrimVtxTexCoordV 7
#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


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


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

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*byteSizeOf)(sqInt oop);
static sqInt (*classArray)(void);
static sqInt (*classBitmap)(void);
static sqInt (*classPoint)(void);
static sqInt (*clone)(sqInt oop);
static sqInt (*failed)(void);
static sqInt (*fetchClassOf)(sqInt oop);
static sqInt (*fetchIntegerofObject)(sqInt fieldIndex, sqInt objectPointer);
static sqInt (*fetchPointerofObject)(sqInt index, sqInt oop);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*floatObjectOf)(double aFloat);
static void * (*ioLoadFunctionFrom)(char *functionName, char *moduleName);
static sqInt (*isBytes)(sqInt oop);
static sqInt (*isPointers)(sqInt oop);
static sqInt (*isWords)(sqInt oop);
static sqInt (*methodArgumentCount)(void);
static sqInt (*nilObject)(void);
static sqInt (*pop)(sqInt nItems);
static sqInt (*popRemappableOop)(void);
static sqInt (*primitiveFail)(void);
static sqInt (*push)(sqInt object);
static sqInt (*pushBool)(sqInt trueOrFalse);
static sqInt (*pushFloat)(double f);
static sqInt (*pushInteger)(sqInt integerValue);
static sqInt (*pushRemappableOop)(sqInt oop);
static sqInt (*slotSizeOf)(sqInt oop);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackObjectValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*storePointerofObjectwithValue)(sqInt index, sqInt oop, sqInt valuePointer);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern sqInt booleanValueOf(sqInt obj);
extern sqInt byteSizeOf(sqInt oop);
extern sqInt classArray(void);
extern sqInt classBitmap(void);
extern sqInt classPoint(void);
extern sqInt clone(sqInt oop);
extern sqInt failed(void);
extern sqInt fetchClassOf(sqInt oop);
extern sqInt fetchIntegerofObject(sqInt fieldIndex, sqInt objectPointer);
extern sqInt fetchPointerofObject(sqInt index, sqInt oop);
extern void * firstIndexableField(sqInt oop);
extern sqInt floatObjectOf(double aFloat);
extern void * ioLoadFunctionFrom(char *functionName, char *moduleName);
extern sqInt isBytes(sqInt oop);
extern sqInt isPointers(sqInt oop);
extern sqInt isWords(sqInt oop);
extern sqInt methodArgumentCount(void);
extern sqInt nilObject(void);
extern sqInt pop(sqInt nItems);
extern sqInt popRemappableOop(void);
extern sqInt primitiveFail(void);
extern sqInt push(sqInt object);
extern sqInt pushBool(sqInt trueOrFalse);
extern sqInt pushFloat(double f);
extern sqInt pushInteger(sqInt integerValue);
extern sqInt pushRemappableOop(sqInt oop);
extern sqInt slotSizeOf(sqInt oop);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackObjectValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt storePointerofObjectwithValue(sqInt index, sqInt oop, sqInt valuePointer);
extern
#endif
struct VirtualMachine* interpreterProxy;
static double l2vDirection[3];
static double l2vDistance;
static double l2vSpecDir[3];
static sqInt lightFlags;
static double lightScale;
static float* litVertex;
static sqInt loadBBFn;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"Squeak3D Balloon3D-Plugins-eem.15 (i)"
#else
	"Squeak3D Balloon3D-Plugins-eem.15 (e)"
#endif
;
static float* primLight;
static float* primMaterial;
static B3DRasterizerState state;
static sqInt vbFlags;
static B3DPrimitiveViewport viewport;
static double vtxInColor[4];
static double vtxOutColor[4];



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

	/* B3DShaderPlugin>>#addPart:from:trackFlag:scale: */
static sqInt
addPartfromtrackFlagscale(float *lightPart, float *materialPart, sqInt vbTrackFlag, double scale)
{
    double aPart;
    double bPart;
    double gPart;
    double rPart;

	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 {

		/* Note: This should be pre-computed. */
		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);
	return 0;
}


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

	/* B3DTransformerPlugin>>#analyzeMatrix3x3Length: */
static sqInt
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 */

	/* B3DTransformerPlugin>>#analyzeMatrix: */
static sqInt
analyzeMatrix(float *m)
{
    sqInt flags;


	/* Check the perspective */
	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.
 */

	/* B3DClipperPlugin>>#b3dClipPolygon */
EXPORT(sqInt)
b3dClipPolygon(void)
{
    sqInt count;
    sqInt count1;
    sqInt outMask;
    int *tempVtxArray;
    int *vtxArray;
    sqInt vtxCount;

	if (!((methodArgumentCount()) == 4)) {
		return primitiveFail();
	}
	outMask = stackIntegerValue(0);
	vtxCount = stackIntegerValue(2);
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxCount + 4);
	tempVtxArray = stackPrimitiveVertexArrayofSize(1, vtxCount + 4);
	if ((vtxArray == null)
	 || ((tempVtxArray == null)
	 || (failed()))) {
		return primitiveFail();
	}
	vtxArray -= PrimVertexSize;
	tempVtxArray -= PrimVertexSize;
	/* begin clipPolygon:count:with:mask: */
	if (outMask == OutLeftBit) {
		count = clipPolygonLeftFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	if (outMask == OutRightBit) {
		count = clipPolygonRightFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	if (outMask == OutTopBit) {
		count = clipPolygonTopFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	if (outMask == OutBottomBit) {
		count = clipPolygonBottomFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	if (outMask == OutFrontBit) {
		count = clipPolygonFrontFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	if (outMask == OutBackBit) {
		count = clipPolygonBackFromtocount(tempVtxArray, vtxArray, vtxCount);
		goto l1;
	}
	count1 = vtxCount;
	count1 = clipPolygonLeftFromtocount(vtxArray, tempVtxArray, count1);
	if (count1 == 0) {
		count = 0;
		goto l1;
	}
	count1 = clipPolygonRightFromtocount(tempVtxArray, vtxArray, count1);
	if (count1 == 0) {
		count = 0;
		goto l1;
	}
	count1 = clipPolygonTopFromtocount(vtxArray, tempVtxArray, count1);
	if (count1 == 0) {
		count = 0;
		goto l1;
	}
	count1 = clipPolygonBottomFromtocount(tempVtxArray, vtxArray, count1);
	if (count1 == 0) {
		count = 0;
		goto l1;
	}
	count1 = clipPolygonFrontFromtocount(vtxArray, tempVtxArray, count1);
	if (count1 == 0) {
		count = 0;
		goto l1;
	}
	count1 = clipPolygonBackFromtocount(tempVtxArray, vtxArray, count1);
	count = count1;
	l1:	/* end clipPolygon:count:with:mask: */;
	pop(5);
	pushInteger(count);
	return 0;
}


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

	/* B3DPickerPlugin>>#b3dComputeMinIndexZ */
EXPORT(sqInt)
b3dComputeMinIndexZ(void)
{
    sqInt i;
    sqInt i1;
    int *idxArray;
    sqInt idxSize;
    int index;
    sqInt minIndex;
    sqInt minIndex1;
    sqInt minIndex2;
    double minZ;
    double minZ1;
    sqInt primType;
    float *vtxArray;
    float *vtxPtr;
    float *vtxPtr1;
    sqInt vtxSize;
    double wValue;
    double wValue1;
    double zValue;
    double zValue1;

	if (!((methodArgumentCount()) == 5)) {
		return primitiveFail();
	}
	idxSize = stackIntegerValue(0);
	vtxSize = stackIntegerValue(2);
	primType = stackIntegerValue(4);
	if (failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxSize);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxSize, 1, vtxSize);
	if ((vtxArray == null)
	 || ((idxArray == null)
	 || (failed()))) {
		return primitiveFail();
	}
	if ((primType < 1)
	 || (primType > 6)) {
		return primitiveFail();
	}
	if (primType <= 3) {
		/* begin processNonIndexedIDX:ofSize: */
		minZ = 10.0;
		minIndex1 = 0;
		vtxPtr = vtxArray;
		for (i = 1; i <= vtxSize; i += 1) {
			zValue = vtxPtr[PrimVtxRasterPosZ];
			wValue = vtxPtr[PrimVtxRasterPosW];
			if (!(wValue == 0.0)) {
				zValue = zValue / wValue;
			}
			if ((minIndex1 == 0)
			 || (zValue < minZ)) {
				minIndex1 = i;
				minZ = zValue;
			}
		}
		minIndex = minIndex1;
	}
	else {
		/* begin processIndexedIDX:ofSize:idxArray:idxSize: */
		minZ1 = 10.0;
		minIndex2 = 0;
		for (i1 = 1; i1 <= idxSize; i1 += 1) {
			index = idxArray[i1];
			if (index > 0) {
				vtxPtr1 = vtxArray + ((index - 1) * PrimVertexSize);
				zValue1 = vtxPtr1[PrimVtxRasterPosZ];
				wValue1 = vtxPtr1[PrimVtxRasterPosW];
				if (!(wValue1 == 0.0)) {
					zValue1 = zValue1 / wValue1;
				}
				if ((minIndex2 == 0)
				 || (zValue1 < minZ1)) {
					minIndex2 = i1;
					minZ1 = zValue1;
				}
			}
		}
		minIndex = minIndex2;
	}
	if (!(failed())) {
		pop(6);
		pushInteger(minIndex);
	}
	return 0;
}


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

	/* B3DPickerPlugin>>#b3dComputeMinZ */
EXPORT(sqInt)
b3dComputeMinZ(void)
{
    sqInt i;
    sqInt i1;
    int *idxArray;
    sqInt idxSize;
    int index;
    double minZ;
    double minZ1;
    double minZ2;
    sqInt primType;
    float *vtxArray;
    float *vtxPtr;
    float *vtxPtr1;
    sqInt vtxSize;
    double wValue;
    double wValue1;
    double zValue;
    double zValue1;

	if (!((methodArgumentCount()) == 5)) {
		return primitiveFail();
	}
	idxSize = stackIntegerValue(0);
	vtxSize = stackIntegerValue(2);
	primType = stackIntegerValue(4);
	if (failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxSize);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxSize, 1, vtxSize);
	if ((vtxArray == null)
	 || ((idxArray == null)
	 || (failed()))) {
		return primitiveFail();
	}
	if ((primType < 1)
	 || (primType > 6)) {
		return primitiveFail();
	}
	if (primType <= 3) {
		/* begin processNonIndexed:ofSize: */
		minZ1 = 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 < minZ1) {
				minZ1 = zValue;
			}
		}
		minZ = minZ1;
	}
	else {
		/* begin processIndexed:ofSize:idxArray:idxSize: */
		minZ2 = 10.0;
		for (i1 = 1; i1 <= idxSize; i1 += 1) {
			index = idxArray[i1];
			if (index > 0) {
				vtxPtr1 = vtxArray + ((index - 1) * PrimVertexSize);
				zValue1 = vtxPtr1[PrimVtxRasterPosZ];
				wValue1 = vtxPtr1[PrimVtxRasterPosW];
				if (!(wValue1 == 0.0)) {
					zValue1 = zValue1 / wValue1;
				}
				if (zValue1 < minZ2) {
					minZ2 = zValue1;
				}
			}
		}
		minZ = minZ2;
	}
	if (!(failed())) {
		pop(6);
		pushFloat(minZ);
	}
	return 0;
}


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

	/* B3DClipperPlugin>>#b3dDetermineClipFlags */
EXPORT(sqInt)
b3dDetermineClipFlags(void)
{
    sqInt flags;
    sqInt fullMask;
    sqInt i;
    sqInt result;
    void *vtxArray;
    sqInt vtxCount;
    float *vtxPtr;
    double w;
    double w2;
    double x;
    double y;
    double z;

	if (!((methodArgumentCount()) == 2)) {
		return primitiveFail();
	}
	vtxCount = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(1, vtxCount);
	if ((vtxArray == null)
	 || (failed())) {
		return primitiveFail();
	}
	/* begin determineClipFlags:count: */
	vtxPtr = ((float *) vtxArray);
	fullMask = InAllMask + OutAllMask;
	for (i = 1; i <= vtxCount; 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;
	}
	result = fullMask;
	if (!(failed())) {
		pop(3);
		pushInteger(result);
	}
	return 0;
}


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

	/* B3DRasterizerPlugin>>#b3dInitializeRasterizerState */
EXPORT(sqInt)
b3dInitializeRasterizerState(void)
{
    sqInt objOop;
    sqInt stateOop;

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

	/* B3DRasterizerPlugin>>#b3dInitPrimitiveObject */
EXPORT(sqInt)
b3dInitPrimitiveObject(void)
{
    int *idxArray;
    sqInt idxSize;
    sqInt primitive;
    void *primObj;
    sqInt primOop;
    sqInt primSize;
    sqInt textureIndex;
    int *vtxArray;
    sqInt vtxSize;


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

	/* Do the work */
	primSize = byteSizeOf(primOop);
	if (primitive == 3) {
		if (b3dAddPolygonObject((void*) primObj, primSize, B3D_FACE_RGB, textureIndex, (B3DPrimitiveVertex*) vtxArray, vtxSize, &viewport) != B3D_NO_ERROR) {
			return 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 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 primitiveFail();
		}
	}
	pop(9);
	push(primOop);
	return 0;
}


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

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

	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 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])));
		}
	}
	return 0;
}


/*	Primitive. Load the given index array into the receiver.
	NOTE: dstStart is a zero-based index. */

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


	/* Load the arguments */
	vtxOffset = stackIntegerValue(0);
	maxValue = stackIntegerValue(1);
	count = stackIntegerValue(2);
	srcArray = stackObjectValue(3);
	dstStart = stackIntegerValue(4);
	dstArray = stackObjectValue(5);
	if (failed()) {
		return null;
	}
	if (!(isWords(srcArray))) {
		return primitiveFail();
	}
	if ((slotSizeOf(srcArray)) < count) {
		return primitiveFail();
	}

	/* Check dstArray */
	srcPtr = ((int*) (firstIndexableField(srcArray)));

	/* Check if there is enough room left in dstArray */
	dstSize = slotSizeOf(dstArray);
	if ((dstStart + count) > dstSize) {
		return primitiveFail();
	}

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


/*	Primitive. Load the data into the given vertex buffer.
	NOTE: dstStart is a zero-based index. */

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

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

	/* Check for all problems above */
	dstPtr = stackPrimitiveVertexArrayofSize(7, dstStart + count);
	if ((dstPtr == null)
	 || ((defaultVtx == null)
	 || (failed()))) {
		return 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; 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;
		}
	}
	pop(9);
	pushInteger(count);
	return 0;
}


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

	/* B3DClipperPlugin>>#b3dMapVertexBuffer */
EXPORT(sqInt)
b3dMapVertexBuffer(void)
{
    double bottom;
    sqInt boxArray;
    int flags;
    sqInt floatOop;
    sqInt i;
    double left;
    sqInt oop;
    double right;
    double top;
    void *vtxArray;
    sqInt vtxCount;
    float *vtxPtr;
    double w;
    double x;
    double y;

	if (!((methodArgumentCount()) == 3)) {
		return primitiveFail();
	}
	boxArray = stackObjectValue(0);
	if (failed()) {
		return null;
	}
	if (!(((fetchClassOf(boxArray)) == (classArray()))
		 && ((slotSizeOf(boxArray)) == 4))) {
		return primitiveFail();
	}
	vtxCount = stackIntegerValue(1);
	if (failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(2, vtxCount);
	if ((vtxArray == null)
	 || (failed())) {
		return primitiveFail();
	}
	/* begin mapVB:ofSize:into: */
	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;
	pushRemappableOop(oop);
	floatOop = floatObjectOf(left);
	oop = popRemappableOop();
	storePointerofObjectwithValue(0, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(top);
	oop = popRemappableOop();
	storePointerofObjectwithValue(1, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(right);
	oop = popRemappableOop();
	storePointerofObjectwithValue(2, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(bottom);
	oop = popRemappableOop();
	storePointerofObjectwithValue(3, oop, floatOop);
	if (!(failed())) {
		pop(3);
	}
	return 0;
}

	/* B3DTransformerPlugin>>#b3dOrthoNormInverseMatrix */
EXPORT(sqInt)
b3dOrthoNormInverseMatrix(void)
{
    float *dst;
    sqInt dstOop;
    double rx;
    double ry;
    double rz;
    float *src;
    sqInt srcOop;
    double x;
    double y;
    double z;

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

	/* reload srcOop in case of GC */
	dstOop = clone(srcOop);
	srcOop = stackObjectValue(0);
	src = firstIndexableField(srcOop);

	/* Transpose upper 3x3 matrix */
	/* dst at: 0 put: (src at: 0). */
	dst = 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)));
	pop(1);
	push(dstOop);
	return 0;
}


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

	/* B3DClipperPlugin>>#b3dPrimitiveNextClippedTriangle */
EXPORT(sqInt)
b3dPrimitiveNextClippedTriangle(void)
{
    sqInt firstIndex;
    sqInt i;
    int idx1;
    int idx2;
    int idx3;
    int *idxArray;
    sqInt idxCount;
    int triMask;
    int *vtxArray;
    sqInt vtxCount;

	if (!((methodArgumentCount()) == 5)) {
		return primitiveFail();
	}
	idxCount = stackIntegerValue(0);
	vtxCount = stackIntegerValue(2);
	firstIndex = stackIntegerValue(4);
	if (failed()) {
		return null;
	}
	vtxArray = stackPrimitiveVertexArrayofSize(3, vtxCount);
	idxArray = stackPrimitiveIndexArrayofSizevalidateforVertexSize(1, idxCount, 1, vtxCount);
	if ((vtxArray == null)
	 || ((idxArray == null)
	 || (failed()))) {
		return 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)) {

				/* Tri is not completely inside -> needs clipping. */
				if (triMask & OutAllMask) {

					/* tri is completely outside. Store all zeros */
					idxArray[i] = 0;
					idxArray[i + 1] = 0;
					idxArray[i + 2] = 0;
				}
				else {

					/* tri must be partially clipped. */
					pop(6);
					pushInteger(i);
					return null;
				}
			}
		}
	}
	pop(6);
	pushInteger(0);
	return 0;
}


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

	/* B3DRasterizerPlugin>>#b3dPrimitiveObjectSize */
EXPORT(sqInt)
b3dPrimitiveObjectSize(void)
{
    sqInt objSize;

	objSize = ((sizeof(B3DPrimitiveObject) + sizeof(B3DPrimitiveVertex)) / 4) + 1;
	pop(1);
	pushInteger(objSize);
	return 0;
}


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

	/* B3DRasterizerPlugin>>#b3dPrimitiveTextureSize */
EXPORT(sqInt)
b3dPrimitiveTextureSize(void)
{
    sqInt objSize;

	objSize = ((sizeof(B3DTexture)) / 4) + 1;
	pop(1);
	pushInteger(objSize);
	return 0;
}


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

	/* B3DRasterizerPlugin>>#b3dRasterizerVersion */
EXPORT(sqInt)
b3dRasterizerVersion(void)
{
	pop(1);
	pushInteger(1);
	return 0;
}


/*	Return the current shader version. */

	/* B3DShaderPlugin>>#b3dShaderVersion */
EXPORT(sqInt)
b3dShaderVersion(void)
{
	pop(1);
	pushInteger(1);
	return 0;
}


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

	/* B3DShaderPlugin>>#b3dShadeVertexBuffer */
EXPORT(sqInt)
b3dShadeVertexBuffer(void)
{
    sqInt a;
    double aPart;
    double aPart1;
    double aPart2;
    sqInt b;
    double bPart;
    double bPart1;
    double bPart2;
    double cosAngle;
    sqInt g;
    double gPart;
    double gPart1;
    double gPart2;
    sqInt i;
    sqInt j;
    sqInt lightArray;
    sqInt lightCount;
    sqInt lightOop;
    float *lightPart;
    float *lightPart1;
    float *lightPart2;
    sqInt r;
    sqInt rgba;
    double rPart;
    double rPart1;
    double rPart2;
    double scale;
    double scale1;
    double scale11;
    double scale2;
    double specularFactor;
    float *vtxArray;
    sqInt vtxCount;

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

	/* Go over all vertices */
	lightCount = slotSizeOf(lightArray);
	for (i = 1; i <= vtxCount; i += 1) {

		/* Load the primitive vertex */
		/* begin loadPrimitiveVertex */
		rgba = (((int*) litVertex))[PrimVtxColor32];
		vtxInColor[2] = ((rgba & 0xFF) * (1.0 / 255.0));
		rgba = ((usqInt) rgba) >> 8;
		vtxInColor[1] = ((rgba & 0xFF) * (1.0 / 255.0));
		rgba = ((usqInt) rgba) >> 8;
		vtxInColor[0] = ((rgba & 0xFF) * (1.0 / 255.0));
		rgba = ((usqInt) rgba) >> 8;
		vtxInColor[3] = ((rgba & 0xFF) * (1.0 / 255.0));
		if (vbFlags & VBTrackEmission) {

			/* Load color from vertex */
			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; j += 1) {

			/* Fetch the light source */
			/* begin fetchLightSource:ofObject: */
			lightOop = fetchPointerofObject(j, lightArray);
			primLight = ((void *) (firstIndexableField(lightOop)));
			/* begin loadPrimitiveLightSource */
			lightFlags = (((int*) primLight))[PrimLightFlags];
			/* begin shadeVertex */
			if (lightFlags & FlagPositional) {

				/* Must compute the direction for this vertex */
				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);
					scale1 = -1.0 / l2vDistance;
				}
				l2vDirection[0] = ((l2vDirection[0]) * scale1);
				l2vDirection[1] = ((l2vDirection[1]) * scale1);
				l2vDirection[2] = ((l2vDirection[2]) * scale1);
			}
			else {
				if (lightFlags & FlagDirectional) {
					l2vDirection[0] = (primLight[PrimLightDirectionX]);
					l2vDirection[1] = (primLight[PrimLightDirectionY]);
					l2vDirection[2] = (primLight[PrimLightDirectionZ]);
				}
			}
			/* 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) {

				/* Compute the ambient part */
				if (lightFlags & FlagAmbientPart) {
					/* begin addPart:from:trackFlag:scale: */
					lightPart = primLight + AmbientPart;
					if (vbFlags & VBTrackAmbient) {
						rPart = ((vtxInColor[0]) * (lightPart[0])) * lightScale;
						gPart = ((vtxInColor[1]) * (lightPart[1])) * lightScale;
						bPart = ((vtxInColor[2]) * (lightPart[2])) * lightScale;
						aPart = ((vtxInColor[3]) * (lightPart[3])) * lightScale;
					}
					else {

						/* Note: This should be pre-computed. */
						rPart = (((primMaterial + AmbientPart)[0]) * (lightPart[0])) * lightScale;
						gPart = (((primMaterial + AmbientPart)[1]) * (lightPart[1])) * lightScale;
						bPart = (((primMaterial + AmbientPart)[2]) * (lightPart[2])) * lightScale;
						aPart = (((primMaterial + AmbientPart)[3]) * (lightPart[3])) * lightScale;
					}
					vtxOutColor[0] = ((vtxOutColor[0]) + rPart);
					vtxOutColor[1] = ((vtxOutColor[1]) + gPart);
					vtxOutColor[2] = ((vtxOutColor[2]) + bPart);
					vtxOutColor[3] = ((vtxOutColor[3]) + aPart);
				}
				if (lightFlags & FlagDiffusePart) {

					/* Compute angle from light->vertex to vertex normal */
					/* begin dotProductOfFloat:withDouble: */
					cosAngle = ((((litVertex + PrimVtxNormal)[0]) * (l2vDirection[0])) + (((litVertex + PrimVtxNormal)[1]) * (l2vDirection[1]))) + (((litVertex + PrimVtxNormal)[2]) * (l2vDirection[2]));
					if (((vbFlags & VBTwoSidedLighting) == 0)
					 && (cosAngle < 0.0)) {
						cosAngle = 0.0 - cosAngle;
					}
					if (cosAngle > 0.0) {
						/* begin addPart:from:trackFlag:scale: */
						lightPart1 = primLight + DiffusePart;
						scale = lightScale * cosAngle;
						if (vbFlags & VBTrackDiffuse) {
							rPart1 = ((vtxInColor[0]) * (lightPart1[0])) * scale;
							gPart1 = ((vtxInColor[1]) * (lightPart1[1])) * scale;
							bPart1 = ((vtxInColor[2]) * (lightPart1[2])) * scale;
							aPart1 = ((vtxInColor[3]) * (lightPart1[3])) * scale;
						}
						else {

							/* Note: This should be pre-computed. */
							rPart1 = (((primMaterial + DiffusePart)[0]) * (lightPart1[0])) * scale;
							gPart1 = (((primMaterial + DiffusePart)[1]) * (lightPart1[1])) * scale;
							bPart1 = (((primMaterial + DiffusePart)[2]) * (lightPart1[2])) * scale;
							aPart1 = (((primMaterial + DiffusePart)[3]) * (lightPart1[3])) * scale;
						}
						vtxOutColor[0] = ((vtxOutColor[0]) + rPart1);
						vtxOutColor[1] = ((vtxOutColor[1]) + gPart1);
						vtxOutColor[2] = ((vtxOutColor[2]) + bPart1);
						vtxOutColor[3] = ((vtxOutColor[3]) + aPart1);
					}
				}
			}
			if ((lightFlags & FlagSpecularPart)
			 && ((primMaterial[MaterialShininess]) > 0.0)) {

				/* Compute specular part */
				l2vSpecDir[0] = (l2vDirection[0]);
				l2vSpecDir[1] = (l2vDirection[1]);
				l2vSpecDir[2] = (l2vDirection[2]);
				if (vbFlags & VBUseLocalViewer) {
					/* begin computeSpecularDirection */
					scale11 = ((((litVertex + PrimVtxPosition)[0]) * ((litVertex + PrimVtxPosition)[0])) + (((litVertex + PrimVtxPosition)[1]) * ((litVertex + PrimVtxPosition)[1]))) + (((litVertex + PrimVtxPosition)[2]) * ((litVertex + PrimVtxPosition)[2]));
					if ((scale11 == 0.0)
					 || (scale11 == 1.0)) {
						scale2 = scale11;
						goto l3;
					}
					scale2 = 1.0 / (sqrt(scale11));
	l3:	/* end inverseLengthOfFloat: */;
					l2vSpecDir[0] = ((l2vSpecDir[0]) - ((litVertex[PrimVtxPositionX]) * scale2));
					l2vSpecDir[1] = ((l2vSpecDir[1]) - ((litVertex[PrimVtxPositionY]) * scale2));
					l2vSpecDir[2] = ((l2vSpecDir[2]) - ((litVertex[PrimVtxPositionZ]) * scale2));
				}
				else {
					l2vSpecDir[2] = ((l2vSpecDir[2]) - 1.0);
				}
				/* begin dotProductOfFloat:withDouble: */
				cosAngle = ((((litVertex + PrimVtxNormal)[0]) * (l2vSpecDir[0])) + (((litVertex + PrimVtxNormal)[1]) * (l2vSpecDir[1]))) + (((litVertex + PrimVtxNormal)[2]) * (l2vSpecDir[2]));
				if (cosAngle > 0.0) {

					/* Normalize the angle */

					/* 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]));
						}
					}
					/* begin addPart:from:trackFlag:scale: */
					lightPart2 = primLight + SpecularPart;
					if (vbFlags & VBTrackSpecular) {
						rPart2 = ((vtxInColor[0]) * (lightPart2[0])) * specularFactor;
						gPart2 = ((vtxInColor[1]) * (lightPart2[1])) * specularFactor;
						bPart2 = ((vtxInColor[2]) * (lightPart2[2])) * specularFactor;
						aPart2 = ((vtxInColor[3]) * (lightPart2[3])) * specularFactor;
					}
					else {

						/* Note: This should be pre-computed. */
						rPart2 = (((primMaterial + SpecularPart)[0]) * (lightPart2[0])) * specularFactor;
						gPart2 = (((primMaterial + SpecularPart)[1]) * (lightPart2[1])) * specularFactor;
						bPart2 = (((primMaterial + SpecularPart)[2]) * (lightPart2[2])) * specularFactor;
						aPart2 = (((primMaterial + SpecularPart)[3]) * (lightPart2[3])) * specularFactor;
					}
					vtxOutColor[0] = ((vtxOutColor[0]) + rPart2);
					vtxOutColor[1] = ((vtxOutColor[1]) + gPart2);
					vtxOutColor[2] = ((vtxOutColor[2]) + bPart2);
					vtxOutColor[3] = ((vtxOutColor[3]) + aPart2);
				}
			}
		}
		/* begin storePrimitiveVertex */
		r = ((sqInt)((vtxOutColor[0]) * 0xFF));
		r = (((((r < 0xFF) ? r : 0xFF)) < 0) ? 0 : (((r < 0xFF) ? r : 0xFF)));
		g = ((sqInt)((vtxOutColor[1]) * 0xFF));
		g = (((((g < 0xFF) ? g : 0xFF)) < 0) ? 0 : (((g < 0xFF) ? g : 0xFF)));
		b = ((sqInt)((vtxOutColor[2]) * 0xFF));
		b = (((((b < 0xFF) ? b : 0xFF)) < 0) ? 0 : (((b < 0xFF) ? b : 0xFF)));
		a = ((sqInt)((vtxOutColor[3]) * 0xFF));

		/* The following is equal to b + (g << 8) + (r << 16) + (a << 24) */
		a = (((((a < 0xFF) ? a : 0xFF)) < 0) ? 0 : (((a < 0xFF) ? a : 0xFF)));
		(((int*) litVertex))[PrimVtxColor32] = (b + (((sqInt)((usqInt)((g + (((sqInt)((usqInt)((r + (((sqInt)((usqInt)(a) << 8))))) << 8))))) << 8))));
		litVertex += PrimVertexSize;
	}
	pop(6);
	pushBool(1);
	return 0;
}


/*	Primitive. Start the rasterizer. */

	/* B3DRasterizerPlugin>>#b3dStartRasterizer */
EXPORT(sqInt)
b3dStartRasterizer(void)
{
    sqInt errCode;


	/* Check argument count */
	if (!((methodArgumentCount()) == 3)) {
		return primitiveFail();
	}
	if (!(loadRasterizerState(2))) {
		return primitiveFail();
	}
	loadTexturesFrom(0);
	if (failed()) {
		return null;
	}
	loadObjectsFrom(1);
	if (failed()) {
		return null;
	}
	errCode = b3dMainLoop(&state, B3D_NO_ERROR);
	storeObjectsInto(1);
	pop(4);
	pushInteger(errCode);
	return 0;
}

	/* B3DTransformerPlugin>>#b3dTransformDirection */
EXPORT(sqInt)
b3dTransformDirection(void)
{
    float *matrix;
    double rx;
    double ry;
    double rz;
    sqInt v3Oop;
    float *vertex;
    double x;
    double y;
    double z;

	if (!((methodArgumentCount()) == 1)) {
		return primitiveFail();
	}
	v3Oop = stackObjectValue(0);
	if (failed()) {
		return null;
	}
	if (!((isWords(v3Oop))
		 && ((slotSizeOf(v3Oop)) == 3))) {
		return primitiveFail();
	}
	vertex = firstIndexableField(v3Oop);
	matrix = stackMatrix(1);
	if (matrix == null) {
		return 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 = clone(v3Oop);
	vertex = firstIndexableField(v3Oop);
	vertex[0] = (((float) rx));
	vertex[1] = (((float) ry));
	vertex[2] = (((float) rz));
	pop(2);
	push(v3Oop);
	return 0;
}


/*	Return the current version of the transformer */

	/* B3DTransformerPlugin>>#b3dTransformerVersion */
EXPORT(sqInt)
b3dTransformerVersion(void)
{
	pop(1);
	pushInteger(1);
	return 0;
}


/*	Transform two matrices into the third */

	/* B3DTransformerPlugin>>#b3dTransformMatrixWithInto */
EXPORT(sqInt)
b3dTransformMatrixWithInto(void)
{
    float c1;
    float c2;
    float c3;
    float c4;
    sqInt i;
    float *m1;
    float *m11;
    float *m2;
    float *m21;
    float *m3;
    float *m31;

	m3 = stackMatrix(0);
	m2 = stackMatrix(1);
	m1 = stackMatrix(2);
	if (((m1 == null) || (m2 == null)) || (m3 == null)) {
		return primitiveFail();
	}
	if (m2 == m3) {
		return primitiveFail();
	}
	/* begin transformMatrix:with:into: */
	m11 = ((float *) m1);
	m21 = ((float *) m2);
	m31 = ((float *) m3);
	for (i = 0; i <= 3; i += 1) {

		/* Compute next row */
		c1 = ((((m11[0]) * (m21[0])) + ((m11[1]) * (m21[4]))) + ((m11[2]) * (m21[8]))) + ((m11[3]) * (m21[12]));
		c2 = ((((m11[0]) * (m21[1])) + ((m11[1]) * (m21[5]))) + ((m11[2]) * (m21[9]))) + ((m11[3]) * (m21[13]));
		c3 = ((((m11[0]) * (m21[2])) + ((m11[1]) * (m21[6]))) + ((m11[2]) * (m21[10]))) + ((m11[3]) * (m21[14]));

		/* Store result */
		c4 = ((((m11[0]) * (m21[3])) + ((m11[1]) * (m21[7]))) + ((m11[2]) * (m21[11]))) + ((m11[3]) * (m21[15]));
		m31[0] = c1;
		m31[1] = c2;
		m31[2] = c3;
		m31[3] = c4;
		m11 += 4;
		m31 += 4;
	}
	pop(3);
	return 0;
}

	/* B3DTransformerPlugin>>#b3dTransformPoint */
EXPORT(sqInt)
b3dTransformPoint(void)
{
    float *matrix;
    double rw;
    double rx;
    double ry;
    double rz;
    sqInt v3Oop;
    float *vertex;
    double x;
    double y;
    double z;

	if (!((methodArgumentCount()) == 1)) {
		return primitiveFail();
	}
	v3Oop = stackObjectValue(0);
	if (failed()) {
		return null;
	}
	if (!((isWords(v3Oop))
		 && ((slotSizeOf(v3Oop)) == 3))) {
		return primitiveFail();
	}
	vertex = firstIndexableField(v3Oop);
	matrix = stackMatrix(1);
	if (matrix == null) {
		return 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 = clone(v3Oop);
	vertex = 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)));
	}
	pop(2);
	push(v3Oop);
	return 0;
}


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

	/* B3DTransformerPlugin>>#b3dTransformPrimitiveNormal */
EXPORT(sqInt)
b3dTransformPrimitiveNormal(void)
{
    float *matrix;
    float *pVertex;
    sqInt rescale;

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


/*	Transform the position of the given primitive vertex the given matrix
	and store the result back inplace. */

	/* B3DTransformerPlugin>>#b3dTransformPrimitivePosition */
EXPORT(sqInt)
b3dTransformPrimitivePosition(void)
{
    float *matrix;
    float *pVertex;

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


/*	Transform the position of the given primitive vertex the given matrix
	and store the result in homogenous coordinates at rasterPos. */

	/* B3DTransformerPlugin>>#b3dTransformPrimitiveRasterPosition */
EXPORT(sqInt)
b3dTransformPrimitiveRasterPosition(void)
{
    float *matrix;
    float *pVertex;

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


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

	/* B3DTransformerPlugin>>#b3dTransformVertexBuffer */
EXPORT(sqInt)
b3dTransformVertexBuffer(void)
{
    sqInt flags;
    int hasNormals;
    sqInt i;
    float *modelViewMatrix;
    sqInt mvFlags;
    sqInt prFlags;
    float *projectionMatrix;
    float *pVertex;
    sqInt rescale;
    float *vtxArray;
    sqInt vtxCount;

	rescale = 0;
	flags = stackIntegerValue(0);
	projectionMatrix = stackMatrix(1);
	modelViewMatrix = stackMatrix(2);
	vtxCount = stackIntegerValue(3);
	vtxArray = stackPrimitiveVertexArrayofSize(4, vtxCount);
	if (((projectionMatrix == null) || (modelViewMatrix == null)) || (vtxArray == null)) {
		return primitiveFail();
	}
	if (failed()) {
		return null;
	}
	/* begin transformVB:count:by:and:flags: */
	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)) {

		/* Modelview matrix has no perspective part and projection is not optimized */
		if ((mvFlags == FlagM44NoTranslation) == 0) {

			/* Modelview matrix with translation */
			for (i = 1; i <= vtxCount; i += 1) {
				if (hasNormals) {
					transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
				}
				transformPrimitivePositionFastby(pVertex, modelViewMatrix);
				transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
				pVertex += PrimVertexSize;
			}
		}
		else {

			/* Modelview matrix without translation */
			for (i = 1; i <= vtxCount; i += 1) {
				if (hasNormals) {
					transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
				}
				transformPrimitivePositionFasterby(pVertex, modelViewMatrix);
				transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
				pVertex += PrimVertexSize;
			}
		}
		goto l1;
	}
	if ((mvFlags & prFlags) & FlagM44Identity) {

		/* If both are identity matrices just copy entries */
		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;
		}
		goto l1;
	}
	if (mvFlags & FlagM44Identity) {

		/* If model view matrix is identity just perform projection */
		for (i = 1; i <= vtxCount; i += 1) {
			transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
			pVertex += PrimVertexSize;
		}
		goto l1;
	}
	if (prFlags & FlagM44Identity) {

		/* If projection matrix is identity just transform and copy.
		   Note: This case is not very likely so it's not been unrolled. */
		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;
		}
		goto l1;
	}
	for (i = 1; i <= vtxCount; i += 1) {
		if (hasNormals) {
			transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
		}
		transformPrimitivePositionby(pVertex, modelViewMatrix);
		transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
		pVertex += PrimVertexSize;
	}
	l1:	/* end transformVB:count:by:and:flags: */;
	pop(5);
	return 0;
}

	/* B3DTransformerPlugin>>#b3dTransposeMatrix */
EXPORT(sqInt)
b3dTransposeMatrix(void)
{
    float *dst;
    sqInt dstOop;
    float *src;
    sqInt srcOop;

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

	/* reload srcOop in case of GC */
	dstOop = clone(srcOop);
	srcOop = stackObjectValue(0);
	src = firstIndexableField(srcOop);

	/* dst at: 0 put: (src at: 0). */
	dst = 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]);
	pop(1);
	push(dstOop);
	return 0;
}

	/* B3DClipperPlugin>>#backClipValueFrom:to: */
static double
backClipValueFromto(sqInt last, sqInt next)
{
	return (((((float *) last))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosW])) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) - (((((float *) next))[PrimVtxRasterPosZ]) - ((((float *) last))[PrimVtxRasterPosZ])));
}

	/* B3DClipperPlugin>>#bottomClipValueFrom:to: */
static double
bottomClipValueFromto(sqInt last, sqInt next)
{
	return (0.0 - (((((float *) last))[PrimVtxRasterPosY]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosY]) - ((((float *) last))[PrimVtxRasterPosY])));
}

	/* B3DClipperPlugin>>#clipPolygonBackFrom:to:count: */
static sqInt
clipPolygonBackFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin backClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygonBottomFrom:to:count: */
static sqInt
clipPolygonBottomFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin bottomClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygonFrontFrom:to:count: */
static sqInt
clipPolygonFrontFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin frontClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygonLeftFrom:to:count: */
static sqInt
clipPolygonLeftFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin leftClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygonRightFrom:to:count: */
static sqInt
clipPolygonRightFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin rightClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygonTopFrom:to:count: */
static sqInt
clipPolygonTopFromtocount(int *buf1, int *buf2, sqInt n)
{
    sqInt i;
    int inLast;
    int inNext;
    sqInt j;
    int *last;
    int *next;
    sqInt outIndex;
    double t;

	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)) {

			/* Passes clip boundary */
			/* begin topClipValueFrom:to: */
			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; j += 1) {
				buf2[(outIndex * PrimVertexSize) + j] = (next[j]);
			}
		}
		last = next;
		inLast = inNext;
		next += PrimVertexSize;
	}
	return outIndex;
}

	/* B3DClipperPlugin>>#clipPolygon:count:with:mask: */
static sqInt
clipPolygoncountwithmask(int *vtxArray, sqInt vtxCount, int *tempVtxArray, sqInt outMask)
{
    sqInt count;


	/* Check if the polygon is outside one boundary only.
	   If so, just do this single clipping operation avoiding multiple enumeration. */
	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;
}


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

	/* B3DShaderPlugin>>#computeAttenuation */
static sqInt
computeAttenuation(void)
{
	lightScale = 1.0;
	if (lightFlags & FlagAttenuated) {
		lightScale = 1.0 / ((primLight[PrimLightAttenuationConstant]) + (l2vDistance * ((primLight[PrimLightAttenuationLinear]) + (l2vDistance * (primLight[PrimLightAttenuationSquared])))));
	}
	return 0;
}


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

	/* B3DShaderPlugin>>#computeDirection */
static sqInt
computeDirection(void)
{
    double scale;

	if (lightFlags & FlagPositional) {

		/* Must compute the direction for this vertex */
		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]);
		}
	}
	return 0;
}


/*	Computes
	l2vSpecDir := l2vSpecDir - vtx position safelyNormalized.
	 */

	/* B3DShaderPlugin>>#computeSpecularDirection */
static sqInt
computeSpecularDirection(void)
{
    double scale;
    double scale1;

	/* begin inverseLengthOfFloat: */
	scale1 = ((((litVertex + PrimVtxPosition)[0]) * ((litVertex + PrimVtxPosition)[0])) + (((litVertex + PrimVtxPosition)[1]) * ((litVertex + PrimVtxPosition)[1]))) + (((litVertex + PrimVtxPosition)[2]) * ((litVertex + PrimVtxPosition)[2]));
	if ((scale1 == 0.0)
	 || (scale1 == 1.0)) {
		scale = scale1;
		goto l1;
	}
	scale = 1.0 / (sqrt(scale1));
	l1:	/* end inverseLengthOfFloat: */;
	l2vSpecDir[0] = ((l2vSpecDir[0]) - ((litVertex[PrimVtxPositionX]) * scale));
	l2vSpecDir[1] = ((l2vSpecDir[1]) - ((litVertex[PrimVtxPositionY]) * scale));
	l2vSpecDir[2] = ((l2vSpecDir[2]) - ((litVertex[PrimVtxPositionZ]) * scale));
	return 0;
}


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

	/* B3DShaderPlugin>>#computeSpotFactor */
static double
computeSpotFactor(void)
{
    double cosAngle;
    double deltaCos;
    double minCos;


	/* Compute cos angle between direction of the spot light and direction to vertex */
	/* begin dotProductOfFloat:withDouble: */
	cosAngle = ((((primLight + PrimLightDirection)[0]) * (l2vDirection[0])) + (((primLight + PrimLightDirection)[1]) * (l2vDirection[1]))) + (((primLight + PrimLightDirection)[2]) * (l2vDirection[2]));
	cosAngle = 0.0 - cosAngle;
	minCos = primLight[SpotLightMinCos];
	if (cosAngle < minCos) {
		return 0.0;
	}
	deltaCos = primLight[SpotLightDeltaCos];
	if (deltaCos <= 1.0e-5) {

		/* No delta -- a sharp boundary between on and off.
		   Since off has already been determined above, we are on */
		return 1.0;
	}
	cosAngle = (cosAngle - minCos) / deltaCos;
	return pow(cosAngle,(primLight[SpotLightExponent]));
}

	/* B3DClipperPlugin>>#determineClipFlags:count: */
static sqInt
determineClipFlagscount(void *vtxArray, sqInt count)
{
    sqInt flags;
    sqInt fullMask;
    sqInt i;
    float *vtxPtr;
    double w;
    double w2;
    double x;
    double y;
    double z;

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

	/* B3DShaderPlugin>>#dotProductOfFloat:withDouble: */
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: 
 */

	/* B3DShaderPlugin>>#fetchLightSource:ofObject: */
static void*
fetchLightSourceofObject(sqInt index, sqInt anArray)
{
    sqInt lightOop;

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

	/* B3DClipperPlugin>>#frontClipValueFrom:to: */
static double
frontClipValueFromto(sqInt last, sqInt 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! */

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

	/* B3DEnginePlugin>>#initialiseModule */
EXPORT(sqInt)
initialiseModule(void)
{
	loadBBFn = ioLoadFunctionFrom("loadBitBltFrom", bbPluginName);
	copyBitsFn = ioLoadFunctionFrom("copyBitsFromtoat", bbPluginName);
	return (loadBBFn != 0)
	 && (copyBitsFn != 0);
}


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

	/* B3DClipperPlugin>>#interpolateFrom:to:at:into: */
static sqInt
interpolateFromtoatinto(float *last, float *next, double t, float *out)
{
    double delta;
    sqInt flags;
    unsigned int lastValue;
    unsigned int newValue;
    unsigned int nextValue;
    unsigned int rgbaLast;
    unsigned int rgbaNext;
    double w;
    double w2;
    double x;
    double y;
    double z;


	/* Interpolate raster position */
	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 & 0xFF;
	rgbaLast = ((usqInt) rgbaLast) >> 8;
	rgbaNext = (((unsigned int *) next))[PrimVtxColor32];
	nextValue = rgbaNext & 0xFF;
	rgbaNext = ((usqInt) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue = ((sqInt)(lastValue + delta));
	lastValue = rgbaLast & 0xFF;
	rgbaLast = ((usqInt) rgbaLast) >> 8;
	nextValue = rgbaNext & 0xFF;
	rgbaNext = ((usqInt) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += ((sqInt)((usqInt)((((sqInt)(lastValue + delta)))) << 8));
	lastValue = rgbaLast & 0xFF;
	rgbaLast = ((usqInt) rgbaLast) >> 8;
	nextValue = rgbaNext & 0xFF;
	rgbaNext = ((usqInt) rgbaNext) >> 8;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += ((sqInt)((usqInt)((((sqInt)(lastValue + delta)))) << 16));
	lastValue = rgbaLast & 0xFF;
	nextValue = rgbaNext & 0xFF;
	delta = (((int) (nextValue - lastValue))) * t;
	newValue += ((sqInt)((usqInt)((((sqInt)(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))));
	return 0;
}

	/* B3DShaderPlugin>>#inverseLengthOfDouble: */
static double
inverseLengthOfDouble(double *aVector)
{
    double scale;


	/* scale := self dotProductOf: aVector with: aVector. */
	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));
}

	/* B3DShaderPlugin>>#inverseLengthOfFloat: */
static double
inverseLengthOfFloat(float *aVector)
{
    double scale;


	/* scale := self dotProductOf: aVector with: aVector. */
	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));
}

	/* B3DClipperPlugin>>#leftClipValueFrom:to: */
static double
leftClipValueFromto(sqInt last, sqInt next)
{
	return (0.0 - (((((float *) last))[PrimVtxRasterPosX]) + ((((float *) last))[PrimVtxRasterPosW]))) / ((((((float *) next))[PrimVtxRasterPosW]) - ((((float *) last))[PrimVtxRasterPosW])) + (((((float *) next))[PrimVtxRasterPosX]) - ((((float *) last))[PrimVtxRasterPosX])));
}

	/* B3DRasterizerPlugin>>#loadObjectsFrom: */
static sqInt
loadObjectsFrom(sqInt stackIndex)
{
    sqInt arrayOop;
    sqInt arraySize;
    sqInt i;
    B3DPrimitiveObject **objArray;
    sqInt objOop;
    B3DPrimitiveObject *objPtr;

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

	/* B3DShaderPlugin>>#loadPrimitiveLightSource */
static sqInt
loadPrimitiveLightSource(void)
{
	lightFlags = (((int*) primLight))[PrimLightFlags];
	return 0;
}


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

	/* B3DShaderPlugin>>#loadPrimitiveVertex */
static sqInt
loadPrimitiveVertex(void)
{
    sqInt rgba;

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


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

	/* B3DRasterizerPlugin>>#loadRasterizerState: */
static sqInt
loadRasterizerState(sqInt stackIndex)
{
    sqInt obj;
    sqInt objLen;
    void *objPtr;
    sqInt stateOop;

	if ((copyBitsFn == 0)
	 || (loadBBFn == 0)) {

		/* We need loadBitBltFrom/copyBits here so try to load it implicitly */
		if (!(initialiseModule())) {
			return 0;
		}
	}
	stateOop = stackValue(stackIndex);
	if (!((isPointers(stateOop))
		 && ((slotSizeOf(stateOop)) >= 10))) {
		return 0;
	}
	obj = fetchPointerofObject(0, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.faceAlloc = objPtr;
	obj = fetchPointerofObject(1, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.edgeAlloc = objPtr;
	obj = fetchPointerofObject(2, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.attrAlloc = objPtr;
	obj = fetchPointerofObject(3, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.aet = objPtr;
	obj = fetchPointerofObject(4, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.addedEdges = objPtr;
	obj = fetchPointerofObject(5, stateOop);
	if (!(isWords(obj))) {
		return 0;
	}
	objPtr = firstIndexableField(obj);
	state.fillList = objPtr;
	obj = fetchPointerofObject(6, stateOop);
	if (obj == (nilObject())) {
		state.nObjects = 0;
		state.objects = NULL;
	}
	else {
		if (!(isWords(obj))) {
			return 0;
		}
		objLen = slotSizeOf(obj);
		objPtr = firstIndexableField(obj);
		state.objects = (B3DPrimitiveObject **)objPtr;
		state.nObjects = objLen;
	}
	obj = fetchPointerofObject(7, stateOop);
	if (obj == (nilObject())) {
		state.nTextures = 0;
		state.textures = NULL;
	}
	else {
		if (!(isWords(obj))) {
			return 0;
		}
		objLen = byteSizeOf(obj);
		objPtr = firstIndexableField(obj);
		state.textures = (B3DTexture *)objPtr;
		state.nTextures = objLen / sizeof(B3DTexture);
	}
	obj = fetchPointerofObject(8, stateOop);
	if (obj == (nilObject())) {
		state.spanSize = 0;
		state.spanBuffer = NULL;
	}
	else {
		if (!((fetchClassOf(obj)) == (classBitmap()))) {
			return 0;
		}
		objLen = slotSizeOf(obj);
		objPtr = firstIndexableField(obj);
		state.spanBuffer = (unsigned int *)objPtr;
		state.spanSize = objLen;
	}
	obj = fetchPointerofObject(9, stateOop);
	if (obj == (nilObject())) {
		state.spanDrawer = NULL;
	}
	else {
		if (!(((sqInt (*) (sqInt))loadBBFn)(obj))) {
			return 0;
		}
		state.spanDrawer = (b3dDrawBufferFunction) copyBitsFn;
	}
	return !(failed());
}

	/* B3DRasterizerPlugin>>#loadTexturesFrom: */
static sqInt
loadTexturesFrom(sqInt stackIndex)
{
    sqInt arrayOop;
    B3DTexture *destPtr;
    sqInt i;
    sqInt n;
    sqInt textureOop;

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


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

	/* B3DRasterizerPlugin>>#loadTexture:into: */
static sqInt
loadTextureinto(sqInt textureOop, B3DTexture *destPtr)
{
    void *bitsPtr;
    sqInt form;
    sqInt formBits;
    sqInt formDepth;
    sqInt formHeight;
    sqInt formWidth;
    sqInt texEnvMode;
    sqInt texInterpolate;
    sqInt texWrap;


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

	/* Set the texture parameters */
	bitsPtr = firstIndexableField(formBits);
	return b3dLoadTexture(destPtr, formWidth, formHeight, formDepth, (unsigned int*) bitsPtr, 0, NULL) == B3D_NO_ERROR;
}


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

	/* B3DRasterizerPlugin>>#loadViewportFrom: */
static sqInt
loadViewportFrom(sqInt stackIndex)
{
    sqInt oop;
    sqInt p1;
    sqInt p2;
    sqInt x0;
    sqInt x1;
    sqInt y0;
    sqInt y1;

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

	/* B3DClipperPlugin>>#mapVB:ofSize:into: */
static sqInt
mapVBofSizeinto(void *vtxArray, sqInt vtxCount, sqInt boxArray)
{
    double bottom;
    int flags;
    sqInt floatOop;
    sqInt i;
    double left;
    sqInt oop;
    double right;
    double top;
    float *vtxPtr;
    double w;
    double x;
    double y;

	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;
	pushRemappableOop(oop);
	floatOop = floatObjectOf(left);
	oop = popRemappableOop();
	storePointerofObjectwithValue(0, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(top);
	oop = popRemappableOop();
	storePointerofObjectwithValue(1, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(right);
	oop = popRemappableOop();
	storePointerofObjectwithValue(2, oop, floatOop);
	pushRemappableOop(oop);
	floatOop = floatObjectOf(bottom);
	oop = popRemappableOop();
	storePointerofObjectwithValue(3, oop, floatOop);
	return 0;
}


/*	The module with the given name was just unloaded.
	Make sure we have no dangling references. */

	/* B3DEnginePlugin>>#moduleUnloaded: */
EXPORT(sqInt)
moduleUnloaded(char *aModuleName)
{
	if ((strcmp(aModuleName, bbPluginName)) == 0) {

		/* BitBlt just shut down. How nasty. */
		loadBBFn = 0;
		copyBitsFn = 0;
	}
	return 0;
}


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

	/* B3DRasterizerPlugin>>#primitiveSetBitBltPlugin */
EXPORT(sqInt)
primitiveSetBitBltPlugin(void)
{
    sqInt i;
    sqInt length;
    sqInt needReload;
    sqInt pluginName;
    char *ptr;


	/* Must be string to work */
	pluginName = stackValue(0);
	if (!(isBytes(pluginName))) {
		return primitiveFail();
	}
	length = byteSizeOf(pluginName);
	if (length >= 256) {
		return primitiveFail();
	}
	ptr = firstIndexableField(pluginName);
	needReload = 0;
	for (i = 0; i < length; i += 1) {

		/* Compare and store the plugin to be used */
		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 primitiveFail();
		}
	}
	pop(1);
	return 0;
}

	/* B3DPickerPlugin>>#processIndexedIDX:ofSize:idxArray:idxSize: */
static sqInt
processIndexedIDXofSizeidxArrayidxSize(float *vtxArray, sqInt vtxSize, int *idxArray, sqInt idxSize)
{
    sqInt i;
    int index;
    sqInt minIndex;
    double minZ;
    float *vtxPtr;
    double wValue;
    double zValue;

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

	/* B3DPickerPlugin>>#processIndexed:ofSize:idxArray:idxSize: */
static double
processIndexedofSizeidxArrayidxSize(float *vtxArray, sqInt vtxSize, int *idxArray, sqInt idxSize)
{
    sqInt i;
    int index;
    double minZ;
    float *vtxPtr;
    double wValue;
    double zValue;

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

	/* B3DPickerPlugin>>#processNonIndexedIDX:ofSize: */
static sqInt
processNonIndexedIDXofSize(float *vtxArray, sqInt vtxSize)
{
    sqInt i;
    sqInt minIndex;
    double minZ;
    float *vtxPtr;
    double wValue;
    double zValue;

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

	/* B3DPickerPlugin>>#processNonIndexed:ofSize: */
static double
processNonIndexedofSize(float *vtxArray, sqInt vtxSize)
{
    sqInt i;
    double minZ;
    float *vtxPtr;
    double wValue;
    double zValue;

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

	/* B3DClipperPlugin>>#rightClipValueFrom:to: */
static double
rightClipValueFromto(sqInt last, sqInt 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 it can be run in Squeak. */

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

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		booleanValueOf = interpreterProxy->booleanValueOf;
		byteSizeOf = interpreterProxy->byteSizeOf;
		classArray = interpreterProxy->classArray;
		classBitmap = interpreterProxy->classBitmap;
		classPoint = interpreterProxy->classPoint;
		clone = interpreterProxy->clone;
		failed = interpreterProxy->failed;
		fetchClassOf = interpreterProxy->fetchClassOf;
		fetchIntegerofObject = interpreterProxy->fetchIntegerofObject;
		fetchPointerofObject = interpreterProxy->fetchPointerofObject;
		firstIndexableField = interpreterProxy->firstIndexableField;
		floatObjectOf = interpreterProxy->floatObjectOf;
		ioLoadFunctionFrom = interpreterProxy->ioLoadFunctionFrom;
		isBytes = interpreterProxy->isBytes;
		isPointers = interpreterProxy->isPointers;
		isWords = interpreterProxy->isWords;
		methodArgumentCount = interpreterProxy->methodArgumentCount;
		nilObject = interpreterProxy->nilObject;
		pop = interpreterProxy->pop;
		popRemappableOop = interpreterProxy->popRemappableOop;
		primitiveFail = interpreterProxy->primitiveFail;
		push = interpreterProxy->push;
		pushBool = interpreterProxy->pushBool;
		pushFloat = interpreterProxy->pushFloat;
		pushInteger = interpreterProxy->pushInteger;
		pushRemappableOop = interpreterProxy->pushRemappableOop;
		slotSizeOf = interpreterProxy->slotSizeOf;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackObjectValue = interpreterProxy->stackObjectValue;
		stackValue = interpreterProxy->stackValue;
		storePointerofObjectwithValue = interpreterProxy->storePointerofObjectwithValue;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}

	/* B3DShaderPlugin>>#shadeVertex */
static sqInt
shadeVertex(void)
{
    double aPart;
    double aPart1;
    double aPart2;
    double bPart;
    double bPart1;
    double bPart2;
    double cosAngle;
    double gPart;
    double gPart1;
    double gPart2;
    float *lightPart;
    float *lightPart1;
    float *lightPart2;
    double rPart;
    double rPart1;
    double rPart2;
    double scale;
    double scale1;
    double scale11;
    double scale2;
    double specularFactor;

	/* begin computeDirection */
	if (lightFlags & FlagPositional) {

		/* Must compute the direction for this vertex */
		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);
			scale1 = -1.0 / l2vDistance;
		}
		l2vDirection[0] = ((l2vDirection[0]) * scale1);
		l2vDirection[1] = ((l2vDirection[1]) * scale1);
		l2vDirection[2] = ((l2vDirection[2]) * scale1);
	}
	else {
		if (lightFlags & FlagDirectional) {
			l2vDirection[0] = (primLight[PrimLightDirectionX]);
			l2vDirection[1] = (primLight[PrimLightDirectionY]);
			l2vDirection[2] = (primLight[PrimLightDirectionZ]);
		}
	}
	/* 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) {

		/* Compute the ambient part */
		if (lightFlags & FlagAmbientPart) {
			/* begin addPart:from:trackFlag:scale: */
			lightPart = primLight + AmbientPart;
			if (vbFlags & VBTrackAmbient) {
				rPart = ((vtxInColor[0]) * (lightPart[0])) * lightScale;
				gPart = ((vtxInColor[1]) * (lightPart[1])) * lightScale;
				bPart = ((vtxInColor[2]) * (lightPart[2])) * lightScale;
				aPart = ((vtxInColor[3]) * (lightPart[3])) * lightScale;
			}
			else {

				/* Note: This should be pre-computed. */
				rPart = (((primMaterial + AmbientPart)[0]) * (lightPart[0])) * lightScale;
				gPart = (((primMaterial + AmbientPart)[1]) * (lightPart[1])) * lightScale;
				bPart = (((primMaterial + AmbientPart)[2]) * (lightPart[2])) * lightScale;
				aPart = (((primMaterial + AmbientPart)[3]) * (lightPart[3])) * lightScale;
			}
			vtxOutColor[0] = ((vtxOutColor[0]) + rPart);
			vtxOutColor[1] = ((vtxOutColor[1]) + gPart);
			vtxOutColor[2] = ((vtxOutColor[2]) + bPart);
			vtxOutColor[3] = ((vtxOutColor[3]) + aPart);
		}
		if (lightFlags & FlagDiffusePart) {

			/* Compute angle from light->vertex to vertex normal */
			/* begin dotProductOfFloat:withDouble: */
			cosAngle = ((((litVertex + PrimVtxNormal)[0]) * (l2vDirection[0])) + (((litVertex + PrimVtxNormal)[1]) * (l2vDirection[1]))) + (((litVertex + PrimVtxNormal)[2]) * (l2vDirection[2]));
			if (((vbFlags & VBTwoSidedLighting) == 0)
			 && (cosAngle < 0.0)) {
				cosAngle = 0.0 - cosAngle;
			}
			if (cosAngle > 0.0) {
				/* begin addPart:from:trackFlag:scale: */
				lightPart1 = primLight + DiffusePart;
				scale = lightScale * cosAngle;
				if (vbFlags & VBTrackDiffuse) {
					rPart1 = ((vtxInColor[0]) * (lightPart1[0])) * scale;
					gPart1 = ((vtxInColor[1]) * (lightPart1[1])) * scale;
					bPart1 = ((vtxInColor[2]) * (lightPart1[2])) * scale;
					aPart1 = ((vtxInColor[3]) * (lightPart1[3])) * scale;
				}
				else {

					/* Note: This should be pre-computed. */
					rPart1 = (((primMaterial + DiffusePart)[0]) * (lightPart1[0])) * scale;
					gPart1 = (((primMaterial + DiffusePart)[1]) * (lightPart1[1])) * scale;
					bPart1 = (((primMaterial + DiffusePart)[2]) * (lightPart1[2])) * scale;
					aPart1 = (((primMaterial + DiffusePart)[3]) * (lightPart1[3])) * scale;
				}
				vtxOutColor[0] = ((vtxOutColor[0]) + rPart1);
				vtxOutColor[1] = ((vtxOutColor[1]) + gPart1);
				vtxOutColor[2] = ((vtxOutColor[2]) + bPart1);
				vtxOutColor[3] = ((vtxOutColor[3]) + aPart1);
			}
		}
	}
	if ((lightFlags & FlagSpecularPart)
	 && ((primMaterial[MaterialShininess]) > 0.0)) {

		/* Compute specular part */
		l2vSpecDir[0] = (l2vDirection[0]);
		l2vSpecDir[1] = (l2vDirection[1]);
		l2vSpecDir[2] = (l2vDirection[2]);
		if (vbFlags & VBUseLocalViewer) {
			/* begin computeSpecularDirection */
			scale11 = ((((litVertex + PrimVtxPosition)[0]) * ((litVertex + PrimVtxPosition)[0])) + (((litVertex + PrimVtxPosition)[1]) * ((litVertex + PrimVtxPosition)[1]))) + (((litVertex + PrimVtxPosition)[2]) * ((litVertex + PrimVtxPosition)[2]));
			if ((scale11 == 0.0)
			 || (scale11 == 1.0)) {
				scale2 = scale11;
				goto l3;
			}
			scale2 = 1.0 / (sqrt(scale11));
	l3:	/* end inverseLengthOfFloat: */;
			l2vSpecDir[0] = ((l2vSpecDir[0]) - ((litVertex[PrimVtxPositionX]) * scale2));
			l2vSpecDir[1] = ((l2vSpecDir[1]) - ((litVertex[PrimVtxPositionY]) * scale2));
			l2vSpecDir[2] = ((l2vSpecDir[2]) - ((litVertex[PrimVtxPositionZ]) * scale2));
		}
		else {
			l2vSpecDir[2] = ((l2vSpecDir[2]) - 1.0);
		}
		/* begin dotProductOfFloat:withDouble: */
		cosAngle = ((((litVertex + PrimVtxNormal)[0]) * (l2vSpecDir[0])) + (((litVertex + PrimVtxNormal)[1]) * (l2vSpecDir[1]))) + (((litVertex + PrimVtxNormal)[2]) * (l2vSpecDir[2]));
		if (cosAngle > 0.0) {

			/* Normalize the angle */

			/* 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]));
				}
			}
			/* begin addPart:from:trackFlag:scale: */
			lightPart2 = primLight + SpecularPart;
			if (vbFlags & VBTrackSpecular) {
				rPart2 = ((vtxInColor[0]) * (lightPart2[0])) * specularFactor;
				gPart2 = ((vtxInColor[1]) * (lightPart2[1])) * specularFactor;
				bPart2 = ((vtxInColor[2]) * (lightPart2[2])) * specularFactor;
				aPart2 = ((vtxInColor[3]) * (lightPart2[3])) * specularFactor;
			}
			else {

				/* Note: This should be pre-computed. */
				rPart2 = (((primMaterial + SpecularPart)[0]) * (lightPart2[0])) * specularFactor;
				gPart2 = (((primMaterial + SpecularPart)[1]) * (lightPart2[1])) * specularFactor;
				bPart2 = (((primMaterial + SpecularPart)[2]) * (lightPart2[2])) * specularFactor;
				aPart2 = (((primMaterial + SpecularPart)[3]) * (lightPart2[3])) * specularFactor;
			}
			vtxOutColor[0] = ((vtxOutColor[0]) + rPart2);
			vtxOutColor[1] = ((vtxOutColor[1]) + gPart2);
			vtxOutColor[2] = ((vtxOutColor[2]) + bPart2);
			vtxOutColor[3] = ((vtxOutColor[3]) + aPart2);
		}
	}
	return 0;
}


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

	/* B3DShaderPlugin>>#stackLightArrayValue: */
static sqInt
stackLightArrayValue(sqInt stackIndex)
{
    sqInt array;
    sqInt arraySize;
    sqInt i;
    sqInt oop;

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


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

	/* B3DShaderPlugin>>#stackMaterialValue: */
static void *
stackMaterialValue(sqInt stackIndex)
{
    sqInt oop;

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


/*	Load a 4x4 transformation matrix from the interpreter stack.
	Return a pointer to the matrix data if successful, nil otherwise. */

	/* B3DEnginePlugin>>#stackMatrix: */
static void*
stackMatrix(sqInt index)
{
    sqInt oop;

	oop = stackObjectValue(index);
	if (oop == null) {
		return null;
	}
	if ((isWords(oop))
	 && ((slotSizeOf(oop)) == 16)) {
		return 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. 
 */

	/* B3DEnginePlugin>>#stackPrimitiveIndexArray:ofSize:validate:forVertexSize: */
static void*
stackPrimitiveIndexArrayofSizevalidateforVertexSize(sqInt stackIndex, sqInt nItems, sqInt aBool, sqInt maxIndex)
{
    sqInt i;
    int *idxPtr;
    int index;
    sqInt oop;
    sqInt oopSize;

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


/*	Load a primitive vertex array from the interpreter stack.
	Return a pointer to the vertex data if successful, nil otherwise. */

	/* B3DEnginePlugin>>#stackPrimitiveVertexArray:ofSize: */
static void*
stackPrimitiveVertexArrayofSize(sqInt index, sqInt nItems)
{
    sqInt oop;
    sqInt oopSize;

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


/*	Load a primitive vertex from the interpreter stack.
	Return a pointer to the vertex data if successful, nil otherwise. */

	/* B3DEnginePlugin>>#stackPrimitiveVertex: */
static void*
stackPrimitiveVertex(sqInt index)
{
    sqInt oop;

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

	/* B3DRasterizerPlugin>>#storeObjectsInto: */
static sqInt
storeObjectsInto(sqInt stackIndex)
{
    sqInt arrayOop;
    sqInt arraySize;
    sqInt i;
    sqInt objOop;

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


/*	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. */

	/* B3DShaderPlugin>>#storePrimitiveVertex */
static sqInt
storePrimitiveVertex(void)
{
    sqInt a;
    sqInt b;
    sqInt g;
    sqInt r;

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

	/* The following is equal to b + (g << 8) + (r << 16) + (a << 24) */
	a = (((((a < 0xFF) ? a : 0xFF)) < 0) ? 0 : (((a < 0xFF) ? a : 0xFF)));
	(((int*) litVertex))[PrimVtxColor32] = (b + (((sqInt)((usqInt)((g + (((sqInt)((usqInt)((r + (((sqInt)((usqInt)(a) << 8))))) << 8))))) << 8))));
	return 0;
}

	/* B3DClipperPlugin>>#topClipValueFrom:to: */
static double
topClipValueFromto(sqInt last, sqInt 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 */

	/* B3DTransformerPlugin>>#transformMatrix:with:into: */
static sqInt
transformMatrixwithinto(float *src, float *arg, float *dst)
{
    float c1;
    float c2;
    float c3;
    float c4;
    sqInt i;
    float *m1;
    float *m2;
    float *m3;

	m1 = ((float *) src);
	m2 = ((float *) arg);
	m3 = ((float *) dst);
	for (i = 0; i <= 3; i += 1) {

		/* Compute next row */
		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;
	}
	return 0;
}


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

	/* B3DTransformerPlugin>>#transformPrimitiveNormal:by:rescale: */
static sqInt
transformPrimitiveNormalbyrescale(float *pVertex, float *matrix, sqInt rescale)
{
    double dot;
    double rx;
    double ry;
    double rz;
    double x;
    double y;
    double z;

	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));
	return 0;
}


/*	Transform the position of the given primitive vertex assuming that 
	matrix a14 = a24 = a34 = a41 = a42 = a43 = 0.0 and a44 = 1.0 */

	/* B3DTransformerPlugin>>#transformPrimitivePositionFaster:by: */
static sqInt
transformPrimitivePositionFasterby(float *pVertex, float *matrix)
{
    double rx;
    double ry;
    double rz;
    double x;
    double y;
    double z;

	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));
	return 0;
}


/*	Transform the position of the given primitive vertex assuming that 
	matrix a41 = a42 = a43 = 0.0 and a44 = 1.0 */

	/* B3DTransformerPlugin>>#transformPrimitivePositionFast:by: */
static sqInt
transformPrimitivePositionFastby(float *pVertex, float *matrix)
{
    double rx;
    double ry;
    double rz;
    double x;
    double y;
    double z;

	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));
	return 0;
}


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

	/* B3DTransformerPlugin>>#transformPrimitivePosition:by: */
static sqInt
transformPrimitivePositionby(float *pVertex, float *matrix)
{
    double rw;
    double rx;
    double ry;
    double rz;
    double x;
    double y;
    double z;

	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)));
	}
	return 0;
}


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

	/* B3DTransformerPlugin>>#transformPrimitiveRasterPosition:by: */
static sqInt
transformPrimitiveRasterPositionby(float *pVertex, float *matrix)
{
    double rw;
    double rx;
    double ry;
    double rz;
    double x;
    double y;
    double z;

	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));
	return 0;
}


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

	/* B3DTransformerPlugin>>#transformVB:count:by:and:flags: */
static sqInt
transformVBcountbyandflags(float *vtxArray, sqInt vtxCount, float *modelViewMatrix, float *projectionMatrix, sqInt flags)
{
    int hasNormals;
    sqInt i;
    sqInt mvFlags;
    sqInt prFlags;
    float *pVertex;
    sqInt rescale;


	/* Analyze the matrices for better performance */
	rescale = 0;
	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)) {

		/* Modelview matrix has no perspective part and projection is not optimized */
		if ((mvFlags == FlagM44NoTranslation) == 0) {

			/* Modelview matrix with translation */
			for (i = 1; i <= vtxCount; i += 1) {
				if (hasNormals) {
					transformPrimitiveNormalbyrescale(pVertex, modelViewMatrix, rescale);
				}
				transformPrimitivePositionFastby(pVertex, modelViewMatrix);
				transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
				pVertex += PrimVertexSize;
			}
		}
		else {

			/* Modelview matrix without translation */
			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) {

		/* If both are identity matrices just copy entries */
		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) {

		/* If model view matrix is identity just perform projection */
		for (i = 1; i <= vtxCount; i += 1) {
			transformPrimitiveRasterPositionby(pVertex, projectionMatrix);
			pVertex += PrimVertexSize;
		}
		return null;
	}
	if (prFlags & FlagM44Identity) {

		/* If projection matrix is identity just transform and copy.
		   Note: This case is not very likely so it's not been unrolled. */
		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;
	}
	return 0;
}


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

	/* B3DVertexBufferPlugin>>#vbLoadArray:size: */
static void*
vbLoadArraysize(sqInt oop, sqInt count)
{
	if (oop == null) {
		primitiveFail();
		return null;
	}
	if (oop == (nilObject())) {
		return null;
	}
	if (!(isWords(oop))) {
		primitiveFail();
		return null;
	}
	if (!((slotSizeOf(oop)) == count)) {
		primitiveFail();
		return null;
	}
	return firstIndexableField(oop);
}


#ifdef SQUEAK_BUILTIN_PLUGIN

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

#else /* ifdef SQ_BUILTIN_PLUGIN */

signed char b3dClipPolygonAccessorDepth = 1;
signed char b3dComputeMinIndexZAccessorDepth = 1;
signed char b3dComputeMinZAccessorDepth = 1;
signed char b3dDetermineClipFlagsAccessorDepth = 1;
signed char b3dInitializeRasterizerStateAccessorDepth = 1;
signed char b3dInitPrimitiveObjectAccessorDepth = 1;
signed char b3dInplaceHouseHolderInvertAccessorDepth = 0;
signed char b3dLoadIndexArrayAccessorDepth = 0;
signed char b3dLoadVertexBufferAccessorDepth = 0;
signed char b3dMapVertexBufferAccessorDepth = 1;
signed char b3dOrthoNormInverseMatrixAccessorDepth = 1;
signed char b3dPrimitiveNextClippedTriangleAccessorDepth = 1;
signed char b3dShadeVertexBufferAccessorDepth = 1;
signed char b3dStartRasterizerAccessorDepth = 2;
signed char b3dTransformDirectionAccessorDepth = 1;
signed char b3dTransformMatrixWithIntoAccessorDepth = 0;
signed char b3dTransformPointAccessorDepth = 1;
signed char b3dTransformPrimitiveNormalAccessorDepth = 0;
signed char b3dTransformPrimitivePositionAccessorDepth = 0;
signed char b3dTransformPrimitiveRasterPositionAccessorDepth = 0;
signed char b3dTransformVertexBufferAccessorDepth = 1;
signed char b3dTransposeMatrixAccessorDepth = 1;
signed char primitiveSetBitBltPluginAccessorDepth = 1;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
