//////////////////////////////////////////////////////////////////////
//
//                             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.h
//  Classes				:	CReyes
//  Description			:	The rasterizer class
//
////////////////////////////////////////////////////////////////////////
#ifndef REYES_H
#define REYES_H

#include "common/global.h"
#include "output.h"
#include "shading.h"
#include "object.h"

const	unsigned int	RASTER_MOVING			=	1 << 0;		// The primitive is moving
const	unsigned int	RASTER_TRANSPARENT		=	1 << 1;		// The primitive is transparent
const	unsigned int	RASTER_POINT			=	1 << 2;		// The primitive is a point
const	unsigned int	RASTER_UNSHADED			=	1 << 3;		// The primitive has not been shaded (only displaced)
const	unsigned int	RASTER_FOCALBLUR		=	1 << 4;		// The primitive has focalblur
const	unsigned int	RASTER_EXTRASAMPLES		=	1 << 5;		// The primitive has extra samples to compute
const	unsigned int	RASTER_GLOBAL_MASK		=	(1 << 6) - 1;// This mask is used to block the lower fields
const	unsigned int	RASTER_DRAW_FRONT		=	1 << 6;		// Draw the front of the primitive
const	unsigned int	RASTER_DRAW_BACK		=	1 << 7;		// Draw the back of the primitive


///////////////////////////////////////////////////////////////////////
// Class				:	CReyes
// Description			:	This class is implementes a REYES like scan
//							line renderer
// Comments				:
// Date last edited		:	4/25/2004
class	CReyes : public CShadingContext {
protected:

	///////////////////////////////////////////////////////////////////////
	//	The misc data structures used in the scan line rendering
	///////////////////////////////////////////////////////////////////////
	typedef struct TRasterPrimitive {
			int					xbound[2],ybound[2];	// The bound on the screen, in samples
			float				*v0;					// The first vertex index (used for sorting)
			T64					data[2];				// The data field - primitive dependent data area
	} TRasterPrimitive;



	///////////////////////////////////////////////////////////////////////
	// Class				:	CRasterGrid
	// Description			:	This class encapsulates a shading grid
	//							line renderer
	// Comments				:
	// Date last edited		:	9/17/2004
	class	CRasterGrid {
	public:
		CSurface				*object;				// The object responsible for the grid
		int						dim;					// Dimensionality (0,1 or 2)
		float					umin,umax,vmin,vmax;	// The parametric range
		int						udiv,vdiv;				// The number of division
		int						numVertices;			// The number of vertices
		float					*vertices;				// Array of vertices
		int						numPrimitives;			// Number of primitives
		TRasterPrimitive		*primitives;			// Array of primitives on this grid
		int						flags;					// The primitive flags
	};



	///////////////////////////////////////////////////////////////////////
	// Class				:	CRasterPatch
	// Description			:	Holds an object
	// Comments				:
	// Date last edited		:	1/30/2002
	class	CRasterObject {
	public:
			CObject				*object;				// The object
			CRasterGrid			*grid;					// The grid
			CRasterObject		*next;					// The next object
			int					xbound[2],ybound[2];	// The bound of the object on the screen, in samples
			float				zmin;					// The minimum z coordinate of the object (used for occlusion culling)
	};	

	///////////////////////////////////////////////////////////////////////
	// Class				:	CBucket
	// Description			:	Holds a bucket
	// Comments				:
	// Date last edited		:	1/30/2002
	class	CBucket {
	public:
								CBucket();
								~CBucket();

			CRasterObject		*objects;				// The list of objects waiting to be rendered
	};


	///////////////////////////////////////////////////////////////////////
	// Class				:	CPqueue
	// Description			:	Priority queue specifically written for CRasterObject
	// Comments				:	I could have used the template in containers.h, but this one allows me to defer objects directly
	// Date last edited		:	9/20/2004
	class CPqueue  {
	public:
								CPqueue(int ss=100)	{
									stepSize	=	ss;
									maxItems	=	stepSize;
									numItems	=	1;
									allItems	=	new CRasterObject*[maxItems];
								}

								~CPqueue()	{
									delete [] allItems;
								}

					void		insert(CRasterObject *cObject) {
									int i,j;

									// Expand the buffer
									if (numItems >= maxItems) {
										CRasterObject	**newItems;
										maxItems		+=	stepSize;
										newItems		=	new CRasterObject*[maxItems+1];
										memcpy(newItems,allItems,numItems*sizeof(CRasterObject*));
										delete [] allItems;
										allItems		=	newItems;
										stepSize		*=	2;
									}
					
									// Insert the item
									i	= numItems++;
									j	= i >> 1;
									while ((i > 1) && (cObject->zmin < allItems[j]->zmin)) {
										allItems[i]	=	allItems[j];
										i			=	j;
										j			=	i >> 1;

									}

									allItems[i]		=	cObject;
								}
					
				CRasterObject	*get() {
									int				i = 1, j;
									CRasterObject	*lItem,*cItem;

									if (numItems <= 1) return NULL;
								
									cItem		=	allItems[1];
								
									numItems--;
									lItem		=	allItems[numItems];

									while (i <= numItems / 2) {
										j = 2 * i;
										if (j >= numItems) break;

										if ((j < (numItems-1)) && (allItems[j]->zmin > allItems[j+1]->zmin))
											j++;

										if (allItems[j]->zmin > lItem->zmin)
											break;

										allItems[i]	=	allItems[j];
										i			=	j;
									}
									allItems[i]				=	lItem;
									return cItem;
								}

					CRasterObject	**allItems;					// Array of the heap
					int				numItems,maxItems,stepSize;	// Misc junk
				};








public:

								CReyes(COptions *,CXform *,SOCKET,unsigned int);
								~CReyes();

								// The main hider interface
	void						renderFrame();									// Right after world end to force rendering of the entire frame

								// The following functions must be overriden by the child rasterizer
	virtual	void				rasterBegin(int,int,int,int)				=	0;
	virtual	void				rasterDrawPrimitives(CRasterGrid *)			=	0;
	virtual	void				rasterEnd(float *)							=	0;
	
	
	void						drawObject(CObject *,const float *,const float *);		// Draw an object
	void						drawGrid(CSurface *,int,int,float,float,float,float);	// Draw a grid
	void						drawRibbon(CSurface *,int,float,float);					// Draw a ribbon (RiCurves)
	void						drawPoints(CSurface *,int);								// Draw points (RiPoints)

protected:
	float						maxDepth;										// The maximum opaque depth in the current bucket
	int							xSampleOffset,ySampleOffset;					// The amount of offset around each bucket in samples

	void						shadeGrid(CRasterGrid *,int);					// Called by the child to force the shading of a grid
private:
	void						copyPoints(int,float **,float *,int);			// Data movement
	void						copySamples(int,float **,float *,int);

	void						makeRibbon(int,float *,float *,const float *,const float *,const float *,int);

	CRasterGrid					*newGrid(CSurface *,int,int);					// Create a new grid
	void						deleteGrid(CRasterGrid *);						// Delete a grid
	void						insertGrid(CRasterGrid *,int);					// Insert a grid into the correct bucket

	void						render();										// Render the current bucket
	void						skip();											// Skip the current bucket
	
	int							numGrids;										// The number of grids allocated
	int							numObjects;										// The number of objects allocated

	CBucket						***buckets;										// All buckets

	int							numVertexSamples;								// The number of samples per pixel
	int							enableMotionBlur;								// TRUE if the motion blur has to be enabled
	int							extraPrimitiveFlags;							// These are the extra primitive flags
	int							xBucketsMinusOne;								// xBuckets-1
	int							yBucketsMinusOne;								// yBuckets-1

	float						dSampledx,dSampledy;							// dSample / dx, dSample / dy
																				// The clipping region in samples
	float						sampleClipRight,sampleClipLeft,sampleClipTop,sampleClipBottom;

	float						invBucketSampleWidth,invBucketSampleHeight;		// The 1 / sample

	int							bucketPixelLeft;								// Left of the current bucket in pixels
	int							bucketPixelTop;									// Top of the current bucket in pixels
	int							bucketPixelWidth;								// Width of the current bucket in pixels
	int							bucketPixelHeight;								// Height of the current bucket in pixels
	int							tbucketLeft;									// Left of the current bucket in samples
	int							tbucketTop;										// Right of the current bucket in samples
	int							tbucketRight;
	int							tbucketBottom;

				///////////////////////////////////////////////////////////////////////
				// Class				:	COutput
				// Method				:	distance2samples
				// Description			:	Project distances into the sample space
				// Return Value			:
				// Comments				:	(inline for speed)
				// Date last edited		:	7/4/2001
				inline void		distance2samples(int n,float *dist,float *P) {
									if(projection == OPTIONS_PROJECTION_PERSPECTIVE) {
										for (;n>0;n--,P+=3) {
											*dist++		=	dSampledx*imagePlane*dist[0]/P[COMP_Z];
										}
									} else {
										for (;n>0;n--,P+=3) {
											*dist++		=	dSampledx*dist[0];
										}
									}
								}

				///////////////////////////////////////////////////////////////////////
				// Class				:	COutput
				// Method				:	camera2samples
				// Description			:	Project from camera space into the sample space
				// Return Value			:
				// Comments				:	(inline for speed)
				// Date last edited		:	7/4/2001
				inline void		camera2samples(int n,float *P) {
									if(projection == OPTIONS_PROJECTION_PERSPECTIVE) {
										for (;n>0;n--,P+=3) {
											P[COMP_X]	=	(imagePlane*P[COMP_X]/P[COMP_Z] - pixelLeft)*dSampledx;
											P[COMP_Y]	=	(imagePlane*P[COMP_Y]/P[COMP_Z] - pixelTop)*dSampledy;
										}
									} else {
										for (;n>0;n--,P+=3) {
											P[COMP_X]	=	(P[COMP_X] - pixelLeft)*dSampledx;
											P[COMP_Y]	=	(P[COMP_Y] - pixelTop)*dSampledy;
										}
									}
								}

				///////////////////////////////////////////////////////////////////////
				// Class				:	COutput
				// Method				:	camera2samples
				// Description			:	Project from camera space into the sample space
				// Return Value			:
				// Comments				:	(inline for speed)
				// Date last edited		:	7/4/2001
				inline void		camera2samples(float *P) {
									if(projection == OPTIONS_PROJECTION_PERSPECTIVE) {
										P[COMP_X]	=	imagePlane*P[COMP_X]/P[COMP_Z];
										P[COMP_Y]	=	imagePlane*P[COMP_Y]/P[COMP_Z];
									}

									P[COMP_X]	=	(P[COMP_X] - pixelLeft)*dSampledx;
									P[COMP_Y]	=	(P[COMP_Y] - pixelTop)*dSampledy;
								}
};

#endif
