void TSShapeInstance::animateNodes(S32 ss) { PROFILE_SCOPE( TSShapeInstance_animateNodes ); if (!mShape->nodes.size()) return; // @todo: When a node is added, we need to make sure to resize the nodeTransforms array as well mNodeTransforms.setSize(mShape->nodes.size()); // temporary storage for node transforms mCurrentRenderState->smNodeCurrentRotations.setSize(mShape->nodes.size()); mCurrentRenderState->smNodeCurrentTranslations.setSize(mShape->nodes.size()); mCurrentRenderState->smNodeLocalTransforms.setSize(mShape->nodes.size()); mCurrentRenderState->smRotationThreads.setSize(mShape->nodes.size()); mCurrentRenderState->smTranslationThreads.setSize(mShape->nodes.size()); TSIntegerSet rotBeenSet; TSIntegerSet tranBeenSet; TSIntegerSet scaleBeenSet; rotBeenSet.setAll(mShape->nodes.size()); tranBeenSet.setAll(mShape->nodes.size()); scaleBeenSet.setAll(mShape->nodes.size()); mCurrentRenderState->smNodeLocalTransformDirty.clearAll(); S32 i,j,nodeIndex,a,b,start,end,firstBlend = mThreadList.size(); for (i=0; i<mThreadList.size(); i++) { TSThread * th = mThreadList[i]; if (th->getSequence()->isBlend()) { // blend sequences need default (if not set by other sequence) // break rather than continue because the rest will be blends too firstBlend = i; break; } rotBeenSet.takeAway(th->getSequence()->rotationMatters); tranBeenSet.takeAway(th->getSequence()->translationMatters); scaleBeenSet.takeAway(th->getSequence()->scaleMatters); } rotBeenSet.takeAway(mCallbackNodes); rotBeenSet.takeAway(mHandsOffNodes); rotBeenSet.overlap(mMaskRotationNodes); TSIntegerSet maskPosNodes=mMaskPosXNodes; maskPosNodes.overlap(mMaskPosYNodes); maskPosNodes.overlap(mMaskPosZNodes); tranBeenSet.overlap(maskPosNodes); tranBeenSet.takeAway(mCallbackNodes); tranBeenSet.takeAway(mHandsOffNodes); // can't add masked nodes since x, y, & z masked separately... // we'll set default regardless of mask status // all the nodes marked above need to have the default transform a = mShape->subShapeFirstNode[ss]; b = a + mShape->subShapeNumNodes[ss]; for (i=a; i<b; i++) { if (rotBeenSet.test(i)) { mShape->defaultRotations[i].getQuatF(&mCurrentRenderState->smNodeCurrentRotations[i]); mCurrentRenderState->smRotationThreads[i] = NULL; } if (tranBeenSet.test(i)) { mCurrentRenderState->smNodeCurrentTranslations[i] = mShape->defaultTranslations[i]; mCurrentRenderState->smTranslationThreads[i] = NULL; } } // don't want a transform in these cases... rotBeenSet.overlap(mHandsOffNodes); rotBeenSet.overlap(mCallbackNodes); tranBeenSet.takeAway(maskPosNodes); tranBeenSet.overlap(mHandsOffNodes); tranBeenSet.overlap(mCallbackNodes); // default scale if (scaleCurrentlyAnimated()) handleDefaultScale(a,b,scaleBeenSet); // handle non-blend sequences for (i=0; i<firstBlend; i++) { TSThread * th = mThreadList[i]; j=0; start = th->getSequence()->rotationMatters.start(); end = b; for (nodeIndex=start; nodeIndex<end; th->getSequence()->rotationMatters.next(nodeIndex), j++) { // skip nodes outside of this detail if (nodeIndex<a) continue; if (!rotBeenSet.test(nodeIndex)) { QuatF q1,q2; mShape->getRotation(*th->getSequence(),th->keyNum1,j,&q1); mShape->getRotation(*th->getSequence(),th->keyNum2,j,&q2); TSTransform::interpolate(q1,q2,th->keyPos,&mCurrentRenderState->smNodeCurrentRotations[nodeIndex]); rotBeenSet.set(nodeIndex); mCurrentRenderState->smRotationThreads[nodeIndex] = th; } } j=0; start = th->getSequence()->translationMatters.start(); end = b; for (nodeIndex=start; nodeIndex<end; th->getSequence()->translationMatters.next(nodeIndex), j++) { if (nodeIndex<a) continue; if (!tranBeenSet.test(nodeIndex)) { if (maskPosNodes.test(nodeIndex)) handleMaskedPositionNode(th,nodeIndex,j); else { const Point3F & p1 = mShape->getTranslation(*th->getSequence(),th->keyNum1,j); const Point3F & p2 = mShape->getTranslation(*th->getSequence(),th->keyNum2,j); TSTransform::interpolate(p1,p2,th->keyPos,&mCurrentRenderState->smNodeCurrentTranslations[nodeIndex]); mCurrentRenderState->smTranslationThreads[nodeIndex] = th; } tranBeenSet.set(nodeIndex); } } if (scaleCurrentlyAnimated()) handleAnimatedScale(th,a,b,scaleBeenSet); } // compute transforms for (i=a; i<b; i++) { if (!mHandsOffNodes.test(i)) TSTransform::setMatrix(mCurrentRenderState->smNodeCurrentRotations[i],mCurrentRenderState->smNodeCurrentTranslations[i],&mCurrentRenderState->smNodeLocalTransforms[i]); else mCurrentRenderState->smNodeLocalTransforms[i] = mNodeTransforms[i]; // in case mNodeTransform was changed externally } // add scale onto transforms if (scaleCurrentlyAnimated()) handleNodeScale(a,b); // get callbacks... start = getMax(mCallbackNodes.start(),a); end = getMin(mCallbackNodes.end(),b); for (i=0; i<mNodeCallbacks.size(); i++) { AssertFatal(mNodeCallbacks[i].callback, "No callback method defined"); S32 nodeIndex = mNodeCallbacks[i].nodeIndex; if (nodeIndex>=start && nodeIndex<end) { mNodeCallbacks[i].callback->setNodeTransform(this, nodeIndex, mCurrentRenderState->smNodeLocalTransforms[nodeIndex]); mCurrentRenderState->smNodeLocalTransformDirty.set(nodeIndex); } } // handle blend sequences for (i=firstBlend; i<mThreadList.size(); i++) { TSThread * th = mThreadList[i]; if (th->blendDisabled) continue; handleBlendSequence(th,a,b); } // transitions... if (inTransition()) handleTransitionNodes(a,b); // multiply transforms... for (i=a; i<b; i++) { S32 parentIdx = mShape->nodes[i].parentIndex; if (parentIdx < 0) mNodeTransforms[i] = mCurrentRenderState->smNodeLocalTransforms[i]; else mNodeTransforms[i].mul(mNodeTransforms[parentIdx],mCurrentRenderState->smNodeLocalTransforms[i]); } }
void TSShapeInstance::updateTransitions() { if (mTransitionThreads.empty()) return; TSIntegerSet transitionNodes; updateTransitionNodeTransforms(transitionNodes); S32 i; mNodeReferenceRotations.setSize(mShape->nodes.size()); mNodeReferenceTranslations.setSize(mShape->nodes.size()); for (i=0; i<mShape->nodes.size(); i++) { if (mTransitionRotationNodes.test(i)) mNodeReferenceRotations[i].set(smNodeCurrentRotations[i]); if (mTransitionTranslationNodes.test(i)) mNodeReferenceTranslations[i] = smNodeCurrentTranslations[i]; } if (animatesScale()) { // Make sure smNodeXXXScale arrays have been resized TSIntegerSet dummySet; handleDefaultScale(0, 0, dummySet); if (animatesUniformScale()) { mNodeReferenceUniformScales.setSize(mShape->nodes.size()); for (i=0; i<mShape->nodes.size(); i++) { if (mTransitionScaleNodes.test(i)) mNodeReferenceUniformScales[i] = smNodeCurrentUniformScales[i]; } } else if (animatesAlignedScale()) { mNodeReferenceScaleFactors.setSize(mShape->nodes.size()); for (i=0; i<mShape->nodes.size(); i++) { if (mTransitionScaleNodes.test(i)) mNodeReferenceScaleFactors[i] = smNodeCurrentAlignedScales[i]; } } else { mNodeReferenceScaleFactors.setSize(mShape->nodes.size()); mNodeReferenceArbitraryScaleRots.setSize(mShape->nodes.size()); for (i=0; i<mShape->nodes.size(); i++) { if (mTransitionScaleNodes.test(i)) { mNodeReferenceScaleFactors[i] = smNodeCurrentArbitraryScales[i].mScale; mNodeReferenceArbitraryScaleRots[i].set(smNodeCurrentArbitraryScales[i].mRotate); } } } } // reset transition durations to account for new reference transforms for (i=0; i<mTransitionThreads.size(); i++) { TSThread * th = mTransitionThreads[i]; if (th->transitionData.inTransition) { th->transitionData.duration *= 1.0f - th->transitionData.pos; th->transitionData.pos = 0.0f; } } }