void TSShapeInstance::animateMatFrame(S32 ss) { PROFILE_SCOPE( TSShapeInstance_animateMatFrame ); S32 i; if (!mMeshObjects.size()) return; // find out who needs default values set TSIntegerSet beenSet; beenSet.setAll(mMeshObjects.size()); for (i=0; i<mThreadList.size(); i++) beenSet.takeAway(mThreadList[i]->getSequence()->matFrameMatters); // set defaults S32 a = mShape->subShapeFirstObject[ss]; S32 b = a + mShape->subShapeNumObjects[ss]; for (i=a; i<b; i++) if (beenSet.test(i)) mMeshObjects[i].matFrame = mShape->objectStates[i].matFrameIndex; // go through each thread and set matFrame on those objects that // are not set yet and are controlled by that thread for (i=0; i<mThreadList.size(); i++) { TSThread * th = mThreadList[i]; // For better or worse, object states are stored together (frame, // matFrame, visibility all in one structure). Thus, indexing into // object state array for animation for any of these attributes needs to // take into account whether or not the other attributes are also animated. // The object states should eventually be separated (like the node states were) // in order to save memory and save the following step. TSIntegerSet objectMatters = th->getSequence()->frameMatters; objectMatters.overlap(th->getSequence()->matFrameMatters); objectMatters.overlap(th->getSequence()->visMatters); // skip to beginining of this sub-shape S32 j=0; S32 start = objectMatters.start(); S32 end = b; for (S32 objectIndex = start; objectIndex<end; objectMatters.next(objectIndex), j++) { if (!beenSet.test(objectIndex) && th->getSequence()->matFrameMatters.test(objectIndex)) { S32 key = (th->keyPos<0.5f) ? th->keyNum1 : th->keyNum2; mMeshObjects[objectIndex].matFrame = mShape->getObjectState(*th->getSequence(),key,j).matFrameIndex; // record change so that later threads don't over-write us... beenSet.set(objectIndex); } } } }
bool TSShapeInstance::initGround() { for (S32 i=0; i<mThreadList.size(); i++) { TSThread * th = mThreadList[i]; if (!th->transitionData.inTransition && th->getSequence()->numGroundFrames>0) { mGroundThread = th; return true; } } return false; }
S32 TSThread::operator<(const TSThread & th2) const { if (getSequence()->isBlend() == th2.getSequence()->isBlend()) { // both blend or neither blend, sort based on priority only -- higher priority first S32 ret = 0; // do it this way to (hopefully) take advantage of 'conditional move' assembly instruction if (priority > th2.priority) ret = -1; if (th2.priority > priority) ret = 1; return ret; } else { // one is blend, the other is not...sort based on blend -- non-blended first AssertFatal(!getSequence()->isBlend() || !th2.getSequence()->isBlend(),"compareThreads: unequal 'trues'"); S32 ret = -1; // do it this way to (hopefully) take advantage of 'conditional move' assembly instruction if (getSequence()->isBlend()) ret = 1; return ret; } }
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]); } }