bool ColladaSceneNode::IsAnimated(FCDSceneNode * originalNode) { for (int t = 0; t < (int)originalNode->GetTransformCount(); ++t) { FCDTransform * transform = originalNode->GetTransform(t); if (transform->IsAnimated()) // process all animations to make CalculateWorldTransform work { return true; } if (transform->GetType() == FCDTransform::TRANSLATION) { FCDTTranslation * translation = dynamic_cast<FCDTTranslation*>(transform); if (translation->IsAnimated()) { return true; } }else if (transform->GetType() == FCDTransform::ROTATION) { FCDTRotation * rotation = dynamic_cast<FCDTRotation*>(transform); if (rotation->IsAnimated()) { return true; } } } return false; }
void CModelConverter::ReadDAESceneTree(FCDSceneNode* pNode, CConversionSceneNode* pScene) { size_t iTransforms = pNode->GetTransformCount(); Matrix4x4 mTransformations; for (size_t t = 0; t < iTransforms; t++) { FCDTransform* pTransform = pNode->GetTransform(t); FMMatrix44 m = pTransform->ToMatrix(); mTransformations *= Matrix4x4(m); } pScene->SetTransformations(mTransformations); size_t iInstances = pNode->GetInstanceCount(); for (size_t i = 0; i < iInstances; i++) { FCDEntityInstance* pInstance = pNode->GetInstance(i); switch (pInstance->GetType()) { case FCDEntityInstance::GEOMETRY: { FCDGeometryInstance* pGeometryInstance = dynamic_cast<FCDGeometryInstance*>(pInstance); FCDEntity* pEntity = pGeometryInstance->GetEntity(); size_t iMesh = pScene->m_pScene->FindMesh(convert_from_fstring(pEntity->GetName())); size_t iMeshInstance = pScene->AddMeshInstance(iMesh); size_t iMaterialInstances = pGeometryInstance->GetMaterialInstanceCount(); for (size_t m = 0; m < iMaterialInstances; m++) { FCDMaterialInstance* pMaterialInstance = pGeometryInstance->GetMaterialInstance(m); FCDMaterial* pMaterial = pMaterialInstance->GetMaterial(); tstring sMaterial = pMaterial?convert_from_fstring(pMaterialInstance->GetMaterial()->GetName()):""; tstring sMaterialStub = convert_from_fstring(pMaterialInstance->GetSemantic()); size_t iMaterial = pScene->m_pScene->FindMaterial(sMaterial); size_t iMaterialStub = pScene->m_pScene->GetMesh(iMesh)->FindMaterialStub(sMaterialStub); pScene->GetMeshInstance(iMeshInstance)->AddMappedMaterial(iMaterialStub, iMaterial); } } } } size_t iChildren = pNode->GetChildrenCount(); for (size_t j = 0; j < iChildren; j++) { FCDSceneNode* pChildNode = pNode->GetChild(j); size_t iNode = pScene->AddChild(convert_from_fstring(pChildNode->GetName())); ReadDAESceneTree(pChildNode, pScene->GetChild(iNode)); } }
void GenerateSampledAnimation(FCDSceneNode* node) { sampleKeys.clear(); sampleValues.clear(); FCDAnimatedList animateds; // Special case for rotation angles: need to check for changes that are greater than 180 degrees. Int32List angleIndices; // Collect all the animation curves size_t transformCount = node->GetTransformCount(); for (size_t t = 0; t < transformCount; ++t) { FCDTransform* transform = node->GetTransform(t); FCDAnimated* animated = transform->GetAnimated(); if (animated != NULL) { if (animated->HasCurve()) animateds.push_back(animated); // Figure out whether this is a rotation and then, which animated value contains the angle. if (!transform->HasType(FCDTRotation::GetClassType())) angleIndices.push_back(-1); else angleIndices.push_back((int32) animated->FindQualifier(".ANGLE")); } } if (animateds.empty()) return; // Make a list of the ordered key times to sample size_t animatedsCount = animateds.size(); for (size_t i = 0; i < animatedsCount; ++i) { FCDAnimated* animated = animateds[i]; int32 angleIndex = angleIndices[i]; const FCDAnimationCurveListList& allCurves = animated->GetCurves(); size_t valueCount = allCurves.size(); for (size_t curveIndex = 0; curveIndex < valueCount; ++curveIndex) { const FCDAnimationCurveTrackList& curves = allCurves[curveIndex]; if (curves.empty()) continue; size_t curveKeyCount = curves.front()->GetKeyCount(); const FCDAnimationKey** curveKeys = curves.front()->GetKeys(); size_t sampleKeyCount = sampleKeys.size(); // Merge this curve's keys in with the sample keys // This assumes both key lists are in increasing order size_t s = 0, c = 0; while (s < sampleKeyCount && c < curveKeyCount) { float sampleKey = sampleKeys[s], curveKey = curveKeys[c]->input; if (IsEquivalent(sampleKey, curveKey)) { ++s; ++c; } else if (sampleKey < curveKey) { ++s; } else { // Add this curve key to the sampling key list sampleKeys.insert(sampleKeys.begin() + (s++), curveKeys[c++]->input); sampleKeyCount++; } } // Add all the left-over curve keys to the sampling key list while (c < curveKeyCount) sampleKeys.push_back(curveKeys[c++]->input); // Check for large angular rotations.. if (angleIndex == (intptr_t) curveIndex) { for (size_t c = 1; c < curveKeyCount; ++c) { const FCDAnimationKey* previousKey = curveKeys[c - 1]; const FCDAnimationKey* currentKey = curveKeys[c]; float halfWrapAmount = (currentKey->output - previousKey->output) / 180.0f; halfWrapAmount *= FMath::Sign(halfWrapAmount); if (halfWrapAmount >= 1.0f) { // Need to add sample times. size_t addSampleCount = (size_t) floorf(halfWrapAmount); for (size_t d = 1; d <= addSampleCount; ++d) { float fd = (float) d; float fid = (float) (addSampleCount + 1 - d); float addSampleTime = (currentKey->input * fd + previousKey->input * fid) / (fd + fid); // Sorted insert. float* endIt = sampleKeys.end(); for (float* sampleKeyTime = sampleKeys.begin(); sampleKeyTime != endIt; ++sampleKeyTime) { if (IsEquivalent(*sampleKeyTime, addSampleTime)) break; else if (*sampleKeyTime > addSampleTime) { sampleKeys.insert(sampleKeyTime, addSampleTime); break; } } } } } } } } size_t sampleKeyCount = sampleKeys.size(); if (sampleKeyCount == 0) return; // Pre-allocate the value array; sampleValues.reserve(sampleKeyCount); // Sample the scene node transform for (size_t i = 0; i < sampleKeyCount; ++i) { float sampleTime = sampleKeys[i]; for (FCDAnimatedList::iterator it = animateds.begin(); it != animateds.end(); ++it) { // Sample each animated, which changes the transform values directly (*it)->Evaluate(sampleTime); } // Retrieve the new transform matrix for the COLLADA scene node sampleValues.push_back(node->ToMatrix()); } }
FMMatrix44 ColladaSceneNode::CalculateTransformForTime(FCDSceneNode * originalNode, float32 time) { FMMatrix44 colladaLocalMatrix; colladaLocalMatrix = FMMatrix44::Identity;// = FMMatrix44::Identity(); for (int t = 0; t < (int)originalNode->GetTransformCount(); ++t) { FCDTransform * transform = originalNode->GetTransform(t); if (transform->IsAnimated()) // process all animations to make CalculateWorldTransform work { FCDAnimated * animated = transform->GetAnimated(); animated->Evaluate(time); } if (transform->GetType() == FCDTransform::TRANSLATION) { FCDTTranslation * translation = dynamic_cast<FCDTTranslation*>(transform); FMVector3 point = FMVector3(0.0f, 0.0f, 0.0f); point = translation->GetTranslation(); if (transform->IsAnimated()) { FCDAnimationCurve* curve; // look for x animation curve = transform->GetAnimated()->FindCurve(".X"); if (curve != 0) point.x = curve->Evaluate(time); // look for y animation curve = transform->GetAnimated()->FindCurve(".Y"); if (curve != 0) point.y = curve->Evaluate(time); // look for z animation curve = transform->GetAnimated()->FindCurve(".Z"); if (curve != 0) point.z = curve->Evaluate(time); } colladaLocalMatrix = colladaLocalMatrix * FMMatrix44::TranslationMatrix(point); }else if (transform->GetType() == FCDTransform::ROTATION) { FCDTRotation * rotation = dynamic_cast<FCDTRotation*>(transform); FMVector3 axis = FMVector3(0.0f, 0.0f, 0.0f); float angle = 0; axis = rotation->GetAxis(); angle = rotation->GetAngle(); if (rotation->IsAnimated()) { FCDAnimationCurve* curve; // look for x animation curve = rotation->GetAnimated()->FindCurve(".X"); if (curve != 0) axis.x = curve->Evaluate(time); // look for y animation curve = rotation->GetAnimated()->FindCurve(".Y"); if (curve != 0) axis.y = curve->Evaluate(time); // look for z animation curve = rotation->GetAnimated()->FindCurve(".Z"); if (curve != 0) axis.z = curve->Evaluate(time); // look for z animation curve = rotation->GetAnimated()->FindCurve(".ANGLE"); if (curve != 0) angle = curve->Evaluate(time); } colladaLocalMatrix = colladaLocalMatrix * FMMatrix44::AxisRotationMatrix(axis, angle * PI / 180.0f); }else { colladaLocalMatrix = colladaLocalMatrix * transform->ToMatrix(); } } return colladaLocalMatrix; }
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 <rotate>, <translate> 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::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; }