// Parse the stride attribute off a node uint32 ReadNodeStride(xmlNode* node) { fm::string strideString = ReadNodeProperty(node, DAE_STRIDE_ATTRIBUTE); uint32 stride = FUStringConversion::ToUInt32(strideString); if (stride == 0) stride = 1; return stride; }
bool FArchiveXML::LoadPhysicsRigidConstraintInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDPhysicsRigidConstraintInstance* physicsRigidConstraintInstance = (FCDPhysicsRigidConstraintInstance*)object; // Check for the expected instantiation node type if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT) || physicsRigidConstraintInstance->GetModelParentInstance() == NULL || physicsRigidConstraintInstance->GetModelParentInstance()->GetEntity() == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line); status = false; } FCDPhysicsModel* model = (FCDPhysicsModel*) physicsRigidConstraintInstance->GetModelParentInstance()->GetEntity(); fm::string physicsRigidConstraintSid = ReadNodeProperty(instanceNode, DAE_CONSTRAINT_ATTRIBUTE); FCDPhysicsRigidConstraint* rigidConstraint = model->FindRigidConstraintFromSid(physicsRigidConstraintSid); if (!rigidConstraint) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_RIGID_CONSTRAINT_MISSING, instanceNode->line); return status; } physicsRigidConstraintInstance->SetRigidConstraint(rigidConstraint); physicsRigidConstraintInstance->SetDirtyFlag(); return status; }
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; }
// return the first node in list of a given property xmlNode* FindNodeInListByProperty(xmlNodeList list, const char* property, const char* prop) { for (xmlNodeList::iterator it = list.begin(); it != list.end(); ++it) { xmlNode* element = *it; fm::string str_prop = ReadNodeProperty(element, property); if (str_prop == prop) return element; } return NULL; }
// return the first child node of a given property value xmlNode* FindChildByProperty(xmlNode* parent, const char* prop, const char* val) { if (parent != NULL) { for (xmlNode* child = parent->children; child != NULL; child = child->next) { fm::string str_pop = ReadNodeProperty(child, prop); if (str_pop == val) return child; } } return NULL; }
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; }
// Calculate the target pointer for a targetable node void CalculateNodeTargetPointer(xmlNode* target, fm::string& pointer) { if (target != NULL) { // The target node should have either a subid or an id if (HasNodeProperty(target, DAE_ID_ATTRIBUTE)) { pointer = ReadNodeId(target); return; } else if (!HasNodeProperty(target, DAE_SID_ATTRIBUTE)) { pointer.clear(); return; } // Generate a list of parent nodes up to the first properly identified parent xmlNodeList traversal; traversal.reserve(16); traversal.push_back(target); xmlNode* current = target->parent; while (current != NULL) { traversal.push_back(current); if (HasNodeProperty(current, DAE_ID_ATTRIBUTE)) break; current = current->parent; } // The top parent should have the ID property FUSStringBuilder builder; intptr_t nodeCount = (intptr_t) traversal.size(); builder.append(ReadNodeId(traversal[nodeCount - 1])); if (builder.empty()) { pointer.clear(); return; } // Build up the target string for (intptr_t i = nodeCount - 2; i >= 0; --i) { xmlNode* node = traversal[i]; fm::string subId = ReadNodeProperty(node, DAE_SID_ATTRIBUTE); if (!subId.empty()) { builder.append('/'); builder.append(subId); } } pointer = builder.ToString(); } else pointer.clear(); }
// return the first child node of a given name xmlNode* FindChildByName(xmlNode* parent, const char* name) { if (parent != NULL) { for (xmlNode* child = parent->children; child != NULL; child = child->next) { if (child->type == XML_ELEMENT_NODE) { fm::string str_name = ReadNodeProperty(child, "name"); if (str_name == name) return child; } } } return NULL; }
// Returns the first child with the given 'sid' value within a given XML hierarchy xmlNode* FindHierarchyChildBySid(xmlNode* hierarchyRoot, const char* sid) { if (hierarchyRoot == NULL) return NULL; if (ReadNodeProperty(hierarchyRoot, DAE_SID_ATTRIBUTE) == sid) return hierarchyRoot; xmlNode* found = NULL; for (xmlNode* child = hierarchyRoot->children; child != NULL && found == NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; //if (ReadNodeProperty(child, DAE_SID_ATTRIBUTE) == sid) return child; found = FindHierarchyChildBySid(child, sid); } return found; }
// 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; }
bool FArchiveXML::LoadExtra(FCDObject* object, xmlNode* extraNode) { FCDExtra* extra = (FCDExtra*)object; bool status = true; // Do NOT assume that we have an <extra> element: we may be parsing a type switch instead. FCDEType* parsingType = NULL; if (IsEquivalent(extraNode->name, DAE_EXTRA_ELEMENT)) { parsingType = extra->AddType(ReadNodeProperty(extraNode, DAE_TYPE_ATTRIBUTE)); } if (parsingType == NULL) parsingType = extra->GetDefaultType(); FArchiveXML::LoadSwitch(parsingType, &parsingType->GetObjectType(), extraNode); extra->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; }
bool FArchiveXML::LoadAsset(FCDObject* object, xmlNode* assetNode) { FCDAsset* asset = (FCDAsset*)object; bool status = true; for (xmlNode* child = assetNode->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; fm::string content = ReadNodeContentFull(child); if (IsEquivalent(child->name, DAE_CONTRIBUTOR_ASSET_ELEMENT)) { FCDAssetContributor* contributor = asset->AddContributor(); status &= FArchiveXML::LoadAssetContributor(contributor, child); } else if (IsEquivalent(child->name, DAE_CREATED_ASSET_PARAMETER)) { FUStringConversion::ToDateTime(content, asset->GetCreationDateTime()); } else if (IsEquivalent(child->name, DAE_KEYWORDS_ASSET_PARAMETER)) { asset->SetKeywords(TO_FSTRING(content)); } else if (IsEquivalent(child->name, DAE_MODIFIED_ASSET_PARAMETER)) { FUStringConversion::ToDateTime(content, asset->GetModifiedDateTime()); } else if (IsEquivalent(child->name, DAE_REVISION_ASSET_PARAMETER)) { asset->SetRevision(TO_FSTRING(content)); } else if (IsEquivalent(child->name, DAE_SUBJECT_ASSET_PARAMETER)) { asset->SetSubject(TO_FSTRING(content)); } else if (IsEquivalent(child->name, DAE_TITLE_ASSET_PARAMETER)) { asset->SetTitle(TO_FSTRING(content)); } else if (IsEquivalent(child->name, DAE_UNITS_ASSET_PARAMETER)) { asset->SetUnitName(TO_FSTRING(ReadNodeName(child))); asset->SetUnitConversionFactor(FUStringConversion::ToFloat(ReadNodeProperty(child, DAE_METERS_ATTRIBUTE))); if (asset->GetUnitName().empty()) asset->SetUnitName(FC("UNKNOWN")); if (IsEquivalent(asset->GetUnitConversionFactor(), 0.0f) || asset->GetUnitConversionFactor() < 0.0f) asset->SetUnitConversionFactor(1.0f); } else if (IsEquivalent(child->name, DAE_UPAXIS_ASSET_PARAMETER)) { if (IsEquivalent(content, DAE_X_UP)) asset->SetUpAxis(FMVector3::XAxis); else if (IsEquivalent(content, DAE_Y_UP)) asset->SetUpAxis(FMVector3::YAxis); else if (IsEquivalent(content, DAE_Z_UP)) asset->SetUpAxis(FMVector3::ZAxis); } else { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_CHILD_ELEMENT, child->line); } } asset->SetDirtyFlag(); return status; }
bool FArchiveXML::LoadPhysicsRigidConstraint(FCDObject* object, xmlNode* physicsRigidConstraintNode) { if (!FArchiveXML::LoadEntity(object, physicsRigidConstraintNode)) return false; bool status = true; FCDPhysicsRigidConstraint* physicsRigidConstraint = (FCDPhysicsRigidConstraint*)object; if (!IsEquivalent(physicsRigidConstraintNode->name, DAE_RIGID_CONSTRAINT_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_RGC_LIB_ELEMENT, physicsRigidConstraintNode->line); return status; } physicsRigidConstraint->SetSubId(FUDaeParser::ReadNodeSid(physicsRigidConstraintNode)); #define PARSE_TRANSFORM(node, className, nodeName, transforms) { \ xmlNodeList transformNodes; \ FindChildrenByType(node, nodeName, transformNodes); \ for (xmlNodeList::iterator itT = transformNodes.begin(); itT != transformNodes.end(); ++itT) \ { \ if (IsEquivalent((*itT)->name, nodeName)) { \ className* transform = new className(physicsRigidConstraint->GetDocument(), NULL); \ transforms.push_back(transform); \ status = FArchiveXML::LoadSwitch(transform, &transform->GetObjectType(), *itT); \ if (!status) { \ FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_NODE_TRANSFORM, (*itT)->line);} \ } \ } } //Reference-frame body xmlNode* referenceBodyNode = FindChildByType(physicsRigidConstraintNode, DAE_REF_ATTACHMENT_ELEMENT); if (referenceBodyNode == NULL) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_RF_NODE_MISSING, physicsRigidConstraintNode->line); } fm::string strRigidBody = ReadNodeProperty(referenceBodyNode, DAE_RIGID_BODY_ELEMENT); physicsRigidConstraint->SetReferenceRigidBody(physicsRigidConstraint->GetParent()->FindRigidBodyFromSid(strRigidBody)); if (physicsRigidConstraint->GetReferenceRigidBody() == NULL) { physicsRigidConstraint->SetReferenceNode(physicsRigidConstraint->GetDocument()->FindSceneNode(strRigidBody)); if ((physicsRigidConstraint->GetReferenceNode() == NULL) && (referenceBodyNode != NULL)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_RF_REF_NODE_MISSING, referenceBodyNode->line); } } // Parse the node's transforms: <rotate>, <translate> PARSE_TRANSFORM(referenceBodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, physicsRigidConstraint->GetTransformsRef()) PARSE_TRANSFORM(referenceBodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, physicsRigidConstraint->GetTransformsRef()) // target body xmlNode* bodyNode = FindChildByType(physicsRigidConstraintNode, DAE_ATTACHMENT_ELEMENT); if (bodyNode == NULL) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_TARGET_BS_NODE_MISSING, physicsRigidConstraintNode->line); } strRigidBody = ReadNodeProperty(bodyNode, DAE_RIGID_BODY_ELEMENT); physicsRigidConstraint->SetTargetRigidBody(physicsRigidConstraint->GetParent()->FindRigidBodyFromSid(strRigidBody)); if (physicsRigidConstraint->GetTargetRigidBody() == NULL) { physicsRigidConstraint->SetTargetNode(physicsRigidConstraint->GetDocument()->FindSceneNode(strRigidBody)); if ((physicsRigidConstraint->GetTargetNode() == NULL) && (bodyNode != NULL)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_TARGE_BS_REF_NODE_MISSING, bodyNode->line); } } // Parse the node's transforms: <rotate>, <scale>, <translate> PARSE_TRANSFORM(bodyNode, FCDTRotation, DAE_ROTATE_ELEMENT, physicsRigidConstraint->GetTransformsTar()) PARSE_TRANSFORM(bodyNode, FCDTTranslation, DAE_TRANSLATE_ELEMENT, physicsRigidConstraint->GetTransformsTar()) #undef PARSE_TRANSFORM //technique_common xmlNode* techniqueNode = FindChildByType(physicsRigidConstraintNode, DAE_TECHNIQUE_COMMON_ELEMENT); if (techniqueNode == NULL) { //return status.Fail(FS("Technique node not specified in rigid_constraint ") + TO_FSTRING(GetDaeId()), physicsRigidConstraintNode->line); FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_TECHNIQUE_NODE_MISSING, physicsRigidConstraintNode->line); return status; } xmlNode* enabledNode = FindChildByType(techniqueNode, DAE_ENABLED_ELEMENT); if (enabledNode != NULL) { physicsRigidConstraint->SetEnabled(FUStringConversion::ToBoolean(ReadNodeContentDirect(enabledNode))); FArchiveXML::LoadAnimatable(&physicsRigidConstraint->GetEnabled(), enabledNode); } xmlNode* interpenetrateNode = FindChildByType(techniqueNode, DAE_INTERPENETRATE_ELEMENT); if (interpenetrateNode != NULL) { physicsRigidConstraint->SetInterpenetrate(FUStringConversion::ToBoolean(ReadNodeContentDirect(interpenetrateNode))); FArchiveXML::LoadAnimatable(&physicsRigidConstraint->GetInterpenetrate(), interpenetrateNode); } xmlNode* limitsNode = FindChildByType(techniqueNode, DAE_LIMITS_ELEMENT); if (limitsNode != NULL) { xmlNode* linearNode = FindChildByType(limitsNode, DAE_LINEAR_ELEMENT); if (linearNode != NULL) { xmlNode* linearMinNode = FindChildByType(linearNode, DAE_MIN_ELEMENT); if (linearMinNode != NULL) { const char* min = ReadNodeContentDirect(linearMinNode); physicsRigidConstraint->SetLimitsLinearMin(FUStringConversion::ToVector3(min)); } xmlNode* linearMaxNode = FindChildByType(linearNode, DAE_MAX_ELEMENT); if (linearMaxNode != NULL) { const char* max = ReadNodeContentDirect(linearMaxNode); physicsRigidConstraint->SetLimitsLinearMax(FUStringConversion::ToVector3(max)); } } xmlNode* sctNode = FindChildByType(limitsNode, DAE_SWING_CONE_AND_TWIST_ELEMENT); if (sctNode != NULL) { xmlNode* sctMinNode = FindChildByType(sctNode, DAE_MIN_ELEMENT); if (sctMinNode != NULL) { const char* min = ReadNodeContentDirect(sctMinNode); physicsRigidConstraint->SetLimitsSCTMin(FUStringConversion::ToVector3(min)); } xmlNode* sctMaxNode = FindChildByType(sctNode, DAE_MAX_ELEMENT); if (sctMaxNode != NULL) { const char* max = ReadNodeContentDirect(sctMaxNode); physicsRigidConstraint->SetLimitsSCTMax(FUStringConversion::ToVector3(max)); } } } xmlNode* spring = FindChildByType(physicsRigidConstraintNode, DAE_SPRING_ELEMENT); if (spring) { xmlNode* linearSpring = FindChildByType(spring, DAE_LINEAR_ELEMENT); if (linearSpring) { xmlNode* param = FindChildByType(linearSpring, DAE_DAMPING_ELEMENT); if (param) physicsRigidConstraint->SetSpringLinearDamping(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); param = FindChildByType(linearSpring, DAE_STIFFNESS_ELEMENT); if (param) physicsRigidConstraint->SetSpringLinearStiffness(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); param = FindChildByType(linearSpring, DAE_TARGET_VALUE_ELEMENT); if (!param) param = FindChildByType(linearSpring, DAE_REST_LENGTH_ELEMENT1_3); // COLLADA 1.3 backward compatibility if (param) physicsRigidConstraint->SetSpringLinearTargetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); } xmlNode* angularSpring = FindChildByType(spring, DAE_ANGULAR_ELEMENT); if (angularSpring) { xmlNode* param = FindChildByType(angularSpring, DAE_DAMPING_ELEMENT); if (param) physicsRigidConstraint->SetSpringAngularDamping(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); param = FindChildByType(angularSpring, DAE_STIFFNESS_ELEMENT); if (param) physicsRigidConstraint->SetSpringAngularStiffness(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); param = FindChildByType(angularSpring, DAE_TARGET_VALUE_ELEMENT); if (!param) param = FindChildByType(angularSpring, DAE_REST_LENGTH_ELEMENT1_3); // COLLADA 1.3 backward compatibility if (param) physicsRigidConstraint->SetSpringAngularTargetValue(FUStringConversion::ToFloat(ReadNodeContentDirect(param))); } } physicsRigidConstraint->SetDirtyFlag(); return status; }
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::LoadPhysicsRigidBodyInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDPhysicsRigidBodyInstance* physicsRigidBodyInstance = (FCDPhysicsRigidBodyInstance*)object; // Check for the expected instantiation node type if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_RIGID_BODY_ELEMENT) || physicsRigidBodyInstance->GetModelParentInstance() == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line); status = false; } // Find the target scene node/rigid body fm::string targetNodeId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE); physicsRigidBodyInstance->SetTargetNode(physicsRigidBodyInstance->GetDocument()->FindSceneNode(SkipPound(targetNodeId))); if (!physicsRigidBodyInstance->GetTargetNode()) { FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, instanceNode->line); } // Find the instantiated rigid body FCDPhysicsRigidBody* body = NULL; fm::string physicsRigidBodySid = ReadNodeProperty(instanceNode, DAE_BODY_ATTRIBUTE); if (physicsRigidBodyInstance->GetModelParentInstance()->GetEntity() != NULL && physicsRigidBodyInstance->GetModelParentInstance()->GetEntity()->GetType() == FCDEntity::PHYSICS_MODEL) { FCDPhysicsModel* model = (FCDPhysicsModel*) physicsRigidBodyInstance->GetModelParentInstance()->GetEntity(); body = model->FindRigidBodyFromSid(physicsRigidBodySid); if (body == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, instanceNode->line); return false; } physicsRigidBodyInstance->SetRigidBody(body); } //Read in the same children as rigid_body + velocity and angular_velocity xmlNode* techniqueNode = FindChildByType(instanceNode, DAE_TECHNIQUE_COMMON_ELEMENT); if (techniqueNode == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_TECHNIQUE_NODE_MISSING, instanceNode->line); return false; } xmlNode* param = FindChildByType(techniqueNode, DAE_ANGULAR_VELOCITY_ELEMENT); if (param != NULL) { physicsRigidBodyInstance->SetAngularVelocity(FUStringConversion::ToVector3( ReadNodeContentDirect(param))); } else { physicsRigidBodyInstance->SetAngularVelocity(FMVector3::Zero); } param = FindChildByType(techniqueNode, DAE_VELOCITY_ELEMENT); if (param != NULL) { physicsRigidBodyInstance->SetVelocity(FUStringConversion::ToVector3(ReadNodeContentDirect(param))); } else { physicsRigidBodyInstance->SetVelocity(FMVector3::Zero); } FArchiveXML::LoadPhysicsRigidBodyParameters(physicsRigidBodyInstance->GetParameters(), techniqueNode, body->GetParameters()); physicsRigidBodyInstance->SetDirtyFlag(); return status; }
// Parse the Url attribute off a node FUUri ReadNodeUrl(xmlNode* node, const char* attribute) { fm::string uriString = ReadNodeProperty(node, attribute); return FUUri(TO_FSTRING(uriString)); }
// Parse the count attribute off a node uint32 ReadNodeCount(xmlNode* node) { fm::string countString = ReadNodeProperty(node, DAE_COUNT_ATTRIBUTE); return FUStringConversion::ToUInt32(countString); }
bool FArchiveXML::LoadSceneNode(FCDObject* object, xmlNode* node) { if (!FArchiveXML::LoadEntity(object, node)) return false; bool status = true; FCDSceneNode* sceneNode = (FCDSceneNode*)object; if (!IsEquivalent(node->name, DAE_VSCENE_ELEMENT) && !IsEquivalent(node->name, DAE_NODE_ELEMENT)) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, node->line); } // Read a subid if we gots one fm::string nodeSubId = ReadNodeProperty(node, DAE_SID_ATTRIBUTE); sceneNode->SetSubId(nodeSubId); // Read in the <node> element's type fm::string nodeType = ReadNodeProperty(node, DAE_TYPE_ATTRIBUTE); if (nodeType == DAE_JOINT_NODE_TYPE) sceneNode->SetJointFlag(true); else if (nodeType.length() == 0 || nodeType == DAE_NODE_NODE_TYPE) {} // No special consideration else { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOW_NODE_ELEMENT_TYPE, node->line); } // The scene node has ordered elements, so process them directly and in order. for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_NODE_ELEMENT)) { // Load the child scene node FCDSceneNode* node = sceneNode->AddChildNode(); status = FArchiveXML::LoadSceneNode(node, child); if (!status) break; } // Although this case can be handled by FCDEntityInstanceFactory, // we can do some special case handling here. else if (IsEquivalent(child->name, DAE_INSTANCE_NODE_ELEMENT)) { FUUri url = ReadNodeUrl(child); if (!url.IsFile()) { // cannot find the node FCDSceneNode* node = sceneNode->GetDocument()->FindSceneNode(TO_STRING(url.GetFragment())); if (node != NULL) { if (!sceneNode->AddChildNode(node)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_CYCLE_DETECTED, child->line); } } else { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_NODE_INST, child->line); } } else { FCDEntityInstance* reference = sceneNode->AddInstance(FCDEntity::SCENE_NODE); FArchiveXML::LoadEntityInstance(reference, child); } } else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT)) {} // Handled by FCDEntity. else if (IsEquivalent(child->name, DAE_ASSET_ELEMENT)) {} // Handled by FCDEntity. else { uint32 transformType = FArchiveXML::GetTransformType(child); if (transformType != (uint32) ~0) { FCDTransform* transform = sceneNode->AddTransform((FCDTransform::Type) transformType); fm::string childSubId = ReadNodeProperty(child, DAE_SID_ATTRIBUTE); transform->SetSubId(childSubId); status &= (FArchiveXML::LoadSwitch(transform, &transform->GetObjectType(), child)); } else { uint32 instanceType = FArchiveXML::GetEntityInstanceType(child); if (instanceType != (uint32) ~0) { FCDEntityInstance* instance = sceneNode->AddInstance((FCDEntity::Type) instanceType); status &= (FArchiveXML::LoadSwitch(instance, &instance->GetObjectType(), child)); } else { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_TRANSFORM, child->line); } } } } status &= FArchiveXML::LoadFromExtraSceneNode(sceneNode); sceneNode->SetTransformsDirtyFlag(); sceneNode->SetDirtyFlag(); return status; }
// Retrieves the target property of a targeting node, split into its pointer and its qualifier(s) void ReadNodeTargetProperty(xmlNode* targetingNode, fm::string& pointer, fm::string& qualifier) { fm::string target = ReadNodeProperty(targetingNode, DAE_TARGET_ATTRIBUTE); FUStringConversion::SplitTarget(target, pointer, qualifier); }