EMI: Implement head limits.

This commit is contained in:
Joni Vähämäki 2014-06-26 16:34:05 +03:00
parent 3adbd1fdcf
commit 23a99a9f2b
10 changed files with 69 additions and 12 deletions

View File

@ -1360,6 +1360,13 @@ void Actor::setHead(const char *joint, const Math::Vector3d &offset) {
}
}
void Actor::setHeadLimits(float yawRange, float maxPitch, float minPitch) {
if (!_costumeStack.empty()) {
EMICostume *costume = static_cast<EMICostume *>(_costumeStack.back());
costume->setHeadLimits(yawRange, maxPitch, minPitch);
}
}
void Actor::setLookAtRate(float rate) {
_costumeStack.back()->setLookAtRate(rate);
}

View File

@ -505,6 +505,7 @@ public:
float getLookAtRate() const;
void setHead(int joint1, int joint2, int joint3, float maxRoll, float maxPitch, float maxYaw);
void setHead(const char *joint, const Math::Vector3d &offset);
void setHeadLimits(float yawRange, float maxPitch, float minPitch);
void setCollisionMode(CollisionMode mode);
void setCollisionScale(float scale);

View File

@ -27,7 +27,7 @@
namespace Grim {
EMIHead::EMIHead(EMICostume *costume) {
EMIHead::EMIHead(EMICostume *costume) : _yawRange(80.0f), _minPitch(-30.0f), _maxPitch(30.0f) {
_cost = costume;
}
@ -36,6 +36,12 @@ void EMIHead::setJoint(const char *joint, const Math::Vector3d &offset) {
_offset = offset;
}
void EMIHead::setLimits(float yawRange, float maxPitch, float minPitch) {
_yawRange = yawRange;
_maxPitch = maxPitch;
_minPitch = minPitch;
}
void EMIHead::lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) {
if (!_cost->_emiSkel || !_cost->_emiSkel->_obj)
return;
@ -77,6 +83,16 @@ void EMIHead::lookAt(bool entering, const Math::Vector3d &point, float rate, con
// Convert from world-space to joint-space.
lookAtTM = worldToJoint * lookAtTM;
// Apply angle limits.
Math::Angle p, y, r;
lookAtTM.getXYZ(&y, &p, &r, Math::EO_ZXY);
y.clampDegrees(_yawRange);
p.clampDegrees(_minPitch, _maxPitch);
r.clampDegrees(30.0f);
lookAtTM.buildFromXYZ(y, p, r, Math::EO_ZXY);
lookAtQuat.fromMatrix(lookAtTM.getRotation());
}
@ -108,6 +124,9 @@ void EMIHead::saveState(SaveGame *state) const {
state->writeFloat(_headRot.y());
state->writeFloat(_headRot.z());
state->writeFloat(_headRot.w());
state->writeFloat(_yawRange);
state->writeFloat(_minPitch);
state->writeFloat(_maxPitch);
}
void EMIHead::restoreState(SaveGame *state) {
@ -118,6 +137,11 @@ void EMIHead::restoreState(SaveGame *state) {
_headRot.y() = state->readFloat();
_headRot.z() = state->readFloat();
_headRot.w() = state->readFloat();
if (state->saveMinorVersion() >= 16) {
_yawRange = state->readFloat();
_minPitch = state->readFloat();
_maxPitch = state->readFloat();
}
} else {
state->readLESint32();
state->readLESint32();

View File

@ -36,6 +36,7 @@ public:
EMIHead(EMICostume *costume);
void setJoint(const char *joint, const Math::Vector3d &offset);
void setLimits(float yawRange, float maxPitch, float minPitch);
void lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) override;
void loadJoints(ModelNode *nodes) override {}
void saveState(SaveGame *state) const override;
@ -46,6 +47,9 @@ private:
Common::String _jointName;
Math::Vector3d _offset;
Math::Quaternion _headRot;
float _yawRange;
float _maxPitch;
float _minPitch;
};
} // end of namespace Grim

View File

@ -314,4 +314,8 @@ void EMICostume::setHead(const char *joint, const Math::Vector3d &offset) {
static_cast<EMIHead *>(_head)->setJoint(joint, offset);
}
void EMICostume::setHeadLimits(float yawRange, float maxPitch, float minPitch) {
static_cast<EMIHead *>(_head)->setLimits(yawRange, maxPitch, minPitch);
}
} // end of namespace Grim

View File

@ -57,6 +57,7 @@ public:
void setWearChoreActive(bool isActive);
void setHead(const char *joint, const Math::Vector3d &offset);
void setHeadLimits(float yawRange, float maxPitch, float minPitch);
public:
EMIChore *_wearChore;
EMISkelComponent *_emiSkel;

View File

@ -843,9 +843,9 @@ void Lua_V2::GetActorPuckVector() {
void Lua_V2::SetActorHeadLimits() {
lua_Object actorObj = lua_getparam(1);
lua_Object param2Obj = lua_getparam(2);
lua_Object param3Obj = lua_getparam(3);
lua_Object param4Obj = lua_getparam(4);
lua_Object yawObj = lua_getparam(2);
lua_Object maxPitchObj = lua_getparam(3);
lua_Object minPitchObj = lua_getparam(4);
if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R'))
return;
@ -854,13 +854,11 @@ void Lua_V2::SetActorHeadLimits() {
if (!actor)
return;
if (lua_isnumber(param2Obj) && lua_isnumber(param3Obj) && lua_isnumber(param4Obj)) {
float param2 = lua_getnumber(param2Obj); // belows needs multiply by some runtime value
float param3 = lua_getnumber(param3Obj);
float param4 = lua_getnumber(param4Obj);
// FIXME: implement missing func
//actor->func(param2, param3, param4);
warning("Lua_V2::SetActorHeadLimits: implement opcode. actor: %s, params: %f, %f, %f", actor->getName().c_str(), param2, param3, param4);
if (lua_isnumber(yawObj) && lua_isnumber(minPitchObj) && lua_isnumber(maxPitchObj)) {
float yaw = lua_getnumber(yawObj);
float maxPitch = lua_getnumber(maxPitchObj);
float minPitch = lua_getnumber(minPitchObj);
actor->setHeadLimits(yaw / 2, maxPitch, -minPitch);
}
}

View File

@ -35,7 +35,7 @@ namespace Grim {
#define SAVEGAME_FOOTERTAG 'ESAV'
uint SaveGame::SAVEGAME_MAJOR_VERSION = 22;
uint SaveGame::SAVEGAME_MINOR_VERSION = 15;
uint SaveGame::SAVEGAME_MINOR_VERSION = 16;
SaveGame *SaveGame::openForLoading(const Common::String &filename) {
Common::InSaveFile *inSaveFile = g_system->getSavefileManager()->openForLoading(filename);

View File

@ -52,6 +52,16 @@ Angle &Angle::clampDegrees(float mag) {
return *this;
}
Angle &Angle::clampDegrees(float min, float max) {
_degrees = getDegrees(-180.f);
if (_degrees >= max)
setDegrees(max);
if (_degrees <= min)
setDegrees(min);
return *this;
}
void Angle::setDegrees(float degrees) {
_degrees = degrees;
}

View File

@ -60,6 +60,14 @@ public:
*/
Angle &clampDegrees(float mag);
/**
* Clamp the angle to range [-min, max]
*
* \param min The lower bound of the range, in degrees.
* \param max The upper bound of the range, in degrees.
*/
Angle &clampDegrees(float min, float max);
void setDegrees(float degrees);
void setRadians(float radians);