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

		PublicUtilities.h

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

		Author:	Ray Dream
		Date:	3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		10/28/99	EricB		More generic constructor for TTreeElementSonsIterator
		09/28/99	Yann		More optimization on the Scene iterators : added IsElemCountEqualTo() and IsElemCountMoreThan()
		09/15/99	Yann		Optimization of the Scene iterators !
		08/10/99	Arnaud		FacetMesh is now counted.
		7/2/99		Ian			TSceneSelectionIterator<T>::First() Use counted ptr.
		4/30/99		Yann		Extracted TBBox3D and TBBox2D from PublicUtilities.h/.cpp
								to avoid getting zillions of unneeded stuff, and moved it
								to a new file : TBBox.h/.cpp (same folder)
		4/20/99		Greg		ISceneSelection uses arrays instead of linked lists
		3/9/99		Joshua		Added FrameToString and TimeToString
		2/8/99		Joshua		Added TTreeUndoInfo
		10/27/98	Alec		added GetWidth/Height/Depth routines to the bbox,
									need to combined TBoundingBox and these into one class
		9/24/98		Joshua		made vertex iterator non-const again for existing
								modifier code
		9/23/98		Alec		facet iterators back to const so IR compiles, probably
									going away anyways

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

#ifndef __PUBLICUTILITIES__
#define __PUBLICUTILITIES__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "COMTypes.h"
#include "MCPtrArray.h"
#include "MCPtr.h"
#include "MCCountedPtr.h"
#include "ISceneSelection.h"
#include "I3DShObject.h"
#include "I3dShFacetMesh.h"
#include "Id.h"
#include "Transforms.h"

struct ISceneSelection;
struct I3DShTreeElement;
class  TSelectionNode;
class  TBBox2D;
class  TBBox3D;
class  TMCRect;
struct IShMasterSound;
struct IShSound;
struct I3DShMasterShader;
struct I3DShMasterGroup;
struct I3DShMasterClip;


/*****************************************************************************\
*                                                                             *
*   Misc Utils                                                                *
*                                                                             *
\*****************************************************************************/

boolean IsEqualObject(IMCUnknown* interface1, IMCUnknown* interface2);

boolean Contains(I3DShTreeElement* This,I3DShTreeElement* SubTree);

void TimeToString(const MicroTick time, const int16 fps, TMCString& str);
void FrameToString(const MicroTick time, const int16 fps, TMCString& str);


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

template <class T>  void GetSelectedObjects(ISceneSelection* inSelection, const MCIID& riid, TMCCountedPtrArray<T>& objects)
{
	if (inSelection)
	{
		const int32 objCount = inSelection->GetObjectCount();
		for (int32 i=0; i<objCount; i++)
		{
			TMCCountedPtr<T> obj;
			inSelection->GetTypedObjectByIndex(i, riid, (void**)&obj);
			if (obj)
			{
				objects.AddElem(obj);
			}
		}
	}
	return;
}

void ComputeVisibleViewPane(
		const TMCRect& 	windowContentRect,
		const TMCRect& 	windowVisibleRect,
		TBBox2D&		viewBox);


/*****************************************************************************\
*                                                                             *
*   Tree Undo Helper Utils                                                    *
*                                                                             *
\*****************************************************************************/
class TTree;

/// Used to restore the position of a tree and of its parents (when doing Inverse Kinematics they all move)
///
class TTreeUndoInfo : public TMCObject
{
private:
	TMCCountedPtrArray<I3DShTreeElement> fTrees;
friend class TTree;
};

/// \addtogroup Data
/// \{

//******************************************************************
//
// Selection Iterators
//
//******************************************************************

/// Iterates only over the elements of the scene selection that support a given interface
///
template <class T> class TSceneSelectionIterator : public TMCObject
{
public:
			TSceneSelectionIterator(ISceneSelection* selection, const MCIID& iid, IDType objectKind, boolean alwaysQuery);
			~TSceneSelectionIterator();	

	T* 		First();							///< returns NULL if there are no elements with the wanted interface
	T* 		Next();								///< returns NULL if there are no more elements
	uint32	GetElemCount();						///< Return the number of elements that we shall scan (slow)
	boolean	IsElemCountEqualTo(uint32 count);	///< Use this to bail out more quickly than when using GetElemCount(), which can be a waste 
												///< if you are interested in a specific count.
	boolean IsElemCountMoreThan(uint32 count);	///< Same idea as IsElemCountEqualTo(). Return true if (GetElemCount() > count)

	boolean IsSelectionUniform	();				///< Returns true if all the elements have the same iid (or objectKind)

protected:
	T*		FindNextFromCurrentPosition();
	boolean	GetElemCount(uint32 minCount, uint32 maxCount, uint32& count);

	virtual boolean IsValidObject(T* object) { return true; }

private:
	ISceneSelection*	fSelection;
	MCIID				fIID;
	IDType				fObjectKind;
	uint32				fCurrentIndex;
	boolean				fAlwaysQuery;
};

/// \}

template <class T> TSceneSelectionIterator<T>::TSceneSelectionIterator(	ISceneSelection*	selection, 
																		const MCIID&		iid,
																		IDType				objectKind,
																		boolean				alwaysQuery)
{
	ThrowIfNil(selection);
	fSelection		= selection;
	fIID			= iid;
	fObjectKind		= objectKind;
	fCurrentIndex	= 0;
	fAlwaysQuery	= alwaysQuery;
}

template <class T> TSceneSelectionIterator<T>::~TSceneSelectionIterator()
{
}

template <class T> T* TSceneSelectionIterator<T>::FindNextFromCurrentPosition()
{
	const int32 objCount = fSelection->GetObjectCount();
	for (int32 objNdx= fCurrentIndex; objNdx < objCount; objNdx++)
	{
		const TSelectionNode& lastNode = fSelection->GetSelectionPathByIndex(objNdx).LastElem();
		if (lastNode.fSelectedObjectKind == fObjectKind)
		{
			ISelectableObject* leaf= fSelection->GetSelectableObjectByIndex(objNdx);
			
			if (MCVerify(leaf))
			{
				TMCCountedPtr<T> pT;
				leaf->QueryInterface(fIID,(void**)&pT);
				if (pT && IsValidObject(pT))
				{
					return pT;
				}
			}
		}
		fCurrentIndex++;
	}

	return NULL;
}

template <class T> boolean TSceneSelectionIterator<T>::GetElemCount(uint32 minCount, uint32 maxCount, uint32& count)
{
	uint32 result = 0;

	const int32 objCount = fSelection->GetObjectCount();
	for (int32 objNdx= fCurrentIndex; objNdx < objCount; objNdx++)
	{
		const TSelectionNode& lastNode = fSelection->GetSelectionPathByIndex(objNdx).LastElem();
		if (lastNode.fSelectedObjectKind == fObjectKind)
		{
			if (fAlwaysQuery)
			{
				ISelectableObject* leaf= fSelection->GetSelectableObjectByIndex(objNdx);
				if (MCVerify(leaf))
				{
					TMCCountedPtr<T> pT;
					leaf->QueryInterface(fIID,(void**)&pT);
					if (pT && IsValidObject(pT))
					{
						result++;
					}
				}
			}
			else
				result++;

			if (result > maxCount)
				return false;

			if (result + objCount - objNdx -1 < minCount) //even if all remaining objects match we won't reach minCount => bail
				return false;
		}
	}

	count = result;
	return true;
}

template <class T> T* TSceneSelectionIterator<T>::First()
{
	fCurrentIndex = 0;
	return FindNextFromCurrentPosition();
}

template <class T> T* TSceneSelectionIterator<T>::Next()
{
	fCurrentIndex++;
	return FindNextFromCurrentPosition();
}

template <class T> uint32 TSceneSelectionIterator<T>::GetElemCount()
{
	uint32 result = 0;
	GetElemCount(0, kUnusedIndex, result);
	return result;
}

template <class T> boolean TSceneSelectionIterator<T>::IsElemCountEqualTo(uint32 count)
{	
	// Use this to bail out more quickly than when using GetElemCount(), which can be a waste 
	// if you are interested in a specific count
	uint32 result = 0;
	if (!GetElemCount(0, count, result))
		return false;
	else
		return result == count;
}

template <class T> boolean TSceneSelectionIterator<T>::IsElemCountMoreThan(uint32 count)
{	
	// Return true if GetElemCount() > count
	// Use this to bail out more quickly than when using GetElemCount(), which can be a waste 
	// if you are interested in a specific count
	uint32 result = 0;
	if (!GetElemCount(0, count, result))
		return true;
	else
		return result > count;
}

template <class T> boolean TSceneSelectionIterator<T>::IsSelectionUniform()
{	
	const int32 selectedCount= fSelection->GetObjectCount();
	uint32 result = 0;
	return GetElemCount(selectedCount, selectedCount, result);
}


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

/// Iterates only over the selected tree elements (I3DShTreeElement)
///
class TTreeSelectionIterator : public TSceneSelectionIterator<I3DShTreeElement>
{
public:
		TTreeSelectionIterator(ISceneSelection* selection);
		~TTreeSelectionIterator();
};

/// Iterates only over the selected master objects (I3DShObject)
/// Note that scenes are excluded from that list.
class TMasterObjectSelectionIterator : public TSceneSelectionIterator<I3DShObject>
{
public:
		TMasterObjectSelectionIterator(ISceneSelection* selection);
		~TMasterObjectSelectionIterator();

		virtual boolean IsValidObject(I3DShObject* object);
};

/// Iterates only over the selected master shaders (I3DShMasterShader)
///
class TMasterShaderSelectionIterator : public TSceneSelectionIterator<I3DShMasterShader>
{
public:
		TMasterShaderSelectionIterator(ISceneSelection* selection);
		~TMasterShaderSelectionIterator();
};

/// Iterates only over the selected master clips (I3DShMasterClip)
///
class TMasterClipSelectionIterator : public TSceneSelectionIterator<I3DShMasterClip>
{
public:
		TMasterClipSelectionIterator(ISceneSelection* selection);
		~TMasterClipSelectionIterator();
};

/// Iterates only over the selected master sounds (IShMasterSound)
///
class TMasterSoundSelectionIterator : public TSceneSelectionIterator<IShMasterSound>
{
public:
		TMasterSoundSelectionIterator(ISceneSelection* selection);
		~TMasterSoundSelectionIterator();
};

/// Iterates only over the selected sound instance (IShSound)
///
class TSoundInstanceSelectionIterator : public TSceneSelectionIterator<IShSound>
{
public:
		TSoundInstanceSelectionIterator(ISceneSelection* selection);
		~TSoundInstanceSelectionIterator();
};


//******************************************************************
//
// I3DShTreeElement Iterators
//
//******************************************************************
static boolean NeverOpen(I3DShTreeElement* /*tree*/)
{
	return false;
}

static boolean AlwaysOpen(I3DShTreeElement* /*tree*/)
{
	return true;
}

/// \addtogroup Data
/// \{

/// iterates over a tree element and its sons
///
class TTreeElementIterator : public TMCObject
{
	public:
						TTreeElementIterator(I3DShTreeElement* treeBase);	
						TTreeElementIterator(I3DShTreeElement* treeBase, boolean goInside, boolean skipRoot, boolean (*filter)(I3DShTreeElement *tree), boolean (*isOpen)(I3DShTreeElement *aTree));	
						~TTreeElementIterator();	

		I3DShTreeElement* 	First();
		boolean 			More() { return fTreeBase != NULL; }
		I3DShTreeElement* 	Next();

		int32 			GetIndex() const;
		int16 			GetLevel() const;

	protected:

		I3DShTreeElement* 		fTreeBase;
		I3DShTreeElement* 		fRoot;

		boolean 		(*fFilter)(I3DShTreeElement *aTree); 
		boolean 		(*fIsOpen)(I3DShTreeElement *aTree);

		boolean 		fGoInside; 
		boolean 		fSkipRoot; 

		int32 			fIndex;
		int16 			fLevel;
};

//******************************************************************
	
/// Same as TTreeIterator, but only iterates through I3DShTreeElements 
/// for which filter(tree) returns true
///
class TTreeElementFilterIterator : public TTreeElementIterator
{
	public:
 		TTreeElementFilterIterator(I3DShTreeElement* treeBase,
 							boolean (*filter)(I3DShTreeElement *tree));
};


/// iterates over the direct sons of a tree element
///
class TTreeElementSonsIterator : public TTreeElementIterator
{	
	public:
		TTreeElementSonsIterator(I3DShTreeElement* treeBase,
  							   boolean (*isOpen)(I3DShTreeElement *aTree) = NeverOpen);
};

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

/// Iterates over the open sons of a tree element.<BR>
/// Example: TTreeElementClosedBoxIterator iterSubSelection(tree, IsTreeOpen, false);
///
class TTreeElementClosedBoxIterator : public TTreeElementIterator 
{
	public:
  		TTreeElementClosedBoxIterator(I3DShTreeElement* treeBase,
  							   boolean (*isOpen)(I3DShTreeElement *aTree), 
  							   boolean goinside = true);
};

// ****************************************************************************
//								TTreePathIterator
// 
/// Iterates over a whole scene going inside the MasterGroups
///	
class TTreePathIterator : public TMCObject 
{
public:
	TTreePathIterator(I3DShTreeElement* treeBase);	
	~TTreePathIterator();

	I3DShTreeElement*	MCCOMAPI First	();
	boolean 			MCCOMAPI More	() { return fTreeBase != nil; }
	I3DShTreeElement* 	MCCOMAPI Next	(boolean skipFirstMaster=false);

	TTreeIdPath			MCCOMAPI GetTreeIDPath	() const;
	int16				MCCOMAPI GetLevel		() const { return fRoots.GetElemCount(); }
	void				MCCOMAPI GetTransform3D	(TTransform3D& outTransform) const;

	void				MCCOMAPI SetSkipRoots	(boolean skipRoots)	{ fSkipRoots= skipRoots; } //skips the root of each master group

protected:
	I3DShTreeElement* 				fTreeBase;
	TMCPtrArray<I3DShTreeElement>	fRoots;
	TMCPtrArray<I3DShTreeElement>	fBack;
	TMCArray<TTransform3D>			fTransforms;

	boolean 		(*fFilter)(I3DShTreeElement *aTree); 

	boolean 		fSkipRoots; 

	TTreeIdPath		fPath;
};

// ****************************************************************************
//								TTargetPathIterator
// 
/// Iterates along a path to a target instance
/// 
class TTargetPathIterator : public TMCObject
{
public:
	TTargetPathIterator(const TTreeIdPath& inPath, I3DShMasterGroup* inRoot) { fPath = inPath; fRoot = inRoot; }

	I3DShTreeElement*	MCCOMAPI First	();
	boolean				MCCOMAPI More	() { return fTree && !fCurrentPath.isRoot(); }
	I3DShTreeElement*	MCCOMAPI Next	();

private:
	TTreeIdPath fPath, fCurrentPath;
	TMCPtr<I3DShMasterGroup> fCurrent;
	TMCPtr<I3DShMasterGroup> fRoot;
	TMCPtr<I3DShTreeElement> fTree;
};

/// \}


/*****************************************************************************\
*                                                                             *
*   FacetMesh Utils                                                           *
*                                                                             *
\*****************************************************************************/


/// \addtogroup Data
/// \{

//****************************************************
//						FacetMeshIterator
//
/// Iterates over a FacetMesh. Note that it is a pretty inefficient way
/// to iterate over a FacetMesh and it is usually better to directly
/// access the FacetMesh.
///
/// <P>usage :</P>
///
/// \code
///
/// while (iter.Next()) 
/// {
///    value=iter.Get...();
/// }
///
/// \endcode
///
class FacetMeshIterator : public TMCObject
{
public:
				FacetMeshIterator(const FacetMesh* mesh);
				FacetMeshIterator();

	/// Initialiaze the iterator.
	void		Initialize(const FacetMesh* mesh);

	int32		GetIndexA()    const { MCAssert(fCurrentFacet); return fCurrentFacet->pt1;}
	int32		GetIndexB()    const { MCAssert(fCurrentFacet); return fCurrentFacet->pt2;}
	int32		GetIndexC()    const { MCAssert(fCurrentFacet); return fCurrentFacet->pt3;}
	uint32		GetUVSpaceID() const { if (fHasUVSpaces) return (*fUVSpaceID)[fCurIndex]; else return 0;}

	/// Move to the first element in the mesh.
	void		First() { fCurIndex=0; }

	/// Moves to the next triangle in the mesh.
	void		Next()  { fCurIndex++; }

	/// Returns true if there are more triangles in the mesh
	boolean     More();

protected:
	boolean						fHasUVSpaces;
		//fHasUVSpaces is false if there is not the same number of facets and ucSpacesID.
		//in that case GetUVSpaceID returns zero

	uint32					 	fCurIndex; // index in the facet Mesh
	const TMCArray<Triangle>*	fFacets;
	const TMCArray<uint32>*		fUVSpaceID;
	const Triangle*				fCurrentFacet;
	TMCCountedPtr<FacetMesh>	fFacetMesh;		//so that the facet mesh doesn't get deleted while we reference its fields (Arnaud)
};


/// \}


inline boolean FacetMeshIterator::More()
{
	if (fCurIndex < fFacets->GetElemCount() )
	{
		fCurrentFacet=&((*fFacets)[fCurIndex]);
		return true;
	}
	else
	{
		fCurrentFacet=NULL;
		return false;
	}
}

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

class FacetMeshFacetIterator : public FacetMeshIterator
{
public:
					FacetMeshFacetIterator(const FacetMesh* mesh);
					FacetMeshFacetIterator();

	void			Initialize(const FacetMesh* mesh);
	const TFacet3D&	GetFacet() const {return fFacet;}

	boolean			More();

protected:
	boolean						 fHasNormals;
		//fHasNormals is false if there is not the same number of vertices and normals.
		//in that case the normal is calculated assuming the facet is right handed
	boolean						 fHasUVs;
		//fHasUVs is false if there is not the same number of vertices and UVs.
		//in that case the uv are set at zero.
	TFacet3D					 fFacet;
	const TMCArray<TVector3>*	 fVertices;
	const TMCArray<TVector3>*	 fNormals;
	const TMCArray<TVector2>*	 fuv;
};

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

// this and co to be removed (per arnaud)
class FacetMeshVertexIterator : public TMCObject
{
public:
	FacetMeshVertexIterator(FacetMesh* mesh) : fCurIndex(kUInt32Minus1),fVertices(mesh->fVertices),fNormals(mesh->fNormals),fuv(mesh->fuv)
	{
		fVerticesNbr= mesh->fVertices.GetElemCount();
		fFacetMesh= mesh;
	}

	void		 First() { fCurIndex=0; }
	void		 Next()  { fCurIndex++; }
	boolean		 More()  { return fCurIndex<fVerticesNbr; }
	
	TVector3	&GetVertex() const { return fVertices[fCurIndex]; }
	TVector3	&GetNormal() const { return fNormals[fCurIndex];   }
	TVector2    &GetUV()	 const { return fuv[fCurIndex];		  }

protected:
	uint32			 fCurIndex;
	uint32			 fVerticesNbr;

	TMCArray<TVector3> &fVertices;
	TMCArray<TVector3> &fNormals;
	TMCArray<TVector2> &fuv;
	TMCCountedPtr<FacetMesh>	fFacetMesh;		//so that the facet mesh doesn't get deleted while we reference its fields (Arnaud)
};


void ConcatFacetMesh(FacetMesh* mesh1,FacetMesh* mesh2, FacetMesh** concat, uint32 *forceUvSpaceId = NULL);

struct IndexedFacet : public TMCObject
{
	int32  fVertexA;
	int32  fVertexB;
	int32  fVertexC;
	uint32 fUVSpaceID;
	int16  fFlags;
};



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

/// \addtogroup Data
/// \{

/// A Facet Mesh Accumulator turns a set of disconnected triangles
/// (triangle soup) into an indexed facetMesh. It merge vertices
/// that are located at the same position that have the same
/// normals and texture coordinates.
///
/// <P>Note that if you already have connection information it might
/// be more efficient to build the FacetMesh directly without going
/// through the accumulator.</P>
///
/// <P>The typical way to use the accumulator is:</P>
///
/// \code
///
/// FacetMeshAccumulator accumulator;
///
/// for (all triangles)
/// {
///    accumulator.AccumulateFacet(triangle);
/// }
/// TMCCountedPtr<FacetMesh> facetMesh;
/// accumulator.MakeFacetMesh(&facetMesh);
///
/// \endcode
///
class FacetMeshAccumulator : public TMCObject
{
public:
				FacetMeshAccumulator();
				~FacetMeshAccumulator();
	
	/// Adds one triangle to the accumulator.
	///
	void	AccumulateFacet(const TFacet3D *aF);

	/// Call this before accumulating facets to preallocate memory for them if you
	/// know how many triangles will be added.
	///
	void	PrepareAccumulation(uint32 estimatedFacetsCount);
	
	/// Computes the normals of the facets and does smoothing if abs(smoothAngle) > 1E-5
	/// Call this after accumulating the facets and before MakeFacetMesh.
	///
	MCErr	CalculateNormals(real smoothAngle);

	/// Generates the actual facet Mesh.
	///
	void	MakeFacetMesh(FacetMesh** outMesh);

	/// Reset
	///
	void	Reset();

	/// Returns the number of triangles that were accumulated.
	///
	uint32	GetAccumulatedFacetsCount()						{ return fOrigFacets.GetElemCount(); }

	/// Set the build mode to dynamic (mesh build during facet accumulation)
	///
	void	SetDynamicBuild(uint32 estimatedFacetsCount);

	int32	GetFinalFacetCount() const;
	int32	GetFinalVertexCount() const;

	TMCArray<TFacet3D>& GetFacetsArray()					{ return fOrigFacets; }

protected:
	struct VertexPlusIndex  : public TMCObject
	{
		TVertex3D fVertex;
		int32 fNextIndex;
	};

	const TMCArray<VertexPlusIndex>&	GetVertices() const {return fVertices;}
	const TMCArray<IndexedFacet>&		GetFacets() const {return fFacets;}

	TVertex3D*				VertexAt(int32 index) {return (TVertex3D *)&fVertices[index];}

	void					BuildUsingHash(const TMCArray<TFacet3D> *facets,const TMCArray<TFacet3D> *facets2=nil);

	int32					AddVertex(const TVertex3D &avertex);
	int32					HashVertex(const TVertex3D &avertex);
	void					AddFacet(const TFacet3D &afacet);

	boolean						fDynamicBuild;

	TMCArray<VertexPlusIndex>	fVertices;
	TMCArray<IndexedFacet>		fFacets;

	TMCArray<int32>			fHashTable;
	int32					fHashTableSize;
	int16					fHashPower;
	
	TMCArray<TFacet3D>		fOrigFacets;

private:
	friend class IndexedFacetIterator;
};

/// \}

/*****************************************************************************\
*                                                                             *
*   Transform Utils                                                           *
*                                                                             *
\*****************************************************************************/

void		CreateRotationMatrix(int32 axis, real32 angle, TMatrix33& out);

void		MirrorMatrix(TMatrix33& inout);

TIndex3		GetEulerAnglesOrder(const EEulerAnglesOrder inOrder);

void		GetEulerAngles(	const EEulerAnglesOrder	inOrder,
							const TMatrix33&		inRotation,
							TVector3&				outAngles,
							boolean&				outMirror);	//In carrara phi, theta, psi: Z, Y, X

void		SetEulerAngles( const EEulerAnglesOrder	inOrder,
							const TVector3&			inAngles,
							boolean					inMirror,
							TMatrix33&				outRotation);

void		GetEulerAxis(	const EEulerAnglesOrder	inOrder,
							const TVector3&			inAngles,
							boolean					inMirror,
							TVector3&				outAxis0,
							TVector3&				outAxis1,
							TVector3&				outAxis2);

int32		GetEulerHalfPIAngleIndex(const EEulerAnglesOrder	inOrder);

void		ClampEulerAngles( const EEulerAnglesOrder	inOrder,
							  TVector3&					inoutClampedAngles );



void InitTreeTransform(TTreeTransform& treeTransform);

void CompleteAxis(const TVector3 &dn,TVector3 &a,TVector3 &b);

TTransform3D AffineToTransform3D(const TTransform3D &AA);

TTransform3D Inverse(const TTransform3D &AA);
void Reset(TTransform3D &AA);
boolean operator == (const TTransform3D &AA,const TTransform3D &BB);
boolean operator != (const TTransform3D &AA,const TTransform3D &BB);
TTransform3D TreeTransform3DToAffine(const TTreeTransform &AA);

void Transform(TVector3 &res,const TMatrix33 &AA,const TVector3 &VV);
void Multiply(TMatrix33 &res,const TMatrix33 &AA,const TMatrix33 &BB);
void Transpose(TMatrix33 &res,const TMatrix33 &AA);

void TransformPoint(TVector3 &res,const TTransform3D &AA,const TVector3 &VV);
void TransformVector(TVector3 &res,const TTransform3D &AA,const TVector3 &VV);

void TransformVector(TVector3 &res,const TTreeTransform &AA,const TVector3 &VV);

TTreeTransform  operator *(const TTransform3D &AA,const TTreeTransform &BB);
TTreeTransform  operator *(const TTreeTransform &AA,const TTransform3D &BB);

void SetToIdentity(TTreeTransform  &AA);


inline TVector3 TransformPoint(const TTransform3D& AA, const TVector3& VV)
{
	TVector3 res;
	for (int32 ii = 0; ii < 3; ii++)
	{
		res[ii] = AA.fRotationAndScale[ii][0] * VV[0] + AA.fRotationAndScale[ii][1] * VV[1] + AA.fRotationAndScale[ii][2] * VV[2] + AA.fTranslation[ii];
	}
	return res;
}

inline TVector3 TransformVector(const TTransform3D& AA, const TVector3& VV)
{
	TVector3 res;
	for (int32 ii = 0; ii < 3; ii++)
	{
		res[ii] = AA.fRotationAndScale[ii][0] * VV[0] + AA.fRotationAndScale[ii][1] * VV[1] + AA.fRotationAndScale[ii][2] * VV[2];
	}
	return res;
}

inline TVector3 TransformNormal(const TTransform3D& invA, const TVector3& VV)
{
	TVector3 res;
	for (int32 ii = 0; ii < 3; ii++)
	{
		res[ii] = invA.fRotationAndScale[0][ii] * VV[0] + invA.fRotationAndScale[1][ii] * VV[1] + invA.fRotationAndScale[2][ii] * VV[2];
	}
	return res;
}

inline TBBox3D TransformBBox(const TTransform3D& transform, const TBBox3D& box)
{
	TBBox3D transformedBox;

	if (!box.IsEmpty())
	{
		for (int ii= 0; ii < 8; ii++)
		{
			transformedBox.AddPoint( transform.TransformPoint(box[ii]) );
		}
	}
	else
	{
		int a=0;
	}
	return transformedBox;
}


boolean RefractedDirection(TVector3& transmittedDirection,real eta,const TVector3& incomingDirection,const TVector3& normal);
real GetFresnelReflectance(const TVector3& incomingDirection,const TVector3& normal,const real invEta);


/// Returns the primitive component associated with object if there is one. Returns NULL if
/// there is no primitive component (for instance if object is not an external primitive)
IShComponent* GetPrimitiveComponent(I3DShObject* object);

#endif

