bool FArchiveXML::LoadPhysicsModelInstance(FCDObject* object, xmlNode* instanceNode)
{
	if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false;

	bool status = true;
	FCDPhysicsModelInstance* physicsModelInstance = (FCDPhysicsModelInstance*)object;

	if (physicsModelInstance->GetEntity() == NULL)
	{
		FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, instanceNode->line);
	}

	// Check for the expected instantiation node type
	if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT))
	{
		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line);
	}

	//this is already done in the FCDSceneNode
//	fm::string physicsModelId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE);
//	entity = GetDocument()->FindPhysicsModel(physicsModelId);
//	if (!entity)	return status.Fail(FS("Couldn't find physics model for instantiation"), instanceNode->line);

	xmlNodeList rigidBodyNodes;
	FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_BODY_ELEMENT, rigidBodyNodes);
	for (xmlNodeList::iterator itB = rigidBodyNodes.begin(); itB != rigidBodyNodes.end(); ++itB)
	{
		FCDPhysicsRigidBodyInstance* instance = physicsModelInstance->AddRigidBodyInstance(NULL);
		status &= (FArchiveXML::LoadPhysicsRigidBodyInstance(instance, *itB));
	}

	xmlNodeList rigidConstraintNodes;
	FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT, rigidConstraintNodes);
	for (xmlNodeList::iterator itC = rigidConstraintNodes.begin(); itC != rigidConstraintNodes.end(); ++itC)
	{
		FCDPhysicsRigidConstraintInstance* instance = physicsModelInstance->AddRigidConstraintInstance(NULL);
		status &= (FArchiveXML::LoadPhysicsRigidConstraintInstance(instance, *itC));
	}

	xmlNodeList forceFieldNodes;
	FindChildrenByType(instanceNode, DAE_INSTANCE_FORCE_FIELD_ELEMENT, forceFieldNodes);
	for (xmlNodeList::iterator itN = forceFieldNodes.begin(); itN != forceFieldNodes.end(); ++itN)
	{
		FCDPhysicsForceFieldInstance* instance = physicsModelInstance->AddForceFieldInstance(NULL);
		status &= (FArchiveXML::LoadPhysicsForceFieldInstance(instance, *itN));
	}

	physicsModelInstance->SetDirtyFlag();
	return status;
}
bool FArchiveXML::LoadEntityInstance(FCDObject* object, xmlNode* instanceNode)
{ 
	FCDEntityInstance* entityInstance = (FCDEntityInstance*)object;

	bool status = true;

	FUUri uri = ReadNodeUrl(instanceNode);
	entityInstance->GetEntityReference()->SetUri(uri);
	if (!entityInstance->IsExternalReference() && entityInstance->GetEntity() == NULL)
	{
		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INST_ENTITY_MISSING, instanceNode->line);
	}

	entityInstance->SetWantedSubId(TO_STRING(ReadNodeSid(instanceNode)));
	entityInstance->SetName(TO_FSTRING(ReadNodeName(instanceNode)));

	// Read in the extra nodes
	xmlNodeList extraNodes;
	FindChildrenByType(instanceNode, DAE_EXTRA_ELEMENT, extraNodes);
	for (xmlNodeList::iterator it = extraNodes.begin(); it != extraNodes.end(); ++it)
	{
		xmlNode* extraNode = (*it);
		FArchiveXML::LoadExtra(entityInstance->GetExtra(), extraNode);
	}

	entityInstance->SetDirtyFlag(); 
	return status;
}
bool FArchiveXML::LoadGeometryInstance(FCDObject* object, xmlNode* instanceNode)
{
	if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false;

	bool status = true;
	FCDGeometryInstance* geometryInstance = (FCDGeometryInstance*)object;

	// Look for the <bind_material> element. The others are discarded for now.
	xmlNode* bindMaterialNode = FindChildByType(instanceNode, DAE_BINDMATERIAL_ELEMENT);
	if (bindMaterialNode != NULL)
	{
		for (xmlNode* child = bindMaterialNode->children; child != NULL; child = child->next)
		{
			if (child->type != XML_ELEMENT_NODE) continue;

			if (IsEquivalent(child->name, DAE_PARAMETER_ELEMENT))
			{
				FCDEffectParameter* parameter = geometryInstance->AddEffectParameter(FArchiveXML::GetEffectParameterType(child));
				parameter->SetAnimator();
				status &= FArchiveXML::LoadSwitch(parameter, &parameter->GetObjectType(), child);
			}
		} 

		// Retrieve the list of the <technique_common><instance_material> elements.
		xmlNode* techniqueNode = FindChildByType(bindMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT);
		xmlNodeList materialNodes;
		FindChildrenByType(techniqueNode, DAE_INSTANCE_MATERIAL_ELEMENT, materialNodes);
		for (xmlNodeList::iterator itM = materialNodes.begin(); itM != materialNodes.end(); ++itM)
		{
			FCDMaterialInstance* material = geometryInstance->AddMaterialInstance();
			status &= (FArchiveXML::LoadMaterialInstance(material, *itM));
		}
	}
	else
	{
		// Blinding attempt to use the material semantic from the polygons as a material id.
		FCDGeometry* geometry = (FCDGeometry*) geometryInstance->GetEntity();
		if (geometry != NULL && geometry->HasType(FCDGeometry::GetClassType()) && geometry->IsMesh())
		{
			FCDGeometryMesh* mesh = geometry->GetMesh();
			size_t polyCount = mesh->GetPolygonsCount();
			for (size_t i = 0; i < polyCount; ++i)
			{
				FCDGeometryPolygons* polys = mesh->GetPolygons(i);
				const fstring& semantic = polys->GetMaterialSemantic();
				fm::string semanticUTF8 = TO_STRING(semantic);
				semanticUTF8 = FCDObjectWithId::CleanId(semanticUTF8.c_str());
				FCDMaterial* material = geometry->GetDocument()->FindMaterial(semanticUTF8);
				if (material != NULL)
				{
					geometryInstance->AddMaterialInstance(material, polys);
				}
			}
		}
	}

	geometryInstance->SetDirtyFlag();
	return status;
}
示例#4
0
bool FArchiveXML::LoadEntity(FCDObject* object, xmlNode* entityNode)
{ 
	FCDEntity* entity = (FCDEntity*)object;

	bool status = true;

	fm::string fileId = FUDaeParser::ReadNodeId(entityNode);
	if (!fileId.empty()) entity->SetDaeId(fileId);
	else entity->RemoveDaeId();

	entity->SetName(TO_FSTRING(FUDaeParser::ReadNodeName(entityNode)));
	if (entity->GetName().empty()) entity->SetName(TO_FSTRING(fileId));

	// Read in the asset information.
	xmlNode* assetNode = FindChildByType(entityNode, DAE_ASSET_ELEMENT);
	if (assetNode != NULL) FArchiveXML::LoadAsset(entity->GetAsset(), assetNode);

	// Read in the extra nodes
	xmlNodeList extraNodes;
	FindChildrenByType(entityNode, DAE_EXTRA_ELEMENT, extraNodes);
	for (xmlNodeList::iterator it = extraNodes.begin(); it != extraNodes.end(); ++it)
	{
		xmlNode* extraNode = (*it);
		FArchiveXML::LoadExtra(entity->GetExtra(), extraNode);

		// Look for an extra node at this level and a valid technique
		FCDETechnique* mayaTechnique = entity->GetExtra()->GetDefaultType()->FindTechnique(DAEMAYA_MAYA_PROFILE);
		FCDETechnique* maxTechnique = entity->GetExtra()->GetDefaultType()->FindTechnique(DAEMAX_MAX_PROFILE);
		FCDETechnique* fcTechnique = entity->GetExtra()->GetDefaultType()->FindTechnique(DAE_FCOLLADA_PROFILE);

		// Read in all the extra parameters
		StringList parameterNames;
		FCDENodeList parameterNodes;
		if (mayaTechnique != NULL) mayaTechnique->FindParameters(parameterNodes, parameterNames);
		if (maxTechnique != NULL) maxTechnique->FindParameters(parameterNodes, parameterNames);
		if (fcTechnique != NULL) fcTechnique->FindParameters(parameterNodes, parameterNames);

		// Look for the note and user-properties, which is the only parameter currently supported at this level
		size_t parameterCount = parameterNodes.size();
		for (size_t i = 0; i < parameterCount; ++i)
		{
			FCDENode* parameterNode = parameterNodes[i];
			const fm::string& parameterName = parameterNames[i];

			if (parameterName == DAEMAX_USERPROPERTIES_NODE_PARAMETER || parameterName == DAEMAYA_NOTE_PARAMETER)
			{
				entity->SetNote(parameterNode->GetContent());
				SAFE_RELEASE(parameterNode);
			}
		}
	}

	entity->SetDirtyFlag();
	return status;	
}
bool FArchiveXML::LoadMaterialInstance(FCDObject* object, xmlNode* instanceNode)
{
	FCDMaterialInstance* materialInstance = (FCDMaterialInstance*)object;

	// This is not loaded the same as the FCDEntityInstance ones.
	// Load it first, otherwise FCDEntityInstance will ASSERT (with no Uri)
	fm::string uri = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE);
	AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, uri);
	if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false;

	materialInstance->SetSemantic(TO_FSTRING(ReadNodeProperty(instanceNode, DAE_SYMBOL_ATTRIBUTE)));

	// Read in the ColladaFX bindings
	while (materialInstance->GetBindingCount() != 0) materialInstance->GetBinding(materialInstance->GetBindingCount() - 1)->Release();
	xmlNodeList bindNodes;
	FindChildrenByType(instanceNode, DAE_BIND_ELEMENT, bindNodes);
	for (xmlNodeList::iterator itB = bindNodes.begin(); itB != bindNodes.end(); ++itB)
	{
		fm::string semantic = ReadNodeSemantic(*itB);
		fm::string target = ReadNodeProperty(*itB, DAE_TARGET_ATTRIBUTE);
		materialInstance->AddBinding(semantic, target);
	}

	// Read in the ColladaFX vertex inputs
	xmlNodeList bindVertexNodes;
	while (materialInstance->GetVertexInputBindingCount() != 0) materialInstance->GetVertexInputBinding(materialInstance->GetVertexInputBindingCount() - 1)->Release();
	FindChildrenByType(instanceNode, DAE_BIND_VERTEX_INPUT_ELEMENT, bindVertexNodes);
	for (xmlNodeList::iterator itB = bindVertexNodes.begin(); itB != bindVertexNodes.end(); ++itB)
	{
		fm::string inputSet = ReadNodeProperty(*itB, DAE_INPUT_SET_ATTRIBUTE);
		fm::string inputSemantic = ReadNodeProperty(*itB, DAE_INPUT_SEMANTIC_ATTRIBUTE);
		materialInstance->AddVertexInputBinding(ReadNodeSemantic(*itB).c_str(), FUDaeGeometryInput::FromString(inputSemantic.c_str()), FUStringConversion::ToInt32(inputSet));
	}


	materialInstance->SetDirtyFlag();
	return true;
}
示例#6
0
bool FArchiveXML::LoadAnimation(FCDObject* object, xmlNode* node)
{ 
	FCDAnimation* animation = (FCDAnimation*)object;
	FCDAnimationData& data = FArchiveXML::documentLinkDataMap[animation->GetDocument()].animationData[animation];

	bool status = FArchiveXML::LoadEntity(animation, node);
	if (!status) return status;
	if (!IsEquivalent(node->name, DAE_ANIMATION_ELEMENT))
	{
		return FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_ANIM_LIB, node->line);
	}

	// Optimization: Grab all the IDs of the child nodes, in CRC format.
	ReadChildrenIds(node, data.childNodes);

	// Parse all the inner <channel> elements
	xmlNodeList channelNodes;
	FindChildrenByType(node, DAE_CHANNEL_ELEMENT, channelNodes);
	for (xmlNodeList::iterator itC = channelNodes.begin(); itC != channelNodes.end(); ++itC)
	{
		// Parse each <channel> element individually
		// They each handle reading the <sampler> and <source> elements
		FCDAnimationChannel* channel = animation->AddChannel();
		status &= (FArchiveXML::LoadAnimationChannel(channel, *itC));
		if (!status) SAFE_RELEASE(channel);
	}

	// Parse all the hierarchical <animation> elements
	xmlNodeList animationNodes;
	FindChildrenByType(node, DAE_ANIMATION_ELEMENT, animationNodes);
	for (xmlNodeList::iterator itA = animationNodes.begin(); itA != animationNodes.end(); ++itA)
	{
		FArchiveXML::LoadAnimation(animation->AddChild(), *itA);
	}
	return status;
}			
示例#7
0
	// Returns the first technique node with a given profile
	xmlNode* FindTechnique(xmlNode* parent, const char* profile)
	{
		if (parent != NULL)
		{
			xmlNodeList techniqueNodes;
			FindChildrenByType(parent, DAE_TECHNIQUE_ELEMENT, techniqueNodes);
			size_t techniqueNodeCount = techniqueNodes.size();
			for (size_t i = 0; i < techniqueNodeCount; ++i)
			{
				xmlNode* techniqueNode = techniqueNodes[i];
				fm::string techniqueProfile = ReadNodeProperty(techniqueNode, DAE_PROFILE_ATTRIBUTE);
				if (techniqueProfile == profile) return techniqueNode;
			}
		}
		return NULL;
	}
示例#8
0
bool FArchiveXML::LoadAnimationClip(FCDObject* object, xmlNode* clipNode)
{ 
	FCDAnimationClip* animationClip = (FCDAnimationClip*)object;

	bool status = FArchiveXML::LoadEntity(animationClip, clipNode);
	if (!status) return status;
	if (!IsEquivalent(clipNode->name, DAE_ANIMCLIP_ELEMENT))
	{
		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_ANIM_LIB_ELEMENT, clipNode->line);
		return status;
	}

	// Read in and verify the clip's time/input bounds
	animationClip->SetStart(FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_START_ATTRIBUTE)));
	animationClip->SetEnd(FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_END_ATTRIBUTE)));
	if (animationClip->GetEnd() - animationClip->GetStart() < FLT_TOLERANCE)
	{
		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SE_PAIR, clipNode->line);
	}

	// Read in the <input> elements and segment the corresponding animation curves
	xmlNodeList inputNodes;
	FindChildrenByType(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT, inputNodes);
	for (xmlNodeList::iterator itI = inputNodes.begin(); itI != inputNodes.end(); ++itI)
	{
		FCDEntityInstance* animationInstance = animationClip->AddInstanceAnimation();
		if (!LoadSwitch(animationInstance, &animationInstance->GetObjectType(), *itI))
		{
			SAFE_DELETE(animationInstance);
			continue;
		}

		fm::string name = ReadNodeProperty(*itI, DAE_NAME_ATTRIBUTE);
		animationClip->SetAnimationName(name, animationClip->GetAnimationCount() - 1);
	}

	// Check for an empty clip
	if (animationClip->GetClipCurves().empty())
	{
		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_EMPTY_ANIM_CLIP, clipNode->line);
	}

	animationClip->SetDirtyFlag();
	return status;
}		
bool FArchiveXML::LoadExtraType(FCDObject* object, xmlNode* extraNode)
{
	FCDEType* eType = (FCDEType*)object;

	bool status = true;

	// Do NOT verify that we have an <extra> element: we may be parsing a technique switch instead.

	// Read in the techniques
	xmlNodeList techniqueNodes;
	FindChildrenByType(extraNode, DAE_TECHNIQUE_ELEMENT, techniqueNodes);
	for (xmlNodeList::iterator itN = techniqueNodes.begin(); itN != techniqueNodes.end(); ++itN)
	{
		xmlNode* techniqueNode = (*itN);
		fm::string profile = ReadNodeProperty(techniqueNode, DAE_PROFILE_ATTRIBUTE);
		FCDETechnique* technique = eType->AddTechnique(profile);
		status &= (FArchiveXML::LoadExtraTechnique(technique, techniqueNode));
	}

	eType->SetDirtyFlag();
	return status;
}
示例#10
0
bool FArchiveXML::LoadAnimationChannel(FCDObject* object, xmlNode* channelNode)
{ 
	FCDAnimationChannel* animationChannel = (FCDAnimationChannel*)object;
	FCDAnimationChannelData& data = FArchiveXML::documentLinkDataMap[animationChannel->GetDocument()].animationChannelData[animationChannel];

	bool status = true;

	// Read the channel-specific ID
	fm::string daeId = ReadNodeId(channelNode);
	fm::string samplerId = ReadNodeSource(channelNode);
	ReadNodeTargetProperty(channelNode, data.targetPointer, data.targetQualifier);

#ifdef DONT_DEFINE_THIS
	FCDAnimation* anim = animationChannel->GetParent();
	FCDExtra* extra = anim->GetExtra();
	extra->SetTransientFlag(); // Dont save this, its wasted whatever it is.
	FCDEType* type = extra->AddType("AnimTargets");
	FCDETechnique* teq = type->AddTechnique("TEMP");
	teq->AddChildNode("pointer")->SetContent(TO_FSTRING(data.targetPointer));
	teq->AddChildNode("pointer")->SetContent(TO_FSTRING(data.targetQualifier));
#endif
	


	xmlNode* samplerNode = FArchiveXML::FindChildByIdFCDAnimation(animationChannel->GetParent(), samplerId);
	if (samplerNode == NULL || !IsEquivalent(samplerNode->name, DAE_SAMPLER_ELEMENT))
	{
		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_MISSING_ELEMENT, channelNode->line);
		return false;
	}

	// Find and process the sources
	xmlNode* inputSource = NULL, * outputSource = NULL, * inTangentSource = NULL, * outTangentSource = NULL, * tcbSource = NULL, * easeSource = NULL, * interpolationSource = NULL;
	xmlNodeList samplerInputNodes;
	fm::string inputDriver;
	FindChildrenByType(samplerNode, DAE_INPUT_ELEMENT, samplerInputNodes);
	for (size_t i = 0; i < samplerInputNodes.size(); ++i) // Don't use iterator here because we are possibly appending source nodes in the loop
	{
		xmlNode* inputNode = samplerInputNodes[i];
		fm::string sourceId = ReadNodeSource(inputNode);
		xmlNode* sourceNode = FArchiveXML::FindChildByIdFCDAnimation(animationChannel->GetParent(), sourceId);
		fm::string sourceSemantic = ReadNodeSemantic(inputNode);

		if (sourceSemantic == DAE_INPUT_ANIMATION_INPUT) inputSource = sourceNode;
		else if (sourceSemantic == DAE_OUTPUT_ANIMATION_INPUT) outputSource = sourceNode;
		else if (sourceSemantic == DAE_INTANGENT_ANIMATION_INPUT) inTangentSource = sourceNode;
		else if (sourceSemantic == DAE_OUTTANGENT_ANIMATION_INPUT) outTangentSource = sourceNode;
		else if (sourceSemantic == DAEFC_TCB_ANIMATION_INPUT) tcbSource = sourceNode;
		else if (sourceSemantic == DAEFC_EASE_INOUT_ANIMATION_INPUT) easeSource = sourceNode;
		else if (sourceSemantic == DAE_INTERPOLATION_ANIMATION_INPUT) interpolationSource = sourceNode;
		else if (sourceSemantic == DAEMAYA_DRIVER_INPUT) inputDriver = sourceId;
	}
	if (inputSource == NULL || outputSource == NULL)
	{
		FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_MISSING_INPUT, samplerNode->line);
		return false;
	}

	// Calculate the number of curves that in contained by this channel
	xmlNode* outputAccessor = FindTechniqueAccessor(outputSource);
	fm::string accessorStrideString = ReadNodeProperty(outputAccessor, DAE_STRIDE_ATTRIBUTE);
	uint32 curveCount = FUStringConversion::ToUInt32(accessorStrideString);
	if (curveCount == 0) curveCount = 1;

	// Create the animation curves
	for (uint32 i = 0; i < curveCount; ++i)
	{
		animationChannel->AddCurve();
	}

	// Read in the animation curves
	// The input keys and interpolations are shared by all the curves
	FloatList inputs;
    ReadSource(inputSource, inputs);
	size_t keyCount = inputs.size();
	if (keyCount == 0) return true; // Valid although very boring channel.

	UInt32List interpolations; interpolations.reserve(keyCount);
	ReadSourceInterpolation(interpolationSource, interpolations);
	if (interpolations.size() < keyCount)
	{
		// Not enough interpolation types provided, so append BEZIER as many times as needed.
		interpolations.insert(interpolations.end(), keyCount - interpolations.size(), FUDaeInterpolation::FromString(""));
	}

	// Read in the interleaved outputs as floats
	fm::vector<FloatList> tempFloatArrays;
	tempFloatArrays.resize(curveCount);
	fm::pvector<FloatList> outArrays(curveCount);
	for (uint32 i = 0; i < curveCount; ++i) outArrays[i] = &tempFloatArrays[i];
	ReadSourceInterleaved(outputSource, outArrays);
	for (uint32 i = 0; i < curveCount; ++i)
	{
		// Fill in the output array with zeroes, if it was not large enough.
		if (tempFloatArrays[i].size() < keyCount)
		{
			tempFloatArrays[i].insert(tempFloatArrays[i].end(), keyCount - tempFloatArrays[i].size(), 0.0f);
		}

		// Create all the keys, on the curves, according to the interpolation types.
		for (size_t j = 0; j < keyCount; ++j)
		{
			FCDAnimationKey* key = animationChannel->GetCurve(i)->AddKey((FUDaeInterpolation::Interpolation) interpolations[j]);
			key->input = inputs[j];
			key->output = tempFloatArrays[i][j];

			// Set the default values for Bezier/TCB interpolations.
			if (key->interpolation == FUDaeInterpolation::BEZIER)
			{
				FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) key;
				float previousInput = (j == 0) ? inputs[j] - 1.0f : inputs[j-1];
				float nextInput = (j == keyCount - 1) ? inputs[j] + 1.0f : inputs[j+1];
				bkey->inTangent.x = (previousInput + 2.0f * bkey->input) / 3.0f;
				bkey->outTangent.x = (nextInput + 2.0f * bkey->input) / 3.0f;
				bkey->inTangent.y = bkey->outTangent.y = bkey->output;
			}
			else if (key->interpolation == FUDaeInterpolation::TCB)
			{
				FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) key;
				tkey->tension = tkey->continuity = tkey->bias = 0.5f;
				tkey->easeIn = tkey->easeOut = 0.0f;
			}
		}
	}
	tempFloatArrays.clear();

	// Read in the interleaved in_tangent source.
	if (inTangentSource != NULL)
	{
		fm::vector<FMVector2List> tempVector2Arrays;
		tempVector2Arrays.resize(curveCount);
		fm::pvector<FMVector2List> arrays(curveCount);
		for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i];

		uint32 stride = ReadSourceInterleaved(inTangentSource, arrays);
		if (stride == curveCount)
		{
			// Backward compatibility with 1D tangents.
			// Remove the relativity from the 1D tangents and calculate the second-dimension.
			for (uint32 i = 0; i < curveCount; ++i)
			{
				FMVector2List& inTangents = tempVector2Arrays[i];
				FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
				size_t end = min(inTangents.size(), keyCount);
				for (size_t j = 0; j < end; ++j)
				{
					if (keys[j]->interpolation == FUDaeInterpolation::BEZIER)
					{
						FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j];
						bkey->inTangent.y = bkey->output - inTangents[j].x;
					}
				}
			}
		}
		else if (stride == curveCount * 2)
		{
			// This is the typical, 2D tangent case.
			for (uint32 i = 0; i < curveCount; ++i)
			{
				FMVector2List& inTangents = tempVector2Arrays[i];
				FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
				size_t end = min(inTangents.size(), keyCount);
				for (size_t j = 0; j < end; ++j)
				{
					if (keys[j]->interpolation == FUDaeInterpolation::BEZIER)
					{
						FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j];
						bkey->inTangent = inTangents[j];
					}
				}
			}
		}
	}

	// Read in the interleaved out_tangent source.
	if (outTangentSource != NULL)
	{
		fm::vector<FMVector2List> tempVector2Arrays;
		tempVector2Arrays.resize(curveCount);
		fm::pvector<FMVector2List> arrays(curveCount);
		for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i];

		uint32 stride = ReadSourceInterleaved(outTangentSource, arrays);
		if (stride == curveCount)
		{
			// Backward compatibility with 1D tangents.
			// Remove the relativity from the 1D tangents and calculate the second-dimension.
			for (uint32 i = 0; i < curveCount; ++i)
			{
				FMVector2List& outTangents = tempVector2Arrays[i];
				FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
				size_t end = min(outTangents.size(), keyCount);
				for (size_t j = 0; j < end; ++j)
				{
					if (keys[j]->interpolation == FUDaeInterpolation::BEZIER)
					{
						FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j];
						bkey->outTangent.y = bkey->output + outTangents[j].x;
					}
				}
			}
		}
		else if (stride == curveCount * 2)
		{
			// This is the typical, 2D tangent case.
			for (uint32 i = 0; i < curveCount; ++i)
			{
				FMVector2List& outTangents = tempVector2Arrays[i];
				FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
				size_t end = min(outTangents.size(), keyCount);
				for (size_t j = 0; j < end; ++j)
				{
					if (keys[j]->interpolation == FUDaeInterpolation::BEZIER)
					{
						FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j];
						bkey->outTangent = outTangents[j];
					}
				}
			}
		}
	}

	if (tcbSource != NULL)
	{
		//Process TCB parameters
		fm::vector<FMVector3List> tempVector3Arrays;
		tempVector3Arrays.resize(curveCount);
		fm::pvector<FMVector3List> arrays(curveCount);
		for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector3Arrays[i];

		ReadSourceInterleaved(tcbSource, arrays);

		for (uint32 i = 0; i < curveCount; ++i)
		{
			FMVector3List& tcbs = tempVector3Arrays[i];
			FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
			size_t end = min(tcbs.size(), keyCount);
			for (size_t j = 0; j < end; ++j)
			{
				if (keys[j]->interpolation == FUDaeInterpolation::TCB)
				{
					FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) keys[j];
					tkey->tension = tcbs[j].x;
					tkey->continuity = tcbs[j].y;
					tkey->bias = tcbs[j].z;
				}
			}
		}
	}

	if (easeSource != NULL)
	{
		//Process Ease-in and ease-out data
		fm::vector<FMVector2List> tempVector2Arrays;
		tempVector2Arrays.resize(curveCount);
		fm::pvector<FMVector2List> arrays(curveCount);
		for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i];

		ReadSourceInterleaved(easeSource, arrays);

		for (uint32 i = 0; i < curveCount; ++i)
		{
			FMVector2List& eases = tempVector2Arrays[i];
			FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys();
			size_t end = min(eases.size(), keyCount);
			for (size_t j = 0; j < end; ++j)
			{
				if (keys[j]->interpolation == FUDaeInterpolation::TCB)
				{
					FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) keys[j];
					tkey->easeIn = eases[j].x;
					tkey->easeOut = eases[j].y;
				}
			}
		}
	}

	// Read in the pre/post-infinity type
	xmlNodeList mayaParameterNodes; StringList mayaParameterNames;
	xmlNode* mayaTechnique = FindTechnique(inputSource, DAEMAYA_MAYA_PROFILE);
	FindParameters(mayaTechnique, mayaParameterNames, mayaParameterNodes);
	size_t parameterCount = mayaParameterNodes.size();
	for (size_t i = 0; i < parameterCount; ++i)
	{
		xmlNode* parameterNode = mayaParameterNodes[i];
		const fm::string& paramName = mayaParameterNames[i];
		const char* content = ReadNodeContentDirect(parameterNode);

		if (paramName == DAEMAYA_PREINFINITY_PARAMETER)
		{
			size_t curveCount = animationChannel->GetCurveCount();
			for (size_t c = 0; c < curveCount; ++c)
			{
				animationChannel->GetCurve(c)->SetPreInfinity(FUDaeInfinity::FromString(content));
			}
		}
		else if (paramName == DAEMAYA_POSTINFINITY_PARAMETER)
		{
			size_t curveCount = animationChannel->GetCurveCount();
			for (size_t c = 0; c < curveCount; ++c)
			{
				animationChannel->GetCurve(c)->SetPostInfinity(FUDaeInfinity::FromString(content));
			}
		}
		else
		{
			// Look for driven-key input target
			if (paramName == DAE_INPUT_ELEMENT)
			{
				fm::string semantic = ReadNodeSemantic(parameterNode);
				if (semantic == DAEMAYA_DRIVER_INPUT)
				{
					inputDriver = ReadNodeSource(parameterNode);
				}
			}
		}
	}

	if (!inputDriver.empty())
	{
		const char* driverTarget = FUDaeParser::SkipPound(inputDriver);
		if (driverTarget != NULL)
		{
			fm::string driverQualifierValue;
			FUStringConversion::SplitTarget(driverTarget, data.driverPointer, driverQualifierValue);
			data.driverQualifier = FUStringConversion::ParseQualifier(driverQualifierValue);
			if (data.driverQualifier < 0) data.driverQualifier = 0;
		}
	}
	animationChannel->SetDirtyFlag();

	return status;
}
bool FArchiveXML::LoadPhysicsRigidBodyParameters(FCDPhysicsRigidBodyParameters* parameters, xmlNode* techniqueNode, FCDPhysicsRigidBodyParameters* defaultParameters)
{
	bool status = true;

	xmlNode* param = FindChildByType(techniqueNode, DAE_DYNAMIC_ELEMENT);
	if (param)
	{
		parameters->SetDynamic(FUStringConversion::ToBoolean(ReadNodeContentDirect(param)));
		FArchiveXML::LoadAnimatable(&parameters->GetDynamic(), param);
	}
	else if (defaultParameters != NULL)
	{
		parameters->SetDynamic(defaultParameters->GetDynamic() > 0.5f);
		if (defaultParameters->GetDynamic().IsAnimated())
		{
			defaultParameters->GetDynamic().GetAnimated()->Clone(parameters->GetDynamic().GetAnimated());
		}
	}

	xmlNode* massFrame;
	massFrame = FindChildByType(techniqueNode, DAE_MASS_FRAME_ELEMENT);
	if (massFrame)
	{
		param = FindChildByType(massFrame, DAE_TRANSLATE_ELEMENT);
		if (param)
		{
			parameters->SetMassFrameTranslate(FUStringConversion::ToVector3(ReadNodeContentDirect(param)));
			FArchiveXML::LoadAnimatable(&parameters->GetMassFrameTranslate(), param);
		}
		else if (defaultParameters != NULL)
		{
			parameters->SetMassFrameTranslate(defaultParameters->GetMassFrameTranslate());
			if (defaultParameters->GetMassFrameTranslate().IsAnimated())
			{
				defaultParameters->GetMassFrameTranslate().GetAnimated()->Clone(parameters->GetMassFrameTranslate().GetAnimated());
			}
		}
		else
		{
			// no movement
			parameters->SetMassFrameTranslate(FMVector3::Zero);
		}

		param = FindChildByType(massFrame, DAE_ROTATE_ELEMENT);
		if (param)
		{
			FMVector4 temp = FUStringConversion::ToVector4(ReadNodeContentDirect(param));
			parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3(temp.x, temp.y, temp.z), temp.w));
			LoadAnimatable(&parameters->GetMassFrameOrientation(), param);
		}
		else if (defaultParameters != NULL)
		{
			parameters->SetMassFrameOrientation(defaultParameters->GetMassFrameOrientation());
			if (defaultParameters->GetMassFrameOrientation().IsAnimated())
			{
				defaultParameters->GetMassFrameOrientation().GetAnimated()->Clone(parameters->GetMassFrameOrientation().GetAnimated());
			}
		}
		else
		{
			// no movement
			parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3::XAxis, 0.0f));
		}
	}
	else if (defaultParameters != NULL)
	{
		parameters->SetMassFrameTranslate(defaultParameters->GetMassFrameTranslate());
		parameters->SetMassFrameOrientation(defaultParameters->GetMassFrameOrientation());
		if (defaultParameters->GetMassFrameTranslate().IsAnimated())
		{
			defaultParameters->GetMassFrameTranslate().GetAnimated()->Clone(parameters->GetMassFrameTranslate().GetAnimated());
		}
		if (defaultParameters->GetMassFrameOrientation().IsAnimated())
		{
			defaultParameters->GetMassFrameOrientation().GetAnimated()->Clone(parameters->GetMassFrameOrientation().GetAnimated());
		}
	}
	else
	{
		// no movement
		parameters->SetMassFrameTranslate(FMVector3::Zero);
		parameters->SetMassFrameOrientation(FMAngleAxis(FMVector3::XAxis, 0.0f));
	}

	xmlNodeList shapeNodes;
	FindChildrenByType(techniqueNode, DAE_SHAPE_ELEMENT, shapeNodes);
	if (shapeNodes.empty())
	{
		FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_SHAPE_NODE_MISSING, techniqueNode->line);
	}
	for (xmlNodeList::iterator itS = shapeNodes.begin(); itS != shapeNodes.end(); ++itS)
	{
		FCDPhysicsShape* shape = parameters->AddPhysicsShape();
		status &= (FArchiveXML::LoadPhysicsShape(shape, *itS));
	}
	// shapes are not taken from the default parameters

	param = FindChildByType(techniqueNode, DAE_PHYSICS_MATERIAL_ELEMENT);
	if (param != NULL) 
	{
		FCDPhysicsMaterial* material = parameters->AddOwnPhysicsMaterial();
		FArchiveXML::LoadPhysicsMaterial(material, param);
	}
	else
	{
		param = FindChildByType(techniqueNode, DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT);
		if (param != NULL)
		{
			FCDEntityInstance* physicsMaterialInstance = FCDEntityInstanceFactory::CreateInstance(parameters->GetDocument(), NULL, FCDEntity::PHYSICS_MATERIAL);
			parameters->SetInstanceMaterial(physicsMaterialInstance);
			FArchiveXML::LoadSwitch(physicsMaterialInstance, &physicsMaterialInstance->GetObjectType(), param);
			FCDPhysicsMaterial* material = (FCDPhysicsMaterial*) physicsMaterialInstance->GetEntity();
			if (material == NULL)
			{
				FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, param->line);
			}
			parameters->SetPhysicsMaterial(material);
		}
		else
		{
			FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_PHYS_MAT_DEF_MISSING, techniqueNode->line);
		}
	}
	// material is not taken fromt he default parameters

	param = FindChildByType(techniqueNode, DAE_MASS_ELEMENT);
	if (param)
	{
		parameters->SetMass(FUStringConversion::ToFloat(ReadNodeContentDirect(param)));
		parameters->SetDensityMoreAccurate(false);
		parameters->SetDensity(0.0f);
		FArchiveXML::LoadAnimatable(&parameters->GetMass(), param);
	}
	else if (defaultParameters != NULL)
	{
		parameters->SetMass(defaultParameters->GetMass());
		parameters->SetDensity(defaultParameters->GetDensity());
		parameters->SetDensityMoreAccurate(defaultParameters->IsDensityMoreAccurate());
		if (defaultParameters->GetMass().IsAnimated())
		{
			defaultParameters->GetMass().GetAnimated()->Clone(parameters->GetMass().GetAnimated());
		}
	}
	else
	{
		/* Default value for mass is density x total shape volume, but 
		   since our shape's mass is already calculated with respect to the
		   volume, we can just read it from there. If the user specified a 
		   mass, then this overrides the calculation of density x volume, 
		   as expected. */
		parameters->SetMass(0.0f);
		float totalDensity = 0.0f;
		parameters->SetDensityMoreAccurate(false);
		for (size_t i = 0; i < parameters->GetPhysicsShapeCount(); ++i)
		{
			FCDPhysicsShape* shape = parameters->GetPhysicsShape(i);
			parameters->SetMass(parameters->GetMass() + shape->GetMass());
			totalDensity += shape->GetDensity();
			parameters->SetDensityMoreAccurate(parameters->IsDensityMoreAccurate() || shape->IsDensityMoreAccurate()); // common case: 1 shape, density = 1.0f
		}
		parameters->SetDensity(totalDensity / parameters->GetPhysicsShapeCount());
	}
	

	param = FindChildByType(techniqueNode, DAE_INERTIA_ELEMENT);
	if (param) 
	{
		parameters->SetInertia(FUStringConversion::ToVector3(ReadNodeContentDirect(param)));
		parameters->SetInertiaAccurate(true);
		FArchiveXML::LoadAnimatable(&parameters->GetInertia(), param);
	}
	else if (defaultParameters != NULL)
	{
		parameters->SetInertia(defaultParameters->GetInertia());
		parameters->SetInertiaAccurate(defaultParameters->IsInertiaAccurate());
		if (defaultParameters->GetInertia().IsAnimated())
		{
			defaultParameters->GetInertia().GetAnimated()->Clone(parameters->GetInertia().GetAnimated());
		}
	}
	else
	{
		/* FIXME: Approximation: sphere shape, with mass distributed 
		   equally across the volume and center of mass is at the center of
		   the sphere. Real moments of inertia call for complex 
		   integration. Sphere it is simply I = k * m * r^2 on all axes. */
		float volume = 0.0f;
		for (size_t i = 0; i < parameters->GetPhysicsShapeCount(); ++i)
		{
			volume += parameters->GetPhysicsShape(i)->CalculateVolume();
		}

		float radiusCubed = 0.75f * volume / (float)FMath::Pi;
		float I = 0.4f * parameters->GetMass() * pow(radiusCubed, 2.0f / 3.0f);
		parameters->SetInertia(FMVector3(I, I, I));
		parameters->SetInertiaAccurate(false);
	}

	return status;
}