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

animationemi.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/stream.h"
00024 #include "math/vector3d.h"
00025 #include "math/quat.h"
00026 #include "engines/grim/resource.h"
00027 #include "engines/grim/emi/animationemi.h"
00028 #include "common/textconsole.h"
00029 
00030 namespace Grim {
00031 
00032 AnimationEmi::AnimationEmi(const Common::String &filename, Common::SeekableReadStream *data) :
00033         _name(""), _duration(0.0f), _numBones(0), _bones(nullptr) {
00034     _fname = filename;
00035     loadAnimation(data);
00036 }
00037 
00038 // Use modelemi's solution for the LA-strings.
00039 void AnimationEmi::loadAnimation(Common::SeekableReadStream *data) {
00040     int len = data->readUint32LE();
00041     char *inString = new char[len];
00042     data->read(inString, len);
00043     _name = inString;
00044     delete[] inString;
00045 
00046     _duration = 1000 * data->readFloatLE();
00047     _numBones = data->readUint32LE();
00048 
00049     _bones = new Bone[_numBones];
00050     for (int i = 0; i < _numBones; i++) {
00051         _bones[i].loadBinary(data);
00052     }
00053 }
00054 
00055 AnimationEmi::~AnimationEmi() {
00056     g_resourceloader->uncacheAnimationEmi(this);
00057     delete[] _bones;
00058 }
00059 
00060 void Bone::loadBinary(Common::SeekableReadStream *data) {
00061     uint32 len = data->readUint32LE();
00062     char *inString = new char[len];
00063     data->read(inString, len);
00064     _boneName = inString;
00065     delete[] inString;
00066     _operation = data->readUint32LE();
00067     _priority = data->readUint32LE();
00068     _c = data->readUint32LE();
00069     _count = data->readUint32LE();
00070 
00071     if (_operation == 3) { // Translation
00072         _translations = new AnimTranslation[_count];
00073         for (int j = 0; j < _count; j++) {
00074             _translations[j]._vec.readFromStream(data);
00075             _translations[j]._time = 1000 * data->readFloatLE();
00076         }
00077     } else if (_operation == 4) { // Rotation
00078         _rotations = new AnimRotation[_count];
00079         for (int j = 0; j < _count; j++) {
00080             _rotations[j]._quat.readFromStream(data);
00081             _rotations[j]._time = 1000 * data->readFloatLE();
00082         }
00083     } else {
00084         error("Unknown animation-operation %d", _operation);
00085     }
00086 }
00087 
00088 Bone::~Bone() {
00089     if (_operation == 3) {
00090         delete[] _translations;
00091     } else if (_operation == 4) {
00092         delete[] _rotations;
00093     }
00094 }
00095 
00096 AnimationStateEmi::AnimationStateEmi(const Common::String &anim) :
00097         _skel(nullptr), _looping(false), _active(false), _paused(false),
00098         _fadeMode(Animation::None), _fade(1.0f), _fadeLength(0), _time(-1), _startFade(1.0f),
00099         _boneJoints(nullptr) {
00100     _anim = g_resourceloader->getAnimationEmi(anim);
00101     if (_anim)
00102         _boneJoints = new int[_anim->_numBones];
00103 }
00104 
00105 AnimationStateEmi::~AnimationStateEmi() {
00106     deactivate();
00107     delete[] _boneJoints;
00108 }
00109 
00110 void AnimationStateEmi::activate() {
00111     if (!_active) {
00112         _active = true;
00113         if (_skel)
00114             _skel->addAnimation(this);
00115     }
00116 }
00117 
00118 void AnimationStateEmi::deactivate() {
00119     if (_active) {
00120         _active = false;
00121         if (_skel)
00122             _skel->removeAnimation(this);
00123     }
00124 }
00125 
00126 void AnimationStateEmi::update(uint time) {
00127     if (!_active)
00128         return;
00129 
00130     if (!_anim) {
00131         deactivate();
00132         return;
00133     }
00134 
00135     if (!_paused) {
00136         int durationMs = (int)_anim->_duration;
00137         if (_time >= durationMs) {
00138             if (_looping) {
00139                 _time = _time % durationMs;
00140             } else {
00141                 if (_fadeMode != Animation::FadeOut)
00142                     deactivate();
00143             }
00144         }
00145         if (_time < 0) {
00146             _time = 0;
00147         } else {
00148             _time += time;
00149         }
00150     }
00151 
00152     if (_fadeMode != Animation::None) {
00153         if (_fadeMode == Animation::FadeIn) {
00154             _fade += (float)time * (1.0f - _startFade) / _fadeLength;
00155             if (_fade >= 1.f) {
00156                 _fade = 1.f;
00157                 _fadeMode = Animation::None;
00158             }
00159         } else {
00160             _fade -= (float)time * _startFade / _fadeLength;
00161             if (_fade <= 0.f) {
00162                 _fade = 0.f;
00163                 // Don't reset the _fadeMode here. This way if fadeOut() was called
00164                 // on a looping chore its keyframe animations will remain faded out
00165                 // when it calls play() again.
00166                 deactivate();
00167                 return;
00168             }
00169         }
00170     }
00171 }
00172 
00173 void AnimationStateEmi::computeWeights() {
00174     if (_fade <= 0.0f)
00175         return;
00176 
00177     for (int bone = 0; bone < _anim->_numBones; ++bone) {
00178         Bone &curBone = _anim->_bones[bone];
00179         int jointIndex = _boneJoints[bone];
00180         if (jointIndex == -1)
00181             continue;
00182 
00183         AnimationLayer *layer = _skel->getLayer(curBone._priority);
00184         JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
00185 
00186         if (curBone._rotations) {
00187             jointAnim._rotWeight += _fade;
00188         }
00189         if (curBone._translations) {
00190             jointAnim._transWeight += _fade;
00191         }
00192     }
00193 }
00194 
00195 void AnimationStateEmi::animate() {
00196     if (_fade <= 0.0f)
00197         return;
00198 
00199     if (_time < 0)
00200         return;
00201 
00202     for (int bone = 0; bone < _anim->_numBones; ++bone) {
00203         Bone &curBone = _anim->_bones[bone];
00204         int jointIndex = _boneJoints[bone];
00205         if (jointIndex == -1)
00206             continue;
00207 
00208         Joint *target = &_skel->_joints[jointIndex];
00209         AnimationLayer *layer = _skel->getLayer(curBone._priority);
00210         JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
00211 
00212         if (curBone._rotations) {
00213             int keyfIdx = -1;
00214             Math::Quaternion quat;
00215 
00216             // Normalize the weight so that the sum of applied weights will equal 1.
00217             float normalizedRotWeight = _fade;
00218             if (jointAnim._rotWeight > 1.0f) {
00219                 // Note: Division by unnormalized sum of weights.
00220                 normalizedRotWeight = _fade / jointAnim._rotWeight;
00221             }
00222 
00223             for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
00224                 if (curBone._rotations[curKeyFrame]._time >= _time) {
00225                     keyfIdx = curKeyFrame;
00226                     break;
00227                 }
00228             }
00229 
00230             if (keyfIdx == 0) {
00231                 quat = curBone._rotations[0]._quat;
00232             }
00233             else if (keyfIdx != -1) {
00234                 float timeDelta = curBone._rotations[keyfIdx]._time - curBone._rotations[keyfIdx - 1]._time;
00235                 float interpVal = (_time - curBone._rotations[keyfIdx - 1]._time) / timeDelta;
00236 
00237                 quat = curBone._rotations[keyfIdx - 1]._quat.slerpQuat(curBone._rotations[keyfIdx]._quat, interpVal);
00238             }
00239             else {
00240                 quat = curBone._rotations[curBone._count - 1]._quat;
00241             }
00242 
00243             Math::Quaternion &quatFinal = jointAnim._quat;
00244             quat = target->_quat.inverse() * quat;
00245             quat = quatFinal * quat;
00246             quatFinal = quatFinal.slerpQuat(quat, normalizedRotWeight);
00247         }
00248 
00249         if (curBone._translations) {
00250             int keyfIdx = -1;
00251             Math::Vector3d vec;
00252 
00253             // Normalize the weight so that the sum of applied weights will equal 1.
00254             float normalizedTransWeight = _fade;
00255             if (jointAnim._transWeight > 1.0f) {
00256                 // Note: Division by unnormalized sum of weights.
00257                 normalizedTransWeight = _fade / jointAnim._transWeight;
00258             }
00259 
00260             for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
00261                 if (curBone._translations[curKeyFrame]._time >= _time) {
00262                     keyfIdx = curKeyFrame;
00263                     break;
00264                 }
00265             }
00266 
00267             if (keyfIdx == 0) {
00268                 vec = curBone._translations[0]._vec;
00269             }
00270             else if (keyfIdx != -1) {
00271                 float timeDelta = curBone._translations[keyfIdx]._time - curBone._translations[keyfIdx - 1]._time;
00272                 float interpVal = (_time - curBone._translations[keyfIdx - 1]._time) / timeDelta;
00273 
00274                 vec = curBone._translations[keyfIdx - 1]._vec +
00275                     (curBone._translations[keyfIdx]._vec - curBone._translations[keyfIdx - 1]._vec) * interpVal;
00276             }
00277             else {
00278                 vec = curBone._translations[curBone._count - 1]._vec;
00279             }
00280 
00281             Math::Vector3d &posFinal = jointAnim._pos;
00282             vec = vec - target->_relMatrix.getPosition();
00283             posFinal = posFinal + vec * normalizedTransWeight;
00284         }
00285     }
00286 }
00287 
00288 void AnimationStateEmi::play() {
00289     if (!_active) {
00290         _time = -1;
00291         if (_fadeMode == Animation::FadeOut)
00292             _fadeMode = Animation::None;
00293         if (_fadeMode == Animation::FadeIn || _fade > 0.f)
00294             activate();
00295     }
00296     _paused = false;
00297 }
00298 
00299 void AnimationStateEmi::stop() {
00300     _fadeMode = Animation::None;
00301     _time = -1;
00302     deactivate();
00303 }
00304 
00305 void AnimationStateEmi::setPaused(bool paused) {
00306     _paused = paused;
00307 }
00308 
00309 void AnimationStateEmi::setLooping(bool loop) {
00310     _looping = loop;
00311 }
00312 
00313 void AnimationStateEmi::setSkeleton(Skeleton *skel) {
00314     if (skel != _skel) {
00315         if (_skel)
00316             _skel->removeAnimation(this);
00317         _skel = skel;
00318         if (_active)
00319             skel->addAnimation(this);
00320 
00321         if (_anim) {
00322             for (int i = 0; i < _anim->_numBones; ++i) {
00323                 _boneJoints[i] = skel->findJointIndex(_anim->_bones[i]._boneName);
00324             }
00325         }
00326     }
00327 }
00328 
00329 void AnimationStateEmi::fade(Animation::FadeMode mode, int fadeLength) {
00330     if (mode == Animation::None) {
00331         _fade = 1.f;
00332     } else if (_fadeMode != Animation::FadeOut && mode == Animation::FadeIn) {
00333         _fade = 0.f;
00334     }
00335     _startFade = _fade;
00336     _fadeMode = mode;
00337     _fadeLength = fadeLength;
00338 }
00339 
00340 void AnimationStateEmi::advance(uint msecs) {
00341     if (_time >= 0) {
00342         _time += msecs;
00343     } else {
00344         _time = msecs;
00345     }
00346 }
00347 
00348 void AnimationStateEmi::saveState(SaveGame *state) {
00349     state->writeBool(_looping);
00350     state->writeBool(_active);
00351     state->writeBool(_paused);
00352     state->writeLESint32(_time);
00353     state->writeFloat(_fade);
00354     state->writeFloat(_startFade);
00355     state->writeLESint32((int)_fadeMode);
00356     state->writeLESint32(_fadeLength);
00357 }
00358 
00359 void AnimationStateEmi::restoreState(SaveGame *state) {
00360     if (state->saveMinorVersion() >= 10) {
00361         _looping = state->readBool();
00362         bool active = state->readBool();
00363         _paused = state->readBool();
00364         if (state->saveMinorVersion() < 22) {
00365             _time = (uint)state->readFloat();
00366         } else {
00367             _time = state->readLESint32();
00368         }
00369         _fade = state->readFloat();
00370         _startFade = state->readFloat();
00371         _fadeMode = (Animation::FadeMode)state->readLESint32();
00372         _fadeLength = state->readLESint32();
00373 
00374         if (active)
00375             activate();
00376     }
00377 }
00378 
00379 } // end of namespace Grim


Generated on Sat Mar 16 2019 05:01:19 for ResidualVM by doxygen 1.7.1
curved edge   curved edge