EMI: Move methods that require animation state information from AnimationEmi to AnimationStateEmi.

This commit is contained in:
Joni Vähämäki 2014-06-12 01:23:14 +03:00
parent af7bc0679c
commit eb26094de1
3 changed files with 122 additions and 117 deletions

View File

@ -59,117 +59,6 @@ AnimationEmi::~AnimationEmi() {
delete[] _bones;
}
void AnimationEmi::computeWeights(const Skeleton *skel, float weight) {
if (weight <= 0.0f)
return;
for (int bone = 0; bone < _numBones; ++bone) {
Bone &curBone = _bones[bone];
Joint *target = skel->getJointNamed(curBone._boneName);
if (!target) {
continue;
}
AnimationLayer *layer = skel->getLayer(curBone._priority);
int jointIndex = skel->getJointIndex(target);
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
if (curBone._rotations) {
jointAnim._rotWeight += weight;
}
if (curBone._translations) {
jointAnim._transWeight += weight;
}
}
}
void AnimationEmi::animate(const Skeleton *skel, float time, bool loop, float weight) {
if (weight <= 0.0f)
return;
for (int bone = 0; bone < _numBones; ++bone) {
Bone &curBone = _bones[bone];
Joint *target = skel->getJointNamed(curBone._boneName);
if (!target) {
continue;
}
AnimationLayer *layer = skel->getLayer(curBone._priority);
int jointIndex = skel->getJointIndex(target);
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
if (curBone._rotations) {
int keyfIdx = -1;
Math::Quaternion quat;
// Normalize the weight so that the sum of applied weights will equal 1.
float normalizedRotWeight = weight;
if (jointAnim._rotWeight > 1.0f) {
// Note: Division by unnormalized sum of weights.
normalizedRotWeight = weight / jointAnim._rotWeight;
}
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
if (curBone._rotations[curKeyFrame]._time >= time) {
keyfIdx = curKeyFrame;
break;
}
}
if (keyfIdx == 0) {
quat = curBone._rotations[0]._quat;
} else if (keyfIdx != -1) {
float timeDelta = curBone._rotations[keyfIdx]._time - curBone._rotations[keyfIdx - 1]._time;
float interpVal = (time - curBone._rotations[keyfIdx - 1]._time) / timeDelta;
quat = curBone._rotations[keyfIdx - 1]._quat.slerpQuat(curBone._rotations[keyfIdx]._quat, interpVal);
} else {
quat = curBone._rotations[curBone._count - 1]._quat;
}
Math::Quaternion &quatFinal = jointAnim._quat;
quat = target->_quat.inverse() * quat;
quat = quatFinal * quat;
quatFinal = quatFinal.slerpQuat(quat, normalizedRotWeight);
}
if (curBone._translations) {
int keyfIdx = -1;
Math::Vector3d vec;
// Normalize the weight so that the sum of applied weights will equal 1.
float normalizedTransWeight = weight;
if (jointAnim._rotWeight > 1.0f) {
// Note: Division by unnormalized sum of weights.
normalizedTransWeight = weight / jointAnim._transWeight;
}
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
if (curBone._translations[curKeyFrame]._time >= time) {
keyfIdx = curKeyFrame;
break;
}
}
if (keyfIdx == 0) {
vec = curBone._translations[0]._vec;
} else if (keyfIdx != -1) {
float timeDelta = curBone._translations[keyfIdx]._time - curBone._translations[keyfIdx - 1]._time;
float interpVal = (time - curBone._translations[keyfIdx - 1]._time) / timeDelta;
vec = curBone._translations[keyfIdx - 1]._vec +
(curBone._translations[keyfIdx]._vec - curBone._translations[keyfIdx - 1]._vec) * interpVal;
} else {
vec = curBone._translations[curBone._count - 1]._vec;
}
Math::Vector3d &posFinal = jointAnim._pos;
vec = vec - target->_relMatrix.getPosition();
posFinal = posFinal + vec * normalizedTransWeight;
}
}
}
void Bone::loadBinary(Common::SeekableReadStream *data) {
uint32 len = data->readUint32LE();
char *inString = new char[len];
@ -277,6 +166,121 @@ void AnimationStateEmi::update(uint time) {
}
}
void AnimationStateEmi::computeWeights() {
if (_fade <= 0.0f)
return;
for (int bone = 0; bone < _anim->_numBones; ++bone) {
Bone &curBone = _anim->_bones[bone];
Joint *target = _skel->getJointNamed(curBone._boneName);
if (!target) {
continue;
}
AnimationLayer *layer = _skel->getLayer(curBone._priority);
int jointIndex = _skel->getJointIndex(target);
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
if (curBone._rotations) {
jointAnim._rotWeight += _fade;
}
if (curBone._translations) {
jointAnim._transWeight += _fade;
}
}
}
void AnimationStateEmi::animate() {
if (_fade <= 0.0f)
return;
for (int bone = 0; bone < _anim->_numBones; ++bone) {
Bone &curBone = _anim->_bones[bone];
Joint *target = _skel->getJointNamed(curBone._boneName);
if (!target) {
continue;
}
AnimationLayer *layer = _skel->getLayer(curBone._priority);
int jointIndex = _skel->getJointIndex(target);
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
if (curBone._rotations) {
int keyfIdx = -1;
Math::Quaternion quat;
// Normalize the weight so that the sum of applied weights will equal 1.
float normalizedRotWeight = _fade;
if (jointAnim._rotWeight > 1.0f) {
// Note: Division by unnormalized sum of weights.
normalizedRotWeight = _fade / jointAnim._rotWeight;
}
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
if (curBone._rotations[curKeyFrame]._time >= _time) {
keyfIdx = curKeyFrame;
break;
}
}
if (keyfIdx == 0) {
quat = curBone._rotations[0]._quat;
}
else if (keyfIdx != -1) {
float timeDelta = curBone._rotations[keyfIdx]._time - curBone._rotations[keyfIdx - 1]._time;
float interpVal = (_time - curBone._rotations[keyfIdx - 1]._time) / timeDelta;
quat = curBone._rotations[keyfIdx - 1]._quat.slerpQuat(curBone._rotations[keyfIdx]._quat, interpVal);
}
else {
quat = curBone._rotations[curBone._count - 1]._quat;
}
Math::Quaternion &quatFinal = jointAnim._quat;
quat = target->_quat.inverse() * quat;
quat = quatFinal * quat;
quatFinal = quatFinal.slerpQuat(quat, normalizedRotWeight);
}
if (curBone._translations) {
int keyfIdx = -1;
Math::Vector3d vec;
// Normalize the weight so that the sum of applied weights will equal 1.
float normalizedTransWeight = _fade;
if (jointAnim._rotWeight > 1.0f) {
// Note: Division by unnormalized sum of weights.
normalizedTransWeight = _fade / jointAnim._transWeight;
}
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
if (curBone._translations[curKeyFrame]._time >= _time) {
keyfIdx = curKeyFrame;
break;
}
}
if (keyfIdx == 0) {
vec = curBone._translations[0]._vec;
}
else if (keyfIdx != -1) {
float timeDelta = curBone._translations[keyfIdx]._time - curBone._translations[keyfIdx - 1]._time;
float interpVal = (_time - curBone._translations[keyfIdx - 1]._time) / timeDelta;
vec = curBone._translations[keyfIdx - 1]._vec +
(curBone._translations[keyfIdx]._vec - curBone._translations[keyfIdx - 1]._vec) * interpVal;
}
else {
vec = curBone._translations[curBone._count - 1]._vec;
}
Math::Vector3d &posFinal = jointAnim._pos;
vec = vec - target->_relMatrix.getPosition();
posFinal = posFinal + vec * normalizedTransWeight;
}
}
}
void AnimationStateEmi::play() {
if (!_active) {
_time = 0.f;

View File

@ -67,8 +67,6 @@ public:
AnimationEmi(const Common::String &filename, Common::SeekableReadStream *data);
~AnimationEmi();
void computeWeights(const Skeleton *skel, float weight);
void animate(const Skeleton *skel, float delta, bool loop, float weight);
const Common::String &getFilename() const { return _fname; }
};
@ -77,9 +75,9 @@ public:
AnimationStateEmi(const Common::String &anim);
~AnimationStateEmi();
void activate();
void deactivate();
void update(uint time);
void computeWeights();
void animate();
void play();
void stop();
void setPaused(bool paused);
@ -91,6 +89,9 @@ public:
void restoreState(SaveGame *state);
private:
void activate();
void deactivate();
friend class Skeleton;
Skeleton *_skel;

View File

@ -129,12 +129,12 @@ void Skeleton::commitAnim() {
// animation layers. The sums must be pre-computed in order to be able to normalize the blend
// weights properly in the next step.
for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
(*j)->_anim->computeWeights(this, (*j)->_fade);
(*j)->computeWeights();
}
// Now make a second pass over the animations to actually accumulate animation to layers.
for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
(*j)->_anim->animate(this, (*j)->_time, (*j)->_looping, (*j)->_fade);
(*j)->animate();
}
// Blend the layers together in priority order to produce the final result. Highest priority