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

		I3DExModifier.h

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

		I3DExModifier definition

		Author:	Joshua
		Date:	9/29/98

		Revision History

		when		who					what & why
		==========	=================	======================================================
		09/28/99	Mathieu				GetMaxTimeWithoutComputation()
		08/26/99	cph					Added family ids
		08/10/99	Arnaud				sFacetMesh is now counted.
		08/11/99	Guillaume&Christy	Added inheritance to all the Basic* classes
		9/29/98		Joshua				Created

*****************************************************************************************/
#ifndef __I3DEXMODIFIER__
#define __I3DEXMODIFIER__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "IExtension.h"
#include "APITypes.h"
#include "InterfaceIDs.h"
#include "BitField.h"


//****** Globally Unique Ids *************************************************
MCDEFINE_GUID2(IID_I3DExModifier, R_IID_I3DExModifier);

//****** Family Id *************************************************

const FourCharT kModifierFamilyID = kRID_ModifierFamilyID;


/*****************************************************************************\
*  I3DExModifier                                                              *
\*****************************************************************************/

struct TDeformInfo;
struct FacetMesh;

/// \addtogroup Data 
/// \{

///	Flags used with I3DExModifier::GetModifierFlags 
///
struct TModifierFlags : public TBitField32
{
	enum
	{
		kTreeModifier		= ( 1 << 0 ), ///< The modifier performs changes on the tree	(behavior in RDS)
		kDeformModifier		= ( 1 << 1 ), ///< The modifier changes the geometry			(deformer in RDS)
		kDisableBackFacing	= ( 1 << 2 )  ///< The modifier opens the geometry and needs to turn off back face culling	(eg explode)
	};

	inline TModifierFlags() : TBitField32( 0 )		{ }

	/// Returns true if the modifier performs changes on the tree (behavior in RDS)
	///
	inline boolean IsTreeModifier()			const	{ return TestMasked( kTreeModifier ); }

	/// Returns true if the modifier changes the geometry (deformer in RDS)
	///
	inline boolean IsDeformModifier()		const	{ return TestMasked( kDeformModifier ); }

	/// Returns true if The modifier opens the geometry and needs to turn off back face culling	(eg explode)
	///
	inline boolean IsBackfacingDisabled()	const	{ return TestMasked( kDisableBackFacing ); }
};
/// \}

#ifndef qDemoVersion //regular interface


/// \addtogroup ExternalInterface
///
/// \{


/// The I3DExModifier Interface is used to apply modifiers to any object or group of objects
/// of the scene, that is any tree except the universe. They can affect the transform of the
/// tree (position and scaling) and the geometry of the objects that belong to the tree.
///
/// For modifiers that change the geometry, you need to implement ::SetBoundingBox, 
/// and either DeformPoint or DeformFacetMesh.
///	If you choose to implement DeformPoint, the application will subdivide the object's mesh.
/// Implementing GetDeformerInfo enables you to "guide" the subdivision process.
///	If you don't implement DeformVertex3D a default implementation will be used.
///
struct I3DExModifier : public IMCUnknown
{
	// ****************************************************************************
	//								GetModifierFlags
	// 
	/// Returns the flags associated with the modifier.
	///
	virtual TModifierFlags MCCOMAPI GetModifierFlags() = 0;

	// ****************************************************************************
	//								Apply
	// 
	/// Gives access to all the parameters of the tree the modifier is on. To implement
	/// a behavior, just change the transforms.
	///
	/// \param tree The tree to which the modifier is applied
	///
	virtual MCCOMErr   MCCOMAPI Apply(I3DShTreeElement* tree) = 0;

	// ****************************************************************************
	//								GetMaxTimeWithoutComputation
	// 
	/// Tells the shell how much cached data the behavior has (starting at zero).
	///
	/// \param tree The tree to which the modifier is applied
	///
	virtual MicroTick  MCCOMAPI GetMaxTimeWithoutComputation (I3DShTreeElement* tree) = 0;

	// ****************************************************************************
	//								IsIKTerminator
	// 
	/// Returns true if the modifier is an IK Terminator.
	/// \param outExcludeFromChain	Tells if the tree should be excluded from the chain.
	///
	virtual boolean	   MCCOMAPI IsIKTerminator	(boolean& outExcludeFromChain) const = 0;

	// ****************************************************************************
	//								SetBoundingBox
	// 
	/// Is called by the 3D Shell to tell the 3D deformation modifier in which boundaries
	/// the 3D data to deform is going to be. This is the bounding box of the facet mesh
	/// before the deformation is applied.
	///
	/// \param bbox The Bounding Box
	///
	virtual void	   MCCOMAPI SetBoundingBox	(const TBBox3D& bbox) = 0;

	// ****************************************************************************
	//								DeformPoint
	// 
	/// Computes result of the deformation of a given point (in local coordinates).
	/// DeformPoint is called by the shell if you do not implement DeformFacetMesh or DeformVertex3D
	/// (the shell will automatically subdivide the facet mesh to achieve a smooth deformation).
	///
	/// \param point The point that needs to be moved
	/// \param result The position of the point after deformation.
	///
	virtual MCCOMErr   MCCOMAPI DeformPoint		(const TVector3 & point,  TVector3 & result) = 0;

	// ****************************************************************************
	//								DeformVertex3D
	// 
	/// Computes the result of the deformation of a given vertex (in local coordinates).
	/// DeformVertex3D called by the 3D Shell if you do not implement DeformFacetMesh
	/// (the shell will automatically subdivide the facet mesh to achieve a smooth deformation).
	///
	/// \param vertex The vertex that needs to be moved
	/// \param result The vertex after deformation.
	///
	/// \return MC_S_OK if it is implemented, MC_E_NOTIMPL if not.
	///
	virtual MCCOMErr   MCCOMAPI DeformVertex3D	(const TVertex3D& vertex, TVertex3D& result) = 0;

	// ****************************************************************************
	//								DeformFacetMesh
	// 
	/// <P>Deforms or creates 3D facets. Given the original facet mesh of a primitive, 
	/// it  produces a (new) deformed mesh. You can modify whatever you want on the mesh:
	/// you can add or remove vertices, normals, facets, or change their position.</P>
	///
	/// <P>But you should NOT modify the in mesh. You need to create a new mesh and return
	/// it in outMesh (yet you can clone in to outMesh and then change outMesh). </P>
	///
	/// If the parameters of your deformer won't deform the mesh, you can have outMesh reference
	/// in thus:
	///
	/// \code
	/// TMCCountedGetHelper<FacetMesh> result(outMesh); result= in;
	/// \endcode
	///
	/// \param lod Level of detail (LOD) of the output mesh (0 is the best quality)
	/// \param in The facet mesh that needs to be deformed.
	/// \param outMesh The mesh after deformation
	///
	/// \return MC_S_OK if it is implemented, MC_E_NOTIMPL if not.
	///
	virtual MCCOMErr   MCCOMAPI DeformFacetMesh	(real lod,FacetMesh* in, FacetMesh** outMesh) = 0;

	// ****************************************************************************
	//								DeformBBox
	// 
	/// Returns an approximation of how the modifier affects a given zone of space
	/// contained in the box in, and returns the box that encompass the deformed space in out.
	///
	/// \param in The bounding box before deformation (in local coordinates)
	/// \param out The bounding box after deformation (in local coordinates)
	///
	/// \return MC_S_OK if it is implemented, MC_E_NOTIMPL if not.
	///
	virtual MCCOMErr   MCCOMAPI DeformBBox		(const TBBox3D& in,TBBox3D& out) = 0;

	// ****************************************************************************
	//								GetNeededLOD
	// 
	/// Returns the level of detail the modifier needs to produce a result at the
	/// precision outputLOD.
	///
	/// \param outputLOD The desired output precision
	/// \param neededLod The necessary input precision to get that result.
	///
	virtual MCCOMErr   MCCOMAPI GetNeededLOD	(const real outputLOD, real& neededLod) = 0;

	// ****************************************************************************
	//								GetDeformerInfo
	// 
	/// Returns information about the modifier. If you implement only DeformPoint
	/// or DeformVertex3D and not DeformFacetMesh, use this function to give the shell
	/// some directions to guide the facet mesh subdivision process.
	///
	/// \param lod The level of detail
	/// \param deformInfo The deformer information.
	///
	virtual MCCOMErr   MCCOMAPI GetDeformerInfo	(real lod, TDeformInfo& deformInfo) = 0;

	// ****************************************************************************
	//								BeginRendering
	// 
	/// Is called just before a rendering
	/// 
	virtual void	 MCCOMAPI BeginRendering() { };

	// ****************************************************************************
	//								EndRendering
	// 
	/// 
	/// Is called just after a rendering
	/// 
	virtual void	 MCCOMAPI EndRendering() { };

	///	Returns true if the modified needs to be updated (called by the shell when the time changed).
	///
	virtual boolean	 MCCOMAPI ModifierChanged() = 0;
};

/// \}


#else 	//(qDemoVersion) begin scrambled interface

struct I3DExModifier : public IMCUnknown
{
	virtual MCCOMErr   MCCOMAPI GetDeformerInfo	(real lod, TDeformInfo& deformInfo) = 0;	
	virtual MCCOMErr   MCCOMAPI DeformFacetMesh	(real lod,FacetMesh* in, FacetMesh** outMesh) = 0;		
	virtual MCCOMErr   MCCOMAPI DeformVertex3D	(const TVertex3D& vertex, TVertex3D& result) = 0;
	virtual MicroTick  MCCOMAPI GetMaxTimeWithoutComputation (I3DShTreeElement* tree) = 0;
	virtual void	   MCCOMAPI SetBoundingBox	(const TBBox3D& bbox) = 0;	
	virtual MCCOMErr   MCCOMAPI DeformPoint		(const TVector3 & point,  TVector3 & result) = 0;
	virtual boolean	   MCCOMAPI IsIKTerminator	(boolean& outExcludeFromChain) const = 0;
	virtual MCCOMErr   MCCOMAPI Apply(I3DShTreeElement* tree) = 0;
	virtual void	 MCCOMAPI BeginRendering() { };
	virtual void	 MCCOMAPI EndRendering() { };
	virtual MCCOMErr   MCCOMAPI DeformBBox		(const TBBox3D& in,TBBox3D& out) = 0;
	virtual MCCOMErr   MCCOMAPI GetNeededLOD	(const real outputLOD, real& neededLod) = 0;
	virtual TModifierFlags MCCOMAPI GetModifierFlags() = 0;	
};

#endif	//(qDemoVersion) end scrambled
	

/// Information returned by GetDeformerInfo to control the deformation when you don't implement DeformFacetMesh.
///
struct TDeformInfo
{
	boolean			fHasNoEffect;			///< Set this field to true if your current settings will not modify any object (eg stretch at 100%)
	uint8			fMaxRecursionLevel;		///< Maximun level of recursive subdivision.	
	real32			fMaxSizeSq;				///< Square of the size over which you always want to subdivide a facet's side.
	real32			fMaxErrorSq;			///< Square of the error over which you always want to subdivide a facet's side.
	real32			fNormalsAngleCos;		///< If the cosine of the angle between the normals of a side is below this, cuts the side.
	uint32			fDeformBBoxMethod;		///< Fill this if you don't implement DeformBBox (use the defines in I3DExModifier.h).
};


//Defines for TDeformInfo::fDeformBBoxMethod
#define kDeformBBox_None		0	///< deformed bbox is the same than the non deformed
#define kDeformBBox_Points		1	///< deform the summits of the bbox faces and their center, and add them to the bbox
#define kDeformBBox_Line		2	///< deforms the edges of the original bbox
#define kDeformBBox_Surface		3	///< deforms the sides of the original bbox
#define kDeformBBox_Volume		4	///< volumic sampling


#endif
