//////////////////////////////////////////////////////////////////////
//
//                             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				:	output.h
//  Classes				:	COutput
//  Description			:	The class that manages display drivers
//
////////////////////////////////////////////////////////////////////////
#ifndef OUTPUT_H
#define OUTPUT_H

#include "common/global.h"
#include "common/containers.h"
#include "options.h"
#include "ray.h"
#include "dsply.h"

#define	RASTER_VERTEX_REFCOUNT	0			// Indices of several things in the vertex array
#define	RASTER_VERTEX_COC		1

// Compute the circle of confusion in the camera system
#define	cocPixels(z)	(float) fabs((1 / z) - invFocaldistance)*cocFactorPixels
#define	cocSamples(z)	(float) fabs((1 / z) - invFocaldistance)*cocFactorSamples
#define	cocScreen(z)	(float) fabs((1 / z) - invFocaldistance)*cocFactorScreen

const	unsigned	int	HIDER_RGBAZ_ONLY			=	1;	// The hider can only produce RGBAZ channels
const	unsigned	int	HIDER_NEEDS_RAYTRACING		=	2;	// The hider requires raytracing
const	unsigned	int	HIDER_BREAK					=	4;	// The hider should stop rendering
const	unsigned	int	HIDER_NODISPLAY				=	8;	// The hider is not actually generating display output
const	unsigned	int	HIDER_DONE					=	16;	// The image has been computed, so stop
const	unsigned	int	HIDER_ILLUMINATIONHOOK		=	32;	// The hider requires the illumination hooks
const	unsigned	int	HIDER_PHOTONMAP_OVERWRITE	=	64;	// Overwrite the photon maps
const	unsigned	int	HIDER_GEOMETRYHOOK			=	128;// The hider requires the geometry hooks

// The clipping codes used by the clipcode()
const	unsigned	int	CLIP_LEFT					=	1;
const	unsigned	int	CLIP_RIGHT					=	2;
const	unsigned	int	CLIP_TOP					=	4;
const	unsigned	int	CLIP_BOTTOM					=	8;
const	unsigned	int	CLIP_NEAR					=	16;
const	unsigned	int	CLIP_FAR					=	32;

///////////////////////////////////////////////////////////////////////
// Class				:	COutput
// Description			:	This class handles the output
// Comments				:	It is just an extended COptions class
// Date last edited		:	7/4/2001
class COutput : public COptions {
public:
							COutput(COptions *,CXform *,SOCKET,unsigned int);
			virtual			~COutput();

			void			commit(int,int,int,int,float *);

			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	camera2pixels
			// Description			:	Project from camera space into the pixel space
			// Return Value			:
			// Comments				:	(inline for speed)
			// Date last edited		:	7/4/2001
			inline void		camera2pixels(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)*dPixeldx;
								P[COMP_Y]	=	(P[COMP_Y] - pixelTop)*dPixeldy;
							}

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

								x[0]	=	(x[0] - pixelLeft)*dPixeldx;
								y[0]	=	(y[0] - pixelTop)*dPixeldy;
							}

			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	camera2pixels
			// Description			:	Project from camera space into the pixel space
			// Return Value			:
			// Comments				:	(inline for speed)
			// Date last edited		:	7/4/2001
			inline void		camera2pixels(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)*dPixeldx;
										P[COMP_Y]	=	(imagePlane*P[COMP_Y]/P[COMP_Z] - pixelTop)*dPixeldy;
									}
								} else {
									for (;n>0;n--,P+=3) {
										P[COMP_X]	=	(P[COMP_X] - pixelLeft)*dPixeldx;
										P[COMP_Y]	=	(P[COMP_Y] - pixelTop)*dPixeldy;
									}
								}
							}

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


			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	pixels2distance
			// Description			:	Convert from pixel distance to camera space distance
			// Return Value			:	-
			// Comments				:
			// Date last edited		:	7/4/2001
			void			pixels2distance(float &a,float &b,float d) {
								a	=	lengthA*d;
								b	=	lengthB*d;
							}

			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	samples2camera
			// Description			:	Back project from sample space into the camera space
			// Return Value			:
			// Comments				:	(inline for speed)
			// Date last edited		:	7/4/2001
			inline void		pixels2camera(float *P,float x,float y,float z) {
								x	=	x*dxdPixel + pixelLeft;
								y	=	y*dydPixel + pixelTop;

								if(projection == OPTIONS_PROJECTION_PERSPECTIVE) {
									P[COMP_X]	=	x*z*invImagePlane;
									P[COMP_Y]	=	y*z*invImagePlane;
									P[COMP_Z]	=	z;
								} else {
									P[COMP_X]	=	x;
									P[COMP_Y]	=	y;
									P[COMP_Z]	=	z;
								}
							}

			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	advanceBucket
			// Description			:	Advance the bucket
			// Return Value			:	TRUE if we're still rendering, FALSE otherwise
			// Comments				:
			// Date last edited		:	7/4/2001
			void			advanceBucket() {
								currentXBucket++;
								if (currentXBucket == xBuckets) {		
									currentXBucket	=	0;
									currentYBucket++;
								}

								if ((currentXBucket == 0) && (currentYBucket == yBuckets)) {
									hiderFlags |=	HIDER_DONE | HIDER_BREAK;
								}
							}

			///////////////////////////////////////////////////////////////////////
			// Class				:	COutput
			// Method				:	advanceBucket
			// Description			:	Advance the bucket
			// Return Value			:	TRUE if we're still rendering, FALSE otherwise
			// Comments				:
			// Date last edited		:	7/4/2001
			void			advanceBucket(int &x,int &y) {
								x	=	currentXBucket;
								y	=	currentYBucket;

								currentXBucket++;
								if (currentXBucket == xBuckets) {		
									currentXBucket	=	0;
									currentYBucket++;
								}

								if ((currentXBucket == 0) && (currentYBucket == yBuckets)) {
									hiderFlags |=	HIDER_DONE | HIDER_BREAK;
								}
							}

			CXform			*world;											// The world transform
			matrix			fromNDC,toNDC;									// Some misc matrices
			matrix			fromRaster,toRaster;
			matrix			fromScreen,toScreen;
			matrix			worldToNDC;										// World to NDC matrix
			unsigned int	hiderFlags;										// The hider flags

			int				inFrustrum(const float *,const float *);		// Return TRUE if the box is in the frustrum
			int				inFrustrum(const float *);						// Return TRUE if the point is in the frustrum
			unsigned int	clipCode(const float *);						// Returns the clipping code
protected:
			int				numSamples;										// The actual number of samples to compute
			int				numExtraSamples;								// The number of actual samples
			int				xPixels,yPixels;								// The number of pixels to compute in X and Y
			unsigned int	additionalParameters;							// Any user specified parameters to be computed
			float			pixelLeft,pixelRight,pixelTop,pixelBottom;		// The rendering window on the screen plane
			float			dydPixel,dxdPixel;								// Stuff
			float			dPixeldx,dPixeldy;
			int				renderLeft,renderRight,renderTop,renderBottom;	// The actual rendering window in pixels
			int				xBuckets,yBuckets;								// The number of buckets
			float			aperture;										// Aperture radius
			float			imagePlane;										// The z coordinate of the image plane
			float			invImagePlane;									// The reciprocal of that
			float			cocFactorPixels;								// The circle of concusion factor for the pixels
			float			cocFactorSamples;								// The circle of concusion factor for the samples
			float			cocFactorScreen;								// The circle of concusion factor for the screen
			float			invFocaldistance;								// 1 / focalDistance
			float			lengthA,lengthB;								// The depth to length conversion

			float			marginXcoverage,marginYcoverage;				// Coverage ratios for the pixel filter
			float			marginX,marginY;
			float			marginalX,marginalY;

			float			leftX,leftZ,leftD;								// The clipping plane equations
			float			rightX,rightZ,rightD;
			float			topY,topZ,topD;
			float			bottomY,bottomZ,bottomD;

			int				numActiveDisplays;								// The number of active displays

			int				currentXBucket;									// The bucket counters
			int				currentYBucket;

			SOCKET			netClient;										// The client socket if any

			FILE			*deepShadowFile;								// Deep shadow map stuff
			int				*deepShadowIndex;
			int				deepShadowIndexStart;							// The offset in the file for the indices

			void			clear(int,int,int,int);								// Clear a window
			void			dispatch(int,int,int,int,float *);					// Dispatch a window to out devices
			void			getDisplayName(char *,const char *,const char *);	// Retrieve the display name

			///////////////////////////////////////////////////////////////////////
			// Class				:	CDisplayData
			// Description			:	This class holds data about a display driver
			// Comments				:
			// Date last edited		:	7/4/2001
			class CDisplayData {
			public:
					void						*module;						// The module handle for the out device
					void						*handle;						// The handle for the out device
					int							sampleStart;					// The sample start index in the shaded vertex array
					int							numSamples;						// The number of samples
					int							outType;						// The output type
					TDisplayStartFunction		start;							// The start function for the out device
					TDisplayDataFunction		data;							// The data function
					TDisplayRawDataFunction		rawData;						// The raw data function
					TDisplayFinishFunction		finish;							// The finish function
					CDisplay					*display;
			};

			int				numDisplays;
			CDisplayData	*datas;

			void			computeDisplayData();
};

#endif





