GRIM: Apply animations in priority order.
This commit is contained in:
parent
d1d0dfe909
commit
6a40b43f16
9 changed files with 215 additions and 118 deletions
|
@ -1205,6 +1205,11 @@ void Actor::update() {
|
||||||
c->update();
|
c->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
|
||||||
|
Costume *c = *i;
|
||||||
|
c->animate();
|
||||||
|
}
|
||||||
|
|
||||||
for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
|
for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
|
||||||
Costume *c = *i;
|
Costume *c = *i;
|
||||||
c->moveHead(_lookingMode, _lookAtVector, _lookAtRate);
|
c->moveHead(_lookingMode, _lookAtVector, _lookAtRate);
|
||||||
|
|
|
@ -132,16 +132,24 @@ public:
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AnimationState {
|
||||||
|
KeyframeAnimPtr _keyf;
|
||||||
|
int _time;
|
||||||
|
float _fade;
|
||||||
|
};
|
||||||
|
|
||||||
class ModelComponent : public Costume::Component {
|
class ModelComponent : public Costume::Component {
|
||||||
public:
|
public:
|
||||||
ModelComponent(Costume::Component *parent, int parentID, const char *filename, Costume::Component *prevComponent, tag32 tag);
|
ModelComponent(Costume::Component *parent, int parentID, const char *filename, Costume::Component *prevComponent, tag32 tag);
|
||||||
void init();
|
void init();
|
||||||
void setKey(int val);
|
void setKey(int val);
|
||||||
void update();
|
void animate();
|
||||||
void reset();
|
void reset();
|
||||||
void resetColormap();
|
void resetColormap();
|
||||||
void setMatrix(Graphics::Matrix4 matrix) { _matrix = matrix; };
|
void setMatrix(Graphics::Matrix4 matrix) { _matrix = matrix; };
|
||||||
void restoreState(SaveGame *state);
|
void restoreState(SaveGame *state);
|
||||||
|
void addActiveAnimation(AnimationState *anim, int priority1, int priority2);
|
||||||
|
void removeActiveAnimation(AnimationState *anim);
|
||||||
~ModelComponent();
|
~ModelComponent();
|
||||||
|
|
||||||
Model::HierNode *getHierarchy() { return _hier; }
|
Model::HierNode *getHierarchy() { return _hier; }
|
||||||
|
@ -150,10 +158,17 @@ public:
|
||||||
void draw();
|
void draw();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
struct AnimationEntry {
|
||||||
|
AnimationState *anim;
|
||||||
|
int priority;
|
||||||
|
bool tagged;
|
||||||
|
};
|
||||||
|
|
||||||
Common::String _filename;
|
Common::String _filename;
|
||||||
ObjectPtr<Model> _obj;
|
ObjectPtr<Model> _obj;
|
||||||
Model::HierNode *_hier;
|
Model::HierNode *_hier;
|
||||||
Graphics::Matrix4 _matrix;
|
Graphics::Matrix4 _matrix;
|
||||||
|
Common::List<AnimationEntry> *_activeAnims;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MainModelComponent : public ModelComponent {
|
class MainModelComponent : public ModelComponent {
|
||||||
|
@ -307,7 +322,7 @@ void SpriteComponent::restoreState(SaveGame *state) {
|
||||||
|
|
||||||
ModelComponent::ModelComponent(Costume::Component *p, int parentID, const char *filename, Costume::Component *prevComponent, tag32 t) :
|
ModelComponent::ModelComponent(Costume::Component *p, int parentID, const char *filename, Costume::Component *prevComponent, tag32 t) :
|
||||||
Costume::Component(p, parentID, t), _filename(filename),
|
Costume::Component(p, parentID, t), _filename(filename),
|
||||||
_obj(NULL), _hier(NULL) {
|
_obj(NULL), _hier(NULL), _activeAnims(NULL) {
|
||||||
const char *comma = strchr(filename, ',');
|
const char *comma = strchr(filename, ',');
|
||||||
|
|
||||||
// Can be called with a comma and a numeric parameter afterward, but
|
// Can be called with a comma and a numeric parameter afterward, but
|
||||||
|
@ -356,6 +371,10 @@ void ModelComponent::init() {
|
||||||
setKey(0);
|
setKey(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_activeAnims) {
|
||||||
|
_activeAnims = new Common::List<AnimationEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
// If we're the child of a mesh component, put our nodes in the
|
// If we're the child of a mesh component, put our nodes in the
|
||||||
// parent object's tree.
|
// parent object's tree.
|
||||||
if (_parent) {
|
if (_parent) {
|
||||||
|
@ -383,16 +402,103 @@ void ModelComponent::reset() {
|
||||||
_hier->_hierVisible = _visible;
|
_hier->_hierVisible = _visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the hierarchy nodes for any keyframe animations (which
|
void ModelComponent::addActiveAnimation(AnimationState *anim, int priority1, int priority2)
|
||||||
// are children of this component and therefore get updated later).
|
{
|
||||||
void ModelComponent::update() {
|
// Keep the list of animations sorted by priorities in descending order. Because
|
||||||
for (int i = 0; i < _obj->getNumNodes(); i++) {
|
// the animations have two different priorities, we add the animation to the list
|
||||||
_hier[i]._priority = -1;
|
// with both priorities.
|
||||||
|
Common::List<AnimationEntry>::iterator i;
|
||||||
|
AnimationEntry entry;
|
||||||
|
entry.anim = anim;
|
||||||
|
entry.priority = priority1;
|
||||||
|
entry.tagged = false;
|
||||||
|
for (i = _activeAnims->begin(); i != _activeAnims->end(); ++i) {
|
||||||
|
if (i->priority < entry.priority) {
|
||||||
|
_activeAnims->insert(i, entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == _activeAnims->end())
|
||||||
|
_activeAnims->push_back(entry);
|
||||||
|
|
||||||
|
entry.priority = priority2;
|
||||||
|
entry.tagged = true;
|
||||||
|
for (i = _activeAnims->begin(); i != _activeAnims->end(); ++i) {
|
||||||
|
if (i->priority < entry.priority) {
|
||||||
|
_activeAnims->insert(i, entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == _activeAnims->end())
|
||||||
|
_activeAnims->push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelComponent::removeActiveAnimation(AnimationState *anim)
|
||||||
|
{
|
||||||
|
Common::List<AnimationEntry>::iterator i;
|
||||||
|
for (i = _activeAnims->begin(); i != _activeAnims->end(); ++i) {
|
||||||
|
if (i->anim == anim)
|
||||||
|
i = _activeAnims->erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelComponent::animate() {
|
||||||
|
// First reset the current animation.
|
||||||
|
for (int i = 0; i < getNumNodes(); i++) {
|
||||||
_hier[i]._animPos.set(0,0,0);
|
_hier[i]._animPos.set(0,0,0);
|
||||||
_hier[i]._animPitch = 0;
|
_hier[i]._animPitch = 0;
|
||||||
_hier[i]._animYaw = 0;
|
_hier[i]._animYaw = 0;
|
||||||
_hier[i]._animRoll = 0;
|
_hier[i]._animRoll = 0;
|
||||||
_hier[i]._totalWeight = 0;
|
}
|
||||||
|
|
||||||
|
// Apply animation to each hierarchy node separately.
|
||||||
|
for (int i = 0; i < getNumNodes(); i++) {
|
||||||
|
Graphics::Vector3d tempPos;
|
||||||
|
float tempYaw = 0.0f, tempPitch = 0.0f, tempRoll = 0.0f;
|
||||||
|
float totalWeight = 0.0f;
|
||||||
|
float remainingWeight = 1.0f;
|
||||||
|
int currPriority = -1;
|
||||||
|
|
||||||
|
// The animations are layered so that animations with a higher priority
|
||||||
|
// are played regardless of the blend weights of lower priority animations.
|
||||||
|
// The highest priority layer gets as much weight as it wants, while the
|
||||||
|
// next layer gets the remaining amount and so on.
|
||||||
|
for (Common::List<AnimationEntry>::iterator j = _activeAnims->begin(); j != _activeAnims->end(); ++j) {
|
||||||
|
if (currPriority != j->priority) {
|
||||||
|
currPriority = j->priority;
|
||||||
|
remainingWeight *= 1 - totalWeight;
|
||||||
|
if (remainingWeight <= 0.0f)
|
||||||
|
break;
|
||||||
|
|
||||||
|
float weightFactor = 1.0f;
|
||||||
|
if (totalWeight > 1.0f) {
|
||||||
|
weightFactor = 1.0f / totalWeight;
|
||||||
|
}
|
||||||
|
tempPos += _hier[i]._animPos * weightFactor;
|
||||||
|
tempYaw += _hier[i]._animYaw * weightFactor;
|
||||||
|
tempPitch += _hier[i]._animPitch * weightFactor;
|
||||||
|
tempRoll += _hier[i]._animRoll * weightFactor;
|
||||||
|
_hier[i]._animPos.set(0,0,0);
|
||||||
|
_hier[i]._animYaw = 0.0f;
|
||||||
|
_hier[i]._animPitch = 0.0f;
|
||||||
|
_hier[i]._animRoll = 0.0f;
|
||||||
|
totalWeight = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float time = j->anim->_time / 1000.0f;
|
||||||
|
float weight = j->anim->_fade * remainingWeight;
|
||||||
|
j->anim->_keyf->animate(_hier, i, time, weight, j->tagged);
|
||||||
|
totalWeight += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
float weightFactor = 1.0f;
|
||||||
|
if (totalWeight > 1.0f) {
|
||||||
|
weightFactor = 1.0f / totalWeight;
|
||||||
|
}
|
||||||
|
_hier[i]._animPos = _hier[i]._animPos * weightFactor + tempPos;
|
||||||
|
_hier[i]._animYaw = _hier[i]._animYaw * weightFactor + tempYaw;
|
||||||
|
_hier[i]._animPitch = _hier[i]._animPitch * weightFactor + tempPitch;
|
||||||
|
_hier[i]._animRoll = _hier[i]._animRoll * weightFactor + tempRoll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,15 +529,11 @@ void translateObject(Model::HierNode *node, bool reset) {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
g_driver->translateViewpointFinish();
|
g_driver->translateViewpointFinish();
|
||||||
} else {
|
} else {
|
||||||
if (node->_totalWeight > 0) {
|
Graphics::Vector3d animPos = node->_pos + node->_animPos;
|
||||||
Graphics::Vector3d animPos = node->_pos + node->_animPos / node->_totalWeight;
|
float animPitch = node->_pitch + node->_animPitch;
|
||||||
float animPitch = node->_pitch + node->_animPitch / node->_totalWeight;
|
float animYaw = node->_yaw + node->_animYaw;
|
||||||
float animYaw = node->_yaw + node->_animYaw / node->_totalWeight;
|
float animRoll = node->_roll + node->_animRoll;
|
||||||
float animRoll = node->_roll + node->_animRoll / node->_totalWeight;
|
g_driver->translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
||||||
g_driver->translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
|
||||||
} else {
|
|
||||||
g_driver->translateViewpointStart(node->_pos, node->_pitch, node->_yaw, node->_roll);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,6 +561,7 @@ MainModelComponent::MainModelComponent(Costume::Component *p, int parentID, cons
|
||||||
MainModelComponent *mmc = dynamic_cast<MainModelComponent *>(prevComponent);
|
MainModelComponent *mmc = dynamic_cast<MainModelComponent *>(prevComponent);
|
||||||
|
|
||||||
if (mmc && mmc->_filename == filename) {
|
if (mmc && mmc->_filename == filename) {
|
||||||
|
_activeAnims = mmc->_activeAnims;
|
||||||
_obj = mmc->_obj;
|
_obj = mmc->_obj;
|
||||||
_hier = mmc->_hier;
|
_hier = mmc->_hier;
|
||||||
_hierShared = true;
|
_hierShared = true;
|
||||||
|
@ -536,16 +639,17 @@ public:
|
||||||
void reset();
|
void reset();
|
||||||
void saveState(SaveGame *state);
|
void saveState(SaveGame *state);
|
||||||
void restoreState(SaveGame *state);
|
void restoreState(SaveGame *state);
|
||||||
|
void activate();
|
||||||
|
void deactivate();
|
||||||
~KeyframeComponent() {}
|
~KeyframeComponent() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KeyframeAnimPtr _keyf;
|
AnimationState _anim;
|
||||||
int _priority1, _priority2;
|
int _priority1, _priority2;
|
||||||
Model::HierNode *_hier;
|
Model::HierNode *_hier;
|
||||||
int _numNodes;
|
int _numNodes;
|
||||||
bool _active;
|
bool _active;
|
||||||
int _repeatMode;
|
int _repeatMode;
|
||||||
int _currTime;
|
|
||||||
Common::String _fname;
|
Common::String _fname;
|
||||||
|
|
||||||
friend class Costume;
|
friend class Costume;
|
||||||
|
@ -557,10 +661,10 @@ KeyframeComponent::KeyframeComponent(Costume::Component *p, int parentID, const
|
||||||
const char *comma = strchr(filename, ',');
|
const char *comma = strchr(filename, ',');
|
||||||
if (comma) {
|
if (comma) {
|
||||||
Common::String realName(filename, comma);
|
Common::String realName(filename, comma);
|
||||||
_keyf = g_resourceloader->getKeyframe(realName);
|
_anim._keyf = g_resourceloader->getKeyframe(realName.c_str());
|
||||||
sscanf(comma + 1, "%d,%d", &_priority1, &_priority2);
|
sscanf(comma + 1, "%d,%d", &_priority1, &_priority2);
|
||||||
} else
|
} else
|
||||||
_keyf = g_resourceloader->getKeyframe(filename);
|
_anim._keyf = g_resourceloader->getKeyframe(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeComponent::setKey(int val) {
|
void KeyframeComponent::setKey(int val) {
|
||||||
|
@ -570,58 +674,70 @@ void KeyframeComponent::setKey(int val) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
if (!_active || val != 1) {
|
if (!_active || val != 1) {
|
||||||
_active = true;
|
if (!_active) {
|
||||||
_currTime = -1;
|
activate();
|
||||||
|
_active = true;
|
||||||
|
}
|
||||||
|
_anim._time = -1;
|
||||||
}
|
}
|
||||||
_repeatMode = val;
|
_repeatMode = val;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
warning("Key 5 (meaning uncertain) used for keyframe %s", _keyf->getFilename().c_str());
|
warning("Key 5 (meaning uncertain) used for keyframe %s", _anim._keyf->getFilename().c_str());
|
||||||
case 4:
|
case 4:
|
||||||
_active = false;
|
if (_active) {
|
||||||
|
deactivate();
|
||||||
|
_active = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
||||||
warning("Unknown key %d for keyframe %s", val, _keyf->getFilename().c_str());
|
warning("Unknown key %d for keyframe %s", val, _anim._keyf->getFilename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeComponent::reset() {
|
void KeyframeComponent::reset() {
|
||||||
_active = false;
|
if (_active) {
|
||||||
|
deactivate();
|
||||||
|
_active = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeComponent::update() {
|
void KeyframeComponent::update() {
|
||||||
if (!_active)
|
if (!_active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_currTime < 0) // For first time through
|
if (_anim._time < 0) // For first time through
|
||||||
_currTime = 0;
|
_anim._time = 0;
|
||||||
else
|
else
|
||||||
_currTime += g_grim->getFrameTime();
|
_anim._time += g_grim->getFrameTime();
|
||||||
|
|
||||||
int animLength = (int)(_keyf->getLength() * 1000);
|
int animLength = (int)(_anim._keyf->getLength() * 1000);
|
||||||
|
|
||||||
if (_currTime > animLength) { // What to do at end?
|
if (_anim._time > animLength) { // What to do at end?
|
||||||
switch (_repeatMode) {
|
switch (_repeatMode) {
|
||||||
case 0: // Stop
|
case 0: // Stop
|
||||||
case 3: // Fade at end
|
case 3: // Fade at end
|
||||||
_active = false;
|
if (_active) {
|
||||||
|
deactivate();
|
||||||
|
_active = false;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case 1: // Loop
|
case 1: // Loop
|
||||||
do
|
do
|
||||||
_currTime -= animLength;
|
_anim._time -= animLength;
|
||||||
while (_currTime > animLength);
|
while (_anim._time > animLength);
|
||||||
break;
|
break;
|
||||||
case 2: // Hold at end
|
case 2: // Hold at end
|
||||||
_currTime = animLength;
|
_anim._time = animLength;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
||||||
warning("Unknown repeat mode %d for keyframe %s", _repeatMode, _keyf->getFilename().c_str());
|
warning("Unknown repeat mode %d for keyframe %s", _repeatMode, _anim._keyf->getFilename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_keyf->animate(_hier, _numNodes, _currTime / 1000.0f, _priority1, _priority2, _fade);
|
_anim._fade = _fade;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeComponent::init() {
|
void KeyframeComponent::init() {
|
||||||
|
@ -631,7 +747,7 @@ void KeyframeComponent::init() {
|
||||||
_numNodes = mc->getNumNodes();
|
_numNodes = mc->getNumNodes();
|
||||||
} else {
|
} else {
|
||||||
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
if (gDebugLevel == DEBUG_MODEL || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
||||||
warning("Parent of %s was not a model", _keyf->getFilename().c_str());
|
warning("Parent of %s was not a model", _anim._keyf->getFilename());
|
||||||
_hier = NULL;
|
_hier = NULL;
|
||||||
_numNodes = 0;
|
_numNodes = 0;
|
||||||
}
|
}
|
||||||
|
@ -640,13 +756,28 @@ void KeyframeComponent::init() {
|
||||||
void KeyframeComponent::saveState(SaveGame *state) {
|
void KeyframeComponent::saveState(SaveGame *state) {
|
||||||
state->writeLESint32(_active);
|
state->writeLESint32(_active);
|
||||||
state->writeLESint32(_repeatMode);
|
state->writeLESint32(_repeatMode);
|
||||||
state->writeLESint32(_currTime);
|
state->writeLESint32(_anim._time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeComponent::restoreState(SaveGame *state) {
|
void KeyframeComponent::restoreState(SaveGame *state) {
|
||||||
_active = state->readLESint32();
|
_active = state->readLESint32();
|
||||||
_repeatMode = state->readLESint32();
|
_repeatMode = state->readLESint32();
|
||||||
_currTime = state->readLESint32();
|
_anim._time = state->readLESint32();
|
||||||
|
|
||||||
|
if (_active)
|
||||||
|
activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeComponent::activate() {
|
||||||
|
ModelComponent *mc = dynamic_cast<ModelComponent *>(_parent);
|
||||||
|
if (mc)
|
||||||
|
mc->addActiveAnimation(&_anim, _priority1, _priority2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeComponent::deactivate() {
|
||||||
|
ModelComponent *mc = dynamic_cast<ModelComponent *>(_parent);
|
||||||
|
if (mc)
|
||||||
|
mc->removeActiveAnimation(&_anim);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshComponent::MeshComponent(Costume::Component *p, int parentID, const char *name, tag32 t) :
|
MeshComponent::MeshComponent(Costume::Component *p, int parentID, const char *name, tag32 t) :
|
||||||
|
@ -1384,16 +1515,19 @@ void Costume::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Costume::animate() {
|
||||||
|
for (int i = 0; i < _numComponents; i++) {
|
||||||
|
if (_components[i]) {
|
||||||
|
_components[i]->animate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Costume::moveHead(bool lookingMode, const Graphics::Vector3d &lookAt, float rate) {
|
void Costume::moveHead(bool lookingMode, const Graphics::Vector3d &lookAt, float rate) {
|
||||||
if (_joint1Node) {
|
if (_joint1Node) {
|
||||||
float step = g_grim->getPerSecond(rate);
|
float step = g_grim->getPerSecond(rate);
|
||||||
float yawStep = step;
|
float yawStep = step;
|
||||||
float pitchStep = step / 3.f;
|
float pitchStep = step / 3.f;
|
||||||
|
|
||||||
_joint1Node->_totalWeight = 1;
|
|
||||||
_joint2Node->_totalWeight = 1;
|
|
||||||
_joint3Node->_totalWeight = 1;
|
|
||||||
|
|
||||||
if (!lookingMode) {
|
if (!lookingMode) {
|
||||||
//animate yaw
|
//animate yaw
|
||||||
if (_headYaw > yawStep) {
|
if (_headYaw > yawStep) {
|
||||||
|
@ -1448,9 +1582,7 @@ void Costume::moveHead(bool lookingMode, const Graphics::Vector3d &lookAt, float
|
||||||
float bodyYaw = _matrix._rot.getYaw();
|
float bodyYaw = _matrix._rot.getYaw();
|
||||||
p = _joint1Node->_parent;
|
p = _joint1Node->_parent;
|
||||||
while (p) {
|
while (p) {
|
||||||
bodyYaw += p->_yaw;
|
bodyYaw += p->_yaw + p->_animYaw;
|
||||||
if (p->_totalWeight > 0)
|
|
||||||
bodyYaw += p->_animYaw / p->_totalWeight;
|
|
||||||
p = p->_parent;
|
p = p->_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
void moveHead(bool lookingMode, const Graphics::Vector3d &lookAt, float rate);
|
void moveHead(bool lookingMode, const Graphics::Vector3d &lookAt, float rate);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
void animate();
|
||||||
void setupTextures();
|
void setupTextures();
|
||||||
void draw();
|
void draw();
|
||||||
void setPosRotate(Graphics::Vector3d pos, float pitch, float yaw, float roll);
|
void setPosRotate(Graphics::Vector3d pos, float pitch, float yaw, float roll);
|
||||||
|
@ -91,6 +92,7 @@ public:
|
||||||
virtual void setKey(int) { }
|
virtual void setKey(int) { }
|
||||||
virtual void setMapName(char *) { }
|
virtual void setMapName(char *) { }
|
||||||
virtual void update() { }
|
virtual void update() { }
|
||||||
|
virtual void animate() { }
|
||||||
virtual void setupTexture() { }
|
virtual void setupTexture() { }
|
||||||
virtual void draw() { }
|
virtual void draw() { }
|
||||||
virtual void reset() { }
|
virtual void reset() { }
|
||||||
|
|
|
@ -489,15 +489,11 @@ void GfxOpenGL::translateViewpointFinish() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxOpenGL::drawHierachyNode(const Model::HierNode *node) {
|
void GfxOpenGL::drawHierachyNode(const Model::HierNode *node) {
|
||||||
if (node->_totalWeight > 0) {
|
Graphics::Vector3d animPos = node->_pos + node->_animPos;
|
||||||
Graphics::Vector3d animPos = node->_pos + node->_animPos / node->_totalWeight;
|
float animPitch = node->_pitch + node->_animPitch;
|
||||||
float animPitch = node->_pitch + node->_animPitch / node->_totalWeight;
|
float animYaw = node->_yaw + node->_animYaw;
|
||||||
float animYaw = node->_yaw + node->_animYaw / node->_totalWeight;
|
float animRoll = node->_roll + node->_animRoll;
|
||||||
float animRoll = node->_roll + node->_animRoll / node->_totalWeight;
|
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
||||||
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
|
||||||
} else {
|
|
||||||
translateViewpointStart(node->_pos, node->_pitch, node->_yaw, node->_roll);
|
|
||||||
}
|
|
||||||
if (node->_hierVisible) {
|
if (node->_hierVisible) {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
|
glTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
|
||||||
|
|
|
@ -526,15 +526,11 @@ void GfxTinyGL::translateViewpointFinish() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxTinyGL::drawHierachyNode(const Model::HierNode *node) {
|
void GfxTinyGL::drawHierachyNode(const Model::HierNode *node) {
|
||||||
if (node->_totalWeight > 0) {
|
Graphics::Vector3d animPos = node->_pos + node->_animPos;
|
||||||
Graphics::Vector3d animPos = node->_pos + node->_animPos / node->_totalWeight;
|
float animPitch = node->_pitch + node->_animPitch;
|
||||||
float animPitch = node->_pitch + node->_animPitch / node->_totalWeight;
|
float animYaw = node->_yaw + node->_animYaw;
|
||||||
float animYaw = node->_yaw + node->_animYaw / node->_totalWeight;
|
float animRoll = node->_roll + node->_animRoll;
|
||||||
float animRoll = node->_roll + node->_animRoll / node->_totalWeight;
|
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
||||||
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
|
|
||||||
} else {
|
|
||||||
translateViewpointStart(node->_pos, node->_pitch, node->_yaw, node->_roll);
|
|
||||||
}
|
|
||||||
if (node->_hierVisible) {
|
if (node->_hierVisible) {
|
||||||
tglPushMatrix();
|
tglPushMatrix();
|
||||||
tglTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
|
tglTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
|
||||||
|
|
|
@ -149,22 +149,19 @@ KeyframeAnim::~KeyframeAnim() {
|
||||||
g_resourceloader->uncacheKeyframe(this);
|
g_resourceloader->uncacheKeyframe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeAnim::animate(Model::HierNode *nodes, int num, float time, int priority1, int priority2, float fade) const {
|
void KeyframeAnim::animate(Model::HierNode *nodes, int num, float time, float fade, bool tagged) const {
|
||||||
|
// Without this sending the bread down the tube in "mo" often crashes,
|
||||||
|
// because it goes outside the bounds of the array of the nodes.
|
||||||
|
if (num >= _numJoints)
|
||||||
|
return;
|
||||||
|
|
||||||
float frame = time * _fps;
|
float frame = time * _fps;
|
||||||
|
|
||||||
if (frame > _numFrames)
|
if (frame > _numFrames)
|
||||||
frame = _numFrames;
|
frame = _numFrames;
|
||||||
|
|
||||||
// Without this sending the bread down the tube in "mo" often crashes,
|
if (_nodes[num] && tagged == ((_type & nodes[num]._type) != 0))
|
||||||
// because it goes outside the bounds of the array of the nodes.
|
_nodes[num]->animate(nodes[num], frame, fade);
|
||||||
if (_numJoints < num) {
|
|
||||||
num = _numJoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < num; i++) {
|
|
||||||
if (_nodes[i])
|
|
||||||
_nodes[i]->animate(nodes[i], frame, ((_type & nodes[i]._type) != 0 ? priority2 : priority1), fade);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeAnim::KeyframeEntry::loadBinary(const char *&data) {
|
void KeyframeAnim::KeyframeEntry::loadBinary(const char *&data) {
|
||||||
|
@ -222,11 +219,9 @@ KeyframeAnim::KeyframeNode::~KeyframeNode() {
|
||||||
delete[] _entries;
|
delete[] _entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeAnim::KeyframeNode::animate(Model::HierNode &node, float frame, int priority, float fade) const {
|
void KeyframeAnim::KeyframeNode::animate(Model::HierNode &node, float frame, float fade) const {
|
||||||
if (_numEntries == 0)
|
if (_numEntries == 0)
|
||||||
return;
|
return;
|
||||||
if (priority < node._priority)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Do a binary search for the nearest previous frame
|
// Do a binary search for the nearest previous frame
|
||||||
// Loop invariant: entries_[low].frame_ <= frame < entries_[high].frame_
|
// Loop invariant: entries_[low].frame_ <= frame < entries_[high].frame_
|
||||||
|
@ -245,23 +240,6 @@ void KeyframeAnim::KeyframeNode::animate(Model::HierNode &node, float frame, int
|
||||||
float yaw = _entries[low]._yaw + dt * _entries[low]._dyaw;
|
float yaw = _entries[low]._yaw + dt * _entries[low]._dyaw;
|
||||||
float roll = _entries[low]._roll + dt * _entries[low]._droll;
|
float roll = _entries[low]._roll + dt * _entries[low]._droll;
|
||||||
|
|
||||||
if (priority > node._priority) {
|
|
||||||
node._priority = priority;
|
|
||||||
if (node._totalWeight > 0) {
|
|
||||||
node._animPos = node._animPos * (1 - fade) / node._totalWeight;
|
|
||||||
node._animPitch = node._animPitch * (1 - fade) / node._totalWeight;
|
|
||||||
node._animYaw = node._animYaw * (1 - fade) / node._totalWeight;
|
|
||||||
node._animRoll = node._animRoll * (1 - fade) / node._totalWeight;
|
|
||||||
node._totalWeight = 1 - fade;
|
|
||||||
} else {
|
|
||||||
node._animPos.set(0,0,0);
|
|
||||||
node._animPitch = 0;
|
|
||||||
node._animYaw = 0;
|
|
||||||
node._animRoll = 0;
|
|
||||||
node._totalWeight = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node._animPos += (pos - node._pos) * fade;
|
node._animPos += (pos - node._pos) * fade;
|
||||||
|
|
||||||
float dpitch = pitch - node._pitch;
|
float dpitch = pitch - node._pitch;
|
||||||
|
@ -284,8 +262,6 @@ void KeyframeAnim::KeyframeNode::animate(Model::HierNode &node, float frame, int
|
||||||
while (droll < -180)
|
while (droll < -180)
|
||||||
droll += 360;
|
droll += 360;
|
||||||
node._animRoll += droll * fade;
|
node._animRoll += droll * fade;
|
||||||
|
|
||||||
node._totalWeight += fade;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end of namespace Grim
|
} // end of namespace Grim
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
|
|
||||||
void loadBinary(const char *data, int len);
|
void loadBinary(const char *data, int len);
|
||||||
void loadText(TextSplitter &ts);
|
void loadText(TextSplitter &ts);
|
||||||
void animate(Model::HierNode *nodes, int num, float time, int priority1 = 1, int priority2 = 5, float fade = 1) const;
|
void animate(Model::HierNode *nodes, int num, float time, float fade, bool tagged) const;
|
||||||
|
|
||||||
float getLength() const { return _numFrames / _fps; }
|
float getLength() const { return _numFrames / _fps; }
|
||||||
const Common::String &getFilename() const { return _fname; }
|
const Common::String &getFilename() const { return _fname; }
|
||||||
|
@ -66,7 +66,7 @@ private:
|
||||||
void loadText(TextSplitter &ts);
|
void loadText(TextSplitter &ts);
|
||||||
~KeyframeNode();
|
~KeyframeNode();
|
||||||
|
|
||||||
void animate(Model::HierNode &node, float frame, int priority, float fade) const;
|
void animate(Model::HierNode &node, float frame, float fade) const;
|
||||||
|
|
||||||
char _meshName[32];
|
char _meshName[32];
|
||||||
int _numEntries;
|
int _numEntries;
|
||||||
|
|
|
@ -273,8 +273,6 @@ void Model::HierNode::loadBinary(const char *&data, Model::HierNode *hierNodes,
|
||||||
_animPitch = 0;
|
_animPitch = 0;
|
||||||
_animYaw = 0;
|
_animYaw = 0;
|
||||||
_animRoll = 0;
|
_animRoll = 0;
|
||||||
_priority = -1;
|
|
||||||
_totalWeight = 0;
|
|
||||||
_sprite = NULL;
|
_sprite = NULL;
|
||||||
|
|
||||||
data += 184;
|
data += 184;
|
||||||
|
@ -393,7 +391,6 @@ void Model::loadText(TextSplitter *ts, CMap *cmap) {
|
||||||
_rootHierNode[num]._pivot = Graphics::Vector3d(pivotx, pivoty, pivotz);
|
_rootHierNode[num]._pivot = Graphics::Vector3d(pivotx, pivoty, pivotz);
|
||||||
_rootHierNode[num]._meshVisible = true;
|
_rootHierNode[num]._meshVisible = true;
|
||||||
_rootHierNode[num]._hierVisible = true;
|
_rootHierNode[num]._hierVisible = true;
|
||||||
_rootHierNode[num]._totalWeight = 0;
|
|
||||||
_rootHierNode[num]._sprite = NULL;
|
_rootHierNode[num]._sprite = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,18 +548,13 @@ void Model::HierNode::update() {
|
||||||
if (!_initialized)
|
if (!_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_totalWeight > 0) {
|
Graphics::Vector3d animPos = _pos + _animPos;
|
||||||
Graphics::Vector3d animPos = _pos + _animPos / _totalWeight;
|
float animPitch = _pitch + _animPitch;
|
||||||
float animPitch = _pitch + _animPitch / _totalWeight;
|
float animYaw = _yaw + _animYaw;
|
||||||
float animYaw = _yaw + _animYaw / _totalWeight;
|
float animRoll = _roll + _animRoll;
|
||||||
float animRoll = _roll + _animRoll / _totalWeight;
|
|
||||||
|
|
||||||
_localMatrix._pos.set(animPos.x(), animPos.y(), animPos.z());
|
_localMatrix._pos.set(animPos.x(), animPos.y(), animPos.z());
|
||||||
_localMatrix._rot.buildFromPitchYawRoll(animPitch, animYaw, animRoll);
|
_localMatrix._rot.buildFromPitchYawRoll(animPitch, animYaw, animRoll);
|
||||||
} else {
|
|
||||||
_localMatrix._pos.set(_pos.x(), _pos.y(), _pos.z());
|
|
||||||
_localMatrix._rot.buildFromPitchYawRoll(_pitch, _yaw, _roll);
|
|
||||||
}
|
|
||||||
|
|
||||||
_matrix *= _localMatrix;
|
_matrix *= _localMatrix;
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,6 @@ public:
|
||||||
Graphics::Vector3d _animPos;
|
Graphics::Vector3d _animPos;
|
||||||
float _animPitch, _animYaw, _animRoll;
|
float _animPitch, _animYaw, _animRoll;
|
||||||
bool _meshVisible, _hierVisible;
|
bool _meshVisible, _hierVisible;
|
||||||
int _priority;
|
|
||||||
float _totalWeight;
|
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
Graphics::Matrix4 _matrix;
|
Graphics::Matrix4 _matrix;
|
||||||
Graphics::Matrix4 _localMatrix;
|
Graphics::Matrix4 _localMatrix;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue