// -*- C++ -*-
#ifndef RIRADOBJECT_H
#define RIRADOBJECT_H
/* Copyright 1996 
 * Tue Jun 17 09:36:10 1997  Brian Smits  (bes@phoenix.cs.utah.edu)
 * 
 * RiRadObject.H
 * 
 *	
 * 
 * $Id: RiRadObject.H,v 1.7 1998/06/22 17:36:47 bes Exp $ 
 * 
 */
#ifndef RICOMMON_H
#include <RiCommon.H>
#endif

#ifndef RIMATERIAL_H
#include <RiMaterial.H>
#endif

#include <rw/tvordvec.h>

class RiRadObject;
/***************************************************************
CLASS
    RiRadRegion
     Encapsulates the notion of a sample on a RiRadObject.

DESCRIPTION
     This class represents a sample on an RiRadObject.  The sample consists of all
     data needed by an RiMaterial (such as position, area, normal, UV's) as well
     as a pointer to a RiRadObject.  The RiRadObject pointer is the particular RiRadObject
     that the sample lives on.  This may not be the RiRadObject that was queried to get the
     sample in the first place.  If a higher level cluster is queried, the result may be a primitive
     object.

****************************************************************/

class RiRadRegion : public RiMaterialRegion {
  public:
				// GROUP: Constructors and assignment
				//// Default Constructor
    RiRadRegion();
				// GROUP: Accessors
				////  Note that the object may not be the object used in the
				//  original call.  The original may have been a composite.
    RiRadObject *GetRadObject() const;
				////  Set the RiRadObject that the sample live on.
    void SetRadObject(RiRadObject *obj);
  private:
    RiRadObject *obj;
};


class RiTransferData;
class RiRefine;
/***************************************************************
CLASS
    RiRadLink
     <one line summary> 

DESCRIPTION
     <Detailed description with any warnings>

****************************************************************/

class RiRadLink {
  public:
    //// Destructor
    virtual ~RiRadLink() {}
    // GROUP: Members
				//// gather the energy down this link
    virtual  RiSpectrum Gather() = 0;
				//// Initialize data for use by RiRefine
    virtual  void	GetRefine(RiRefine &data, RiRadObject *rec) = 0;
				//// Get the Source object for this link
    virtual  RiRadObject *GetSrc() = 0;
};



/***************************************************************
CLASS
    RiRadData
     Holds all algorithm specific radiosity, emission, link, and error data.

DESCRIPTION
     This is where things like lists of links, estimates of radiance or irradiance,
     and all solution data goes.  This makes it simpler to change algorithms and add fields,
     because it can all be done here, instead of in each object.

****************************************************************/

class RiRadData {
  public:
				// GROUP: Constructors and assignment
				//// Default Constructor
    RiRadData();
				////
    RiRadData(const RiSpectrum &rad);
				////
    RiRadData(const RiSpectrum &rad, const RiSpectrum &emit);
				// GROUP: Accessors
				//// Average in units of Radiance over object
    RiSpectrum 	GetEmission() const;
				//// Set average Emission
    void 	SetEmission(const RiSpectrum &emit);
				//// Average over object
    RiSpectrum 	GetRadiance() const;
				//// Set average radiance
    void	SetRadiance(const RiSpectrum &rad);
				//// Average over object
    RiMaterial *GetMaterial() const;
				//// Set average radiance
    void	SetMaterial(RiMaterial *mat);
				//// Initialize the data based on parent's data and areas
    void	InitializeFrom(RiRadData *data, RiReal myArea, RiReal parentsArea);
				//// Give access to the links
    RWTValOrderedVector<RiRadLink *> &GetLinks();
  private:
    RiSpectrum  rad;
    RiSpectrum  emit;
    RiMaterial *mat;
    RWTValOrderedVector<RiRadLink *> links;
};


/***************************************************************
CLASS
    RiTransferData
     Encapsulate the data representing a transfer.

DESCRIPTION
     This class eliminates the messy problem of how to encapsulate objects that
     only compute form factors and objects that only compute energy transfered (sky object).
     All error and data is stored here.  This makes it easier to change algorithms without
     changing quadrature strategies, as basic operation needed to do quadrature on this data
     are implemented in the class, and can be changed to compute things differently.

****************************************************************/

class RiTransferData {
  public:
				// GROUP: Constructors and assignment
				//// Default Constructor
    RiTransferData();
				////Copy Constructor
    RiTransferData(const RiTransferData &);
				//// Assignment
    RiTransferData &operator=(const RiTransferData &);
				// GROUP: Accessors
				//// Set energy data
    void  SetIrradiance(const RiSpectrum &energy, RiReal energyError);
				//// Set form factor data
    void  SetFormFactor(RiReal ff, RiReal ffError);
				//// Set visibility data
    void  SetVisibility(RiReal vis, RiReal visError);
				//// Get energy data
    void  GetIrradiance(RiSpectrum &energy, RiReal &energyError) const;
				//// Get form factor data
    void  GetFormFactor(RiReal &ff, RiReal &ffError) const;
				//// Get visibility data
    void  GetVisibility(RiReal &vis, RiReal &visError) const;
				//// Get the estimated occluded irradiance
    RiSpectrum 	GetOccludedIrradiance() const;
				//// Get the estimated occluded form factor
    RiReal 	GetOccludedFormFactor() const;
				// GROUP: Members
				//// accumulate the total (handle errors appropriately)
    void  operator+=(const RiTransferData &);
				//// scale results (handle errors appropriately)
    void  operator*=(RiReal rhs);
				//// reset everything to zero
    void  Clear();
				//// does this hold energy?
    bool  IsEnergy();
  private:
				//// Hold the type of the data (makes things more efficient and safe?)
    enum Type {undefined, hasEnergy, hasFormFactor};
    Type      	type;
    RiSpectrum 	energy;
    RiReal     	energyError;
    RiReal     	ff;
    RiReal     	ffError;
    RiReal     	vis;
    RiReal     	visError;
};



/***************************************************************
CLASS
    RiConvexHull
     Represents a general convex hull for use by the Rad system for culling objects

DESCRIPTION
     Abstract away the notion of the region of space and RiRadObject occupies.  Allows
     any object to do visibility checks on any other object without
     knowing what the other object is.

IMPLEMENTATION
     Currently this is implement with a maximum number of points of 8.  After 8, the
     hull is represented as a bounding box of the points.

****************************************************************/

class RiConvexHull {
  public:
				// GROUP: Constructors and assignment
				//// Default Constructor
    RiConvexHull();
				// GROUP: Accessors
				//// Add a point to the hull.  The resulting hull will contain all previous
				// points, even if they aren't stored explicitly.
    void AddPoint(const  RiVector3 &pnt);
				//// Get a point defining the hull
    RiVector3 		 GetPoint(int i) const;
				//// Get the number of points defining the hull (<= number added)
    int			 GetNumPoints() const;
  private:
    RiVector3 	pnts[8];
    int 	numPoints;
    bool	isBox;
};


/*
class RiProjectedAreaSphere {
    AddDirection(const RiUnitVector3 &dir, RiFloat weight);
    RiReal GetProjectedArea(const RiVector3 &dir);
};
    
*/



/***************************************************************
CLASS
    RiRadObject
     Abstraction of all operations needed for an object to participate
     in a radiosity simulation.

DESCRIPTION
     All operations needed for an object to participate in a radiosity
     simulation are included here.  This task was made simpler by three other
     classes.  RiRadRegion hides the notion of a sample point on a RiRadObject.
     RiTransferData hides the data needed to describe a transfer, either energy or
     form factors. RiRadData hides the energy and link values and temporaries that
     may be needed by the simulation.

****************************************************************/

class RiRadObject {
  public:
				//// Sets parent to NULL
    RiRadObject();
				//// Empty virtual destructor
    virtual ~RiRadObject(){}
				// GROUP: Members
				//// Fills in the data in sample, and returns the Area Weight
				//   for the sample.  This is the probability density of this
				//   point being chosen (1 over the area of the object for uniform sampling.
    virtual RiReal GetSample(RiRadRegion &sample, const RiVector2 &uv) = 0;
				//// Fills in the data in sample, and returns the Form Factor weight
				//   for the sample to the interestedSample.  interestedSample is used to 
				//   direct the object so that it will hopefully pick a point visible to
				//   the intersted point, reducing variance.  Form Factor weight is
				//   FFdi,dx / p(x)  where p(x) is often the return value from GetSample
    virtual RiReal GetFormFactorSample(RiRadRegion &sample, const RiMaterialRegion &interestedSample,
				       const RiVector2 &uv);
				//// Compute transfer data for links and lighting.  Should eventually
				// include visibility, but currently it does not.
    virtual void	 ComputeTransfer(const RiMaterialRegion &sample, RiTransferData &data) = 0;
				//// Get the Rad Data from the object
    virtual RiRadData  *GetRadData() = 0;
				//// Get a convex hull containing the object
    virtual RiConvexHull GetConvexHull() = 0;
				//// Can the object see the convex hull.  Note that this operation ONLY
				//   involves the object and the hull, not the environment.  This is
				//   the equivalent of back face culling.
    virtual bool	 IsVisible(const RiConvexHull &hull) = 0;
				// GROUP: Structural
				//// Determine the number of children this object has. (0 if no
				//     subdivision has been done	
    virtual int		 GetNumChildren() = 0;
				//// Get the ith child (i MUST be less than GetNumChildren)
    virtual RiRadObject *GetChild(int i) = 0;
				//// Subdivide if possible.  If already subdivided, do nothing. Return
				//  true if subdividable.
    virtual bool	 Subdivide() = 0;
				//// Compute the surface area (or a good estimate of it) of the object
    virtual RiReal	 GetArea() = 0;
				//// find the leaf associated with this sample (If no leaf, return NULL)
    virtual RiRadObject *GetRadObject(const RiMaterialRegion &sample);
				////
    void	 SetParent(RiRadObject *obj);
				////
    RiRadObject *GetParent();
  private:
    RiRadObject *parent;
};






/***************************************************************
CLASS
    RiRadHierarchyBuilder
     Build a ray accelerator from a bunch of ray objects

DESCRIPTION
     <Detailed description with any warnings>

PATTERN
     Builder
     Iterator (sort of.  no Next, no GetCurrent, build does the equivalent of GetCurrent; Next();)
     
WARNINGS
     The RiRadObject returned from the builder is orphaned by the
     builder.  The client is responsible for deleting the object.
     Each call to Build will build the next object, returning NULL if
     no next object.

****************************************************************/

class RiRadHierarchyBuilder {
  public:
				//// Destructor
    virtual ~RiRadHierarchyBuilder() {};
				//// Add an object to the future accelerator
    virtual void 	 AddObject(RiRadObject *) = 0;
				//// Build the RiRadObject and return it.
				// Each call to Build will build and return the next object.
    virtual RiRadObject *Build() = 0;
				//// Some situations result in a RiRadObjectBuilder
				// building more than a single object.  As long as IsDone
				// returns false, there are more objects that need to be built
    virtual bool	 IsDone() = 0;
};


// Should we assume source to point transfer is accurate (for ff and vis?)  It's cleaner and probably
// reasonable, as estimating those errors would be difficult and perhaps not even useful.



#endif /* RIRADOBJECT_H */

