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

skeleton.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/vector4d.h"
00026 #include "math/quat.h"
00027 #include "engines/grim/debug.h"
00028 #include "engines/grim/emi/animationemi.h"
00029 #include "engines/grim/emi/skeleton.h"
00030 
00031 namespace Grim {
00032 
00033 #define ROTATE_OP 4
00034 #define TRANSLATE_OP 3
00035 
00036 Skeleton::Skeleton(const Common::String &filename, Common::SeekableReadStream *data) :
00037         _numJoints(0), _joints(nullptr), _animLayers(nullptr) {
00038     loadSkeleton(data);
00039 }
00040 
00041 Skeleton::~Skeleton() {
00042     for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
00043         delete[] _animLayers[i]._jointAnims;
00044     }
00045     delete[] _animLayers;
00046     delete[] _joints;
00047 }
00048 
00049 void Skeleton::loadSkeleton(Common::SeekableReadStream *data) {
00050     _numJoints = data->readUint32LE();
00051     _joints = new Joint[_numJoints];
00052 
00053     char inString[32];
00054 
00055     for (int i = 0; i < _numJoints; i++) {
00056         data->read(inString, 32);
00057         _joints[i]._name = inString;
00058         data->read(inString, 32);
00059         _joints[i]._parent = inString;
00060 
00061         _joints[i]._trans.readFromStream(data);
00062         _joints[i]._quat.readFromStream(data);
00063 
00064         _joints[i]._parentIndex = findJointIndex(_joints[i]._parent);
00065 
00066         _jointsMap[_joints[i]._name] = i;
00067     }
00068     initBones();
00069     resetAnim();
00070 }
00071 
00072 void Skeleton::initBone(int index) {
00073     // The matrix should have identity at this point.
00074     _joints[index]._quat.toMatrix(_joints[index]._relMatrix);
00075     // Might need to be translate instead.
00076     _joints[index]._relMatrix.setPosition(_joints[index]._trans);
00077     if (_joints[index]._parentIndex == -1) {
00078         _joints[index]._absMatrix = _joints[index]._relMatrix;
00079     } else {
00080         _joints[index]._absMatrix = _joints[_joints[index]._parentIndex]._absMatrix;
00081 
00082         // Might be the other way around.
00083         _joints[index]._absMatrix =  _joints[index]._absMatrix * _joints[index]._relMatrix;
00084     }
00085 }
00086 
00087 void Skeleton::initBones() {
00088     for (int i = 0; i < _numJoints; i++) {
00089         initBone(i);
00090     }
00091 
00092     _animLayers = new AnimationLayer[MAX_ANIMATION_LAYERS];
00093     for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
00094         _animLayers[i]._jointAnims = new JointAnimation[_numJoints];
00095     }
00096 }
00097 
00098 void Skeleton::resetAnim() {
00099     for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
00100         AnimationLayer &layer = _animLayers[i];
00101         for (int j = 0; j < _numJoints; ++j) {
00102             JointAnimation &jointAnim = layer._jointAnims[j];
00103             jointAnim._pos.set(0.f, 0.f, 0.f);
00104             jointAnim._quat.set(0.f, 0.f, 0.f, 1.f);
00105             jointAnim._transWeight = 0.0f;
00106             jointAnim._rotWeight = 0.0f;
00107         }
00108     }
00109     for (int i = 0; i < _numJoints; ++i) {
00110         _joints[i]._animMatrix = _joints[i]._relMatrix;
00111         _joints[i]._animQuat = _joints[i]._quat;
00112     }
00113 }
00114 
00115 void Skeleton::animate() {
00116     resetAnim();
00117 
00118     // This first pass over the animations calculates bone-specific sums of blend weights for all
00119     // animation layers. The sums must be pre-computed in order to be able to normalize the blend
00120     // weights properly in the next step.
00121     for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
00122         (*j)->computeWeights();
00123     }
00124 
00125     // Now make a second pass over the animations to actually accumulate animation to layers.
00126     for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
00127         (*j)->animate();
00128     }
00129 
00130     // Blend the layers together in priority order to produce the final result. Highest priority
00131     // layer will get as much weight as it wants, while the next highest priority will get the
00132     // amount that remains and so on.
00133     for (int i = 0; i < _numJoints; ++i) {
00134         float remainingTransWeight = 1.0f;
00135         float remainingRotWeight = 1.0f;
00136 
00137         for (int j = MAX_ANIMATION_LAYERS - 1; j >= 0; --j) {
00138             AnimationLayer &layer = _animLayers[j];
00139             JointAnimation &jointAnim = layer._jointAnims[i];
00140 
00141             if (remainingRotWeight > 0.0f && jointAnim._rotWeight != 0.0f) {
00142                 Math::Vector3d pos = _joints[i]._animMatrix.getPosition();
00143                 _joints[i]._animQuat = _joints[i]._animQuat.slerpQuat(_joints[i]._animQuat * jointAnim._quat, remainingRotWeight);
00144                 _joints[i]._animQuat.toMatrix(_joints[i]._animMatrix);
00145                 _joints[i]._animMatrix.setPosition(pos);
00146 
00147                 remainingRotWeight *= 1.0f - jointAnim._rotWeight;
00148             }
00149 
00150             if (remainingTransWeight > 0.0f && jointAnim._transWeight != 0.0f) {
00151                 Math::Vector3d pos = _joints[i]._animMatrix.getPosition();
00152                 Math::Vector3d delta = jointAnim._pos;
00153                 _joints[i]._animMatrix.setPosition(pos + delta * remainingTransWeight);
00154 
00155                 remainingTransWeight *= 1.0f - jointAnim._transWeight;
00156             }
00157 
00158             if (remainingRotWeight <= 0.0f && remainingTransWeight <= 0.0f)
00159                 break;
00160         }
00161     }
00162 
00163     commitAnim();
00164 }
00165 
00166 void Skeleton::addAnimation(AnimationStateEmi *anim) {
00167     _activeAnims.push_back(anim);
00168 }
00169 void Skeleton::removeAnimation(AnimationStateEmi *anim) {
00170     _activeAnims.remove(anim);
00171 }
00172 
00173 void Skeleton::commitAnim() {
00174     for (int m = 0; m < _numJoints; ++m) {
00175         const Joint *parent = getParentJoint(&_joints[m]);
00176         if (parent) {
00177             _joints[m]._finalMatrix = parent->_finalMatrix * _joints[m]._animMatrix;
00178             _joints[m]._finalQuat = parent->_finalQuat * _joints[m]._animQuat;
00179         } else {
00180             _joints[m]._finalMatrix = _joints[m]._animMatrix;
00181             _joints[m]._finalQuat = _joints[m]._animQuat;
00182         }
00183     }
00184 }
00185 
00186 int Skeleton::findJointIndex(const Common::String &name) const {
00187     JointMap::const_iterator it = _jointsMap.find(name);
00188     if (it != _jointsMap.end())
00189         return it->_value;
00190     return -1;
00191 }
00192 
00193 bool Skeleton::hasJoint(const Common::String &name) const {
00194     return name.empty() || findJointIndex(name) >= 0;
00195 }
00196 
00197 Joint *Skeleton::getJointNamed(const Common::String &name) const {
00198     int idx = findJointIndex(name);
00199     if (name.empty()) {
00200         return & _joints[0];
00201     } else if (idx == -1) {
00202         warning("Skeleton has no joint named '%s'!", name.c_str());
00203         return nullptr;
00204     } else {
00205         return & _joints[idx];
00206     }
00207 }
00208 
00209 Joint *Skeleton::getParentJoint(const Joint *j) const {
00210     assert(j);
00211     if (j->_parentIndex == -1)
00212         return nullptr;
00213     return &_joints[j->_parentIndex];
00214 }
00215 
00216 int Skeleton::getJointIndex(const Joint *j) const {
00217     int idx = j - _joints;
00218     assert(idx >= 0 && idx < _numJoints);
00219     return idx;
00220 }
00221 
00222 AnimationLayer* Skeleton::getLayer(int priority) const {
00223     assert(priority >= 0 && priority < MAX_ANIMATION_LAYERS);
00224     return &_animLayers[priority];
00225 }
00226 
00227 
00228 } // end of namespace Grim


Generated on Sat Mar 23 2019 05:02:11 for ResidualVM by doxygen 1.7.1
curved edge   curved edge