mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 20:15:33 +00:00
Restore ranged weapon aiming
This commit is contained in:
parent
71bafcb52b
commit
ed4863ad7d
8 changed files with 170 additions and 94 deletions
|
@ -20,7 +20,7 @@ set(GAME_HEADER
|
|||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
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
|
||||
bulletdebugdraw globalmap characterpreview camera localmap
|
||||
# occlusionquery water shadows
|
||||
|
|
|
@ -171,14 +171,16 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem()
|
|||
return mResourceSystem;
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::addControllers()
|
||||
{
|
||||
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
|
||||
}
|
||||
|
||||
osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)
|
||||
{
|
||||
osg::Vec3f ret = Animation::runAnimation(duration);
|
||||
|
||||
/*
|
||||
if (mSkelBase)
|
||||
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
|
||||
*/
|
||||
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -46,11 +46,13 @@ namespace MWRender
|
|||
virtual void showWeapon(bool show) { showWeapons(show); }
|
||||
virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); }
|
||||
|
||||
virtual void addControllers();
|
||||
|
||||
virtual osg::Vec3f runAnimation(float duration);
|
||||
|
||||
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched
|
||||
/// to indicate the facing orientation of the character.
|
||||
//virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
||||
virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "camera.hpp"
|
||||
#include "rotatecontroller.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -72,64 +73,6 @@ std::string getVampireHead(const std::string& race, bool female)
|
|||
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.
|
||||
/// @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.
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -906,6 +839,8 @@ void NpcAnimation::addControllers()
|
|||
{
|
||||
mFirstPersonNeckController = NULL;
|
||||
mHeadController = NULL;
|
||||
WeaponAnimation::deleteControllers();
|
||||
|
||||
if (mViewMode == VM_FirstPerson)
|
||||
{
|
||||
NodeMap::iterator found = mNodeMap.find("bip01 neck");
|
||||
|
@ -927,6 +862,8 @@ void NpcAnimation::addControllers()
|
|||
node->addUpdateCallback(mHeadController);
|
||||
mActiveControllers.insert(std::make_pair(node, mHeadController));
|
||||
}
|
||||
|
||||
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
57
apps/openmw/mwrender/rotatecontroller.cpp
Normal file
57
apps/openmw/mwrender/rotatecontroller.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
36
apps/openmw/mwrender/rotatecontroller.hpp
Normal file
36
apps/openmw/mwrender/rotatecontroller.hpp
Normal file
|
@ -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 <osg/MatrixTransform>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
|
@ -15,6 +17,7 @@
|
|||
#include "../mwmechanics/combat.hpp"
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "rotatecontroller.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
@ -46,6 +49,11 @@ WeaponAnimation::WeaponAnimation()
|
|||
{
|
||||
}
|
||||
|
||||
WeaponAnimation::~WeaponAnimation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
||||
{
|
||||
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||
|
@ -149,28 +157,49 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel)
|
||||
void WeaponAnimation::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)
|
||||
{
|
||||
if (mPitchFactor == 0)
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
mSpineControllers[i] = NULL;
|
||||
|
||||
std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WeaponAnimation::deleteControllers()
|
||||
{
|
||||
for (int i=0; i<2; ++i)
|
||||
mSpineControllers[i] = NULL;
|
||||
}
|
||||
|
||||
void WeaponAnimation::configureControllers(float characterPitchRadians)
|
||||
{
|
||||
if (!mSpineControllers[0])
|
||||
return;
|
||||
|
||||
float pitch = xrot * mPitchFactor;
|
||||
Ogre::Node *node;
|
||||
if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
|
||||
{
|
||||
for (int i=0; i<2; ++i)
|
||||
mSpineControllers[i]->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive?
|
||||
if (skel->hasBone("Bip01 spine2"))
|
||||
node = skel->getBone("Bip01 spine2");
|
||||
else
|
||||
node = skel->getBone("Bip01 Spine2");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
|
||||
if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif
|
||||
node = skel->getBone("Bip01 spine1");
|
||||
else
|
||||
node = skel->getBone("Bip01 Spine1");
|
||||
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
|
||||
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
|
||||
{
|
||||
|
||||
class RotateController;
|
||||
|
||||
class WeaponAnimationTime : public SceneUtil::ControllerSource
|
||||
{
|
||||
private:
|
||||
|
@ -28,7 +30,7 @@ namespace MWRender
|
|||
{
|
||||
public:
|
||||
WeaponAnimation();
|
||||
virtual ~WeaponAnimation() {}
|
||||
virtual ~WeaponAnimation();
|
||||
|
||||
/// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op.
|
||||
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.
|
||||
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:
|
||||
PartHolderPtr mAmmunition;
|
||||
|
||||
osg::ref_ptr<RotateController> mSpineControllers[2];
|
||||
|
||||
virtual osg::Group* getArrowBone() = 0;
|
||||
virtual osg::Node* getWeaponNode() = 0;
|
||||
virtual Resource::ResourceSystem* getResourceSystem() = 0;
|
||||
|
|
Loading…
Reference in a new issue