bool LIRenAttachmentEntity::create_skeleton () { Ogre::SkeletonInstance* skeleton = entity->getSkeleton (); if (skeleton == NULL) return false; /* Set the initial bone transformations. */ /* The mesh may not have set these correctly if it depended on bones in external skeletons. Because of external bones, we need to set the transformations using the pose skeleton of the object. */ LIRenModelData* model = get_model (); if (model != NULL && model->rest_pose_buffer != NULL) { for (int i = 0 ; i < model->rest_pose_buffer->bones.count ; i++) { const LIMdlPoseBufferBone* group = model->rest_pose_buffer->bones.array + i; if (!group->name) continue; LIMatTransform t; if (!object->get_node_transform (group->name, t)) continue; Ogre::Bone* bone = skeleton->getBone (i); bone->setPosition (t.position.x, t.position.y, t.position.z); bone->setOrientation (t.rotation.w, t.rotation.x, t.rotation.y, t.rotation.z); } } /* Make all bones manually controlled. */ for (int i = 0 ; i < skeleton->getNumBones () ; i++) { Ogre::Bone* bone = skeleton->getBone (i); bone->setManuallyControlled (true); } /* Set the binding pose. */ skeleton->setBindingPose (); return true; }
void EC_OgreAnimationController::Update(f64 frametime) { Ogre::Entity* entity = GetEntity(); if (!entity) return; std::vector<std::string> erase_list; // Loop through all animations & update them as necessary for (AnimationMap::iterator i = animations_.begin(); i != animations_.end(); ++i) { Ogre::AnimationState* animstate = GetAnimationState(entity, i->first); if (!animstate) continue; switch(i->second.phase_) { case PHASE_FADEIN: // If period is infinitely fast, skip to full weight & PLAY status if (i->second.fade_period_ == 0.0f) { i->second.weight_ = 1.0f; i->second.phase_ = PHASE_PLAY; } else { i->second.weight_ += (1.0f / i->second.fade_period_) * frametime; if (i->second.weight_ >= 1.0f) { i->second.weight_ = 1.0f; i->second.phase_ = PHASE_PLAY; } } break; case PHASE_PLAY: if (i->second.auto_stop_ || i->second.num_repeats_ != 1) { if ((i->second.speed_factor_ >= 0.f && animstate->getTimePosition() >= animstate->getLength()) || (i->second.speed_factor_ < 0.f && animstate->getTimePosition() <= 0.f)) { if (i->second.num_repeats_ != 1) { if (i->second.num_repeats_ > 1) i->second.num_repeats_--; Ogre::Real rewindpos = i->second.speed_factor_ >= 0.f ? (animstate->getTimePosition() - animstate->getLength()) : animstate->getLength(); animstate->setTimePosition(rewindpos); } else { i->second.phase_ = PHASE_FADEOUT; } } } break; case PHASE_FADEOUT: // If period is infinitely fast, skip to disabled status immediately if (i->second.fade_period_ == 0.0f) { i->second.weight_ = 0.0f; i->second.phase_ = PHASE_STOP; } else { i->second.weight_ -= (1.0f / i->second.fade_period_) * frametime; if (i->second.weight_ <= 0.0f) { i->second.weight_ = 0.0f; i->second.phase_ = PHASE_STOP; } } break; } // Set weight & step the animation forward if (i->second.phase_ != PHASE_STOP) { Ogre::Real advance = i->second.speed_factor_ * frametime; Ogre::Real new_weight = i->second.weight_ * i->second.weight_factor_; if (new_weight != animstate->getWeight()) animstate->setWeight((Ogre::Real)i->second.weight_ * i->second.weight_factor_); if (advance != 0.0f) animstate->addTime((Ogre::Real)(i->second.speed_factor_ * frametime)); if (!animstate->getEnabled()) animstate->setEnabled(true); } else { // If stopped, disable & remove this animation from list animstate->setEnabled(false); erase_list.push_back(i->first); } } for (uint i = 0; i < erase_list.size(); ++i) { animations_.erase(erase_list[i]); } // High-priority/low-priority blending code if (entity->hasSkeleton()) { Ogre::SkeletonInstance* skel = entity->getSkeleton(); if (!skel) return; if (highpriority_mask_.size() != skel->getNumBones()) highpriority_mask_.resize(skel->getNumBones()); if (lowpriority_mask_.size() != skel->getNumBones()) lowpriority_mask_.resize(skel->getNumBones()); for (uint i = 0; i < skel->getNumBones(); ++i) { highpriority_mask_[i] = 1.0; lowpriority_mask_[i] = 1.0; } // Loop through all high priority animations & update the lowpriority-blendmask based on their active tracks for (AnimationMap::iterator i = animations_.begin(); i != animations_.end(); ++i) { Ogre::AnimationState* animstate = GetAnimationState(entity, i->first); if (!animstate) continue; // Create blend mask if animstate doesn't have it yet if (!animstate->hasBlendMask()) animstate->createBlendMask(skel->getNumBones()); if ((i->second.high_priority_) && (i->second.weight_ > 0.0)) { // High-priority animations get the full weight blend mask animstate->_setBlendMaskData(&highpriority_mask_[0]); if (!skel->hasAnimation(animstate->getAnimationName())) continue; Ogre::Animation* anim = skel->getAnimation(animstate->getAnimationName()); Ogre::Animation::NodeTrackIterator it = anim->getNodeTrackIterator(); while (it.hasMoreElements()) { Ogre::NodeAnimationTrack* track = it.getNext(); unsigned id = track->getHandle(); // For each active track, reduce corresponding bone weight in lowpriority-blendmask // by this animation's weight if (id < lowpriority_mask_.size()) { lowpriority_mask_[id] -= i->second.weight_; if (lowpriority_mask_[id] < 0.0) lowpriority_mask_[id] = 0.0; } } } } // Now set the calculated blendmask on low-priority animations for (AnimationMap::iterator i = animations_.begin(); i != animations_.end(); ++i) { Ogre::AnimationState* animstate = GetAnimationState(entity, i->first); if (!animstate) continue; if (i->second.high_priority_ == false) animstate->_setBlendMaskData(&lowpriority_mask_[0]); } } }