-----------------------------------------------------------------------------------
| 64 | } |
| 65 | //----------------------------------------------------------------------------------- |
| 66 | void SkeletonAnimationDef::build( const v1::Skeleton *skeleton, const v1::Animation *animation, |
| 67 | Real frameRate ) |
| 68 | { |
| 69 | mOriginalFrameRate = frameRate; |
| 70 | mNumFrames = animation->getLength() * frameRate; |
| 71 | |
| 72 | // Converts Bone Index -> Slot Index |
| 73 | const SkeletonDef::BoneToSlotVec &boneToSlot = mSkeletonDef->getBoneToSlot(); |
| 74 | const SkeletonDef::IndexToIndexMap &slotToBone = mSkeletonDef->getSlotToBone(); |
| 75 | |
| 76 | // 1st Pass: Count the number of keyframes, so we know how |
| 77 | // much memory to allocate, as we don't listen for resizes. |
| 78 | // We also build a list of unique keyframe timestamps per block |
| 79 | //(i.e. merge the keyframes from two bones that the same block) |
| 80 | v1::Animation::OldNodeTrackIterator itor = animation->getOldNodeTrackIterator(); |
| 81 | { |
| 82 | // Count the number of blocks needed by counting the number of unique keyframes per block. |
| 83 | // i.e. When ARRAY_PACKED_REALS = 4; if 2 bones are in the same block and have the same |
| 84 | // keyframe time value, we'll need 4 slots (aka. 1 block). If those 2 bones have two |
| 85 | // different time values, we'll need 8 slots. |
| 86 | TimestampVec emptyVec; |
| 87 | TimestampsPerBlock timestampsByBlock; |
| 88 | |
| 89 | while( itor.hasMoreElements() ) |
| 90 | { |
| 91 | size_t boneIdx = itor.peekNextKey(); |
| 92 | v1::OldNodeAnimationTrack *track = itor.getNext(); |
| 93 | |
| 94 | if( track->getNumKeyFrames() > 0 ) |
| 95 | { |
| 96 | // Old V1 skeletons would wrap around to keyframe[0] if keyframe[n-1] did not |
| 97 | // cover until the end of the animation. We need to mimic that behavior. |
| 98 | // (See v1::AnimationTrack::getKeyFramesAtTime) |
| 99 | const bool extraKeyFrameAtEnd = |
| 100 | track->getKeyFrame( track->getNumKeyFrames() - 1u )->getTime() < |
| 101 | animation->getLength(); |
| 102 | |
| 103 | uint32 slotIdx = boneToSlot[boneIdx]; |
| 104 | uint32 blockIdx = SkeletonDef::slotToBlockIdx( slotIdx ); |
| 105 | |
| 106 | TimestampsPerBlock::iterator itKeyframes = timestampsByBlock.find( blockIdx ); |
| 107 | if( itKeyframes == timestampsByBlock.end() ) |
| 108 | { |
| 109 | itKeyframes = timestampsByBlock.emplace( (size_t)blockIdx, emptyVec ).first; |
| 110 | } |
| 111 | |
| 112 | itKeyframes->second.reserve( track->getNumKeyFrames() + (size_t)extraKeyFrameAtEnd ); |
| 113 | |
| 114 | for( size_t i = 0; i < track->getNumKeyFrames(); ++i ) |
| 115 | { |
| 116 | Real timestamp = track->getKeyFrame( (uint16)i )->getTime(); |
| 117 | TimestampVec::iterator it = std::lower_bound( |
| 118 | itKeyframes->second.begin(), itKeyframes->second.end(), timestamp ); |
| 119 | if( it == itKeyframes->second.end() || *it != timestamp ) |
| 120 | itKeyframes->second.insert( it, timestamp ); |
| 121 | } |
| 122 | |
| 123 | if( extraKeyFrameAtEnd ) |
no test coverage detected