ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

animhandler.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/model/animhandler.h"
00024 
00025 #include "engines/stark/model/model.h"
00026 #include "engines/stark/model/skeleton_anim.h"
00027 
00028 namespace Stark {
00029 
00030 AnimHandler::AnimHandler() :
00031         _model(nullptr),
00032         _anim(nullptr),
00033         _animTime(-1),
00034         _framesBeforeCandidateReady(0),
00035         _candidateAnim(nullptr),
00036         _candidateAnimTime(-1),
00037         _blendAnim(nullptr),
00038         _blendAnimTime(-1),
00039         _blendTimeRemaining(0) {
00040 
00041 }
00042 
00043 AnimHandler::~AnimHandler() {
00044 }
00045 
00046 void AnimHandler::setAnim(SkeletonAnim *anim) {
00047     if (_candidateAnim == anim) {
00048         return;
00049     }
00050 
00051     if (_anim == anim) {
00052         // If we already have the correct anim, clean any candidates
00053         // that may have been set but not yet enacted as the active anim.
00054         _candidateAnim = nullptr;
00055         _candidateAnimTime = -1;
00056         _framesBeforeCandidateReady = 0;
00057         return;
00058     }
00059 
00060     // Don't use new animations the first frame they are set.
00061     // Scripts may change animation the very next frame,
00062     // causing animations to blend with animations that
00063     // were only visible for one frame, leading to animation
00064     // jumps. Instead store them as candidates.
00065     _framesBeforeCandidateReady = 2; // 2 because we are at the end of the frame
00066     _candidateAnim = anim;
00067     _candidateAnimTime = 0;
00068 }
00069 
00070 void AnimHandler::setModel(Model *model) {
00071     _model = model;
00072 }
00073 
00074 void AnimHandler::setNode(uint32 time, BoneNode *bone, const BoneNode *parent) {
00075     const Common::Array<BoneNode *> &bones = _model->getBones();
00076 
00077     if (_blendTimeRemaining <= 0) {
00078         _anim->getCoordForBone(time, bone->_idx, bone->_animPos, bone->_animRot);
00079     } else {
00080         // Blend the coordinates of the previous and the current animation
00081         Math::Vector3d previousAnimPos, animPos;
00082         Math::Quaternion previousAnimRot, animRot;
00083         _blendAnim->getCoordForBone(_blendAnimTime, bone->_idx, previousAnimPos, previousAnimRot);
00084         _anim->getCoordForBone(time, bone->_idx, animPos, animRot);
00085 
00086         float blendingRatio = 1.0 - _blendTimeRemaining / (float)_blendDuration;
00087 
00088         bone->_animPos = previousAnimPos + (animPos - previousAnimPos) * blendingRatio;
00089         bone->_animRot = previousAnimRot.slerpQuat(animRot, blendingRatio);
00090     }
00091 
00092     if (parent) {
00093         parent->_animRot.transform(bone->_animPos);
00094 
00095         bone->_animPos = parent->_animPos + bone->_animPos;
00096         bone->_animRot = parent->_animRot * bone->_animRot;
00097     }
00098 
00099     for (uint i = 0; i < bone->_children.size(); ++i) {
00100         setNode(time, bones[bone->_children[i]], bone);
00101     }
00102 }
00103 
00104 void AnimHandler::animate(uint32 time) {
00105     if (!_anim && _candidateAnim) {
00106         // This is the first time we animate this item.
00107         enactCandidate();
00108     }
00109 
00110     if (_candidateAnim && _anim && _anim->getBoneCount() != _model->getBones().size()) {
00111         // We changed to an incompatible model
00112         enactCandidate();
00113         assert(_anim->getBoneCount() == _model->getBones().size());
00114     }
00115 
00116     if (_candidateAnim && _framesBeforeCandidateReady > 0) {
00117 
00118         _candidateAnimTime = time;
00119         _framesBeforeCandidateReady--;
00120 
00121         // We need to animate here, because the model may have
00122         // changed from under us.
00123         const Common::Array<BoneNode *> &bones = _model->getBones();
00124         setNode(_animTime, bones[0], nullptr);
00125         return;
00126     }
00127 
00128     if (_candidateAnim && _framesBeforeCandidateReady <= 0) {
00129         if (_anim) {
00130             startBlending();
00131         }
00132         enactCandidate();
00133     }
00134 
00135     int32 deltaTime = time - _animTime;
00136     if (deltaTime < 0 || time > _blendDuration / 2) {
00137         deltaTime = 33;
00138     }
00139 
00140     updateBlending(deltaTime);
00141 
00142     // Start at root bone
00143     // For each child
00144     //  - Set childs animation coordinate
00145     //  - Process that childs children
00146 
00147     const Common::Array<BoneNode *> &bones = _model->getBones();
00148     if (deltaTime >= 0) {
00149         setNode(time, bones[0], nullptr);
00150         _animTime = time;
00151     }
00152 }
00153 
00154 void AnimHandler::enactCandidate() {
00155     _anim = _candidateAnim;
00156     _animTime = _candidateAnimTime;
00157     _candidateAnim = nullptr;
00158     _candidateAnimTime = -1;
00159     _framesBeforeCandidateReady = 0;
00160 }
00161 
00162 void AnimHandler::startBlending() {
00163     _blendTimeRemaining = _blendDuration;
00164     _blendAnim = _anim;
00165     _blendAnimTime = _animTime;
00166 }
00167 
00168 void AnimHandler::updateBlending(int32 deltaTime) {
00169     _blendTimeRemaining -= deltaTime;
00170     if (_blendTimeRemaining > 0) {
00171         // If we are blending, also update the previous animation's time
00172         _blendAnimTime += deltaTime;
00173         if (_blendAnimTime >= (int32) _blendAnim->getLength()) {
00174             _blendAnimTime = _blendAnim->getLength() - 1;
00175         }
00176     } else {
00177         // Otherwise make sure blending is not enabled
00178         stopBlending();
00179     }
00180 }
00181 
00182 void AnimHandler::stopBlending() {
00183     _blendAnim = nullptr;
00184     _blendAnimTime = -1;
00185     _blendTimeRemaining = 0;
00186 }
00187 
00188 void AnimHandler::resetBlending() {
00189     stopBlending();
00190     if (_candidateAnim) {
00191         enactCandidate();
00192     }
00193 }
00194 
00195 } // End of namespace Stark


Generated on Sat Feb 16 2019 05:00:44 for ResidualVM by doxygen 1.7.1
curved edge   curved edge