bool FArchiveXML::LoadTransformSkew(FCDObject* object, xmlNode* skewNode) { FCDTSkew* tSkew = (FCDTSkew*)object; const char* content = FUDaeParser::ReadNodeContentDirect(skewNode); FloatList factors; factors.reserve(7); FUStringConversion::ToFloatList(content, factors); if (factors.size() != 7) return false; tSkew->SetAngle(factors[0]); tSkew->SetRotateAxis(FMVector3(factors[1], factors[2], factors[3])); tSkew->SetAroundAxis(FMVector3(factors[4], factors[5], factors[6])); // Check and pre-process the axises if (IsEquivalent(tSkew->GetRotateAxis(), FMVector3::Origin) || IsEquivalent(tSkew->GetAroundAxis(), FMVector3::Origin)) return false; tSkew->SetRotateAxis(tSkew->GetRotateAxis().Normalize()); tSkew->SetAroundAxis(tSkew->GetAroundAxis().Normalize()); // Register the animated values FArchiveXML::LoadAnimatable(&tSkew->GetSkew(), skewNode); tSkew->SetDirtyFlag(); return true; }
bool FArchiveXML::LoadTransformTranslation(FCDObject* object, xmlNode* node) { FCDTTranslation* tTranslation = (FCDTTranslation*)object; const char* content = FUDaeParser::ReadNodeContentDirect(node); FloatList factors; factors.reserve(3); FUStringConversion::ToFloatList(content, factors); if (factors.size() != 3) return false; tTranslation->SetTranslation(factors[0], factors[1], factors[2]); FArchiveXML::LoadAnimatable(&tTranslation->GetTranslation(), node); tTranslation->SetDirtyFlag(); return true; }
bool FArchiveXML::LoadTransformScale(FCDObject* object, xmlNode* node) { FCDTScale* tScale = (FCDTScale*)object; const char* content = FUDaeParser::ReadNodeContentDirect(node); FloatList factors; factors.reserve(3); FUStringConversion::ToFloatList(content, factors); if (factors.size() != 3) return false; tScale->SetScale(factors[0], factors[1], factors[2]); // Register the animated values FArchiveXML::LoadAnimatable(&tScale->GetScale(), node); tScale->SetDirtyFlag(); return true; }
bool FArchiveXML::LoadTransformLookAt(FCDObject* object, xmlNode* lookAtNode) { FCDTLookAt* tLookAt = (FCDTLookAt*)object; const char* content = FUDaeParser::ReadNodeContentDirect(lookAtNode); FloatList factors; factors.reserve(9); FUStringConversion::ToFloatList(content, factors); if (factors.size() != 9) return false; tLookAt->GetPosition().Set(factors[0], factors[1], factors[2]); tLookAt->GetTarget().Set(factors[3], factors[4], factors[5]); tLookAt->GetUp().Set(factors[6], factors[7], factors[8]); // Register the animated values FArchiveXML::LoadAnimatable(&tLookAt->GetLookAt(), lookAtNode); tLookAt->SetDirtyFlag(); return true; }
float *flattenFVecList(int t, int vecDim, FloatVecList* pfloatVecList) { if (NULL == pfloatVecList) return false; int szvec = 0; int arraySz = 0; float *array = NULL; // walk through the vector list and check few things then send the packed version float *p = NULL; for(int i=0; i<(int)pfloatVecList->size(); i++) { if(szvec == 0) { szvec = (int)((*pfloatVecList)[i]->size()); arraySz = szvec * pfloatVecList->size(); p = array = new float[arraySz]; // we assume all vectors are the same size } else if(szvec != (*pfloatVecList)[i]->size()) { yyerror("Vector list has inconsistent vectors\n"); continue; } FloatList* pfl = (*pfloatVecList)[i]; if (NULL!=pfl) { for(int j=0; j<(int)pfl->size(); j++) *p++ = (*pfl)[j]; delete pfl; pfl = NULL; } } if(vecDim < 0) vecDim = (int)pfloatVecList->size(); // we do the test here in any case : the previous loop needed to do some "delete" anyways if((t * vecDim) != (arraySz)) { yyerror("Vector dimension in value assignment don't match the type\n"); delete array; return NULL; } return array; }
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()); } }
bool FArchiveXML::LoadAnimationChannel(FCDObject* object, xmlNode* channelNode) { FCDAnimationChannel* animationChannel = (FCDAnimationChannel*)object; FCDAnimationChannelData& data = FArchiveXML::documentLinkDataMap[animationChannel->GetDocument()].animationChannelData[animationChannel]; bool status = true; // Read the channel-specific ID fm::string daeId = ReadNodeId(channelNode); fm::string samplerId = ReadNodeSource(channelNode); ReadNodeTargetProperty(channelNode, data.targetPointer, data.targetQualifier); #ifdef DONT_DEFINE_THIS FCDAnimation* anim = animationChannel->GetParent(); FCDExtra* extra = anim->GetExtra(); extra->SetTransientFlag(); // Dont save this, its wasted whatever it is. FCDEType* type = extra->AddType("AnimTargets"); FCDETechnique* teq = type->AddTechnique("TEMP"); teq->AddChildNode("pointer")->SetContent(TO_FSTRING(data.targetPointer)); teq->AddChildNode("pointer")->SetContent(TO_FSTRING(data.targetQualifier)); #endif xmlNode* samplerNode = FArchiveXML::FindChildByIdFCDAnimation(animationChannel->GetParent(), samplerId); if (samplerNode == NULL || !IsEquivalent(samplerNode->name, DAE_SAMPLER_ELEMENT)) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_MISSING_ELEMENT, channelNode->line); return false; } // Find and process the sources xmlNode* inputSource = NULL, * outputSource = NULL, * inTangentSource = NULL, * outTangentSource = NULL, * tcbSource = NULL, * easeSource = NULL, * interpolationSource = NULL; xmlNodeList samplerInputNodes; fm::string inputDriver; FindChildrenByType(samplerNode, DAE_INPUT_ELEMENT, samplerInputNodes); for (size_t i = 0; i < samplerInputNodes.size(); ++i) // Don't use iterator here because we are possibly appending source nodes in the loop { xmlNode* inputNode = samplerInputNodes[i]; fm::string sourceId = ReadNodeSource(inputNode); xmlNode* sourceNode = FArchiveXML::FindChildByIdFCDAnimation(animationChannel->GetParent(), sourceId); fm::string sourceSemantic = ReadNodeSemantic(inputNode); if (sourceSemantic == DAE_INPUT_ANIMATION_INPUT) inputSource = sourceNode; else if (sourceSemantic == DAE_OUTPUT_ANIMATION_INPUT) outputSource = sourceNode; else if (sourceSemantic == DAE_INTANGENT_ANIMATION_INPUT) inTangentSource = sourceNode; else if (sourceSemantic == DAE_OUTTANGENT_ANIMATION_INPUT) outTangentSource = sourceNode; else if (sourceSemantic == DAEFC_TCB_ANIMATION_INPUT) tcbSource = sourceNode; else if (sourceSemantic == DAEFC_EASE_INOUT_ANIMATION_INPUT) easeSource = sourceNode; else if (sourceSemantic == DAE_INTERPOLATION_ANIMATION_INPUT) interpolationSource = sourceNode; else if (sourceSemantic == DAEMAYA_DRIVER_INPUT) inputDriver = sourceId; } if (inputSource == NULL || outputSource == NULL) { FUError::Error(FUError::ERROR_LEVEL, FUError::ERROR_MISSING_INPUT, samplerNode->line); return false; } // Calculate the number of curves that in contained by this channel xmlNode* outputAccessor = FindTechniqueAccessor(outputSource); fm::string accessorStrideString = ReadNodeProperty(outputAccessor, DAE_STRIDE_ATTRIBUTE); uint32 curveCount = FUStringConversion::ToUInt32(accessorStrideString); if (curveCount == 0) curveCount = 1; // Create the animation curves for (uint32 i = 0; i < curveCount; ++i) { animationChannel->AddCurve(); } // Read in the animation curves // The input keys and interpolations are shared by all the curves FloatList inputs; ReadSource(inputSource, inputs); size_t keyCount = inputs.size(); if (keyCount == 0) return true; // Valid although very boring channel. UInt32List interpolations; interpolations.reserve(keyCount); ReadSourceInterpolation(interpolationSource, interpolations); if (interpolations.size() < keyCount) { // Not enough interpolation types provided, so append BEZIER as many times as needed. interpolations.insert(interpolations.end(), keyCount - interpolations.size(), FUDaeInterpolation::FromString("")); } // Read in the interleaved outputs as floats fm::vector<FloatList> tempFloatArrays; tempFloatArrays.resize(curveCount); fm::pvector<FloatList> outArrays(curveCount); for (uint32 i = 0; i < curveCount; ++i) outArrays[i] = &tempFloatArrays[i]; ReadSourceInterleaved(outputSource, outArrays); for (uint32 i = 0; i < curveCount; ++i) { // Fill in the output array with zeroes, if it was not large enough. if (tempFloatArrays[i].size() < keyCount) { tempFloatArrays[i].insert(tempFloatArrays[i].end(), keyCount - tempFloatArrays[i].size(), 0.0f); } // Create all the keys, on the curves, according to the interpolation types. for (size_t j = 0; j < keyCount; ++j) { FCDAnimationKey* key = animationChannel->GetCurve(i)->AddKey((FUDaeInterpolation::Interpolation) interpolations[j]); key->input = inputs[j]; key->output = tempFloatArrays[i][j]; // Set the default values for Bezier/TCB interpolations. if (key->interpolation == FUDaeInterpolation::BEZIER) { FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) key; float previousInput = (j == 0) ? inputs[j] - 1.0f : inputs[j-1]; float nextInput = (j == keyCount - 1) ? inputs[j] + 1.0f : inputs[j+1]; bkey->inTangent.x = (previousInput + 2.0f * bkey->input) / 3.0f; bkey->outTangent.x = (nextInput + 2.0f * bkey->input) / 3.0f; bkey->inTangent.y = bkey->outTangent.y = bkey->output; } else if (key->interpolation == FUDaeInterpolation::TCB) { FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) key; tkey->tension = tkey->continuity = tkey->bias = 0.5f; tkey->easeIn = tkey->easeOut = 0.0f; } } } tempFloatArrays.clear(); // Read in the interleaved in_tangent source. if (inTangentSource != NULL) { fm::vector<FMVector2List> tempVector2Arrays; tempVector2Arrays.resize(curveCount); fm::pvector<FMVector2List> arrays(curveCount); for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i]; uint32 stride = ReadSourceInterleaved(inTangentSource, arrays); if (stride == curveCount) { // Backward compatibility with 1D tangents. // Remove the relativity from the 1D tangents and calculate the second-dimension. for (uint32 i = 0; i < curveCount; ++i) { FMVector2List& inTangents = tempVector2Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(inTangents.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::BEZIER) { FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j]; bkey->inTangent.y = bkey->output - inTangents[j].x; } } } } else if (stride == curveCount * 2) { // This is the typical, 2D tangent case. for (uint32 i = 0; i < curveCount; ++i) { FMVector2List& inTangents = tempVector2Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(inTangents.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::BEZIER) { FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j]; bkey->inTangent = inTangents[j]; } } } } } // Read in the interleaved out_tangent source. if (outTangentSource != NULL) { fm::vector<FMVector2List> tempVector2Arrays; tempVector2Arrays.resize(curveCount); fm::pvector<FMVector2List> arrays(curveCount); for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i]; uint32 stride = ReadSourceInterleaved(outTangentSource, arrays); if (stride == curveCount) { // Backward compatibility with 1D tangents. // Remove the relativity from the 1D tangents and calculate the second-dimension. for (uint32 i = 0; i < curveCount; ++i) { FMVector2List& outTangents = tempVector2Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(outTangents.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::BEZIER) { FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j]; bkey->outTangent.y = bkey->output + outTangents[j].x; } } } } else if (stride == curveCount * 2) { // This is the typical, 2D tangent case. for (uint32 i = 0; i < curveCount; ++i) { FMVector2List& outTangents = tempVector2Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(outTangents.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::BEZIER) { FCDAnimationKeyBezier* bkey = (FCDAnimationKeyBezier*) keys[j]; bkey->outTangent = outTangents[j]; } } } } } if (tcbSource != NULL) { //Process TCB parameters fm::vector<FMVector3List> tempVector3Arrays; tempVector3Arrays.resize(curveCount); fm::pvector<FMVector3List> arrays(curveCount); for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector3Arrays[i]; ReadSourceInterleaved(tcbSource, arrays); for (uint32 i = 0; i < curveCount; ++i) { FMVector3List& tcbs = tempVector3Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(tcbs.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::TCB) { FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) keys[j]; tkey->tension = tcbs[j].x; tkey->continuity = tcbs[j].y; tkey->bias = tcbs[j].z; } } } } if (easeSource != NULL) { //Process Ease-in and ease-out data fm::vector<FMVector2List> tempVector2Arrays; tempVector2Arrays.resize(curveCount); fm::pvector<FMVector2List> arrays(curveCount); for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &tempVector2Arrays[i]; ReadSourceInterleaved(easeSource, arrays); for (uint32 i = 0; i < curveCount; ++i) { FMVector2List& eases = tempVector2Arrays[i]; FCDAnimationKey** keys = animationChannel->GetCurve(i)->GetKeys(); size_t end = min(eases.size(), keyCount); for (size_t j = 0; j < end; ++j) { if (keys[j]->interpolation == FUDaeInterpolation::TCB) { FCDAnimationKeyTCB* tkey = (FCDAnimationKeyTCB*) keys[j]; tkey->easeIn = eases[j].x; tkey->easeOut = eases[j].y; } } } } // Read in the pre/post-infinity type xmlNodeList mayaParameterNodes; StringList mayaParameterNames; xmlNode* mayaTechnique = FindTechnique(inputSource, DAEMAYA_MAYA_PROFILE); FindParameters(mayaTechnique, mayaParameterNames, mayaParameterNodes); size_t parameterCount = mayaParameterNodes.size(); for (size_t i = 0; i < parameterCount; ++i) { xmlNode* parameterNode = mayaParameterNodes[i]; const fm::string& paramName = mayaParameterNames[i]; const char* content = ReadNodeContentDirect(parameterNode); if (paramName == DAEMAYA_PREINFINITY_PARAMETER) { size_t curveCount = animationChannel->GetCurveCount(); for (size_t c = 0; c < curveCount; ++c) { animationChannel->GetCurve(c)->SetPreInfinity(FUDaeInfinity::FromString(content)); } } else if (paramName == DAEMAYA_POSTINFINITY_PARAMETER) { size_t curveCount = animationChannel->GetCurveCount(); for (size_t c = 0; c < curveCount; ++c) { animationChannel->GetCurve(c)->SetPostInfinity(FUDaeInfinity::FromString(content)); } } else { // Look for driven-key input target if (paramName == DAE_INPUT_ELEMENT) { fm::string semantic = ReadNodeSemantic(parameterNode); if (semantic == DAEMAYA_DRIVER_INPUT) { inputDriver = ReadNodeSource(parameterNode); } } } } if (!inputDriver.empty()) { const char* driverTarget = FUDaeParser::SkipPound(inputDriver); if (driverTarget != NULL) { fm::string driverQualifierValue; FUStringConversion::SplitTarget(driverTarget, data.driverPointer, driverQualifierValue); data.driverQualifier = FUStringConversion::ParseQualifier(driverQualifierValue); if (data.driverQualifier < 0) data.driverQualifier = 0; } } animationChannel->SetDirtyFlag(); return status; }
//--------------------------------------------------------------- void ControllerExporter::exportMorphController( ExportNode* exportNode, MorphController* morphController, const String& controllerId, const String& morphSource ) { MorphR3* morpher = morphController->getMorph(); FloatList listOfWeights; StringList listOfTargetIds; String weightsId = controllerId + WEIGHTS_SOURCE_ID_SUFFIX; size_t channelBankCount = morpher->chanBank.size(); for ( size_t i = 0; i<channelBankCount; ++i) { morphChannel& channel = morpher->chanBank[i]; if (!channel.mActive || channel.mNumPoints == 0) continue; INode* targetINode = channel.mConnection; listOfWeights.push_back(ConversionFunctors::fromPercent(channel.cblock->GetFloat(morphChannel::cblock_weight_index, mDocumentExporter->getOptions().getAnimationStart()))); Control* weightController = channel.cblock->GetController(morphChannel::cblock_weight_index); mDocumentExporter->getAnimationExporter()->addAnimatedFloat(weightController, weightsId, EMPTY_STRING, (int)i, true, &ConversionFunctors::fromPercent ); if ( !targetINode ) { MorphControllerHelperGeometry morphControllerHelperGeometry; morphControllerHelperGeometry.exportNode = exportNode; morphControllerHelperGeometry.controllerId = controllerId; morphControllerHelperGeometry.morphController = morphController; morphControllerHelperGeometry.channelBankindex = i; String targetId = ExportSceneGraph::getMorphControllerHelperId(morphControllerHelperGeometry); listOfTargetIds.push_back(targetId); } else { ExportNode* targetExportNode = mExportSceneGraph->getExportNode(targetINode); assert(targetExportNode); ExportNode* geometryExportNode = mDocumentExporter->getExportedObjectExportNode(ObjectIdentifier(targetExportNode->getInitialPose())); assert( geometryExportNode ); // listOfTargetIds.push_back(geometryExportNode); listOfTargetIds.push_back(GeometriesExporter::getGeometryId(*geometryExportNode)); } } openMorph(controllerId, EMPTY_STRING, morphSource); //export weights source String targetId = controllerId + TARGETS_SOURCE_ID_SUFFIX; COLLADASW::IdRefSource targetsSource(mSW); targetsSource.setId(targetId); targetsSource.setArrayId(targetId + ARRAY_ID_SUFFIX); targetsSource.setAccessorStride(1); targetsSource.getParameterNameList().push_back("MORPH_TARGET"); targetsSource.setAccessorCount((unsigned long)listOfTargetIds.size()); targetsSource.prepareToAppendValues(); for ( StringList::const_iterator it = listOfTargetIds.begin(); it != listOfTargetIds.end(); ++it) targetsSource.appendValues(*it); targetsSource.finish(); //export weights source COLLADASW::FloatSource weightsSource(mSW); weightsSource.setId(weightsId); weightsSource.setArrayId(weightsId + ARRAY_ID_SUFFIX); weightsSource.setAccessorStride(1); weightsSource.getParameterNameList().push_back("MORPH_WEIGHT"); weightsSource.setAccessorCount((unsigned long)listOfWeights.size()); weightsSource.prepareToAppendValues(); for ( FloatList::const_iterator it = listOfWeights.begin(); it != listOfWeights.end(); ++it) weightsSource.appendValues(*it); weightsSource.finish(); COLLADASW::TargetsElement targets(mSW); targets.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_TARGET, "#" + targetId)); targets.getInputList().push_back(COLLADASW::Input(COLLADASW::InputSemantic::MORPH_WEIGHT, "#" + weightsId)); targets.add(); closeMorph(); }
xmlNode* FArchiveXML::WriteAnimationChannel(FCDObject* object, xmlNode* parentNode) { FCDAnimationChannel* animationChannel = (FCDAnimationChannel*)object; FCDAnimationChannelData& data = FArchiveXML::documentLinkDataMap[animationChannel->GetDocument()].animationChannelData[animationChannel]; //FUAssert(!data.targetPointer.empty(), NULL); fm::string baseId = FCDObjectWithId::CleanId(animationChannel->GetParent()->GetDaeId() + "_" + data.targetPointer); // Check for curve merging uint32 realCurveCount = 0; const FCDAnimationCurve* masterCurve = NULL; FCDAnimationCurveList mergingCurves; mergingCurves.resize(data.defaultValues.size()); bool mergeCurves = true; size_t curveCount = animationChannel->GetCurveCount(); for (size_t i = 0; i < curveCount; ++i) { const FCDAnimationCurve* curve = animationChannel->GetCurve(i); if (curve != NULL) { // Check that we have a default placement for this curve in the default value listing size_t dv; for (dv = 0; dv < data.defaultValues.size(); ++dv) { if (data.defaultValues[dv].curve == curve) { mergingCurves[dv] = const_cast<FCDAnimationCurve*>(curve); break; } } mergeCurves &= dv != data.defaultValues.size(); // Check that the curves can be merged correctly. ++realCurveCount; if (masterCurve == NULL) { masterCurve = curve; } else { // Check the infinity types, the keys and the interpolations. size_t curveKeyCount = curve->GetKeyCount(); size_t masterKeyCount = masterCurve->GetKeyCount(); mergeCurves &= masterKeyCount == curveKeyCount; if (!mergeCurves) break; for (size_t j = 0; j < curveKeyCount && mergeCurves; ++j) { const FCDAnimationKey* curveKey = curve->GetKey(j); const FCDAnimationKey* masterKey = masterCurve->GetKey(j); mergeCurves &= IsEquivalent(curveKey->input, masterKey->input); mergeCurves &= curveKey->interpolation == masterKey->interpolation; // Prevent curve having TCB interpolation from merging mergeCurves &= curveKey->interpolation != FUDaeInterpolation::TCB; mergeCurves &= masterKey->interpolation != FUDaeInterpolation::TCB; } if (!mergeCurves) break; mergeCurves &= curve->GetPostInfinity() == masterCurve->GetPostInfinity(); mergeCurves &= curve->GetPreInfinity() == masterCurve->GetPreInfinity(); } // Disallow the merging of any curves with a driver. mergeCurves &= !curve->HasDriver(); } } if (mergeCurves && realCurveCount > 1) { // Prepare the list of default values FloatList values; values.reserve(data.defaultValues.size()); for (FAXAnimationChannelDefaultValueList::iterator itDV = data.defaultValues.begin(); itDV != data.defaultValues.end(); ++itDV) { values.push_back((*itDV).defaultValue); } FUAssert(data.animatedValue != NULL, return parentNode); const char** qualifiers = new const char*[values.size()]; memset(qualifiers, 0, sizeof(char*) * values.size()); for (size_t i = 0; i < values.size() && i < data.animatedValue->GetValueCount(); ++i) { qualifiers[i] = data.animatedValue->GetQualifier(i); } // Merge and export the curves FCDAnimationMultiCurve* multiCurve = FCDAnimationCurveTools::MergeCurves(mergingCurves, values); FArchiveXML::WriteSourceFCDAnimationMultiCurve(multiCurve, parentNode, qualifiers, baseId); FArchiveXML::WriteSamplerFCDAnimationMultiCurve(multiCurve, parentNode, baseId); FArchiveXML::WriteChannelFCDAnimationMultiCurve(multiCurve, parentNode, baseId, data.targetPointer); SAFE_RELEASE(multiCurve); }