//////////////////////////////////////////////////////////////////////
//
//                             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				:	gatherCache.h
//  Classes				:	CGatherCache
//  Description			:	This class holds a gather cache information
//
////////////////////////////////////////////////////////////////////////
#ifndef GATHERCACHE_H
#define GATHERCACHE_H

#include "common/global.h"
#include "common/algebra.h"
#include "attributes.h"
#include "fileResource.h"
#include "cache.h"
#include "hierarchy.h"
#include "random.h"

///////////////////////////////////////////////////////////////////////
// Class				:	CGatherCache
// Description			:	Defines a gather cache we querry for the incident junk
// Comments				:
// Date last edited		:	11/5/2003
class	CGatherCache : public CCache {
public:

	///////////////////////////////////////////////////////////////////////
	// Class				:	CGatherTriangle
	// Description			:	Encapsulates a gather triangle
	// Comments				:
	// Date last edited		:	11/5/2003
	class	CGatherTriangle {
	public:
		float							corners[3*3];			// The array of corners (xyzxyzxyz)
		vector							P;						// The centroid of the triangle
		vector							N,C;					// The normal vector and the radiosity
		float							dA;						// The area of the triangle
		CAttributes						*attributes;			// The triangle attributes;
		int								cluster;				// The cluster index for partitioning
	};

	///////////////////////////////////////////////////////////////////////
	// Class				:	CGatherCluster
	// Description			:	Encapsulates a cluster of triangle
	// Comments				:
	// Date last edited		:	11/5/2003
	class	CGatherCluster {
	public:
		vector							C,P,N,NdA;				// The cluster center and the normal vector
		float							dP,dN;					// The cluster radius and normal deviation
		int								planar;					// TRUE if the cluster is planar
		CGatherCluster					*children[2];			// The children clusters
		CGatherCluster					*parent;				// The parent of this cluster
		CGatherTriangle					*triangle;				// The triangle pointer
	};

	///////////////////////////////////////////////////////////////////////
	// Class				:	CGatherSurface
	// Description			:	Holds a cluster of triangles
	// Comments				:
	// Date last edited		:	11/5/2003
	class	CGatherHarmonic {
	public:
		float							Y[27];					// The spherical harmonic coefficients for this cluster
		vector							P,N;					// The position, normal
		float							dP,dPSmooth;			// The radius of the cluster
		float							dN;						// The normal deviation
		CGatherHarmonic					*next;					// The next pointers
	};

	///////////////////////////////////////////////////////////////////////
	// Class				:	CShadingPoint
	// Description			:	Holds a shading point
	// Comments				:
	// Date last edited		:	11/5/2003
	class	CShadingPoint {
	public:
		vector							P,N;					// The position and normal of the shading point
		CShadingPoint					*next;					// Next shading point in the list
	};

	///////////////////////////////////////////////////////////////////////
	// Class				:	CGatherCache
	// Description			:	Defines a cache gather node
	// Comments				:
	// Date last edited		:	11/5/2003
	class	CGatherNode {
	public:
		CGatherNode						*children[8];			// The children nodes
		CGatherHarmonic					*samples;				// The list of harmonic samples
		vector							center;					// The center of the node
		float							side;					// The side length of the node
	};

public:
									CGatherCache(const char *,unsigned int,const float *,const float *,CXform *,CHierarchy *,FILE *,CArray<CTriangle *> *);
									~CGatherCache();

									// Overloaded cache functionality
	void							lookup(float *,const float *,const float *,const CGlobalIllumLookup *);
	void							cachesample(float *,const float *,const float *,float);
	void							finalize(const CGlobalIllumLookup *);

private:

	// The following functions are used to allocate - de-allocate triangles and clusters
	inline	CGatherTriangle			*newTriangle() {
										if (freeTriangles == NULL) {
											return (CGatherTriangle *) memory->alloc(sizeof(CGatherTriangle));
										} else {
											CGatherTriangle	*cTriangle	=	freeTriangles;
											freeTriangles				=	(CGatherTriangle *) cTriangle->attributes;
											return cTriangle;
										}
									}

	inline CGatherCluster			*newCluster() {
										if (freeClusters == NULL) {
											return (CGatherCluster *) memory->alloc(sizeof(CGatherCluster));
										} else {
											CGatherCluster	*cCluster	=	freeClusters;
											freeClusters				=	(CGatherCluster *) cCluster->parent;
											return cCluster;
										}
									}

	inline void						deleteTriangle(CGatherTriangle *cTriangle) {
										cTriangle->attributes			=	(CAttributes *) freeTriangles;
										freeTriangles					=	cTriangle;
									}

	inline void						deleteCluster(CGatherCluster *cCluster) {
										cCluster->parent				=	(CGatherCluster *) freeClusters;
										freeClusters					=	cCluster;
									}


	// Disk IO
	void							writeNode(FILE *,CGatherNode *);
	CGatherNode						*readNode(FILE *);

	void							writeCluster(FILE *,CGatherCluster *);
	CGatherCluster					*readCluster(FILE *);

	// Geometry clustering
	CGatherCluster					*cluster(int,CGatherTriangle **);
	int								partition(int,CGatherTriangle **);
	int								split(CGatherTriangle **,const CGatherTriangle *,float);
	int								depth(const CGatherCluster *);
	void							printCluster(CGatherCluster *,int);

	// Shading point clustering
	void							compute(int,CShadingPoint **);
	int								partition(int,CShadingPoint **,float);
	void							processGeometry(const float *,float,int,const float *);








	CMemStack						*memory;					// The global memory area

	CGatherTriangle					*freeTriangles;				// The list of free triangles
	CGatherCluster					*freeClusters;				// The list of free clusters

	CHierarchy						*hierarchy;					// The raytracing hierarchy

	CArray<CGatherTriangle *>		*microTriangles;			// The array of microtriangles we created

	CShadingPoint					*samplePoints;				// The list of shading points saved
	int								numSamplePoints;			// The number of shading points in the list

	CGatherCluster					*rootCluster;				// The root geometry cluster
	int								maxClusterDepth;			// The maximum depth of the cluster hierarchy
	CGatherCluster					**clusterStack;				// The temporary array allocated for the cluster traversal

	CGatherNode						*root;						// The root sample cluster
	int								maxDepth;					// The maximum depth of the sample hierarchy
	CGatherNode						**nodeStack;				// The temporary array allocated for the node traversal

	float							*gatherTable;				// Precomputed alpha / sin(alpha) table

	CSobol<4>						generator;					// Random number generator for the ray-casting
};

#endif





