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, ¶meter->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; }
bool FArchiveXML::LoadPhysicsScene(FCDObject* object, xmlNode* sceneNode) { if (!FArchiveXML::LoadEntity(object, sceneNode)) return false; bool status = true; FCDPhysicsScene* physicsScene = (FCDPhysicsScene*)object; if (IsEquivalent(sceneNode->name, DAE_PHYSICS_SCENE_ELEMENT)) { for (xmlNode* child = sceneNode->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; // Look for instantiation elements if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT)) { FCDPhysicsModelInstance* instance = physicsScene->AddPhysicsModelInstance(NULL); status &= (FArchiveXML::LoadPhysicsModelInstance(instance, child)); continue; } else if (IsEquivalent(child->name, DAE_TECHNIQUE_COMMON_ELEMENT)) { xmlNode* gravityNode = FindChildByType(child, DAE_GRAVITY_ATTRIBUTE); if (gravityNode) { const char* gravityVal = ReadNodeContentDirect(gravityNode); FMVector3 gravity; gravity.x = FUStringConversion::ToFloat(&gravityVal); gravity.y = FUStringConversion::ToFloat(&gravityVal); gravity.z = FUStringConversion::ToFloat(&gravityVal); physicsScene->SetGravity(gravity); } xmlNode* timestepNode = FindChildByType(child, DAE_TIME_STEP_ATTRIBUTE); if (timestepNode) { physicsScene->SetTimestep(FUStringConversion::ToFloat(ReadNodeContentDirect(timestepNode))); } } else if (IsEquivalent(child->name, DAE_INSTANCE_FORCE_FIELD_ELEMENT)) { FCDPhysicsForceFieldInstance* instance = physicsScene->AddForceFieldInstance(NULL); status &= (FArchiveXML::LoadPhysicsForceFieldInstance(instance, child)); } else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT)) { // The extra information is loaded by the FCDEntity class. } } } physicsScene->SetDirtyFlag(); return status; }
// Retrieves a list of strings from a source node void ReadSource(xmlNode* sourceNode, StringList& array) { if (sourceNode != NULL) { // Get the accessor's count xmlNode* accessorNode = FindTechniqueAccessor(sourceNode); array.resize(ReadNodeCount(accessorNode)); xmlNode* arrayNode = FindChildByType(sourceNode, DAE_NAME_ARRAY_ELEMENT); if (arrayNode == NULL) arrayNode = FindChildByType(sourceNode, DAE_IDREF_ARRAY_ELEMENT); const char* arrayContent = ReadNodeContentDirect(arrayNode); FUStringConversion::ToStringList(arrayContent, array); } }
bool FArchiveXML::LoadPhysicsRigidBody(FCDObject* object, xmlNode* physicsRigidBodyNode) { if (!FArchiveXML::LoadEntity(object, physicsRigidBodyNode)) return false; bool status = true; FCDPhysicsRigidBody* physicsRigidBody = (FCDPhysicsRigidBody*)object; if (!IsEquivalent(physicsRigidBodyNode->name, DAE_RIGID_BODY_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PRB_LIB_ELEMENT, physicsRigidBodyNode->line); return status; } physicsRigidBody->SetSubId(FUDaeParser::ReadNodeSid(physicsRigidBodyNode)); xmlNode* techniqueNode = FindChildByType(physicsRigidBodyNode, DAE_TECHNIQUE_COMMON_ELEMENT); if (techniqueNode != NULL) { FArchiveXML::LoadPhysicsRigidBodyParameters(physicsRigidBody->GetParameters(), techniqueNode); } else { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_COMMON_TECHNIQUE_MISSING, physicsRigidBodyNode->line); } return status; }
bool FArchiveXML::LoadPhysicsMaterial(FCDObject* object, xmlNode* physicsMaterialNode) { if (!FArchiveXML::LoadEntity(object, physicsMaterialNode)) return false; bool status = true; FCDPhysicsMaterial* physicsMaterial = (FCDPhysicsMaterial*)object; if (!IsEquivalent(physicsMaterialNode->name, DAE_PHYSICS_MATERIAL_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PHYS_MAT_LIB_ELEMENT, physicsMaterialNode->line); return status; } // Read in the <technique_common> element xmlNode* commonTechniqueNode = FindChildByType(physicsMaterialNode, DAE_TECHNIQUE_COMMON_ELEMENT); if (commonTechniqueNode == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_COMMON_TECHNIQUE_MISSING, physicsMaterialNode->line); } xmlNode* paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_STATIC_FRICTION); if (paramNode != NULL) { const char* content = ReadNodeContentDirect(paramNode); physicsMaterial->SetStaticFriction(FUStringConversion::ToFloat(content)); } paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_DYNAMIC_FRICTION); if (paramNode != NULL) { const char* content = ReadNodeContentDirect(paramNode); physicsMaterial->SetDynamicFriction(FUStringConversion::ToFloat(content)); } paramNode = FindChildByType(commonTechniqueNode, DAE_PHYSICS_RESTITUTION); if (paramNode != NULL) { const char* content = ReadNodeContentDirect(paramNode); physicsMaterial->SetRestitution(FUStringConversion::ToFloat(content)); } physicsMaterial->SetDirtyFlag(); return status; }
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; }
// Retrieves a list of floats from a source node // Returns the data's stride. uint32 ReadSource(xmlNode* sourceNode, FloatList& array) { uint32 stride = 0; if (sourceNode != NULL) { // Get the accessor's count xmlNode* accessorNode = FindTechniqueAccessor(sourceNode); stride = ReadNodeStride(accessorNode); array.resize(ReadNodeCount(accessorNode) * stride); xmlNode* arrayNode = FindChildByType(sourceNode, DAE_FLOAT_ARRAY_ELEMENT); const char* arrayContent = ReadNodeContentDirect(arrayNode); FUStringConversion::ToFloatList(arrayContent, array); } return stride; }
// Retrieves a series of interpolation values from a source node void ReadSourceInterpolation(xmlNode* sourceNode, UInt32List& array) { if (sourceNode != NULL) { // Get the accessor's count xmlNode* accessorNode = FindTechniqueAccessor(sourceNode); uint32 count = ReadNodeCount(accessorNode); array.resize(count); // Backward compatibility: drop the unwanted interpolation values. // Before, we exported one interpolation token for each dimension of a merged curve. // Now, we export one interpolation token for each key of a merged curve. uint32 stride = ReadNodeStride(accessorNode); StringList stringArray(count * stride); xmlNode* arrayNode = FindChildByType(sourceNode, DAE_NAME_ARRAY_ELEMENT); const char* arrayContent = ReadNodeContentDirect(arrayNode); FUStringConversion::ToStringList(arrayContent, stringArray); for (uint32 i = 0; i < count; ++i) { array[i] = (uint32) FUDaeInterpolation::FromString(stringArray[i * stride]); } } }
// Retrieves a series of interleaved floats from a source node void ReadSourceInterleaved(xmlNode* sourceNode, fm::pvector<FloatList>& arrays) { if (sourceNode != NULL) { // Get the accessor's count xmlNode* accessorNode = FindTechniqueAccessor(sourceNode); uint32 count = ReadNodeCount(accessorNode); for (fm::pvector<FloatList>::iterator it = arrays.begin(); it != arrays.end(); ++it) { (*it)->resize(count); } // Use the stride to pad the interleaved float lists or remove extra elements uint32 stride = ReadNodeStride(accessorNode); while (stride < arrays.size()) arrays.pop_back(); while (stride > arrays.size()) arrays.push_back(NULL); // Read and parse the float array xmlNode* arrayNode = FindChildByType(sourceNode, DAE_FLOAT_ARRAY_ELEMENT); const char* arrayContent = ReadNodeContentDirect(arrayNode); FUStringConversion::ToInterleavedFloatList(arrayContent, arrays); } }
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::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(¶meters->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(¶meters->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(¶meters->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(¶meters->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(¶meters->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; }
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; }
// Returns the accessor node for a given source node xmlNode* FindTechniqueAccessor(xmlNode* parent) { xmlNode* techniqueNode = FindChildByType(parent, DAE_TECHNIQUE_COMMON_ELEMENT); return FindChildByType(techniqueNode, DAE_ACCESSOR_ELEMENT); }
uint32 ReadSourceInterleaved(xmlNode* sourceNode, fm::pvector<FMVector3List>& arrays) { uint32 stride = 1; if (sourceNode != NULL) { // Get the accessor's count xmlNode* accessorNode = FindTechniqueAccessor(sourceNode); uint32 count = ReadNodeCount(accessorNode); for (fm::pvector<FMVector3List>::iterator it = arrays.begin(); it != arrays.end(); ++it) { (*it)->resize(count); } // Backward Compatibility: if the stride is exactly half the expected value, // then we have the old 1D tangents that we need to parse correctly. stride = ReadNodeStride(accessorNode); if (stride > 0 && stride == arrays.size()) { // Read and parse the float array xmlNode* arrayNode = FindChildByType(sourceNode, DAE_FLOAT_ARRAY_ELEMENT); const char* value = ReadNodeContentDirect(arrayNode); for (size_t i = 0; i < count && *value != 0; ++i) { for (size_t j = 0; j < stride && *value != 0; ++j) { arrays[j]->at(i) = FMVector3(FUStringConversion::ToFloat(&value), 0.0f, 0.0f); } } while (*value != 0) { for (size_t i = 0; i < stride && *value != 0; ++i) { arrays[i]->push_back(FMVector3(FUStringConversion::ToFloat(&value), 0.0f, 0.0f)); } } } else { // Use the stride to pad the interleaved float lists or remove extra elements while (stride < arrays.size() * 3) arrays.pop_back(); while (stride > arrays.size() * 3) arrays.push_back(NULL); // Read and parse the float array xmlNode* arrayNode = FindChildByType(sourceNode, DAE_FLOAT_ARRAY_ELEMENT); const char* value = ReadNodeContentDirect(arrayNode); for (size_t i = 0; i < count && *value != 0; ++i) { for (size_t j = 0; 3 * j < stride && *value != 0; ++j) { if (arrays[j] != NULL) { arrays[j]->at(i).x = FUStringConversion::ToFloat(&value); arrays[j]->at(i).y = FUStringConversion::ToFloat(&value); arrays[j]->at(i).z = FUStringConversion::ToFloat(&value); } else { FUStringConversion::ToFloat(&value); FUStringConversion::ToFloat(&value); FUStringConversion::ToFloat(&value); } } } while (*value != 0) { for (size_t i = 0; 2 * i < stride && *value != 0; ++i) { if (arrays[i] != NULL) { FMVector3 v; v.x = FUStringConversion::ToFloat(&value); v.y = FUStringConversion::ToFloat(&value); v.z = FUStringConversion::ToFloat(&value); arrays[i]->push_back(v); } else { FUStringConversion::ToFloat(&value); FUStringConversion::ToFloat(&value); FUStringConversion::ToFloat(&value); } } } } } return stride; }