//-----------------------------
	void PostProcessor::createMissingAnimationList( const Loader::AnimationSidAddressBinding& binding )
	{
		const SidTreeNode* sidTreeNode = resolveSid( binding.sidAddress);
		if ( sidTreeNode )
		{
			if ( sidTreeNode->getTargetType() == SidTreeNode::TARGETTYPECLASS_ANIMATABLE )
			{
				COLLADAFW::Animatable* animatable = sidTreeNode->getAnimatableTarget();
				COLLADAFW::UniqueId animationListUniqueId = animatable->getAnimationList();
				if ( !animationListUniqueId.isValid() )
				{
					animationListUniqueId = createUniqueId( COLLADAFW::AnimationList::ID() );
					animatable->setAnimationList( animationListUniqueId );
				}
				COLLADAFW::AnimationList*& animationList = getAnimationListByUniqueId(animationListUniqueId);

				if ( !animationList )
				{
					animationList = new COLLADAFW::AnimationList( animationListUniqueId );
				}

				// TODO handle this for arrays
				COLLADAFW::AnimationList::AnimationBinding animationBinding;
				animationBinding.animation = binding.animationInfo.uniqueId;
				animationBinding.animationClass = binding.animationInfo.animationClass;

				switch ( binding.sidAddress.getMemberSelection() )
				{
				case SidAddress::MEMBER_SELECTION_ONE_INDEX:
					animationBinding.firstIndex = binding.sidAddress.getFirstIndex();
					animationBinding.secondIndex = 0;
					animationBinding.animationClass = COLLADAFW::AnimationList::ARRAY_ELEMENT_1D;
					break;
				case SidAddress::MEMBER_SELECTION_TWO_INDICES:
					animationBinding.firstIndex = binding.sidAddress.getFirstIndex();
					animationBinding.secondIndex = binding.sidAddress.getSecondIndex();
					animationBinding.animationClass = COLLADAFW::AnimationList::ARRAY_ELEMENT_2D;
					break;
				default:
					animationBinding.firstIndex = 0;
					animationBinding.secondIndex = 0;
				}

				animationList->getAnimationBindings().append( animationBinding );
			}
		}

	}
	//------------------------------
	const COLLADAFW::AnimationList* ImporterBase::getAnimationList( const COLLADAFW::Animatable* animatable )
	{
		if ( !animatable )
		{
			return 0;
		}

		const COLLADAFW::UniqueId& referencedAnimationListUniqueId = animatable->getAnimationList();

		if ( !referencedAnimationListUniqueId.isValid() )
		{
			return 0;
		}

		return getAnimationListByUniqueId( referencedAnimationListUniqueId );
	}
	//------------------------------
	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;
	}