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

animation.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 COPYRIGHT
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 "common/foreach.h"
00024 
00025 #include "engines/grim/animation.h"
00026 #include "engines/grim/resource.h"
00027 #include "engines/grim/model.h"
00028 #include "engines/grim/debug.h"
00029 #include "engines/grim/savegame.h"
00030 
00031 namespace Grim {
00032 
00033 Animation::Animation(const Common::String &keyframe, AnimManager *manager, int pr1, int pr2) :
00034         _manager(manager), _priority1(pr1), _priority2(pr2), _paused(true),
00035         _active(false), _time(-1), _fade(1.f), _fadeMode(None) {
00036     _keyframe = g_resourceloader->getKeyframe(keyframe);
00037 }
00038 
00039 Animation::~Animation() {
00040     deactivate();
00041 }
00042 
00043 void Animation::activate() {
00044     if (!_active) {
00045         _active = true;
00046         _manager->addAnimation(this, _priority1, _priority2);
00047     }
00048 }
00049 
00050 void Animation::deactivate() {
00051     if (_active) {
00052         _active = false;
00053         _manager->removeAnimation(this);
00054     }
00055 }
00056 
00057 void Animation::play(RepeatMode repeatMode) {
00058     _repeatMode = repeatMode;
00059     if (_repeatMode != Looping)
00060         _time = -1;
00061     _paused = false;
00062     // Reset the fading, so that a fading out a chore and playing another one with an animation in common
00063     // results in the animation being actually played. (You can check that with Olivia by the car in set me,
00064     // when jumping with j+ts; me.olivia_search_idles() in me.lua)
00065     if (_fadeMode == FadeOut)
00066         _fadeMode = None;
00067     activate();
00068 }
00069 
00070 void Animation::fade(FadeMode fadeMode, int fadeLength) {
00071     if (!_active) {
00072         if (fadeMode == FadeIn) {
00073             _repeatMode = PauseAtEnd;
00074             _time = -1;
00075             _fade = 0.f;
00076             _paused = false;
00077         }
00078     }
00079     _fadeMode = fadeMode;
00080     _fadeLength = fadeLength;
00081 }
00082 
00083 void Animation::pause(bool p) {
00084     _paused = p;
00085 }
00086 
00087 void Animation::stop() {
00088     _fadeMode = None;
00089     _time = -1;
00090     _fade = 1.f;
00091     _paused = false;
00092     deactivate();
00093 }
00094 
00095 bool Animation::getIsActive() const {
00096     return _active;
00097 }
00098 
00099 Animation::FadeMode Animation::getFadeMode() const {
00100     return _fadeMode;
00101 
00102 }
00103 
00104 int Animation::update(uint time) {
00105     // For first time through newTime will be 0
00106     int newTime = 0;
00107     if (_time >= 0 && !_paused)
00108         newTime = _time + time;
00109 
00110     int marker = 0;
00111     if (!_paused) {
00112         marker = _keyframe->getMarker(_time / 1000.f, newTime / 1000.f);
00113         _time = newTime;
00114     }
00115 
00116     int animLength = (int)(_keyframe->getLength() * 1000);
00117 
00118     if (_fadeMode != None) {
00119         if (_fadeMode == FadeIn) {
00120             _fade += (float)time / (float)_fadeLength;
00121             if (_fade >= 1.f) {
00122                 _fade = 1.f;
00123                 _fadeMode = None;
00124             }
00125         } else {
00126             _fade -= (float)time / (float)_fadeLength;
00127             if (_fade <= 0.f) {
00128                 _fade = 0.f;
00129                 // Don't reset the _fadeMode here. This way if fadeOut() was called
00130                 // on a looping chore its keyframe animations will remain faded out
00131                 // when it calls play() again.
00132                 deactivate();
00133                 return 0;
00134             }
00135         }
00136     } else {
00137         _fade = 1.f;
00138     }
00139 
00140     if (_time > animLength) { // What to do at end?
00141         switch (_repeatMode) {
00142             case Once:
00143                 if (_fadeMode == None)
00144                     deactivate();
00145                 else
00146                     _time = animLength;
00147                 break;
00148             case Looping:
00149                 _time = -1;
00150                 break;
00151             case PauseAtEnd:
00152                 _time = animLength;
00153                 _paused = true;
00154                 break;
00155             case FadeAtEnd:
00156                 if (_fadeMode != FadeOut) {
00157                     _fadeMode = FadeOut;
00158                     _fadeLength = 250;
00159                 }
00160                 _time = animLength;
00161                 break;
00162             default:
00163                 Debug::warning(Debug::Keyframes, "Unknown repeat mode %d for keyframe %s", _repeatMode, _keyframe->getFilename().c_str());
00164         }
00165     }
00166 
00167     return marker;
00168 }
00169 
00170 void Animation::saveState(SaveGame *state) const {
00171     state->writeBool(_active);
00172     state->writeLESint32((int)_repeatMode);
00173     state->writeLESint32(_time);
00174     state->writeLESint32((int)_fadeMode);
00175     state->writeFloat(_fade);
00176     state->writeLESint32(_fadeLength);
00177     state->writeBool(_paused);
00178 }
00179 
00180 void Animation::restoreState(SaveGame *state) {
00181     bool active = state->readBool();
00182     _repeatMode = (RepeatMode)state->readLESint32();
00183     _time = state->readLESint32();
00184     _fadeMode = (FadeMode)state->readLESint32();
00185     _fade = state->readFloat();
00186     _fadeLength = state->readLESint32();
00187     _paused = state->readBool();
00188 
00189     if (active)
00190         activate();
00191 }
00192 
00197 AnimManager::AnimManager() {
00198 
00199 }
00200 
00201 AnimManager::~AnimManager() {
00202     foreach (const AnimationEntry &entry, _activeAnims) {
00203         Animation *anim = entry._anim;
00204         // Don't call deactivate() here so we don't mess with the list we're using.
00205         anim->_manager = nullptr;
00206         anim->_active = false;
00207     }
00208 }
00209 
00210 void AnimManager::addAnimation(Animation *anim, int priority1, int priority2) {
00211     // Keep the list of animations sorted by priorities in descending order. Because
00212     // the animations have two different priorities, we add the animation to the list
00213     // with both priorities.
00214     Common::List<AnimationEntry>::iterator i;
00215     AnimationEntry entry;
00216     entry._anim = anim;
00217     entry._priority = priority1;
00218     entry._tagged = false;
00219     for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
00220         if (i->_priority < entry._priority) {
00221             _activeAnims.insert(i, entry);
00222             break;
00223         }
00224     }
00225     if (i == _activeAnims.end())
00226         _activeAnims.push_back(entry);
00227 
00228     entry._priority = priority2;
00229     entry._tagged = true;
00230     for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
00231         if (i->_priority < entry._priority) {
00232             _activeAnims.insert(i, entry);
00233             break;
00234         }
00235     }
00236     if (i == _activeAnims.end())
00237         _activeAnims.push_back(entry);
00238 }
00239 
00240 void AnimManager::removeAnimation(const Animation *anim) {
00241     Common::List<AnimationEntry>::iterator i;
00242     for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
00243         if (i->_anim == anim) {
00244             i = _activeAnims.erase(i);
00245             --i;
00246         }
00247     }
00248 }
00249 
00250 void AnimManager::animate(ModelNode *hier, int numNodes) {
00251     // Apply animation to each hierarchy node separately.
00252     for (int i = 0; i < numNodes; i++) {
00253         float remainingWeight = 1.0f;
00254         int currPriority = -1;
00255         float layerWeight = 0.0f;
00256 
00257         // The animations are layered so that animations with a higher priority
00258         // are played regardless of the blend weights of lower priority animations.
00259         // The highest priority layer gets as much weight as it wants, while the
00260         // next layer gets the remaining amount and so on.
00261         for (Common::List<AnimationEntry>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
00262             if (currPriority != j->_priority) {
00263                 remainingWeight *= 1.0f - layerWeight;
00264                 layerWeight = 0.0f;
00265                 for (Common::List<AnimationEntry>::iterator k = j; k != _activeAnims.end(); ++k) {
00266                     if (j->_priority != k->_priority)
00267                         break;
00268                     float time = k->_anim->_time / 1000.0f;
00269                     if (k->_anim->_keyframe->isNodeAnimated(hier, i, time, k->_tagged))
00270                         layerWeight += k->_anim->_fade;
00271                 }
00272 
00273                 currPriority = j->_priority;
00274                 if (remainingWeight <= 0.0f)
00275                     break;
00276             }
00277 
00278             float time = j->_anim->_time / 1000.0f;
00279             float weight = j->_anim->_fade;
00280             if (layerWeight > 1.0f)
00281                 weight /= layerWeight;
00282             weight *= remainingWeight;
00283             j->_anim->_keyframe->animate(hier, i, time, weight, j->_tagged);
00284         }
00285     }
00286 }
00287 
00288 }


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