ImpNode* SceneGraphCreator::importInstance( const COLLADAFW::Node* node, INode* parentINode )
	{
		const COLLADAFW::PointerArray<Instance>& instances = (node->*getInstances)();
		if ( instances.getCount() != 1 )
			return 0;

		ImpNode* newImportNode = getMaxImportInterface()->CreateNode();
		setNodeProperties(node, newImportNode);
		INode* newNode = newImportNode->GetINode();

		Instance* instance = instances[0];
		const COLLADAFW::UniqueId& uniqueId = instance->getInstanciatedObjectId();

		Object* object = getObjectByUniqueId(uniqueId);
		if ( object )
		{
			newImportNode->Reference(object);
			const String& objectName = getObjectNameByObject(object);

			if ( node->getName().empty() && !objectName.empty() )
			{
#ifdef UNICODE
				WideString wideObjectName = COLLADABU::StringUtils::toWideString(objectName.c_str());
				newImportNode->SetName( wideObjectName.c_str() );
#else
				newImportNode->SetName( objectName.c_str() );
#endif
			}
		}
		else
		{
			newImportNode->Reference( getDummyObject() );
		}

		const COLLADAFW::UniqueId& instanceGeometryUniqueId = instance->getInstanciatedObjectId();
		// Store mapping between unique ids and nodes referencing the corresponding object.
		// Used to clone nodes
		addObjectINodeUniqueIdPair(newNode, instanceGeometryUniqueId);
		// Used to resolve instancing of objects
		addUniqueIdObjectINodePair(instanceGeometryUniqueId, newNode);
		parentINode->AttachChild(newNode, FALSE);

		// post process the creation
		if ( postProcess )
			(this->*postProcess)(newNode, instance);

		return newImportNode;
	}
		bool SceneGraphCreator::importInstances( const COLLADAFW::PointerArray<Instance>& instanceArray, ImpNode* parentImportNode )
	{
		for ( size_t i = 0, count = instanceArray.getCount(); i < count; ++i)
		{
			Instance* instance = instanceArray[i];

			ImpNode* newImportNode = getMaxImportInterface()->CreateNode();
			INode* newNode = newImportNode->GetINode();
			const COLLADAFW::UniqueId& uniqueId = instance->getInstanciatedObjectId();

			Object* object = getObjectByUniqueId(uniqueId);
			if ( object )
			{
				newImportNode->Reference(object);
			}
			else
			{
				newImportNode->Reference( getDummyObject() );
			}
			const COLLADAFW::UniqueId& instanceUniqueId = instance->getInstanciatedObjectId();
			// Store mapping between unique ids and nodes referencing the corresponding object.
			// Used to clone nodes
			addObjectINodeUniqueIdPair(newNode, instanceUniqueId);
			// Used to resolve instancing of objects
			addUniqueIdObjectINodePair(instanceUniqueId, newNode);

			INode* parentNode = parentImportNode->GetINode();
			parentNode->AttachChild(newNode, FALSE);

			// post process the creation
			if ( postProcess )
				(this->*postProcess)(newNode, instance);
		}

		return true;
	}
	//------------------------------
	bool MorphControllerCreator::createMorphController( const COLLADAFW::MorphController* morphController, INode* referencingINode )
	{
		Object* sourceObject = getObjectByUniqueId( morphController->getSource() );

		if ( !sourceObject )
		{
			// TODO handle error
			// morph source object not present
			return true;
		}

		mMorphModifier = (MorphR3*) createMaxObject(OSM_CLASS_ID, MORPHER_CLASS_ID);

		if ( !mMorphModifier )
		{
			// TODO handle error
			// morph controller could not be created
			return true;
		}

		if ( (sourceObject->ClassID() == derivObjClassID) || (sourceObject->ClassID() == WSMDerivObjClassID) )
		{
			// Object is a derived object, just attach ourselves to it
			mDerivedObject = (IDerivedObject*) sourceObject;
		}
		else
		{
			// Create the derived object for the target and the modifier
			mDerivedObject = CreateDerivedObject(sourceObject);
		}

		mDerivedObject->AddModifier(mMorphModifier);
		mMorphModifier->cache.MakeCache(sourceObject);

		const COLLADAFW::FloatOrDoubleArray& morphWeights = morphController->getMorphWeights();
		const COLLADAFW::UniqueIdArray& morphTargets = morphController->getMorphTargets();
		// There is a maximum number of channels supported by the 3dsMax morpher:
		// Calculate the number of channels to process
		size_t colladaTargetCount = morphTargets.getCount();
		int channelCount = (int) min(colladaTargetCount, mMorphModifier->chanBank.size());

		const COLLADAFW::UniqueId& morphWeightsAnimationListId = morphWeights.getAnimationList();
		const COLLADAFW::AnimationList* morphWeightsAnimationList = getAnimationListByUniqueId( morphWeightsAnimationListId );

		for (int i = 0; i < channelCount; ++i)
		{
			const COLLADAFW::UniqueId& targetUniqueId = morphTargets[i];
			Object* targetObject = getObjectByUniqueId( targetUniqueId );
			if ( !targetObject )
			{
				// TODO handle error
				// the target has not been created, might be missing in dae file
				return true;
			}
			INodeList targetINodes;
			getObjectINodesByUniqueId( targetUniqueId, targetINodes );
			INode* targetINode = 0;
			if ( !targetINodes.empty() )
			{
				// it does not seem to make a difference which INode we use, as long as it references the correct geometry
				targetINode = targetINodes[0];
			}
		
			morphChannel* channel = &mMorphModifier->chanBank[i];
			if ( targetINode )
			{
				channel->buildFromNode(targetINode);
				channel->mConnection = targetINode;
			}
			else
			{
				// Manually initializes this channel
				initializeChannelGeometry(channel, targetObject);
			}

			if ( !morphWeightsAnimationList )
			{
				float weight = 0;
				if ( morphWeights.getType() == COLLADAFW::FloatOrDoubleArray::DATA_TYPE_FLOAT )
				{
					weight = (*morphWeights.getFloatValues())[i];
				}
				else if ( morphWeights.getType() == COLLADAFW::FloatOrDoubleArray::DATA_TYPE_DOUBLE )
				{
					weight = (float)(*morphWeights.getDoubleValues())[i];
				}
				channel->cblock->SetValue(0, 0, weight * 100);
			}
		}


		if ( morphWeightsAnimationList )
		{
			const COLLADAFW::AnimationList::AnimationBindings& animationBindings = morphWeightsAnimationList->getAnimationBindings();
			for ( size_t i = 0, count = animationBindings.getCount(); i < count; ++i)
			{
				const COLLADAFW::AnimationList::AnimationBinding& animationBinding = animationBindings[i];
				if ( animationBinding.animationClass != COLLADAFW::AnimationList::ARRAY_ELEMENT_1D)
				{
					// this animation does not animate one element of a one dimensional array
					continue;
				}
				const DocumentImporter::MaxControllerList& maxControllerList = getMaxControllerListByAnimationUniqueId( animationBinding.animation );
				assert(maxControllerList.size()==1);
				if ( maxControllerList.size() < 1 )
				{
					// this animation does not animate one element of a one dimensional array
					continue;
				}
				Control* weightController = maxControllerList[0];

				size_t channelNumber = animationBinding.firstIndex;
				if ( (int)channelNumber >= channelCount )
				{
					// invalid channel
					continue;
				}
				morphChannel* channel = &mMorphModifier->chanBank[channelNumber];

				if ( !channel )
				{
					continue;
				}
				Control* scaledWeightController = cloneController( weightController, &ConversionFunctors::toPercent);
				//Control* scaledWeightController = cloneController( weightController);
				//channel->cblock->SetController(0, weightController);
				channel->cblock->SetController(0, scaledWeightController);
			}
		}


		//assign the morph controller to all INodes referencing it
		INodeList referencingINodes;
		getObjectINodesByUniqueId( morphController->getUniqueId(), referencingINodes );

		for ( size_t i = 0, count = referencingINodes.size(); i < count; ++i)
		{
			INode* referencingINode = referencingINodes[i];
			referencingINode->SetObjectRef(mDerivedObject);
		}

		addUniqueIdObjectPair( morphController->getUniqueId(), mDerivedObject );
		return true;
	}