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     }
00114 
00115     if (_candidateAnim && _framesBeforeCandidateReady > 0) {
00116 
00117         _candidateAnimTime = time;
00118         _framesBeforeCandidateReady--;
00119 
00120         // We need to animate here, because the model may have
00121         // changed from under us.
00122         const Common::Array<BoneNode *> &bones = _model->getBones();
00123         setNode(_animTime, bones[0], nullptr);
00124         return;
00125     }
00126 
00127     if (_candidateAnim && _framesBeforeCandidateReady <= 0) {
00128         if (_anim) {
00129             startBlending();
00130         }
00131         enactCandidate();
00132     }
00133 
00134     int32 deltaTime = time - _animTime;
00135     if (deltaTime < 0 || time > _blendDuration / 2) {
00136         deltaTime = 33;
00137     }
00138 
00139     updateBlending(deltaTime);
00140 
00141     // Start at root bone
00142     // For each child
00143     //  - Set childs animation coordinate
00144     //  - Process that childs children
00145 
00146     const Common::Array<BoneNode *> &bones = _model->getBones();
00147     if (deltaTime >= 0) {
00148         setNode(time, bones[0], nullptr);
00149         _animTime = time;
00150     }
00151 }
00152 
00153 void AnimHandler::enactCandidate() {
00154     _anim = _candidateAnim;
00155     _animTime = _candidateAnimTime;
00156     _candidateAnim = nullptr;
00157     _candidateAnimTime = -1;
00158     _framesBeforeCandidateReady = 0;
00159 }
00160 
00161 void AnimHandler::startBlending() {
00162     _blendTimeRemaining = _blendDuration;
00163     _blendAnim = _anim;
00164     _blendAnimTime = _animTime;
00165 }
00166 
00167 void AnimHandler::updateBlending(int32 deltaTime) {
00168     _blendTimeRemaining -= deltaTime;
00169     if (_blendTimeRemaining > 0) {
00170         // If we are blending, also update the previous animation's time
00171         _blendAnimTime += deltaTime;
00172         if (_blendAnimTime >= (int32) _blendAnim->getLength()) {
00173             _blendAnimTime = _blendAnim->getLength() - 1;
00174         }
00175     } else {
00176         // Otherwise make sure blending is not enabled
00177         stopBlending();
00178     }
00179 }
00180 
00181 void AnimHandler::stopBlending() {
00182     _blendAnim = nullptr;
00183     _blendAnimTime = -1;
00184     _blendTimeRemaining = 0;
00185 }
00186 
00187 void AnimHandler::resetBlending() {
00188     stopBlending();
00189     if (_candidateAnim) {
00190         enactCandidate();
00191     }
00192 }
00193 
00194 } // End of namespace Stark


Generated on Sat Mar 23 2019 05:01:17 for ResidualVM by doxygen 1.7.1
curved edge   curved edge