// -*- C++ -*-
#ifndef RIBBOX_H
#define RIBBOX_H
/* Copyright 1996 
 * Wed Mar 26 10:03:14 1997  Brian Edward Smits  (bes@burn.cs.utah.edu)
 * 
 * RiBBox.H
 * 
 *	
 * 
 * $Id: RiBBox.H,v 1.6 1999/07/15 00:06:54 bes Exp $ 
 * 
 */
#ifndef RICOMMON_H
#include <RiCommon.H>
#endif

#ifndef RIRIINTERVAL_H
#include <RiInterval.H>
#endif

#ifndef RIVECTOR3_H
#include <RiVector3.H>
#endif


class RiRayObject;

/***************************************************************
CLASS
    RiBBox
    Bounding Box for 3D objects.

DESCRIPTION
    Currently an axis aligned bounding box.  This class stores
    nothing, it just represents a region of space.  

THEORY
    from Arvo & Kirk Survey of Ray Tracing Acceleration (in Glassners Ray Tracing Book)
    based on the Goldsmith and Salmon article
    EXAMPLE
       IC(A) = Sum( EC(Bi) + (Area(Bi) / Area(A)) * IC(Bi) )
       IC(A) = Sum( EC(Bi) ) + (1 / Area(A)) * Sum( Area(Bi) * IC(Bi) )
       IC(A) = Sum( EC(Bi) ) + (1 / Area(A)) * Sum( AIC(Bi) )
       IC(A) = sum_EC  + (1 / Area(A)) * sum_AIC

       AIC(A) = Area(A) * IC(A)
       AIC(A) = Area(A) * Sum( EC(Bi) + (Area(Bi) / Area(A)) * IC(Bi) )
       AIC(A) = Area(A) * Sum( EC(Bi) ) +  Sum( Area(Bi) * IC(Bi) )
       AIC(A) = Area(A) * Sum( EC(Bi) ) + Sum( AIC(Bi) )
       AIC(A) = Area(A) * sum_EC  + sum_AIC
    END
    
****************************************************************/

class RiBBox {
  public:
				////
    RiBBox();
				////
    RiBBox(RiInterval x, RiInterval y, RiInterval z);
				////
    RiBBox(RiRayObject *obj);
				////
    RiReal  	 	 GetArea();
				////
    RiBBox 	 operator|(const RiBBox &) const;
				////
    const RiBBox &operator|=(const RiBBox &);
				////
    const RiBBox &operator&=(const RiBBox &);
				////
//    void AddPoint(const RiVector3 &pnt);
				////
    bool Intersect(RiReal bmin, RiReal bmax, RiReal *num, RiReal *den) const;
				////
    bool IntersectPPP(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectPPM(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectPMP(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectPMM(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectMPP(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectMPM(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectMMP(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    bool IntersectMMM(RiReal bmin, RiReal bmax, const RiReal *num, const RiReal *den) const;
				////
    RiInterval	GetSlab(int i) const;
				////
    RiInterval  GetMinMax(const RiUnitVector3 &dir) const ;
  private:
				////
    RiInterval xSlab;
				////
    RiInterval ySlab;
				////
    RiInterval zSlab;    
};


/***************************************************************
CLASS
    RiBBoxNode
     A bounding box with the notion of a hierarchy of RiBBox and
     storage of RiRayObject

DESCRIPTION
    Holds RiRayObject in a tree while the hierarchy is being built.  The
    tree is then cleaned up and converted into an RiBBoxArray for efficient
    traversal.

WARNINGS
    User is responsible for cleaning up all RiRayObject and RiBBoxNode stored
    in a node.  
    
****************************************************************/

class RiBBoxNode : public RiBBox {
  public:
    RiBBoxNode();
    RiBBoxNode(RiRayObject *);

    RiReal  	 EC();
    RiReal  	 AIC();
    RiReal  	&SumEC();
    RiReal	&SumAIC();

    RiBBoxNode	*&SkipNode() {return skip;}
    RiBBoxNode	*&LeftChild();
    RiBBoxNode	*&RightSibling();
    RiBBoxNode	*&Parent();
    RiRayObject	*&Primitive();

    RiBBoxNode	 *SkipNode() 	 const {return skip;}
    RiBBoxNode	 *LeftChild() 	 const;
    RiBBoxNode	 *RightSibling() const;
    RiBBoxNode	 *Parent() 	 const;
    RiRayObject	 *Primitive() 	 const;

    void	  SwapData(RiBBoxNode &node2);
    int	  NumChildren() const;
    // create new node, *this & *sib become children (sib is an empty node allocated by the caller)
    void  AddAsSibling(RiBBoxNode *child, RiBBoxNode *sib); 
    void  AddAsChild(RiBBoxNode *child);  		// not if *this has primitive (use AddAsSibling)

  private:
    RiBBoxNode  *skip;
    RiBBoxNode  *parent;
    RiBBoxNode  *leftChild;
    RiBBoxNode  *rightSibling;
    RiRayObject *primitive;

    RiReal	 sec;
    RiReal	 saic;
};


/***************************************************************
CLASS
    RiBBoxArray
     An efficient representation of a bounding box hiearchy.

DESCRIPTION
    Store the tree in depth first order with a pointer to the node to
    go to if this node is missed.

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

class RiBBoxArray : public RiBBox {
  public:
    // GROUP: Constructors and assignment
    //// Default Constructor
    RiBBoxArray();
    //// 
    RiBBoxArray(const RiBBoxNode *node, RiBBoxArray *skip);
    // GROUP: Accessors
				////
    RiRayObject *GetPrimitive();
				////
    RiBBoxArray *GetSkip();
  private:
    RiBBoxArray *skip;
    RiRayObject *primitive;
};

inline RiRayObject *RiBBoxArray::GetPrimitive()
{
    return primitive;
}

inline RiBBoxArray *RiBBoxArray::GetSkip()
{
    return skip;
}

#endif /* RIBBOX_H */

