/* Copyright (C) 2005-2007 Feeling Software Inc. Portions of the code are: Copyright (C) 2005-2007 Sony Computer Entertainment America MIT License: http://www.opensource.org/licenses/mit-license.php */ #include "StdAfx.h" #include "FArchiveXML.h" #include "FCDocument/FCDAnimated.h" #include "FCDocument/FCDocument.h" #include "FCDocument/FCDEntityInstance.h" #include "FCDocument/FCDEntityReference.h" #include "FCDocument/FCDPhysicsForceFieldInstance.h" #include "FCDocument/FCDGeometryInstance.h" #include "FCDocument/FCDPhysicsModelInstance.h" #include "FCDocument/FCDPhysicsRigidBodyParameters.h" #include "FCDocument/FCDPhysicsAnalyticalGeometry.h" #include "FCDocument/FCDPhysicsMaterial.h" #include "FCDocument/FCDPhysicsModel.h" #include "FCDocument/FCDPhysicsRigidBody.h" #include "FCDocument/FCDPhysicsRigidConstraint.h" #include "FCDocument/FCDPhysicsScene.h" #include "FCDocument/FCDPhysicsShape.h" 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::AttachModelInstancesFCDPhysicsModel(FCDPhysicsModel* physicsModel) { bool status = true; FCDPhysicsModelDataMap::iterator it = FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap.find(physicsModel); FUAssert(it != FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap.end(),); FCDPhysicsModelData& data = it->second; for (ModelInstanceNameNodeMap::iterator it = data.modelInstancesMap.begin(); it != data.modelInstancesMap.end(); ++it) { FCDPhysicsModelInstance* instance = physicsModel->AddPhysicsModelInstance(); status &= FArchiveXML::LoadPhysicsModelInstance(instance, it->first); } data.modelInstancesMap.clear(); return status; } bool FArchiveXML::LoadPhysicsShape(FCDObject* object, xmlNode* physicsShapeNode) { FCDPhysicsShape* physicsShape = (FCDPhysicsShape*)object; bool status = true; if (!IsEquivalent(physicsShapeNode->name, DAE_SHAPE_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOW_PS_LIB_ELEMENT, physicsShapeNode->line); return status; } // Read in the first valid child element found for (xmlNode* child = physicsShapeNode->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HOLLOW_ELEMENT)) { physicsShape->SetHollow(FUStringConversion::ToBoolean(ReadNodeContentDirect(child))); } else if (IsEquivalent(child->name, DAE_MASS_ELEMENT)) { physicsShape->SetMass(FUStringConversion::ToFloat(ReadNodeContentDirect(child))); physicsShape->SetDensityMoreAccurate(false); } else if (IsEquivalent(child->name, DAE_DENSITY_ELEMENT)) { physicsShape->SetDensity(FUStringConversion::ToFloat(ReadNodeContentDirect(child))); physicsShape->SetDensityMoreAccurate(physicsShape->GetMassPointer() == NULL); // mass before density in COLLADA 1.4.1 } else if (IsEquivalent(child->name, DAE_PHYSICS_MATERIAL_ELEMENT)) { FCDPhysicsMaterial* material = physicsShape->AddOwnPhysicsMaterial(); FArchiveXML::LoadPhysicsMaterial(material, child); } else if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MATERIAL_ELEMENT)) { physicsShape->SetInstanceMaterial(FCDEntityInstanceFactory::CreateInstance(physicsShape->GetDocument(), NULL, FCDEntity::PHYSICS_MATERIAL)); FArchiveXML::LoadSwitch(physicsShape->GetInstanceMaterial(), &physicsShape->GetInstanceMaterial()->GetObjectType(), child); if (!HasNodeProperty(child, DAE_URL_ATTRIBUTE)) { //inline definition of physics_material FCDPhysicsMaterial* material = physicsShape->AddOwnPhysicsMaterial(); FArchiveXML::LoadPhysicsMaterial(material, child); physicsShape->GetInstanceMaterial()->SetEntity(material); } } else if (IsEquivalent(child->name, DAE_INSTANCE_GEOMETRY_ELEMENT)) { FUUri url = ReadNodeUrl(child); if (!url.IsFile()) { FCDGeometry* entity = physicsShape->GetDocument()->FindGeometry(TO_STRING(url.GetFragment())); if (entity != NULL) { physicsShape->SetAnalyticalGeometry(NULL); physicsShape->SetGeometryInstance((FCDGeometryInstance*)FCDEntityInstanceFactory::CreateInstance(physicsShape->GetDocument(), NULL, FCDEntity::GEOMETRY)); physicsShape->GetGeometryInstance()->SetEntity((FCDEntity*)entity); status &= (FArchiveXML::LoadGeometryInstance(physicsShape->GetGeometryInstance(), child)); continue; } } FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_FCDGEOMETRY_INST_MISSING, child->line); } #define PARSE_ANALYTICAL_SHAPE(type, nodeName) \ else if (IsEquivalent(child->name, nodeName)) { \ FCDPhysicsAnalyticalGeometry* analytical = physicsShape->CreateAnalyticalGeometry(FCDPhysicsAnalyticalGeometry::type); \ status = FArchiveXML::LoadPhysicsAnalyticalGeometry(analytical, child); \ if (!status) { \ FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SHAPE_NODE, child->line); break; \ } } PARSE_ANALYTICAL_SHAPE(BOX, DAE_BOX_ELEMENT) PARSE_ANALYTICAL_SHAPE(PLANE, DAE_PLANE_ELEMENT) PARSE_ANALYTICAL_SHAPE(SPHERE, DAE_SPHERE_ELEMENT) PARSE_ANALYTICAL_SHAPE(CYLINDER, DAE_CYLINDER_ELEMENT) PARSE_ANALYTICAL_SHAPE(CAPSULE, DAE_CAPSULE_ELEMENT) PARSE_ANALYTICAL_SHAPE(TAPERED_CAPSULE, DAE_TAPERED_CAPSULE_ELEMENT) PARSE_ANALYTICAL_SHAPE(TAPERED_CYLINDER, DAE_TAPERED_CYLINDER_ELEMENT) #undef PARSE_ANALYTICAL_SHAPE // Parse the physics shape transforms , are supported. else if (IsEquivalent(child->name, DAE_ASSET_ELEMENT)) {} else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT)) {} else { uint32 transformType = FArchiveXML::GetTransformType(child); if (transformType == FCDTransform::TRANSLATION || transformType == FCDTransform::ROTATION) { FCDTransform* transform = physicsShape->AddTransform((FCDTransform::Type) transformType); status &= (FArchiveXML::LoadSwitch(transform, &transform->GetObjectType(), child)); } } } if ((physicsShape->GetMassPointer() == NULL) && (physicsShape->GetDensityPointer() == NULL)) { physicsShape->SetDensity(1.0f); physicsShape->SetDensityMoreAccurate(true); } // default value if only one is defined. if ((physicsShape->GetMassPointer() == NULL) && (physicsShape->GetDensityPointer() != NULL)) { physicsShape->SetMass(physicsShape->GetDensity() * physicsShape->CalculateVolume()); } else if ((physicsShape->GetMassPointer() != NULL) && (physicsShape->GetDensityPointer() == NULL)) { physicsShape->SetDensity(physicsShape->GetMass() / physicsShape->CalculateVolume()); } physicsShape->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPhysicsAnalyticalGeometry(FCDObject* object, xmlNode* node) { return FArchiveXML::LoadSwitch(object, &object->GetObjectType(), node); } bool FArchiveXML::LoadPASBox(FCDObject* object, xmlNode* node) { FCDPASBox* pASBox = (FCDPASBox*)object; bool status = true; if (!IsEquivalent(node->name, DAE_BOX_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_BOX_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HALF_EXTENTS_ELEMENT)) { const char* halfExt = ReadNodeContentDirect(child); pASBox->halfExtents.x = FUStringConversion::ToFloat(&halfExt); pASBox->halfExtents.y = FUStringConversion::ToFloat(&halfExt); pASBox->halfExtents.z = FUStringConversion::ToFloat(&halfExt); } } pASBox->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASCapsule(FCDObject* object, xmlNode* node) { FCDPASCapsule* pASCapsule = (FCDPASCapsule*)object; bool status = true; if (!IsEquivalent(node->name, DAE_CAPSULE_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_CAPSULE_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT)) { pASCapsule->height = FUStringConversion::ToFloat(ReadNodeContentDirect(child)); } else if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASCapsule->radius.x = FUStringConversion::ToFloat(&stringRadius); pASCapsule->radius.y = FUStringConversion::ToFloat(&stringRadius); } } pASCapsule->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASTaperedCapsule(FCDObject* object, xmlNode* node) { FCDPASTaperedCapsule* pASTaperedCapsule = (FCDPASTaperedCapsule*)object; bool status = true; if (!IsEquivalent(node->name, DAE_TAPERED_CAPSULE_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_TCAPSULE_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT)) { const char* h = ReadNodeContentDirect(child); pASTaperedCapsule->height = FUStringConversion::ToFloat(&h); } else if (IsEquivalent(child->name, DAE_RADIUS1_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASTaperedCapsule->radius.x = FUStringConversion::ToFloat(&stringRadius); pASTaperedCapsule->radius.y = FUStringConversion::ToFloat(&stringRadius); } else if (IsEquivalent(child->name, DAE_RADIUS2_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASTaperedCapsule->radius2.x = FUStringConversion::ToFloat(&stringRadius); pASTaperedCapsule->radius2.y = FUStringConversion::ToFloat(&stringRadius); } } pASTaperedCapsule->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASCylinder(FCDObject* object, xmlNode* node) { FCDPASCylinder* pASCylinder = (FCDPASCylinder*)object; bool status = true; if (!IsEquivalent(node->name, DAE_CYLINDER_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SPHERE_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT)) { pASCylinder->height = FUStringConversion::ToFloat(ReadNodeContentDirect(child)); } else if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASCylinder->radius.x = FUStringConversion::ToFloat(&stringRadius); pASCylinder->radius.y = FUStringConversion::ToFloat(&stringRadius); } } pASCylinder->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASTaperedCylinder(FCDObject* object, xmlNode* node) { FCDPASTaperedCylinder* pASTaperedCylinder = (FCDPASTaperedCylinder*)object; bool status = true; if (!IsEquivalent(node->name, DAE_TAPERED_CYLINDER_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_TCYLINDER_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_HEIGHT_ELEMENT)) { const char* h = ReadNodeContentDirect(child); pASTaperedCylinder->height = FUStringConversion::ToFloat(&h); } else if (IsEquivalent(child->name, DAE_RADIUS1_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASTaperedCylinder->radius.x = FUStringConversion::ToFloat(&stringRadius); pASTaperedCylinder->radius.y = FUStringConversion::ToFloat(&stringRadius); } else if (IsEquivalent(child->name, DAE_RADIUS2_ELEMENT)) { const char* stringRadius = ReadNodeContentDirect(child); pASTaperedCylinder->radius2.x = FUStringConversion::ToFloat(&stringRadius); pASTaperedCylinder->radius2.y = FUStringConversion::ToFloat(&stringRadius); } } pASTaperedCylinder->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASPlane(FCDObject* object, xmlNode* node) { FCDPASPlane* pASPlane = (FCDPASPlane*)object; bool status = true; if (!IsEquivalent(node->name, DAE_PLANE_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_PLANE_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_EQUATION_ELEMENT)) { const char* eq = ReadNodeContentDirect(child); pASPlane->normal.x = FUStringConversion::ToFloat(&eq); pASPlane->normal.y = FUStringConversion::ToFloat(&eq); pASPlane->normal.z = FUStringConversion::ToFloat(&eq); pASPlane->d = FUStringConversion::ToFloat(&eq); } } pASPlane->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPASSphere(FCDObject* object, xmlNode* node) { FCDPASSphere* pASSphere = (FCDPASSphere*)object; bool status = true; if (!IsEquivalent(node->name, DAE_SPHERE_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INVALID_SPHERE_TYPE, node->line); return status; } for (xmlNode* child = node->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_RADIUS_ELEMENT)) { pASSphere->radius = FUStringConversion::ToFloat(ReadNodeContentDirect(child)); } } pASSphere->SetDirtyFlag(); 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 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::LoadPhysicsModel(FCDObject* object, xmlNode* physicsModelNode) { if (!FArchiveXML::LoadEntity(object, physicsModelNode)) return false; bool status = true; FCDPhysicsModel* physicsModel = (FCDPhysicsModel*)object; FCDPhysicsModelData& data = FArchiveXML::documentLinkDataMap[physicsModel->GetDocument()].physicsModelDataMap[physicsModel]; if (!IsEquivalent(physicsModelNode->name, DAE_PHYSICS_MODEL_ELEMENT)) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_PHYS_LIB_ELEMENT, physicsModelNode->line); return status; } // Read in the first valid child element found for (xmlNode* child = physicsModelNode->children; child != NULL; child = child->next) { if (child->type != XML_ELEMENT_NODE) continue; if (IsEquivalent(child->name, DAE_RIGID_BODY_ELEMENT)) { FCDPhysicsRigidBody* rigidBody = physicsModel->AddRigidBody(); status &= (FArchiveXML::LoadPhysicsRigidBody(rigidBody, child)); } else if (IsEquivalent(child->name, DAE_RIGID_CONSTRAINT_ELEMENT)) { FCDPhysicsRigidConstraint* rigidConstraint = physicsModel->AddRigidConstraint(); status &= (FArchiveXML::LoadPhysicsRigidConstraint(rigidConstraint, child)); } else if (IsEquivalent(child->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT)) { data.modelInstancesMap.insert(child, ReadNodeUrl(child)); } } physicsModel->SetDirtyFlag(); return status; } 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::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: , 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: , , 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::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; }