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]);			    			   
		    }
        }
    }
Example #2
0
void TutorialApplication::createFrameListener(void) {
	BaseApplication::createFrameListener();
	
	
	// create a params panel for displaying sample details
    Ogre::StringVector items;
   // items.push_back("Filtering");
   // items.push_back("Poly Mode");

    mStatusPanel = mTrayMgr->createParamsPanel(OgreBites::TL_BOTTOMRIGHT, "Params", 300, items);
	
	OgreBites::Slider* slider = NULL;

	mTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "Reset pose", "Reset pose");
	mTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "Reload controller", "Reload controller");
	mTrayMgr->createButton(OgreBites::TL_BOTTOMRIGHT, "Go to pose", "Go to pose");
	

	// animations control
	slider = mTrayMgr->createLongSlider(OgreBites::TL_TOPLEFT, "Gravity X", "Gravity X", 400, 150, 50, -9.8, 9.8, 149 );
	slider->setValue(0);
	slider = mTrayMgr->createLongSlider(OgreBites::TL_TOPLEFT, "Gravity Y", "Gravity Y", 400, 150, 50, -9.8, 9.8, 149 );
	slider->setValue(0.0f);
	slider = mTrayMgr->createLongSlider(OgreBites::TL_TOPLEFT, "Gravity Z", "Gravity Z", 400, 150, 50, -9.8, 9.8, 149 );
	slider->setValue(0.0f);
	slider = mTrayMgr->createLongSlider(OgreBites::TL_TOPLEFT, "Time multiplier", "Time multiplier", 400, 150, 50, 0, 1, 1000 );
	slider->setValue(DEFAULT_TIME_MULTIPLIER);
	slider = mTrayMgr->createLongSlider(OgreBites::TL_TOPLEFT, "Animation speed", "Animation speed", 400, 150, 50, 0, 2, 1000 );
	slider->setValue(DEFAULT_ANIMATION_SPEED);
	
	
	// animation selector
	int defaultAnimationIndex = 0;
	Ogre::SkeletonInstance* skel = mFigureEnt->getSkeleton();
	
	Ogre::StringVector animationNames;
	animationNames.push_back("<none>");
	if ( skel ) {
		std::cout << "got skeleton" << std::endl;
		for ( int i=0; i<skel->getNumAnimations(); i++ ) {
			std::string name = skel->getAnimation(i)->getName();
			std::cout << " animation: " << name << std::endl;
			if ( /*i<5 || name == "WalkNew"*/true )
			{
				animationNames.push_back(name);
				if ( name == DEFAULT_ANIMATION ) {
					defaultAnimationIndex = i;
				}
			}
		}
		//mFigureEnt->setDisplaySkeleton(true);
	} else {
		std::cout << "no skeleton" << std::endl;
	}
	mAnimationSelectMenu = mTrayMgr->createThickSelectMenu( OgreBites::TL_TOPLEFT, "Animation", "Animation", 400, animationNames.size());
	if ( animationNames.size() ) {
		mAnimationSelectMenu->setItems(animationNames);
		mAnimationSelectMenu->selectItem(defaultAnimationIndex);
	}
	
	static const int debugDrawStyleCount = 8;
	OgreBites::SelectMenu* select = mTrayMgr->createThickSelectMenu( OgreBites::TL_BOTTOMRIGHT, "Debug draw", "Debug draw", 400, debugDrawStyleCount );
	Ogre::StringVector debugDrawStates;
	const char* debugDrawStateNames[debugDrawStyleCount] =  { "None", "Nodes", "Links", "Faces", "FaceAnchors", "Tetras", "TetraForces", "BadTetras" };
	for ( int i=0; i<debugDrawStyleCount; i++ ) {
		debugDrawStates.push_back(debugDrawStateNames[i]);
	}
	select->setItems(debugDrawStates);
	select->selectItem(0);
	
	
	showControls(false);
	
}