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

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

		Author:	Arnaud
		Date:	10/25/2001

		Contains code useful for character animation

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

#ifndef __BonesUtilities__
#define __BonesUtilities__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "I3DShJoint.h"
#include "PublicUtilities.h"
#include "I3DShTreeElement.h"

struct I3DShExternalPrimitive;
struct I3dExSkinable;

// -Description:
//		If the given tree is a skinned instance, returns usefull pointers
// -Parameters:
//		outInstance: the tree as an instance
//		outPrimitive: the instance's master
//		outSkinable: the master's skinable component
//
void GetSkinableFromTree(	I3DShTreeElement*			inTree, 
							I3DShInstance**				outInstance,
							I3DShExternalPrimitive**	outPrimitive, 
							I3dExSkinable**				outSkinable);

// ****************************************************************************
//								SkinableFromTree
// 
// -Description:
//
// Returns a pointer to a skinned instance
//
// -Parameters:
//
// inTree		: the tree for which we want to skinable interface
// outSkinable	: the pointer to the skinable interface
//
void SkinableFromTree(I3DShTreeElement* inTree,I3dExSkinable** outSkinable);


// -Description:
//		Gets the skinable component of an object (if any)
// -Parameters:
//		inObject	: the presumed skinable object 
//		outSkinable	: the master's skinable component
//
void GetSkinableFromObject( I3DShObject*				inObject, 
						    I3dExSkinable**				outSkinable);

/// Returns 
///	true if the unknown supports the I3DShJoint interface.
///	false if NULL or not an I3DShJoint 
///
inline boolean IsJoint(IMCUnknown* unknown)
{
	if (unknown)
	{
		TMCCountedPtr<I3DShJoint> joint;
		unknown->QueryInterface(IID_I3DShJoint, (void**)&joint);
		if (joint) return true;
	}
	return false;
}

//Same as IsJoint(IMCUnknown* unknown)
inline boolean IsTreeAJoint(I3DShTreeElement* treeElem)
{
	return IsJoint(treeElem);
}

/// \addtogroup Data
/// \{

/// Iterates over a hierarchy of joints
///
class TJointIterator : public TTreeElementFilterIterator 
{
public:	
	///pass NeverOpen if you only want the direct sons
	inline TJointIterator(I3DShJoint*		jointBase, boolean (*isOpen)(I3DShTreeElement *aTree) = NULL);
	inline TJointIterator(I3DShTreeElement*	treeBase, boolean (*isOpen)(I3DShTreeElement *aTree) = NULL);

	inline I3DShJoint* 	FirstJoint();
	inline I3DShJoint* 	NextJoint();
};

/// \}

TJointIterator::TJointIterator(I3DShTreeElement* treeBase, boolean (*isOpen)(I3DShTreeElement *aTree))
: TTreeElementFilterIterator(treeBase, IsTreeAJoint)
{
	fIsOpen= isOpen;
}

TJointIterator::TJointIterator(I3DShJoint* jointBase, boolean (*isOpen)(I3DShTreeElement *aTree))
: TTreeElementFilterIterator(NULL, IsTreeAJoint)
{
	fIsOpen= isOpen;
	if (jointBase)
	{
		TMCCountedPtr<I3DShTreeElement> tree;
		jointBase->QueryInterface(IID_I3DShTreeElement, (void**)&tree);
		fRoot = tree;
	}
}

I3DShJoint* TJointIterator::FirstJoint()
{
	I3DShTreeElement* tree= First();
	if (tree)
	{
		TMCCountedPtr<I3DShJoint> joint;
		tree->QueryInterface(IID_I3DShJoint, (void**)&joint);
		return joint;
	}
	return NULL;
}


I3DShJoint* TJointIterator::NextJoint()
{
	I3DShTreeElement* tree= Next();
	if (tree)
	{
		TMCCountedPtr<I3DShJoint> joint;
		tree->QueryInterface(IID_I3DShJoint, (void**)&joint);
		return joint;
	}
	return NULL;
}

#endif
