//////////////////////////////////////////////////////////////////////
//
//                             Pixie
//
// Copyright © 1999 - 2003, Okan Arikan
//
// Contact: okan@cs.berkeley.edu
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
//  File				:	reyes.cpp
//  Classes				:	CReyes
//  Description			:
//
////////////////////////////////////////////////////////////////////////
#include "rendererc.h"
#include "error.h"
#include "ri.h"
#include "stats.h"
#include "memory.h"
#include "points.h"
#include "reyes.h"






#define	deleteRasterPrimitive(__a)	{																	\
										CRasterGrid	*grid	=	(CRasterGrid *) __a->grid;				\
										grid->refCount--;												\
										if (grid->refCount == 0) deleteGrid(grid);						\
									}

#define newRasterObject(__a)		__a = new CRasterObject;											\
									numObjects++;														\
									if (numObjects > stats.numPeakRasterObjects)						\
										stats.numPeakRasterObjects = numObjects;
									
#define	deleteRasterObject(__a)		__a->object->detach();												\
									delete __a;															\
									numObjects--;


// Returns the bucket numbers
#define	xbucket(__x)	(int) floor((__x - xSampleOffset) * invBucketSampleWidth);

#define	ybucket(__y)	(int) floor((__y - ySampleOffset) * invBucketSampleHeight);


// Insert an object into a bucket
#define	objectInsert(__o) {																				\
		int				bx			=	xbucket(__o->xbound[0]);										\
		int				by			=	ybucket(__o->ybound[0]);										\
																										\
		if (by <= currentYBucket) {																		\
			by	=	currentYBucket;																		\
			if (bx < currentXBucket)																	\
				bx	=	currentXBucket;																	\
		} else {																						\
			if (bx < 0) bx = 0;																			\
		}																								\
																										\
		CBucket			*cBucket	=	buckets[by][bx];												\
																										\
		assert(cBucket != NULL);																		\
																										\
		__o->next				=	cBucket->objects;													\
		cBucket->objects		=	__o;																\
		cBucket->numObjects++;																			\
	}

// Insert an object into a bucket
#define	objectExplicitInsert(__o,__bx,__by) {															\
		CBucket			*cBucket	=	buckets[__by][__bx];											\
																										\
		__o->next				=	cBucket->objects;													\
		cBucket->objects		=	__o;																\
		cBucket->numObjects++;																			\
	}


// Insert a primitive into the bucket it intersects
#define	primitiveInsert(__p) {																			\
		int				bx			=	xbucket(__p->xbound[0]);										\
		int				by			=	ybucket(__p->ybound[0]);										\
																										\
		if (by <= currentYBucket) {																		\
			by	=	currentYBucket;																		\
			if (bx < currentXBucket)																	\
				bx	=	currentXBucket;																	\
		} else {																						\
			if (bx < 0) bx = 0;																			\
		}																								\
																										\
		CBucket			*cBucket	=	buckets[by][bx];												\
																										\
		assert(cBucket != NULL);																		\
																										\
		__p->next			=	cBucket->primitives;													\
		cBucket->primitives	=	__p;																	\
	}

#define	tprimitiveInsert(__p) {																			\
		int				bx			=	xbucket(__p->xbound[0]);										\
		int				by			=	ybucket(__p->ybound[0]);										\
																										\
		if (by <= currentYBucket) {																		\
			by	=	currentYBucket;																		\
			if (bx < currentXBucket)																	\
				bx	=	currentXBucket;																	\
		} else {																						\
			if (bx < 0) bx = 0;																			\
		}																								\
																										\
		CBucket			*cBucket	=	buckets[by][bx];												\
																										\
		assert(cBucket != NULL);																		\
																										\
		__p->next			=	cBucket->tprimitives;													\
		cBucket->tprimitives	=	__p;																\
		cBucket->numTPrimitives++;																		\
	}


// Defer the object to the next bucket that'll need it
#define	objectDefer(__cObject)																								\
	if (		(__cObject->xbound[1] >= tbucketRight)	&&	(currentXBucket < xBucketsMinusOne)) {							\
		assert(buckets[currentYBucket][currentXBucket+1] != NULL);															\
		stats.numObjectDeferRight++;																						\
																															\
		objectExplicitInsert(__cObject,currentXBucket+1,currentYBucket);													\
	} else if (	(__cObject->ybound[1] >= tbucketBottom)	&&	(currentYBucket < yBucketsMinusOne)) {							\
		int	xb	=	xbucket(__cObject->xbound[0]);																			\
		if (xb < 0)	xb = 0;																									\
		assert(xb < (int) xBuckets);																						\
		assert(buckets[currentYBucket+1][xb] != NULL);																		\
		stats.numObjectDeferBottom++;																						\
																															\
		objectExplicitInsert(__cObject,xb,currentYBucket+1);																\
	} else {																												\
		deleteRasterObject(__cObject);																						\
	}

// Defer the primitive to the next bucket that'll need it
#define primitiveDefer(__cPrimitive)																						\
	if (		(__cPrimitive->xbound[1] >= tbucketRight)	&&	(currentXBucket < xBucketsMinusOne)) {						\
		assert(buckets[currentYBucket][currentXBucket+1] != NULL);															\
		__cPrimitive->next										=	buckets[currentYBucket][currentXBucket+1]->primitives;	\
		buckets[currentYBucket][currentXBucket+1]->primitives	=	__cPrimitive;											\
	} else if (	(__cPrimitive->ybound[1] >= tbucketBottom)	&&	(currentYBucket < yBucketsMinusOne)) {						\
		int	xb	=	xbucket(__cPrimitive->xbound[0]);																		\
		if (xb < 0)	xb = 0;																									\
		assert(xb < (int) xBuckets);																						\
		assert(buckets[currentYBucket+1][xb] != NULL);																		\
		__cPrimitive->next										=	buckets[currentYBucket+1][xb]->primitives;				\
		buckets[currentYBucket+1][xb]->primitives				=	__cPrimitive;											\
	} else {																												\
		deleteRasterPrimitive(__cPrimitive);																				\
	}

// Defer the primitive to the next bucket that'll need it
#define tprimitiveDefer(__cPrimitive)																						\
	if (		(__cPrimitive->xbound[1] >= tbucketRight)	&&	(currentXBucket < xBucketsMinusOne)) {						\
		assert(buckets[currentYBucket][currentXBucket+1] != NULL);															\
		__cPrimitive->next										=	buckets[currentYBucket][currentXBucket+1]->tprimitives;	\
		buckets[currentYBucket][currentXBucket+1]->tprimitives	=	__cPrimitive;											\
		buckets[currentYBucket][currentXBucket+1]->numTPrimitives++;														\
	} else if (	(__cPrimitive->ybound[1] >= tbucketBottom)	&&	(currentYBucket < yBucketsMinusOne)) {						\
		int	xb	=	xbucket(__cPrimitive->xbound[0]);																		\
		if (xb < 0)	xb = 0;																									\
		assert(xb < (int) xBuckets);																						\
		assert(buckets[currentYBucket+1][xb] != NULL);																		\
		__cPrimitive->next										=	buckets[currentYBucket+1][xb]->tprimitives;				\
		buckets[currentYBucket+1][xb]->tprimitives				=	__cPrimitive;											\
		buckets[currentYBucket+1][xb]->numTPrimitives++;																	\
	} else {																												\
		deleteRasterPrimitive(__cPrimitive);																				\
	}



///////////////////////////////////////////////////////////////////////
// Class				:	CReyes::CBucket
// Method				:	CBucket
// Description			:	Ctor
// Return Value			:	-
// Comments				:
// Date last edited		:	10/14/2002
CReyes::CBucket::CBucket() {
	objects			=	NULL;
	numObjects		=	0;
	primitives		=	NULL;
	tprimitives		=	NULL;
	numTPrimitives	=	0;
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes::CBucket
// Method				:	~CBucket
// Description			:	Dtor
// Return Value			:	-
// Comments				:
// Date last edited		:	10/14/2002
CReyes::CBucket::~CBucket() {
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	CReyes
// Description			:	Ctor
// Return Value			:	-
// Comments				:
// Date last edited		:	2/1/2002
CReyes::CReyes(COptions *o,CXform *x,SOCKET s,unsigned int hf) : CShadingContext(o,x,s,hf) {
	int			cx,cy;

	// Allocate the buckets
	buckets	=	new CBucket**[yBuckets];
	for (cy=0;cy<yBuckets;cy++) {
		buckets[cy]	=	new CBucket*[xBuckets];

		for (cx=0;cx<xBuckets;cx++) {
			buckets[cy][cx]						=	new CBucket;
		}
	}

	// The sample offsets
	xSampleOffset		=	(int) ceil(max(	(pixelFilterWidth-1)*pixelXsamples  / (float) 2 , 0));
	ySampleOffset		=	(int) ceil(max(	(pixelFilterHeight-1)*pixelYsamples / (float) 2 , 0));

	// Compute the inv bucket width and height in samples
	invBucketSampleWidth	=	1 / (float) (bucketWidth*pixelXsamples);
	invBucketSampleHeight	=	1 / (float) (bucketHeight*pixelYsamples);

	// dSample / dx,dy
	dSampledx			=	dPixeldx*pixelXsamples;
	dSampledy			=	dPixeldy*pixelYsamples;

	// The clipping region we have
	sampleClipLeft		=	(float) (-xSampleOffset);
	sampleClipRight		=	(float) (xPixels*pixelXsamples + xSampleOffset);
	sampleClipTop		=	(float) (-ySampleOffset);
	sampleClipBottom	=	(float) (yPixels*pixelYsamples + ySampleOffset);

	// Init the stats
	numGrids			=	0;
	numObjects			=	0;

	// The length of a raster vertex
	if (flags & OPTIONS_FLAGS_MOTIONBLUR) {
		numVertexSamples	=	(numExtraSamples + 10)*2;
		enableMotionBlur	=	TRUE;
	} else {
		numVertexSamples	=	(numExtraSamples + 10);
		enableMotionBlur	=	FALSE;
	}

	extraPrimitiveFlags	=	0;
	if (numExtraSamples > 0)	extraPrimitiveFlags	|=	RASTER_EXTRASAMPLES;
	if (aperture != 0)			extraPrimitiveFlags	|=	RASTER_FOCALBLUR;

	// Compute misc junk
	xBucketsMinusOne	=	xBuckets-1;
	yBucketsMinusOne	=	yBuckets-1;
	invBucketWidth		=	1 / (double) bucketWidth;
	invBucketHeight		=	1 / (double) bucketHeight;
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	~CReyes
// Description			:	Dtor
// Return Value			:	-
// Comments				:
// Date last edited		:	2/1/2002
CReyes::~CReyes() {
	int		x,y;
	int		dirty	=	FALSE;
	CBucket	*cBucket;

	// Ditch the buckets
	for (y=0;y<yBuckets;y++) {
		for (x=0;x<xBuckets;x++) {
			if ((cBucket = buckets[y][x]) != NULL)	{
				CRasterObject		*cObject;
				TRasterPrimitive	*cPrimitive;

				while((cPrimitive=cBucket->primitives) != NULL) {
					cBucket->primitives	=	cPrimitive->next;

					deleteRasterPrimitive(cPrimitive);
				}

				while((cPrimitive=cBucket->tprimitives) != NULL) {
					cBucket->primitives	=	cPrimitive->next;

					deleteRasterPrimitive(cPrimitive);
				}

				for (cObject=cBucket->objects;cObject!=NULL;cObject=cObject->next) {
					cObject->object->detach();
				}

				delete buckets[y][x];
				dirty	=	TRUE;	// A dirty termination
			}
		}
		delete [] buckets[y];
	}
	delete [] buckets;

	if (dirty == FALSE) {
		// Memory check
		assert(numObjects			==	0);
		assert(numGrids				==	0);
	}
}


///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	renderFrame
// Description			:	Render the entire frame
// Return Value			:	-
// Comments				:
// Date last edited		:	2/1/2002
void		CReyes::renderFrame() {
	int				numRenderedBuckets	=	0;
	const	char	*previousActivity	=	stats.activity;

	stats.activity	=	"Rasterizer - rendering";

	if (netClient != INVALID_SOCKET) {
		// Let the client know that we're ready to render
		T32		netBuffer;

		netBuffer.integer	=	NET_READY;
		rcSend(netClient,(char *) &netBuffer,1*sizeof(T32));
	}


	// While not done
	while(TRUE) {

		// If we have a client, ask for a bucket
		if (netClient != INVALID_SOCKET) {
			T32	netBuffer[3];
			int	x,y;

			// Receive the bucket to render from the client
			rcRecv(netClient,(char *) netBuffer,3*sizeof(T32));

			// Process the render order
			if (netBuffer[0].integer == NET_RENDER_BUCKET) {
				x	=	netBuffer[1].integer;
				y	=	netBuffer[2].integer;
			} else if (netBuffer[0].integer == NET_FINISH_FRAME) {
				// We have finished the frame, so terminate
				netBuffer[0].integer	=	NET_ACK;
				rcSend(netClient,(char *) netBuffer,1*sizeof(T32));
				break;
			} else {
				error(CODE_BUG,"Unrecognised network request\n");
			}

			assert(x < xBuckets);
			assert(y < yBuckets);

			while((currentXBucket != x) || (currentYBucket != y)) {
				// Compute the extend of the bucket
				bucketPixelLeft		=	currentXBucket*bucketWidth;
				bucketPixelTop		=	currentYBucket*bucketHeight;
				bucketPixelWidth	=	min(bucketWidth,xPixels-bucketPixelLeft);
				bucketPixelHeight	=	min(bucketHeight,yPixels-bucketPixelTop);
				tbucketLeft			=	bucketPixelLeft*pixelXsamples - xSampleOffset;
				tbucketTop			=	bucketPixelTop*pixelYsamples - ySampleOffset;
				tbucketRight		=	(bucketPixelLeft + bucketPixelWidth)*pixelXsamples - xSampleOffset;
				tbucketBottom		=	(bucketPixelTop + bucketPixelHeight)*pixelYsamples - ySampleOffset;

				numRenderedBuckets++;
				skip();
			}
		} else {
			if (hiderFlags & HIDER_BREAK)	break;
		}

		// Compute the extend of the bucket
		bucketPixelLeft		=	currentXBucket*bucketWidth;
		bucketPixelTop		=	currentYBucket*bucketHeight;
		bucketPixelWidth	=	min(bucketWidth,xPixels-bucketPixelLeft);
		bucketPixelHeight	=	min(bucketHeight,yPixels-bucketPixelTop);
		tbucketLeft			=	bucketPixelLeft*pixelXsamples - xSampleOffset;
		tbucketTop			=	bucketPixelTop*pixelYsamples - ySampleOffset;
		tbucketRight		=	(bucketPixelLeft + bucketPixelWidth)*pixelXsamples - xSampleOffset;
		tbucketBottom		=	(bucketPixelTop + bucketPixelHeight)*pixelYsamples - ySampleOffset;

		render();
		numRenderedBuckets++;

		stats.progress	=	(numRenderedBuckets*100) / (float) (xBuckets*yBuckets);
	}

	stats.progress	=	100;
	stats.activity	=	previousActivity;
}



///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	render
// Description			:	Render the current bucket
// Return Value			:	-
// Comments				:
// Date last edited		:	2/1/2002
void	CReyes::render() {
	float			*pixelBuffer;
	CRasterObject	*cObject;
	CBucket			*cBucket	=	buckets[currentYBucket][currentXBucket];

	// Begin a new memory page
	memBegin();

	// Allocate the framebuffer area
	pixelBuffer			=	(float *) ralloc(bucketWidth*bucketHeight*numSamples*sizeof(float));

	// Initialize the opaque depths
	maxDepth			=	INFINITY;

	// Init the rasterizer
	rasterBegin(	bucketPixelWidth,
					bucketPixelHeight,
					tbucketLeft,
					tbucketTop);

	// Make sure we dont have micropolygons from the previous buckets
	flushPrimitives(FALSE);

	// Perform a rough sort of the objects here
	if (cBucket->numObjects > 1) {
		sortObjects(cBucket);
	}

	// Process the objects and patches
	while((cObject=cBucket->objects) != NULL) {
		cBucket->objects	=	cObject->next;

		// Is the object behind the maximum opaque depth ?
		if (cObject->zmin < maxDepth) {

			// The object does not have a set of pseudo triangles, dice it
			cObject->object->dice(this);
			deleteRasterObject(cObject);
			continue;
		}

		// At this point, the object is not needed in this bucket, so defer it
		objectDefer(cObject);
	}

	// Make sure we don't have any triangles waiting to be rendered
	flushPrimitives(TRUE);

	// Get the framebuffer
	rasterEnd(pixelBuffer);

	// Flush the data to the out devices
	commit(bucketPixelLeft,bucketPixelTop,bucketPixelWidth,bucketPixelHeight,pixelBuffer);

	// Just have rendered this bucket, so deallocate it
	delete cBucket;
	buckets[currentYBucket][currentXBucket]	=	NULL;

	// Update the statistics
	const int	cnBucket			=	currentYBucket*xBuckets+currentXBucket;
	stats.avgRasterObjects			=	(stats.avgRasterObjects*cnBucket	+ numObjects) / (float) (cnBucket+1);
	stats.avgRasterGrids			=	(stats.avgRasterGrids*cnBucket		+ numGrids) / (float) (cnBucket+1);

	// Restore the memory
	memEnd();

	// Advance the bucket
	advanceBucket();
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	skip
// Description			:	Skip the current bucket
// Return Value			:
// Comments				:
// Date last edited		:	2/1/2002
void	CReyes::skip() {
	CRasterObject		*cObject;
	CBucket				*cBucket			=	buckets[currentYBucket][currentXBucket];
	TRasterPrimitive	*cPrimitive;

	// Defer the objects
	while((cObject	=	cBucket->objects) != NULL) {
		cBucket->objects	=	cObject->next;

		objectDefer(cObject);
	}

	// Defer the triangles
	while((cPrimitive=cBucket->primitives) != NULL) {
		cBucket->primitives		=	cPrimitive->next;

		primitiveDefer(cPrimitive);
	}

	// Defer the triangles
	while((cPrimitive=cBucket->tprimitives) != NULL) {
		cBucket->tprimitives	=	cPrimitive->next;

		primitiveDefer(cPrimitive);
	}

	// Just have rendered this bucket, so deallocate it
	delete cBucket;
	buckets[currentYBucket][currentXBucket]	=	NULL;

	// Update the statistics
	const int	cnBucket			=	currentYBucket*xBuckets+currentXBucket;
	stats.avgRasterObjects			=	(stats.avgRasterObjects*cnBucket	+ numObjects) / (float) (cnBucket+1);
	stats.avgRasterGrids			=	(stats.avgRasterGrids*cnBucket		+ numGrids) / (float) (cnBucket+1);

	// Advance the bucket
	advanceBucket();
}


///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	flushPrimitives
// Description			:	Process and render the primitives in the current bucket
// Return Value			:	-
// Comments				:
// Date last edited		:	2/1/2002
void			CReyes::flushPrimitives(int finalFlush) {
	CBucket				*cBucket			=	buckets[currentYBucket][currentXBucket];
	TRasterPrimitive	*cPrimitive;

	// Render all the triangles within the bucket
	if (cBucket->primitives != NULL) {
		rasterDrawPrimitives(cBucket->primitives,FALSE);
	}

	// Defer the primitives that are not needed
	while((cPrimitive=cBucket->primitives) != NULL) {
		cBucket->primitives	=	cPrimitive->next;

		primitiveDefer(cPrimitive);

		stats.numTrianglesRendered++;
	}

	// We're flushing the current bucket
	if ((finalFlush == TRUE) && (cBucket->tprimitives != NULL)) {
		TRasterPrimitive	**sortedPrimitives;
		int					i;
		TRasterPrimitive	*tmp;
		int					start,end;
		int					*sortStack;
		int					*stack;
		int					last;
		int					numPrimitives	=	cBucket->numTPrimitives;

		stats.numTrianglesRendered	+=	numPrimitives;

		if (numPrimitives > 1) {
			// Start a new memory page
			memBegin();

			sortedPrimitives	=	(TRasterPrimitive **) ralloc(numPrimitives*sizeof(TRasterPrimitive *));

			for (i=0,cPrimitive=cBucket->tprimitives;cPrimitive!=NULL;i++,cPrimitive=cPrimitive->next) {
				sortedPrimitives[i]	=	cPrimitive;
			}

			assert(i == numPrimitives);

			stack		=	sortStack	=	(int *) ralloc(i*sizeof(int)*2);

			*stack++	=	0;
			*stack++	=	i-1;

			while(stack > sortStack) {
				float	pivot;

				end		=	*(--stack);
				start	=	*(--stack);

				pivot	=	sortedPrimitives[start]->v0[1+COMP_Z];

				for (last=start,i=start+1;i<=end;i++) {
					if (sortedPrimitives[i]->v0[1+COMP_Z] > pivot) {
						last++;
						tmp						=	sortedPrimitives[last];
						sortedPrimitives[last]	=	sortedPrimitives[i];
						sortedPrimitives[i]		=	tmp;
					}
				}

				tmp						=	sortedPrimitives[last];
				sortedPrimitives[last]	=	sortedPrimitives[start];
				sortedPrimitives[start]	=	tmp;

				if (last > (start+1)) {
					*stack++	=	start;
					*stack++	=	last-1;
				}

				if (end > (last+1)) {
					*stack++	=	last+1;
					*stack++	=	end;
				}
			}

#ifdef _DEBUG
			for (i=0;i<numPrimitives-1;i++) {
				assert(sortedPrimitives[i]->v0[1+COMP_Z] >= sortedPrimitives[i+1]->v0[1+COMP_Z]);
			}
#endif


			// Insert the points pack in the list
			cBucket->tprimitives	=	cPrimitive			=	sortedPrimitives[0];
			sortedPrimitives++;
			for (i=numPrimitives-1;i>0;i--) {
				cPrimitive->next	=	*sortedPrimitives++;
				cPrimitive			=	cPrimitive->next;
			}
			cPrimitive->next	=	NULL;

			// Finish the memory page
			memEnd();
		}

		// Send the primitives over the rasterizer
		rasterDrawPrimitives(cBucket->tprimitives,TRUE);

		// Defer the triangles we don't need
		while((cPrimitive=cBucket->tprimitives) != NULL) {
			cBucket->tprimitives	=	cPrimitive->next;

			tprimitiveDefer(cPrimitive);
		}

		cBucket->numTPrimitives				=	0;
	}
}























///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawObject
// Description			:	Draw an object
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::drawObject(CObject *object,const float *bmin,const float *bmax) {
	float				xmin,xmax,ymin,ymax;
	float				x[4],y[4];
	int					i;
	CRasterObject		*cObject;
	float				zmin,zmax;

	// Trivial reject
	if (bmax[COMP_Z] < clipMin)	{	return;	}
	if (bmin[COMP_Z] > clipMax)	{	return;	}

	// Clamp da bounding box
	zmin	=	max(bmin[COMP_Z],clipMin);
	zmax	=	min(bmax[COMP_Z],clipMax);

	// Compute the projected extend of the bound in the pixel space
	if (projection == OPTIONS_PROJECTION_PERSPECTIVE) {
		if (zmin < EPSILON)	{				// Spanning the eye plane ?
			if (inFrustrum(bmin,bmax)) {	// Are we in the frustrum ?
											// If we can not make the perspective divide
											// Go ahead and process the object now
				newRasterObject(cObject);
				cObject->object					=	object;
				cObject->xbound[0]				=	0;
				cObject->xbound[1]				=	0;
				cObject->ybound[0]				=	0;
				cObject->ybound[1]				=	0;
				cObject->zmin					=	zmin;
				object->attach();

				// Make sure the object gets processed in the current bucket
				objectExplicitInsert(cObject,currentXBucket,currentYBucket);
			}

			return;
		}

		// Do the perspective divide and figure put the extend on the screen
		const double	invMin	=	imagePlane	/	(double) zmin;
		const double	invMax	=	imagePlane	/	(double) zmax;

		x[0]	=	(float) (bmin[COMP_X]*invMin);
		x[1]	=	(float) (bmin[COMP_X]*invMax);
		x[2]	=	(float) (bmax[COMP_X]*invMin);
		x[3]	=	(float) (bmax[COMP_X]*invMax);
		y[0]	=	(float) (bmin[COMP_Y]*invMin);
		y[1]	=	(float) (bmin[COMP_Y]*invMax);
		y[2]	=	(float) (bmax[COMP_Y]*invMin);
		y[3]	=	(float) (bmax[COMP_Y]*invMax);

		xmin	=	xmax	=	x[0];
		ymin	=	ymax	=	y[0];
		for (i=1;i<4;i++) {
			if			(x[i] < xmin)	xmin	=	x[i];
			else	if	(x[i] > xmax)	xmax	=	x[i];

			if			(y[i] < ymin)	ymin	=	y[i];
			else	if	(y[i] > ymax)	ymax	=	y[i];
		}
	} else {
		xmin	=	bmin[COMP_X];
		ymin	=	bmin[COMP_Y];
		xmax	=	bmax[COMP_X];
		ymax	=	bmax[COMP_Y];
	}

	xmin		-=	pixelLeft;
	xmax		-=	pixelLeft;
	ymin		-=	pixelTop;
	ymax		-=	pixelTop;

	// Account for the depth of field
	if (aperture != 0) {
		const	float	mcoc	=	max(cocScreen(zmin),cocScreen(zmax));
		xmin					=	xmin-mcoc;
		xmax					=	xmax+mcoc;
		ymin					=	ymin-mcoc;
		ymax					=	ymax+mcoc;
	}

	// Convert to samples
	xmin	*=	dSampledx;
	ymin	*=	dSampledy;
	xmax	*=	dSampledx;
	ymax	*=	dSampledy;

	if (xmax < xmin) {
		const float	t	=	xmax;
		xmax			=	xmin;
		xmin			=	t;
	}

	if (ymax < ymin) {
		const float	t	=	ymax;
		ymax			=	ymin;
		ymin			=	t;
	}

	// Trivial reject
	if (xmin > sampleClipRight)		return;
	if (ymin > sampleClipBottom)	return;
	if (xmax < sampleClipLeft)		return;
	if (ymax < sampleClipTop)		return;

	xmin							=	max(xmin,0);
	ymin							=	max(ymin,0);

	// Record the object
	newRasterObject(cObject);
	cObject->xbound[0]				=	(int) floor(xmin);	// Save the bound of the object for future reference
	cObject->xbound[1]				=	(int) floor(xmax);
	cObject->ybound[0]				=	(int) floor(ymin);
	cObject->ybound[1]				=	(int) floor(ymax);
	cObject->object					=	object;
	cObject->zmin					=	zmin;
	object->attach();

	// Insert the object into the bucket its in
	objectInsert(cObject);
}





















///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawGrid
// Description			:	Draw a grid
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::drawGrid(CSurface *object,int udiv,int vdiv,float umin,float umax,float vmin,float vmax) {
	// Create a grid on the surface
	CRasterGrid			*nGrid;
	int					numVertices,numTriangles;
	int					uVertex,vVertex;
	TRasterPrimitive	*cPrimitive,*primitives;
	TRasterPrimitive	*allPrimitives;

	// Initialize the grid
	numVertices		=	(udiv+1)*(vdiv+1);							// The number of vertices to shade
	numTriangles	=	udiv*vdiv*2;								// The number of microtriangles to create
	nGrid			=	initGrid(object,numVertices,numTriangles);	// Create the grid
	nGrid->dim		=	2;
	nGrid->umin		=	umin;
	nGrid->umax		=	umax;
	nGrid->vmin		=	vmin;
	nGrid->vmax		=	vmax;
	nGrid->udiv		=	udiv;
	nGrid->vdiv		=	vdiv;

	// Sample the grid
	shadeGrid(nGrid,TRUE);									// Just the position

	// Create the triangles
	primitives			=	nGrid->primitives;
	allPrimitives		=	NULL;
	for (vVertex=0;vVertex<vdiv;vVertex++) {
		for (uVertex=0;uVertex<udiv;uVertex++) {
			int		v0,v1,v2;

			v0							=	vVertex*(udiv+1)+uVertex;
			v1							=	vVertex*(udiv+1)+uVertex+1;
			v2							=	(vVertex+1)*(udiv+1)+uVertex+1;
			cPrimitive					=	primitives;		primitives++;
			cPrimitive->v0				=	nGrid->vertices + v0*numVertexSamples;
			cPrimitive->data[0].pointer	=	nGrid->vertices + v1*numVertexSamples;
			cPrimitive->data[1].pointer	=	nGrid->vertices + v2*numVertexSamples;
			cPrimitive->next			=	allPrimitives;
			cPrimitive->flags			=	nGrid->primitiveFlags;
			allPrimitives				=	cPrimitive;

			v0							=	vVertex*(udiv+1)+uVertex;
			v1							=	(vVertex+1)*(udiv+1)+uVertex+1;
			v2							=	(vVertex+1)*(udiv+1)+uVertex;
			cPrimitive					=	primitives;		primitives++;
			cPrimitive->v0				=	nGrid->vertices + v0*numVertexSamples;
			cPrimitive->data[0].pointer	=	nGrid->vertices + v1*numVertexSamples;
			cPrimitive->data[1].pointer	=	nGrid->vertices + v2*numVertexSamples;
			cPrimitive->next			=	allPrimitives;
			cPrimitive->flags			=	nGrid->primitiveFlags;
			allPrimitives				=	cPrimitive;
		}
	}

	drawTriangles(allPrimitives);

	stats.numPatchesRendered++;
}



///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawRibbon
// Description			:	Draw a ribbon
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::drawRibbon(CSurface *object,int numDiv,float vmin,float vmax) {
	// Create a grid on the surface
	CRasterGrid			*nGrid;
	int					numVertices,numTriangles;
	TRasterPrimitive	*cTriangle,*primitives;
	TRasterPrimitive	*allTriangles;
	float				*leftVertices,*rightVertices;
	float				*vl0;
	float				*vl1;
	float				*vr0;
	float				*vr1;
	int					i;

	// Initialize the grid
	numVertices		=	(numDiv+1)*2;								// The number of vertices to shade
	numTriangles	=	numDiv*2;									// The number of microtriangles to create
	nGrid			=	initGrid(object,numVertices,numTriangles);	// Create the grid
	nGrid->dim		=	1;
	nGrid->umin		=	0;
	nGrid->umax		=	0;
	nGrid->vmin		=	vmin;
	nGrid->vmax		=	vmax;
	nGrid->udiv		=	1;
	nGrid->vdiv		=	numDiv;

	// Sample the grid
	shadeGrid(nGrid,TRUE);									// Just the position

	// Create the triangles
	primitives			=	nGrid->primitives;
	allTriangles		=	NULL;

	leftVertices		=	nGrid->vertices;
	rightVertices		=	leftVertices + (numDiv+1)*numVertexSamples;
	for (i=numDiv;i>0;i--) {
		vl0								=	leftVertices;
		vl1								=	leftVertices + numVertexSamples;
		vr0								=	rightVertices;
		vr1								=	rightVertices + numVertexSamples;

		cTriangle						=	primitives;	primitives++;
		cTriangle->flags				=	nGrid->primitiveFlags;
		cTriangle->v0					=	vl0;
		cTriangle->data[0].pointer		=	vl1;
		cTriangle->data[1].pointer		=	vr1;
		cTriangle->next					=	allTriangles;
		allTriangles					=	cTriangle;

		cTriangle						=	primitives; primitives++;
		cTriangle->flags				=	nGrid->primitiveFlags;
		cTriangle->v0					=	vl0;
		cTriangle->data[0].pointer		=	vr1;
		cTriangle->data[1].pointer		=	vr0;
		cTriangle->next					=	allTriangles;
		allTriangles					=	cTriangle;

		leftVertices					=	vl1;
		rightVertices					=	vr1;
	}

	// Dispatch the lines to the renderer
	drawTriangles(allTriangles);

	stats.numPatchesRendered++;
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawPoints
// Description			:	Draw bunch of points
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::drawPoints(CSurface *object,int numPoints) {
	// Create a grid on the surface
	CRasterGrid			*nGrid;
	int					numVertices;
	TRasterPrimitive	*cPrimitive,*primitives;
	TRasterPrimitive	*allPrimitives;
	int					i;
	float				*cVertex;

	// Initialize the grid
	numVertices		=	numPoints;								// The number of vertices to shade
	nGrid			=	initGrid(object,numVertices,numPoints);	// Create the grid
	nGrid->dim		=	0;
	nGrid->umin		=	0;
	nGrid->umax		=	0;
	nGrid->vmin		=	0;
	nGrid->vmax		=	0;
	nGrid->udiv		=	0;
	nGrid->vdiv		=	numPoints;

	// Sample the grid
	shadeGrid(nGrid,TRUE);									// Just the position

	// Create the triangles
	primitives			=	nGrid->primitives;
	cVertex				=	nGrid->vertices;
	allPrimitives		=	NULL;

	for (i=numPoints;i>0;i--,cVertex+=numVertexSamples) {
		cPrimitive						=	primitives;	primitives++;
		cPrimitive->flags				=	nGrid->primitiveFlags;
		cPrimitive->v0					=	cVertex;
		cPrimitive->next				=	allPrimitives;
		allPrimitives					=	cPrimitive;
	}

	// Dispatch the lines to the renderer
	drawPoints(allPrimitives);

	stats.numPatchesRendered++;
}




















































///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	initGrid
// Description			:	Initialize a grid by copying the points
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
CReyes::CRasterGrid		*CReyes::initGrid(CSurface *object,int numVertices,int numPrimitives) {
	CRasterGrid			*grid	=	new CRasterGrid;
	TRasterPrimitive	*cPrimitive;
	int					i;

	grid->object			=	object;				object->attach();
	grid->numVertices		=	numVertices;
	grid->numPrimitives		=	numPrimitives;
	grid->vertices			=	new float[numVertices*numVertexSamples];
	grid->primitives		=	new TRasterPrimitive[numPrimitives];
	grid->refCount			=	numPrimitives;
	grid->shaded			=	FALSE;

	for (cPrimitive = grid->primitives,i=numPrimitives;i>0;i--,cPrimitive++) {
		cPrimitive->grid	=	grid;
	}

	numGrids++;
	if (numGrids > stats.numPeakRasterGrids)	stats.numPeakRasterGrids	=	numGrids;
	stats.numRasterGridsCreated++;

	return grid;
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	shadeGrid
// Description			:	Shade a grid
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::shadeGrid(CRasterGrid *grid,int Ponly) {
	int	transparent	=	FALSE;

	if (grid->dim == 0) {
		// This is a 0 dimensional point cloud
		int					i;
		float				**varying		=	currentShadingState->varying;
		int					numPoints		=	grid->vdiv;
		float				*sizeArray;
		CSurface			*object			=	grid->object;
		TRasterPrimitive	*cPrimitive;
		
		grid->primitiveFlags	=	extraPrimitiveFlags | RASTER_POINT;
		if (enableMotionBlur && (object->moving())) {
			grid->primitiveFlags	|=	RASTER_MOVING;
		}

		if (Ponly) {
			// We have not shaded the primitive yet
			grid->primitiveFlags				|=	RASTER_UNSHADED;

			// Reset the size variable
			varying[VARIABLE_WIDTH][0]			=	-INFINITY;
			varying[VARIABLE_CONSTANTWIDTH][0]	=	-INFINITY;

			// Shade the points
			displace(object,numPoints,1,0,PARAMETER_BEGIN_SAMPLE | PARAMETER_P);

			// Figure out the size of the ribbon
			sizeArray	=	varying[VARIABLE_WIDTH];
			if (varying[VARIABLE_WIDTH][0] == -INFINITY) {
				if (varying[VARIABLE_CONSTANTWIDTH][0] == -INFINITY) {
					// So width is set
					for (i=0;i<numPoints;i++)	sizeArray[i]	=	1;
				} else {
					const float	tmp	=	varying[VARIABLE_CONSTANTWIDTH][0];

					for (i=0;i<numPoints;i++)	sizeArray[i]	=	tmp;
				}
			}

			// Project the points
			distance2samples(numPoints,sizeArray,varying[VARIABLE_P]);
			camera2samples(numPoints,varying[VARIABLE_P]);

			// Copy the point samples
			copyPoints(numPoints,varying,grid->vertices,0);

			// Make sure we record the point sizes
			for (cPrimitive=grid->primitives,i=numPoints;i>0;i--,cPrimitive++) {
				cPrimitive->data[0].real	=	*sizeArray++;
			}

		} else {
			T32				*Oi;
			T32				one;

			// Sanity check
			assert(grid->shaded == FALSE);
			grid->shaded	=	TRUE;
			stats.numRasterGridsShaded++;

			// Shade the points
			shade(object,numPoints,1,0,PARAMETER_BEGIN_SAMPLE | PARAMETER_P);

			// Copy the point samples
			copySamples(numPoints,varying,grid->vertices,0);

			// Check if we're opaque
			for (one.real=1,Oi=(T32 *) varying[VARIABLE_OI],i=numPoints;i>0;i--,Oi+=3) {
				if ((Oi[0].integer ^ one.integer) | (Oi[1].integer ^ one.integer) | (Oi[2].integer ^ one.integer)) {
					transparent	=	TRUE;
					break;
				}
			}
		}

		// Do we have motion ?
		if (grid->primitiveFlags & RASTER_MOVING) {

			if (Ponly) {
				// Reset the size variable
				varying[VARIABLE_WIDTH][0]			=	-INFINITY;
				varying[VARIABLE_CONSTANTWIDTH][0]	=	-INFINITY;

				// Shade the points
				displace(object,numPoints,1,0,PARAMETER_END_SAMPLE | PARAMETER_P);

				// Figure out the size of the ribbon
				sizeArray	=	varying[VARIABLE_WIDTH];
				if (varying[VARIABLE_WIDTH][0] == -INFINITY) {
					if (varying[VARIABLE_CONSTANTWIDTH][0] == -INFINITY) {
						// So width is set
						for (i=0;i<numPoints;i++)	sizeArray[i]	=	1;
					} else {
						const float	tmp	=	varying[VARIABLE_CONSTANTWIDTH][0];

						for (i=0;i<numPoints;i++)	sizeArray[i]	=	tmp;
					}
				}

				// Project the points
				distance2samples(numPoints,sizeArray,varying[VARIABLE_P]);
				camera2samples(numPoints,varying[VARIABLE_P]);

				// Copy the point samples
				copyPoints(numPoints,varying,grid->vertices,1);

				// Make sure we record the point sizes
				for (cPrimitive=grid->primitives,i=numPoints;i>0;i--,cPrimitive++) {
					cPrimitive->data[1].real	=	*sizeArray++;
				}
			} else {
				// Shade the points
				shade(object,numPoints,1,0,PARAMETER_END_SAMPLE | PARAMETER_P);

				// Copy the point samples
				copySamples(numPoints,varying,grid->vertices,1);
			}
		}
	} else if (grid->dim == 1) {
		// This is a 1 dimensional ribbon
		const int			numVertices		=	grid->vdiv + 1;
		int					j;
		float				*size;
		int					i;
		float				**varying;
		float				*u;
		float				*v;
		float				*time;
		float				*leftVertices,*rightVertices;
		CSurface			*object			=	grid->object;
		const CAttributes	*attributes		=	object->attributes;

		// Are we double sided ?
		if (attributes->nSides == 2) {
			grid->primitiveFlags	=	RASTER_DRAW_FRONT | RASTER_DRAW_BACK | RASTER_UNSHADED | extraPrimitiveFlags;
		} else {
			if (attributes->flags & ATTRIBUTES_FLAGS_INSIDE) {	// Flip
				grid->primitiveFlags	=	RASTER_DRAW_FRONT | RASTER_UNSHADED | extraPrimitiveFlags;
			} else {
				grid->primitiveFlags	=	RASTER_DRAW_BACK | RASTER_UNSHADED | extraPrimitiveFlags;
			}
		}

		// Do we have motion blur ?
		if (enableMotionBlur && (object->moving())) {
			grid->primitiveFlags	|=	RASTER_MOVING;
		}

		varying		=	currentShadingState->varying;
		u			=	varying[VARIABLE_U];
		v			=	varying[VARIABLE_V];
		time		=	varying[VARIABLE_TIME];

		// Put the sampling coordinates
		for (j=0;j<numVertices;j++) {
			const float t	=	(float) j / (float) (numVertices - 1);
			*u++	=	0;
			*v++	=	grid->vmin*(1-t) + grid->vmax*t;
			*time++	=	0;
		}

		if (Ponly) {
			// Reset the size variable
			varying[VARIABLE_WIDTH][0]			=	-INFINITY;
			varying[VARIABLE_CONSTANTWIDTH][0]	=	-INFINITY;

			// Shade the points on the curve
			displace(object,1,numVertices,1,PARAMETER_BEGIN_SAMPLE | PARAMETER_N | PARAMETER_DPDV | PARAMETER_P);

			// Figure out the size of the ribbon
			size	=	varying[VARIABLE_WIDTH];
			if (varying[VARIABLE_WIDTH][0] == -INFINITY) {
				if (varying[VARIABLE_CONSTANTWIDTH][0] == -INFINITY) {
					// No width is set
					for (i=0;i<numVertices;i++)	size[i]	=	1;
				} else {
					const float	tmp	=	varying[VARIABLE_CONSTANTWIDTH][0];

					for (i=0;i<numVertices;i++)	size[i]	=	tmp;
				}
			}

			// Copy the vertex samples
			leftVertices	=	grid->vertices;
			rightVertices	=	leftVertices + numVertices*numVertexSamples;
			copyPoints(numVertices,varying,leftVertices,0);
			copyPoints(numVertices,varying,rightVertices,0);

			// Create the ribbon
			makeRibbon(numVertices,leftVertices,rightVertices,size,varying[VARIABLE_N],varying[VARIABLE_DPDV],0);
		} else {
			T32					one;
			int					opaque;
			T32					*Oi;

			// Sanity check
			assert(grid->shaded == FALSE);
			grid->shaded	=	TRUE;
			stats.numRasterGridsShaded++;

			// Shade the points on the curve
			shade(object,1,numVertices,1,PARAMETER_BEGIN_SAMPLE | PARAMETER_N | PARAMETER_DPDV | PARAMETER_P);

			// Copy the vertex samples
			leftVertices	=	grid->vertices;
			rightVertices	=	leftVertices + numVertices*numVertexSamples;
			copySamples(numVertices,varying,leftVertices,0);
			copySamples(numVertices,varying,rightVertices,0);

			// Check if we're opaque
			for (one.real=1,opaque=0,Oi=(T32 *) varying[VARIABLE_OI],i=numVertices;i>0;i--,Oi+=3) {
				if ((Oi[0].integer ^ one.integer) | (Oi[1].integer ^ one.integer) | (Oi[2].integer ^ one.integer)) {
					transparent	=	TRUE;
					break;
				}
			}
		}


		// Take care of the motion
		if (grid->primitiveFlags & RASTER_MOVING) {
			// Sample points along the curve
			u				=	varying[VARIABLE_U];
			v				=	varying[VARIABLE_V];
			time			=	varying[VARIABLE_TIME];

			// Put the sampling coordinates
			for (j=0;j<numVertices;j++) {
				const float t	=	(float) j / (float) (numVertices - 1);
				*u++	=	0;
				*v++	=	grid->vmin*(1-t) + grid->vmax*t;
				*time++	=	1;
			}

			if (Ponly) {
				// Reset the size variable
				varying[VARIABLE_WIDTH][0]			=	-INFINITY;
				varying[VARIABLE_CONSTANTWIDTH][0]	=	-INFINITY;

				// Shade the points on the curve
				displace(object,1,numVertices,1,PARAMETER_END_SAMPLE | PARAMETER_N | PARAMETER_DPDV | PARAMETER_P);

				// Figure out the size of the ribbon
				size	=	varying[VARIABLE_WIDTH];
				if (varying[VARIABLE_WIDTH][0] == -INFINITY) {
					if (varying[VARIABLE_CONSTANTWIDTH][0] == -INFINITY) {
						// No width is set
						for (i=0;i<numVertices;i++)	size[i]	=	1;
					} else {
						const float	tmp	=	varying[VARIABLE_CONSTANTWIDTH][0];

						for (i=0;i<numVertices;i++)	size[i]	=	tmp;
					}
				}

				// Copy the vertex samples
				leftVertices	=	grid->vertices;
				rightVertices	=	leftVertices + numVertices*numVertexSamples;
				copyPoints(numVertices,varying,leftVertices,1);
				copyPoints(numVertices,varying,rightVertices,1);

				// Create the ribbon
				makeRibbon(numVertices,leftVertices,rightVertices,size,varying[VARIABLE_N],varying[VARIABLE_DPDV],1);
			} else {
				// Shade the points on the curve
				shade(object,1,numVertices,1,PARAMETER_END_SAMPLE | PARAMETER_N | PARAMETER_DPDV | PARAMETER_P);

				// Copy the vertex samples
				leftVertices	=	grid->vertices;
				rightVertices	=	leftVertices + numVertices*numVertexSamples;
				copySamples(numVertices,varying,leftVertices,1);
				copySamples(numVertices,varying,rightVertices,1);
			}
		}
	} else {
		assert(grid->dim == 2);
		// This is a 2 dimensional surface
		int					i,j;
		float				ustart;
		float				ustep;
		float				vstart;
		float				vstep;
		int					k;
		int					numVertices;
		float				**varying	=	currentShadingState->varying;
		T32					one;
		CSurface			*object		=	grid->object;
		const CAttributes	*attributes	=	object->attributes;
		const int			udiv		=	grid->udiv;
		const int			vdiv		=	grid->vdiv;
		float				*u;
		float				*v;
		float				*time;
		float				cu,cv;
		T32					*Oi;

		// Are we double sided ?
		if (attributes->nSides == 2) {
			grid->primitiveFlags	=	RASTER_DRAW_FRONT | RASTER_DRAW_BACK | RASTER_UNSHADED | extraPrimitiveFlags;
		} else {
			if (attributes->flags & ATTRIBUTES_FLAGS_INSIDE) {	// Flip
				grid->primitiveFlags	=	RASTER_DRAW_FRONT | RASTER_UNSHADED | extraPrimitiveFlags;
			} else {
				grid->primitiveFlags	=	RASTER_DRAW_BACK | RASTER_UNSHADED | extraPrimitiveFlags;
			}
		}

		// Do we have motion blur ?
		if (enableMotionBlur && (object->moving())) {
			grid->primitiveFlags	|=	RASTER_MOVING;
		}

		numVertices	=	(udiv+1)*(vdiv+1);			// The number of vertices to shade
		ustart		=	grid->umin;					// The minimum step sizes
		ustep		=	(grid->umax - ustart) / (float) udiv;
		vstart		=	grid->vmin;
		vstep		=	(grid->vmax - vstart) / (float) vdiv;

		assert(numVertices <= (int) maxGridSize);

		// Shade the points in the patch
		u			=	varying[VARIABLE_U];
		v			=	varying[VARIABLE_V];
		time		=	varying[VARIABLE_TIME];

		// Shade the minimum grid
		for (j=vdiv,cv=vstart;j>=0;j--,cv+=vstep) {
			for (i=udiv,cu=ustart;i>=0;i--,cu+=ustep) {
				*u++		=	cu;
				*v++		=	cv;
				*time++		=	0;
			}
		}

		if (Ponly) {
			// Displace the sucker
			displace(object,udiv+1,vdiv+1,2,PARAMETER_BEGIN_SAMPLE | PARAMETER_P);

			// Project the P into samples
			camera2samples(numVertices,varying[VARIABLE_P]);

			// Save the vertex data
			copyPoints(numVertices,varying,grid->vertices,0);
		} else {
			// Sanity check
			assert(grid->shaded == FALSE);
			grid->shaded	=	TRUE;
			stats.numRasterGridsShaded++;

			// Shade the sucker
			shade(object,udiv+1,vdiv+1,2,PARAMETER_BEGIN_SAMPLE | PARAMETER_P);

			// Project the P into samples
			camera2samples(numVertices,varying[VARIABLE_P]);

			// Save the vertex data
			copySamples(numVertices,varying,grid->vertices,0);

			// Check the transparency
			Oi			=	(T32 *) varying[VARIABLE_OI];
			one.real	=	1;
			for (k=0;k<numVertices;k++,Oi+=3) {
				if ((Oi[0].integer ^ one.integer) | (Oi[1].integer ^ one.integer) | (Oi[2].integer ^ one.integer)) {
					transparent	=	TRUE;
					break;
				}
			}
		}

		// Do we have motion blur ?
		if (grid->primitiveFlags & RASTER_MOVING) {
			u			=	varying[VARIABLE_U];
			v			=	varying[VARIABLE_V];
			time		=	varying[VARIABLE_TIME];

			// Shade the minimum grid
			for (j=vdiv,cv=vstart;j>=0;j--,cv+=vstep) {
				for (i=udiv,cu=ustart;i>=0;i--,cu+=ustep) {
					*u++		=	cu;
					*v++		=	cv;
					*time++		=	1;
				}
			}

			if (Ponly) {
				// Shade the sucker
				displace(object,udiv+1,vdiv+1,2,PARAMETER_END_SAMPLE | PARAMETER_P);

				// Project the P into samples
				camera2samples(numVertices,varying[VARIABLE_P]);

				// Copy the vertex data
				copyPoints(numVertices,varying,grid->vertices,1);
			} else {
				// Shade the sucker
				shade(object,udiv+1,vdiv+1,2,PARAMETER_END_SAMPLE | PARAMETER_P);

				// Project the P into samples
				camera2samples(numVertices,varying[VARIABLE_P]);

				// Copy the vertex data
				copySamples(numVertices,varying,grid->vertices,1);
			}
		}
	}

	// Clear the unshaded flags of all primitives
	if (Ponly == FALSE) {
		int					i;
		TRasterPrimitive	*cPrimitive	=	grid->primitives;
		unsigned int		t			=	(transparent ? RASTER_TRANSPARENT : 0);

		for (i=grid->numPrimitives;i>0;i--,cPrimitive++) {
			cPrimitive->flags	&=	~RASTER_UNSHADED;
			cPrimitive->flags	|=	t;
		}
	}
}



///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	deleteGrid
// Description			:	Delete the grid
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void			CReyes::deleteGrid(CRasterGrid *grid) {
	grid->object->detach();
	delete [] grid->primitives;
	delete [] grid->vertices;
	delete grid;

	numGrids--;
	assert(numGrids >= 0);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	sortObject
// Description			:	Perform a rough sort of the objects in the bucket
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void			CReyes::copyPoints(int numVertices,float **varying,float *vertices,int stage) {
	const	float	*P			=	varying[VARIABLE_P];
	const	int		disp		=	(numExtraSamples + 10)*stage;
	int				i;

	// Copy the samples
	for (i=numVertices;i>0;i--,P+=3,vertices+=numVertexSamples) {
		movvv(vertices+disp,P);
	}

	// If we have depth of field, compute that
	if ((aperture != 0) && (stage == 0)) {
		vertices	-=	numVertices*numVertexSamples;

		// Compute the circle of confusion amount
		for (i=numVertices;i>0;i--,vertices+=numVertexSamples) {
			const	float	z	=	vertices[COMP_Z];

			vertices[9]			=	cocSamples(z);
		}
	}
}


///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	sortObject
// Description			:	Perform a rough sort of the objects in the bucket
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void			CReyes::copySamples(int numVertices,float **varying,float *vertices,int stage) {
	const	float	*C		=	varying[VARIABLE_CI];
	const	float	*O		=	varying[VARIABLE_OI];
	int				i,j,k;
	int				disp	=	(numExtraSamples + 10)*stage;
	const	float	*s;
	float			*d;

	// Copy the samples
	for (i=numVertices;i>0;i--,C+=3,O+=3,vertices+=numVertexSamples) {
		float	*dest	=	vertices + disp;

		movvv(dest+3,C);
		movvv(dest+6,O);
	}


	// Do the extra samples
	k	=	disp + 10;
	for (i=0;i<numDisplays;i++) {
		if (datas[i].outType == -1)	continue;

		switch(datas[i].numSamples) {
		case 0:
			break;
		case 1:
			vertices	-=	numVertices*numVertexSamples;
			s			=	varying[datas[i].outType];
			for (j=0;j<numVertices;j++,vertices+=numVertexSamples) {
				d		=	vertices + k;
				*d++	=	*s++;
			}
			k++;
			break;
		case 2:
			vertices	-=	numVertices*numVertexSamples;
			s			=	varying[datas[i].outType];
			for (j=0;j<numVertices;j++,vertices+=numVertexSamples) {
				d		=	vertices + k;
				*d++	=	*s++;
				*d++	=	*s++;
			}
			k	+=	2;
			break;
		case 3:
			vertices	-=	numVertices*numVertexSamples;
			s			=	varying[datas[i].outType];
			for (j=0;j<numVertices;j++,vertices+=numVertexSamples) {
				d		=	vertices + k;
				*d++	=	*s++;
				*d++	=	*s++;
				*d++	=	*s++;
			}
			k	+=	3;
			break;
		case 4:
			vertices	-=	numVertices*numVertexSamples;
			s			=	varying[datas[i].outType];
			for (j=0;j<numVertices;j++,vertices+=numVertexSamples) {
				d		=	vertices + k;
				*d++	=	*s++;
				*d++	=	*s++;
				*d++	=	*s++;
				*d++	=	*s++;
			}
			k	+=	4;
			break;
		}
	}
}




























///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	sortObject
// Description			:	Perform a rough sort of the objects in the bucket
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::sortObjects(CBucket *cBucket) {
	memBegin();

	CRasterObject	**objects	=	(CRasterObject **) ralloc(cBucket->numObjects*sizeof(CRasterObject *));
	int				i;
	CRasterObject	*cObject;
	int				start,end,last;
	int				*stack		=	(int *) ralloc(cBucket->numObjects*sizeof(int)*2);
	int				*stackBase	=	stack;
	float			pivot;
	CRasterObject	*tmp;

	// Put the objects in an array
	for (i=0,cObject=cBucket->objects;cObject!=NULL;cObject=cObject->next)
		objects[i++]	=	cObject;

	assert(i == cBucket->numObjects);

	*stack++	=	0;
	*stack++	=	i-1;

	// Do a quick sort
	while(stack > stackBase) {
		end		=	*(--stack);
		start	=	*(--stack);

		pivot	=	objects[start]->zmin;

		for (last=start,i=start+1;i<=end;i++) {
			if (objects[i]->zmin > pivot) {
				last++;
				tmp				=	objects[last];
				objects[last]	=	objects[i];
				objects[i]		=	tmp;
			}
		}

		tmp				=	objects[last];
		objects[last]	=	objects[start];
		objects[start]	=	tmp;

		if (last > (start+1)) {
			*stack++	=	start;
			*stack++	=	last-1;
		}

		if (end > (last+1)) {
			*stack++	=	last+1;
			*stack++	=	end;
		}
	}

	// Re-insert the objects in order
	cBucket->objects		=	NULL;
	for (i=cBucket->numObjects;i>0;i--) {
		tmp					=	*objects++;
		tmp->next			=	cBucket->objects;
		cBucket->objects	=	tmp;
	}

	memEnd();
}

///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	makeRibbon
// Description			:	Displace the left and right vertices from each other
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::makeRibbon(int numVertices,float *leftVertices,float *rightVertices,const float *size,const float *N,const float *dPdv,int disp) {
	float				*leftStart	=	leftVertices;
	float				*rightStart	=	rightVertices;
	int					i;
	float				*pl;
	float				*pr;
	vector				tmp;

	disp		*=	(numExtraSamples+10);

	for (i=numVertices;i>0;i--) {
		pl		=	leftVertices	+ disp;	leftVertices	+=	numVertexSamples;
		pr		=	rightVertices	+ disp;	rightVertices	+=	numVertexSamples;
	
		crossvv(tmp,N,dPdv);		// This is the extrude direction

		normalizevf(tmp);			// Use the fast normalization as it doesn't create catastrophic error

		mulvf(tmp,(*size++) * (float) 0.5);

		addvv(pl,tmp);
		subvv(pr,tmp);

		camera2samples(pl);
		camera2samples(pr);

		N		+=	3;
		dPdv	+=	3;
	}
}














///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawTriangles
// Description			:	Draw bunch of triangles
// Return Value			:	-
// Comments				:
// Date last edited		:	6/5/2003
void		CReyes::drawTriangles(TRasterPrimitive *triangles) {
	TRasterPrimitive	*cTriangle;

	while((cTriangle=triangles) != NULL) {
		// Process the triangles and put them into the first bucket that they intersect
		float			xbound[2];
		float			ybound[2];
		float			*v0			=	cTriangle->v0;
		float			*v1			=	(float *) cTriangle->data[0].pointer;
		float			*v2			=	(float *) cTriangle->data[1].pointer;
		const float		*P			=	v0;

		triangles					=	cTriangle->next;

		xbound[1]	=	xbound[0]	=	P[COMP_X];
		ybound[1]	=	ybound[0]	=	P[COMP_Y];

		P	=	v1;
		if		(P[COMP_X] < xbound[0])	xbound[0]	=	P[COMP_X];
		else if	(P[COMP_X] > xbound[1])	xbound[1]	=	P[COMP_X];
		if		(P[COMP_Y] < ybound[0])	ybound[0]	=	P[COMP_Y];
		else if	(P[COMP_Y] > ybound[1])	ybound[1]	=	P[COMP_Y];

		P	=	v2;
		if		(P[COMP_X] < xbound[0])	xbound[0]	=	P[COMP_X];
		else if	(P[COMP_X] > xbound[1])	xbound[1]	=	P[COMP_X];
		if		(P[COMP_Y] < ybound[0])	ybound[0]	=	P[COMP_Y];
		else if	(P[COMP_Y] > ybound[1])	ybound[1]	=	P[COMP_Y];

		if (cTriangle->flags & RASTER_MOVING) {
			P	=	v0 + numExtraSamples+10;
			if		(P[COMP_X] < xbound[0])	xbound[0]	=	P[COMP_X];
			else if	(P[COMP_X] > xbound[1])	xbound[1]	=	P[COMP_X];
			if		(P[COMP_Y] < ybound[0])	ybound[0]	=	P[COMP_Y];
			else if	(P[COMP_Y] > ybound[1])	ybound[1]	=	P[COMP_Y];

			P	=	v1 + numExtraSamples+10;
			if		(P[COMP_X] < xbound[0])	xbound[0]	=	P[COMP_X];
			else if	(P[COMP_X] > xbound[1])	xbound[1]	=	P[COMP_X];
			if		(P[COMP_Y] < ybound[0])	ybound[0]	=	P[COMP_Y];
			else if	(P[COMP_Y] > ybound[1])	ybound[1]	=	P[COMP_Y];

			P	=	v2 + numExtraSamples+10;
			if		(P[COMP_X] < xbound[0])	xbound[0]	=	P[COMP_X];
			else if	(P[COMP_X] > xbound[1])	xbound[1]	=	P[COMP_X];
			if		(P[COMP_Y] < ybound[0])	ybound[0]	=	P[COMP_Y];
			else if	(P[COMP_Y] > ybound[1])	ybound[1]	=	P[COMP_Y];
		}

		if (aperture != 0) {
			// Expand the bound by the maximum focal blur amount
			const	float	mcoc	=	max(max(v0[9],v1[9]),v2[9]);

			xbound[0]	-=	mcoc;
			xbound[1]	+=	mcoc;
			ybound[0]	-=	mcoc;
			ybound[1]	+=	mcoc;
		}

		// Trivial rejects:
		if	(	(xbound[1] <	sampleClipLeft)		||
				(xbound[0] >=	sampleClipRight)	||
				(ybound[1] <	sampleClipTop)		||
				(ybound[0] >=	sampleClipBottom))	{
			deleteRasterPrimitive(cTriangle);
		} else {
			cTriangle->xbound[0]	=	(int) floor(xbound[0]);
			cTriangle->xbound[1]	=	(int) floor(xbound[1]);
			cTriangle->ybound[0]	=	(int) floor(ybound[0]);
			cTriangle->ybound[1]	=	(int) floor(ybound[1]);

			if (cTriangle->flags & RASTER_TRANSPARENT) {
				tprimitiveInsert(cTriangle);
			} else {
				primitiveInsert(cTriangle);
			}
		}

		stats.numTrianglesCreated++;
	}

	flushPrimitives(FALSE);
}


///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Method				:	drawPoints
// Description			:	Draw bunch of points
// Return Value			:	-
// Comments				:
// Date last edited		:	6/13/2003
void		CReyes::drawPoints(TRasterPrimitive *primitives) {
	TRasterPrimitive	*cPrimitive;

	while((cPrimitive = primitives) != NULL) {
		float	xbound[2];
		float	ybound[2];
		float	*P			=	cPrimitive->v0;

		primitives			=	cPrimitive->next;

		xbound[0]			=	P[0];
		xbound[1]			=	P[0];
		ybound[0]			=	P[1];
		ybound[1]			=	P[1];

		if (cPrimitive->flags & RASTER_MOVING) {
			P				=	cPrimitive->v0 + numExtraSamples+10;

			xbound[0]		=	min(xbound[0],P[0]);
			xbound[1]		=	max(xbound[1],P[0]);
			ybound[0]		=	min(ybound[0],P[1]);
			ybound[1]		=	max(ybound[1],P[1]);

			const float maxSize	=	max(cPrimitive->data[0].real,cPrimitive->data[1].real);
			xbound[0]		-=	maxSize;
			ybound[0]		-=	maxSize;
			xbound[1]		+=	maxSize;
			ybound[1]		+=	maxSize;
		} else {
			xbound[0]		-=	cPrimitive->data[0].real;
			ybound[0]		-=	cPrimitive->data[0].real;
			xbound[1]		+=	cPrimitive->data[0].real;
			ybound[1]		+=	cPrimitive->data[0].real;
		}

		// Trivial rejects:
		if	(	(xbound[1] <	sampleClipLeft)		||
				(xbound[0] >=	sampleClipRight)	||
				(ybound[1] <	sampleClipTop)		||
				(ybound[0] >=	sampleClipBottom))	{

			deleteRasterPrimitive(cPrimitive);
		} else {
			cPrimitive->xbound[0]	=	(int) floor(xbound[0]);
			cPrimitive->xbound[1]	=	(int) floor(xbound[1]);
			cPrimitive->ybound[0]	=	(int) floor(ybound[0]);
			cPrimitive->ybound[1]	=	(int) floor(ybound[1]);

			if (cPrimitive->flags & RASTER_TRANSPARENT) {
				tprimitiveInsert(cPrimitive);
			} else {
				primitiveInsert(cPrimitive);
			}
		}

		stats.numTrianglesCreated++;
	}

	flushPrimitives(FALSE);
}

