Restore ranged weapon aiming

c++11
scrawl 10 years ago
parent 71bafcb52b
commit ed4863ad7d

@ -20,7 +20,7 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER}) source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
actors objects renderingmanager animation sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap bulletdebugdraw globalmap characterpreview camera localmap
# occlusionquery water shadows # occlusionquery water shadows

@ -171,14 +171,16 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem()
return mResourceSystem; return mResourceSystem;
} }
void CreatureWeaponAnimation::addControllers()
{
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
}
osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)
{ {
osg::Vec3f ret = Animation::runAnimation(duration); osg::Vec3f ret = Animation::runAnimation(duration);
/* WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
if (mSkelBase)
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
*/
return ret; return ret;
} }

@ -46,11 +46,13 @@ namespace MWRender
virtual void showWeapon(bool show) { showWeapons(show); } virtual void showWeapon(bool show) { showWeapons(show); }
virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); }
virtual void addControllers();
virtual osg::Vec3f runAnimation(float duration); virtual osg::Vec3f runAnimation(float duration);
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// A relative factor (0-1) that decides if and how much the skeleton should be pitched
/// to indicate the facing orientation of the character. /// to indicate the facing orientation of the character.
//virtual void setPitchFactor(float factor) { mPitchFactor = factor; } virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
private: private:

@ -26,6 +26,7 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "camera.hpp" #include "camera.hpp"
#include "rotatecontroller.hpp"
namespace namespace
{ {
@ -72,64 +73,6 @@ std::string getVampireHead(const std::string& race, bool female)
namespace MWRender namespace MWRender
{ {
/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller.
/// The rotation is then applied on top of that orientation.
/// @note Must be set on a MatrixTransform.
class RotateController : public osg::NodeCallback
{
public:
RotateController(osg::Node* relativeTo)
: mEnabled(true)
, mRelativeTo(relativeTo)
{
}
void setEnabled(bool enabled)
{
mEnabled = enabled;
}
void setRotate(const osg::Quat& rotate)
{
mRotate = rotate;
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (!mEnabled)
return;
osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node);
osg::Matrix matrix = transform->getMatrix();
osg::Quat worldOrient = getWorldOrientation(node);
osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate();
matrix.setRotate(orient);
transform->setMatrix(matrix);
traverse(node,nv);
}
osg::Quat getWorldOrientation(osg::Node* node)
{
// this could be optimized later, we just need the world orientation, not the full matrix
osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo);
osg::Quat worldOrient;
if (!worldMats.empty())
{
osg::Matrixf worldMat = worldMats[0];
worldOrient = worldMat.getRotate();
}
return worldOrient;
}
protected:
bool mEnabled;
osg::Quat mRotate;
osg::ref_ptr<osg::Node> mRelativeTo;
};
/// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// Subclass RotateController to add a Z-offset for sneaking in first person mode.
/// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice.
/// @note Must be set on a MatrixTransform. /// @note Must be set on a MatrixTransform.
@ -710,17 +653,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed)
mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1)));
} }
/* WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
if (mSkelBase)
{
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
if(mViewMode != VM_FirstPerson)
{
// In third person mode we may still need pitch for ranged weapon targeting
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
}
}
*/
return ret; return ret;
} }
@ -906,6 +839,8 @@ void NpcAnimation::addControllers()
{ {
mFirstPersonNeckController = NULL; mFirstPersonNeckController = NULL;
mHeadController = NULL; mHeadController = NULL;
WeaponAnimation::deleteControllers();
if (mViewMode == VM_FirstPerson) if (mViewMode == VM_FirstPerson)
{ {
NodeMap::iterator found = mNodeMap.find("bip01 neck"); NodeMap::iterator found = mNodeMap.find("bip01 neck");
@ -927,6 +862,8 @@ void NpcAnimation::addControllers()
node->addUpdateCallback(mHeadController); node->addUpdateCallback(mHeadController);
mActiveControllers.insert(std::make_pair(node, mHeadController)); mActiveControllers.insert(std::make_pair(node, mHeadController));
} }
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
} }
} }

@ -0,0 +1,57 @@
#include "rotatecontroller.hpp"
#include <osg/MatrixTransform>
namespace MWRender
{
RotateController::RotateController(osg::Node *relativeTo)
: mEnabled(true)
, mRelativeTo(relativeTo)
{
}
void RotateController::setEnabled(bool enabled)
{
mEnabled = enabled;
}
void RotateController::setRotate(const osg::Quat &rotate)
{
mRotate = rotate;
}
void RotateController::operator()(osg::Node *node, osg::NodeVisitor *nv)
{
if (!mEnabled)
{
traverse(node, nv);
return;
}
osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node);
osg::Matrix matrix = transform->getMatrix();
osg::Quat worldOrient = getWorldOrientation(node);
osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate();
matrix.setRotate(orient);
transform->setMatrix(matrix);
traverse(node,nv);
}
osg::Quat RotateController::getWorldOrientation(osg::Node *node)
{
// this could be optimized later, we just need the world orientation, not the full matrix
osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo);
osg::Quat worldOrient;
if (!worldMats.empty())
{
osg::Matrixf worldMat = worldMats[0];
worldOrient = worldMat.getRotate();
}
return worldOrient;
}
}

@ -0,0 +1,36 @@
#ifndef OPENMW_MWRENDER_ROTATECONTROLLER_H
#define OPENMW_MWRENDER_ROTATECONTROLLER_H
#include <osg/NodeCallback>
#include <osg/Quat>
namespace MWRender
{
/// Applies a rotation in \a relativeTo's space.
/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller.
/// The rotation is then applied on top of that orientation.
/// @note Must be set on a MatrixTransform.
class RotateController : public osg::NodeCallback
{
public:
RotateController(osg::Node* relativeTo);
void setEnabled(bool enabled);
void setRotate(const osg::Quat& rotate);
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
protected:
osg::Quat getWorldOrientation(osg::Node* node);
bool mEnabled;
osg::Quat mRotate;
osg::ref_ptr<osg::Node> mRelativeTo;
};
}
#endif

@ -1,5 +1,7 @@
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
#include <osg/MatrixTransform>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
@ -15,6 +17,7 @@
#include "../mwmechanics/combat.hpp" #include "../mwmechanics/combat.hpp"
#include "animation.hpp" #include "animation.hpp"
#include "rotatecontroller.hpp"
namespace MWRender namespace MWRender
{ {
@ -46,6 +49,11 @@ WeaponAnimation::WeaponAnimation()
{ {
} }
WeaponAnimation::~WeaponAnimation()
{
}
void WeaponAnimation::attachArrow(MWWorld::Ptr actor) void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
{ {
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
@ -149,28 +157,49 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
} }
} }
/* void WeaponAnimation::addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> > &map, osg::Node* objectRoot)
{ {
if (mPitchFactor == 0) for (int i=0; i<2; ++i)
return; {
mSpineControllers[i] = NULL;
float pitch = xrot * mPitchFactor; std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
Ogre::Node *node; if (found != nodes.end())
{
osg::Node* node = found->second;
mSpineControllers[i] = new RotateController(objectRoot);
node->addUpdateCallback(mSpineControllers[i]);
map.insert(std::make_pair(node, mSpineControllers[i]));
}
}
}
// In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive? void WeaponAnimation::deleteControllers()
if (skel->hasBone("Bip01 spine2")) {
node = skel->getBone("Bip01 spine2"); for (int i=0; i<2; ++i)
else mSpineControllers[i] = NULL;
node = skel->getBone("Bip01 Spine2"); }
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif void WeaponAnimation::configureControllers(float characterPitchRadians)
node = skel->getBone("Bip01 spine1"); {
else if (!mSpineControllers[0])
node = skel->getBone("Bip01 Spine1"); return;
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
{
for (int i=0; i<2; ++i)
mSpineControllers[i]->setEnabled(false);
return;
}
float pitch = characterPitchRadians * mPitchFactor;
osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0));
for (int i=0; i<2; ++i)
{
mSpineControllers[i]->setRotate(rotate);
mSpineControllers[i]->setEnabled(true);
}
} }
*/
} }

@ -9,6 +9,8 @@
namespace MWRender namespace MWRender
{ {
class RotateController;
class WeaponAnimationTime : public SceneUtil::ControllerSource class WeaponAnimationTime : public SceneUtil::ControllerSource
{ {
private: private:
@ -28,7 +30,7 @@ namespace MWRender
{ {
public: public:
WeaponAnimation(); WeaponAnimation();
virtual ~WeaponAnimation() {} virtual ~WeaponAnimation();
/// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op.
void attachArrow(MWWorld::Ptr actor); void attachArrow(MWWorld::Ptr actor);
@ -36,9 +38,20 @@ namespace MWRender
/// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op.
void releaseArrow(MWWorld::Ptr actor); void releaseArrow(MWWorld::Ptr actor);
/// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map.
void addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> >& map, osg::Node* objectRoot);
void deleteControllers();
/// Configure controllers, should be called every animation frame.
void configureControllers(float characterPitchRadians);
protected: protected:
PartHolderPtr mAmmunition; PartHolderPtr mAmmunition;
osg::ref_ptr<RotateController> mSpineControllers[2];
virtual osg::Group* getArrowBone() = 0; virtual osg::Group* getArrowBone() = 0;
virtual osg::Node* getWeaponNode() = 0; virtual osg::Node* getWeaponNode() = 0;
virtual Resource::ResourceSystem* getResourceSystem() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0;

Loading…
Cancel
Save