/* 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/FCDocument.h" #include "FCDocument/FCDExtra.h" #include "FCDocument/FCDEntityReference.h" #include "FCDocument/FCDEntityInstance.h" #include "FCDocument/FCDEmitterInstance.h" #include "FCDocument/FCDGeometry.h" #include "FCDocument/FCDGeometryInstance.h" #include "FCDocument/FCDGeometryMesh.h" #include "FCDocument/FCDGeometryPolygons.h" #include "FCDocument/FCDControllerInstance.h" #include "FCDocument/FCDMaterialInstance.h" #include "FCDocument/FCDPhysicsForceFieldInstance.h" #include "FCDocument/FCDPhysicsModelInstance.h" #include "FCDocument/FCDPhysicsRigidBodyInstance.h" #include "FCDocument/FCDPhysicsRigidConstraintInstance.h" #include "FCDocument/FCDSkinController.h" #include "FCDocument/FCDSceneNode.h" #include "FCDocument/FCDPhysicsModel.h" #include "FCDocument/FCDPhysicsRigidBody.h" bool FArchiveXML::LoadEntityInstance(FCDObject* object, xmlNode* instanceNode) { FCDEntityInstance* entityInstance = (FCDEntityInstance*)object; bool status = true; FUUri uri = ReadNodeUrl(instanceNode); entityInstance->GetEntityReference()->SetUri(uri); if (!entityInstance->IsExternalReference() && entityInstance->GetEntity() == NULL) { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_INST_ENTITY_MISSING, instanceNode->line); } entityInstance->SetWantedSubId(TO_STRING(ReadNodeSid(instanceNode))); entityInstance->SetName(TO_FSTRING(ReadNodeName(instanceNode))); // Read in the extra nodes xmlNodeList extraNodes; FindChildrenByType(instanceNode, DAE_EXTRA_ELEMENT, extraNodes); for (xmlNodeList::iterator it = extraNodes.begin(); it != extraNodes.end(); ++it) { xmlNode* extraNode = (*it); FArchiveXML::LoadExtra(entityInstance->GetExtra(), extraNode); } entityInstance->SetDirtyFlag(); return status; } bool FArchiveXML::LoadEmitterInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; FCDEmitterInstance* emitterInstance = (FCDEmitterInstance*)object; bool status = true; // Check for the expected instantiation node type if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_EMITTER_ELEMENT)) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line); return false; } emitterInstance->SetDirtyFlag(); return status; } bool FArchiveXML::LoadGeometryInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDGeometryInstance* geometryInstance = (FCDGeometryInstance*)object; // Look for the 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 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::LoadControllerInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadGeometryInstance(object, instanceNode)) return false; bool status = true; FCDControllerInstance* controllerInstance = (FCDControllerInstance*)object; xmlNodeList skeletonList; FUDaeParser::FindChildrenByType(instanceNode, DAE_SKELETON_ELEMENT, skeletonList); size_t numRoots = skeletonList.size(); controllerInstance->GetSkeletonRoots().resize(numRoots); for (size_t i = 0; i < numRoots; ++i) { controllerInstance->GetSkeletonRoots()[i] = FUUri(TO_FSTRING(FUDaeParser::ReadNodeContentDirect(skeletonList[i]))); } return status; } bool FArchiveXML::LoadMaterialInstance(FCDObject* object, xmlNode* instanceNode) { FCDMaterialInstance* materialInstance = (FCDMaterialInstance*)object; // This is not loaded the same as the FCDEntityInstance ones. // Load it first, otherwise FCDEntityInstance will ASSERT (with no Uri) fm::string uri = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE); AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, uri); if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; materialInstance->SetSemantic(TO_FSTRING(ReadNodeProperty(instanceNode, DAE_SYMBOL_ATTRIBUTE))); // Read in the ColladaFX bindings while (materialInstance->GetBindingCount() != 0) materialInstance->GetBinding(materialInstance->GetBindingCount() - 1)->Release(); xmlNodeList bindNodes; FindChildrenByType(instanceNode, DAE_BIND_ELEMENT, bindNodes); for (xmlNodeList::iterator itB = bindNodes.begin(); itB != bindNodes.end(); ++itB) { fm::string semantic = ReadNodeSemantic(*itB); fm::string target = ReadNodeProperty(*itB, DAE_TARGET_ATTRIBUTE); materialInstance->AddBinding(semantic, target); } // Read in the ColladaFX vertex inputs xmlNodeList bindVertexNodes; while (materialInstance->GetVertexInputBindingCount() != 0) materialInstance->GetVertexInputBinding(materialInstance->GetVertexInputBindingCount() - 1)->Release(); FindChildrenByType(instanceNode, DAE_BIND_VERTEX_INPUT_ELEMENT, bindVertexNodes); for (xmlNodeList::iterator itB = bindVertexNodes.begin(); itB != bindVertexNodes.end(); ++itB) { fm::string inputSet = ReadNodeProperty(*itB, DAE_INPUT_SET_ATTRIBUTE); fm::string inputSemantic = ReadNodeProperty(*itB, DAE_INPUT_SEMANTIC_ATTRIBUTE); materialInstance->AddVertexInputBinding(ReadNodeSemantic(*itB).c_str(), FUDaeGeometryInput::FromString(inputSemantic.c_str()), FUStringConversion::ToInt32(inputSet)); } materialInstance->SetDirtyFlag(); return true; } bool FArchiveXML::LoadPhysicsForceFieldInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDPhysicsForceFieldInstance* physicsForceFieldInstance = (FCDPhysicsForceFieldInstance*)object; if (physicsForceFieldInstance->GetEntity() == NULL && !physicsForceFieldInstance->IsExternalReference()) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_INVALID_URI, instanceNode->line); } // Check for the expected instantiation node type if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_FORCE_FIELD_ELEMENT)) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line); status = false; } // nothing interesting in force field instance to load physicsForceFieldInstance->SetDirtyFlag(); return status; } bool FArchiveXML::LoadPhysicsModelInstance(FCDObject* object, xmlNode* instanceNode) { if (!FArchiveXML::LoadEntityInstance(object, instanceNode)) return false; bool status = true; FCDPhysicsModelInstance* physicsModelInstance = (FCDPhysicsModelInstance*)object; if (physicsModelInstance->GetEntity() == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::WARNING_MISSING_URI_TARGET, instanceNode->line); } // Check for the expected instantiation node type if (!IsEquivalent(instanceNode->name, DAE_INSTANCE_PHYSICS_MODEL_ELEMENT)) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_UNKNOWN_ELEMENT, instanceNode->line); } //this is already done in the FCDSceneNode // fm::string physicsModelId = ReadNodeProperty(instanceNode, DAE_TARGET_ATTRIBUTE); // entity = GetDocument()->FindPhysicsModel(physicsModelId); // if (!entity) return status.Fail(FS("Couldn't find physics model for instantiation"), instanceNode->line); xmlNodeList rigidBodyNodes; FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_BODY_ELEMENT, rigidBodyNodes); for (xmlNodeList::iterator itB = rigidBodyNodes.begin(); itB != rigidBodyNodes.end(); ++itB) { FCDPhysicsRigidBodyInstance* instance = physicsModelInstance->AddRigidBodyInstance(NULL); status &= (FArchiveXML::LoadPhysicsRigidBodyInstance(instance, *itB)); } xmlNodeList rigidConstraintNodes; FindChildrenByType(instanceNode, DAE_INSTANCE_RIGID_CONSTRAINT_ELEMENT, rigidConstraintNodes); for (xmlNodeList::iterator itC = rigidConstraintNodes.begin(); itC != rigidConstraintNodes.end(); ++itC) { FCDPhysicsRigidConstraintInstance* instance = physicsModelInstance->AddRigidConstraintInstance(NULL); status &= (FArchiveXML::LoadPhysicsRigidConstraintInstance(instance, *itC)); } xmlNodeList forceFieldNodes; FindChildrenByType(instanceNode, DAE_INSTANCE_FORCE_FIELD_ELEMENT, forceFieldNodes); for (xmlNodeList::iterator itN = forceFieldNodes.begin(); itN != forceFieldNodes.end(); ++itN) { FCDPhysicsForceFieldInstance* instance = physicsModelInstance->AddForceFieldInstance(NULL); status &= (FArchiveXML::LoadPhysicsForceFieldInstance(instance, *itN)); } physicsModelInstance->SetDirtyFlag(); return status; } bool FArchiveXML::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; } 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::LinkControllerInstance(FCDControllerInstance* controllerInstance) { const FCDSkinController* skin = FArchiveXML::FindSkinController(controllerInstance, controllerInstance->GetEntity()); if (skin == NULL) return true; FCDSkinControllerData& data = FArchiveXML::documentLinkDataMap[skin->GetDocument()].skinControllerDataMap.find(const_cast(skin))->second; // Look for each joint, by COLLADA id, within the scene graph size_t jointCount = skin->GetJointCount(); FCDSceneNodeList rootNodes; controllerInstance->FindSkeletonNodes(rootNodes); size_t numRoots = rootNodes.size(); while (controllerInstance->GetJointCount() != 0) controllerInstance->RemoveJoint(controllerInstance->GetJointCount() - 1); for (size_t i = 0; i < jointCount; ++i) { const fm::string& jid = skin->GetJoint(i)->GetId(); FCDSceneNode* boneNode = NULL; if (data.jointAreSids) { // Find by subId for (size_t i = 0; i < numRoots; i++) { boneNode = (FCDSceneNode*)rootNodes[i]->FindSubId(jid); if (boneNode != NULL) break; } } else { // Find by DaeId for (size_t i = 0; i < numRoots; i++) { boneNode = (FCDSceneNode*)rootNodes[i]->FindDaeId(jid); if (boneNode != NULL) break; } } if (boneNode != NULL) { controllerInstance->AddJoint(boneNode); } else { FUError::Error(FUError::WARNING_LEVEL, FUError::WARNING_UNKNOWN_JOINT, 0); } } return true; } bool FArchiveXML::LinkEmitterInstance(FCDEmitterInstance* emitterInstance) { (void) emitterInstance; return true; } bool FArchiveXML::ImportEmittedInstanceList(FCDEmitterInstance* emitterInstance, xmlNode* node) { bool status = true; (void) emitterInstance; (void) node; return status; } uint32 FArchiveXML::GetEntityInstanceType(xmlNode* node) { if (IsEquivalent(node->name, DAE_INSTANCE_CAMERA_ELEMENT)) return FCDEntity::CAMERA; else if (IsEquivalent(node->name, DAE_INSTANCE_CONTROLLER_ELEMENT)) return FCDEntity::CONTROLLER; else if (IsEquivalent(node->name, DAE_INSTANCE_EMITTER_ELEMENT)) return FCDEntity::EMITTER; else if (IsEquivalent(node->name, DAE_INSTANCE_FORCE_FIELD_ELEMENT)) return FCDEntity::FORCE_FIELD; else if (IsEquivalent(node->name, DAE_INSTANCE_GEOMETRY_ELEMENT)) return FCDEntity::GEOMETRY; else if (IsEquivalent(node->name, DAE_INSTANCE_SPRITE_ELEMENT)) return FCDEntity::GEOMETRY; // same class does 2 jobs else if (IsEquivalent(node->name, DAE_INSTANCE_LIGHT_ELEMENT)) return FCDEntity::LIGHT; else if (IsEquivalent(node->name, DAE_INSTANCE_NODE_ELEMENT)) return FCDEntity::SCENE_NODE; else return (uint32) ~0; }