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

		I3DShGroup.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Ray Dream
		Date:	04/16/99

		Revision History

		when		who			what & why
		==========	==========	======================================================
		04/19/99	Charles		Created
*****************************************************************************************/

#ifndef __I3DSHGROUP__
#define __I3DSHGROUP__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCCompObj.h"
#include "ApiTypes.h"
#include "TreeTypes.h"
#include "Transforms.h"
#include "MCCountedPtr.h"

//****** Globally Unique Ids **************************************************
MCDEFINE_GUID_H(IID_I3DShGroup);

// Classes always available
MCDEFINE_GUID_H(CLSID_StandardGroup);


/*****************************************************************************\
*  I3DShGroup                                                                 *
*                                                                             *
*    I3DShGroup is a tree element that can be collapsed ("closed") or not.    *
*    It can return a I3DShTreeElement interface on demand.                    *
*                                                                             *
\*****************************************************************************/

struct RayHitParameters;
struct RayHit3D;
struct I3DShTreeElement;
class  TInstancePath;
template<class T> class TMCClassArray;


/// \addtogroup Data
/// \{

/// Describes all the information used to raytrace an instance. See I3DShGroup::GetRaytracedInstances().
/// The raytraced instances are different from I3DShInstance ! The reason for that is Master Groups.
/// If an instance is placed in a Master Group and the Master Group is instanced twice, there is
/// still only once I3DShInstance however there will be two RaytracedInstance with a different
/// global transform (the transform of I3DShInstance is local to the Master Group that contains it)
/// The index (fIndex) defines a unique identifier over all the raytraced instances.
///
struct RaytracedInstance : public TMCObject
{
	I3DShInstance*					fI;				///< A pointer to the instance
	int32							fIndex;			///< The index of the instance
	TTransform3D					fT;				///< The global transform including the transform of the parent Master Groups.
	TTransform3D					fInvT;			///< The inverse global transform
	boolean							fIsInfinite;	///< True if the instance is infinite.
	TMCCountedPtr<TInstancePath>	fInstancePath;	///< Path of tha t Master Groups that contain this instance.
	boolean							fSelfRaytracable;	///< True if the instance is self raytracable
	boolean							fVolumePrimitive;   ///< True if the instance is a volume primitive
};

/// \}


// Filter function used to select instances. Returns false if the instance should be ignored.
typedef boolean (*InstanceFilterFunction)(const RaytracedInstance& instance);


/// \addtogroup ShellInterface
/// \{

/// Defines a group of objects. Note that such a group cannot be instantiated. To instantied a group
/// you need to turn it into a Master Group (see I3DShMasterGroup) first.
///
/// <P>Other interfaces surported: I3DShTreeElement, I3DShShadableTree, ISelectableObject</P>
///
struct I3DShGroup: public IMCUnknown
{
	// ****************************************************************************
	//								DoOpenClose
	// 
	/// Use this call to open or close a group. When a group is open, its elements
	/// can be manipulated individually.
	/// 
	/// \param openIt  True if the group should be open.
	/// 
	virtual MCCOMErr MCCOMAPI DoOpenClose(boolean openIt) = 0;
	
	// ****************************************************************************
	//								OpenClose
	// 
	/// This lower level call just changes the status. Use  DoOpenClose() instead.
	/// 
	/// \param openIt  True if the group should be open.
	/// 
	virtual MCCOMErr MCCOMAPI OpenClose(boolean openIt) = 0;
	
	// ****************************************************************************
	//								IsOpen
	// 
	/// Return true if the group is open (see DoOpenClose() ).
	/// 
	virtual boolean  MCCOMAPI IsOpen() = 0;
	
	// ****************************************************************************
	//								RayHit
	// 
	/// Calculates the intersection of a ray and all the objects in the group
	/// 
	/// \param param  The parameters of the ray coming in and of the result of the hit.
	virtual boolean  MCCOMAPI RayHit(RayHitParameters &param) = 0;
	
	// ****************************************************************************
	//								RayHitRaytracables
	// 
	/// Calculates the intersection of a ray and all the objects raytracable in the group
	/// 
	/// \param param  The parameters of the ray coming in and of the result of the hit.
	virtual boolean  MCCOMAPI RayHitRaytracables(RayHitParameters &param) = 0;
	
	// intersection of a ray and the group without using instance grid, bboxOnly returns first bounding box intersection ( no facet mesh used )
	// ****************************************************************************
	//								RayHitNoGrid
	// 
	/// Calculates the intersection of a ray and all the objects in the group. This
	/// call is useful when you do not want to take the time to build a grid to
	/// optimize the intersection of the rays. You should use this call if you plan
	/// to send only a few rays before the scene is modified. Use RayHit() if you plan
	/// to send many rays without modify the scene.
	/// 
	/// \param param  The parameters of the ray coming in and of the result of the hit.
	/// \param bboxOnly  True if the hit should only consider the bounding boxes and not the geometry.
	/// 
	virtual boolean	 MCCOMAPI RayHitNoGrid(RayHitParameters &param, boolean bboxOnly, InstanceFilterFunction filter=NULL) =0;

	// ****************************************************************************
	//								GetBoundingBox
	// 
	/// Returns the bounding box of the group.
	/// 
	/// \param bbox        The bounding box that is returned.
	/// \param deformMode  Defines how the deformers are applied to calculate to bbox. (see ETreeDeformBBoxModes)
	/// \param rendering   True if you want a bounding box for rendering or just for previewing
	/// 
	virtual void	 MCCOMAPI GetBoundingBox(TBBox3D &bbox, ETreeDeformBBoxModes deformMode, boolean rendering=true) = 0;

	// ****************************************************************************
	//								GetRaytracedInstances
	// 
	/// Returns the list of instances used for the raytracing (except for infinite primitives).
	/// Note that the index in this array is the same as the fInstanceIndex field of RayHit3D as
	/// well as the originInstanceIndex field of RayHitParameters.
	/// 
	virtual const TMCClassArray<RaytracedInstance>& MCCOMAPI GetRaytracedInstances() = 0;

	// ****************************************************************************
	//								GetTreeElement
	// 
	/// Returns a pointer to the I3DShTreeElement interface.
	/// 
	virtual I3DShTreeElement* MCCOMAPI GetTreeElement	() = 0;

	// ****************************************************************************
	//								CanSelectChildren
	// 
	/// Returns true if the user can select the children of the group.
	/// 
	virtual boolean				MCCOMAPI CanSelectChildren() = 0;

	// ****************************************************************************
	//								GetSelectChildrenWhenClosed
	// 
	virtual boolean				MCCOMAPI GetSelectChildrenWhenClosed() = 0;

	// ****************************************************************************
	//								SetSelectChildrenWhenClosed
	// 
	virtual void				MCCOMAPI SetSelectChildrenWhenClosed(boolean value) = 0;
};

/// \}

#endif