mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-04 00:45:33 +00:00
Merge remote-tracking branch 'kcat/first-person'
This commit is contained in:
commit
1bc343f363
9 changed files with 263 additions and 120 deletions
|
@ -172,16 +172,19 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||||
if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
|
if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
|
||||||
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle)));
|
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Idle)));
|
||||||
else
|
else
|
||||||
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1)));
|
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim, CharState_Death1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mActors.erase(iter);
|
mActors.erase(iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
|
@ -189,10 +192,10 @@ namespace MWMechanics
|
||||||
PtrControllerMap::iterator iter = mActors.find(old);
|
PtrControllerMap::iterator iter = mActors.find(old);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
{
|
{
|
||||||
CharacterController ctrl = iter->second;
|
CharacterController *ctrl = iter->second;
|
||||||
mActors.erase(iter);
|
mActors.erase(iter);
|
||||||
|
|
||||||
ctrl.updatePtr(ptr);
|
ctrl->updatePtr(ptr);
|
||||||
mActors.insert(std::make_pair(ptr, ctrl));
|
mActors.insert(std::make_pair(ptr, ctrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +206,10 @@ namespace MWMechanics
|
||||||
while(iter != mActors.end())
|
while(iter != mActors.end())
|
||||||
{
|
{
|
||||||
if(iter->first.getCell()==cellStore)
|
if(iter->first.getCell()==cellStore)
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mActors.erase(iter++);
|
mActors.erase(iter++);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
@ -222,8 +228,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
|
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
|
||||||
{
|
{
|
||||||
if(iter->second.getState() >= CharState_Death1)
|
if(iter->second->getState() >= CharState_Death1)
|
||||||
iter->second.setState(CharState_Idle);
|
iter->second->setState(CharState_Idle);
|
||||||
|
|
||||||
updateActor(iter->first, totalDuration);
|
updateActor(iter->first, totalDuration);
|
||||||
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
||||||
|
@ -250,10 +256,10 @@ namespace MWMechanics
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter->second.getState() >= CharState_Death1)
|
if(iter->second->getState() >= CharState_Death1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
iter->second.setState(CharState_Death1);
|
iter->second->setState(CharState_Death1);
|
||||||
|
|
||||||
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
|
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
|
||||||
|
|
||||||
|
@ -270,7 +276,7 @@ namespace MWMechanics
|
||||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
{
|
{
|
||||||
Movement movement;
|
Movement movement;
|
||||||
iter->second.update(duration, movement);
|
iter->second->update(duration, movement);
|
||||||
mMovement.push_back(std::make_pair(iter->first, movement));
|
mMovement.push_back(std::make_pair(iter->first, movement));
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
|
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
|
||||||
|
@ -297,27 +303,27 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.forceStateUpdate();
|
iter->second->forceStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
|
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.playGroup(groupName, mode, number);
|
iter->second->playGroup(groupName, mode, number);
|
||||||
}
|
}
|
||||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.skipAnim();
|
iter->second->skipAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
return iter->second.isAnimPlaying(groupName);
|
return iter->second->isAnimPlaying(groupName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
class Actors
|
class Actors
|
||||||
{
|
{
|
||||||
typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
|
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||||
PtrControllerMap mActors;
|
PtrControllerMap mActors;
|
||||||
|
|
||||||
MWWorld::PtrMovementList mMovement;
|
MWWorld::PtrMovementList mMovement;
|
||||||
|
|
|
@ -45,6 +45,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL
|
||||||
|
|
||||||
Animation::Animation(const MWWorld::Ptr &ptr)
|
Animation::Animation(const MWWorld::Ptr &ptr)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
|
, mCamera(NULL)
|
||||||
, mInsert(NULL)
|
, mInsert(NULL)
|
||||||
, mSkelBase(NULL)
|
, mSkelBase(NULL)
|
||||||
, mAccumRoot(NULL)
|
, mAccumRoot(NULL)
|
||||||
|
@ -72,8 +73,9 @@ Animation::~Animation()
|
||||||
|
|
||||||
void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
|
void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
|
||||||
{
|
{
|
||||||
OgreAssert(!mInsert, "Object already has a root!");
|
OgreAssert(mAnimSources.size() == 0, "Setting object root while animation sources are set!");
|
||||||
mInsert = node->createChildSceneNode();
|
if(!mInsert)
|
||||||
|
mInsert = node->createChildSceneNode();
|
||||||
|
|
||||||
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
||||||
std::string::size_type p = mdlname.rfind('\\');
|
std::string::size_type p = mdlname.rfind('\\');
|
||||||
|
@ -89,6 +91,9 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
Misc::StringUtils::toLower(mdlname);
|
Misc::StringUtils::toLower(mdlname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSkelBase = NULL;
|
||||||
|
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||||
|
|
||||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||||
if(mObjectRoot.mSkelBase)
|
if(mObjectRoot.mSkelBase)
|
||||||
|
@ -110,7 +115,23 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
|
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
|
||||||
while(boneiter.hasMoreElements())
|
while(boneiter.hasMoreElements())
|
||||||
boneiter.getNext()->setManuallyControlled(true);
|
boneiter.getNext()->setManuallyControlled(true);
|
||||||
|
|
||||||
|
// Reattach any objects that have been attached to this one
|
||||||
|
ObjectAttachMap::iterator iter = mAttachedObjects.begin();
|
||||||
|
while(iter != mAttachedObjects.end())
|
||||||
|
{
|
||||||
|
if(!skelinst->hasBone(iter->second))
|
||||||
|
mAttachedObjects.erase(iter++);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSkelBase->attachObjectToBone(iter->second, iter->first);
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mAttachedObjects.clear();
|
||||||
|
|
||||||
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++)
|
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++)
|
||||||
{
|
{
|
||||||
if(mObjectRoot.mControllers[i].getSource().isNull())
|
if(mObjectRoot.mControllers[i].getSource().isNull())
|
||||||
|
@ -736,4 +757,24 @@ bool Animation::isPriorityActive(int priority) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ogre::TagPoint *Animation::attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj)
|
||||||
|
{
|
||||||
|
Ogre::TagPoint *tag = NULL;
|
||||||
|
Ogre::SkeletonInstance *skel = (mSkelBase ? mSkelBase->getSkeleton() : NULL);
|
||||||
|
if(skel && skel->hasBone(bonename))
|
||||||
|
{
|
||||||
|
tag = mSkelBase->attachObjectToBone(bonename, obj);
|
||||||
|
mAttachedObjects[obj] = bonename;
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||||
|
{
|
||||||
|
ObjectAttachMap::iterator iter = mAttachedObjects.find(obj);
|
||||||
|
if(iter != mAttachedObjects.end())
|
||||||
|
mAttachedObjects.erase(iter);
|
||||||
|
mSkelBase->detachObjectFromBone(obj);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
class Camera;
|
||||||
|
|
||||||
class Animation
|
class Animation
|
||||||
{
|
{
|
||||||
|
@ -79,7 +80,10 @@ protected:
|
||||||
};
|
};
|
||||||
typedef std::map<std::string,AnimState> AnimStateMap;
|
typedef std::map<std::string,AnimState> AnimStateMap;
|
||||||
|
|
||||||
|
typedef std::map<Ogre::MovableObject*,std::string> ObjectAttachMap;
|
||||||
|
|
||||||
MWWorld::Ptr mPtr;
|
MWWorld::Ptr mPtr;
|
||||||
|
Camera *mCamera;
|
||||||
|
|
||||||
Ogre::SceneNode *mInsert;
|
Ogre::SceneNode *mInsert;
|
||||||
Ogre::Entity *mSkelBase;
|
Ogre::Entity *mSkelBase;
|
||||||
|
@ -94,6 +98,8 @@ protected:
|
||||||
|
|
||||||
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
||||||
|
|
||||||
|
ObjectAttachMap mAttachedObjects;
|
||||||
|
|
||||||
float mAnimVelocity;
|
float mAnimVelocity;
|
||||||
float mAnimSpeedMult;
|
float mAnimSpeedMult;
|
||||||
|
|
||||||
|
@ -131,7 +137,18 @@ protected:
|
||||||
|
|
||||||
bool handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
|
bool handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
|
||||||
|
|
||||||
|
/* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle
|
||||||
|
* systems in the model are ignored (useful for NPCs, where only the skeleton is needed for
|
||||||
|
* the root).
|
||||||
|
*
|
||||||
|
* Note that you must make sure all animation sources are cleared before reseting the object
|
||||||
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||||
|
*/
|
||||||
void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
|
void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
|
||||||
|
|
||||||
|
/* Adds the keyframe controllers in the specified model as a new animation source. Note that
|
||||||
|
* the filename portion of the provided model name will be prepended with 'x', and the .nif
|
||||||
|
* extension will be replaced with .kf. */
|
||||||
void addAnimSource(const std::string &model);
|
void addAnimSource(const std::string &model);
|
||||||
|
|
||||||
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
||||||
|
@ -199,7 +216,16 @@ public:
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
|
|
||||||
|
void setCamera(Camera *cam)
|
||||||
|
{ mCamera = cam; }
|
||||||
|
|
||||||
Ogre::Node *getNode(const std::string &name);
|
Ogre::Node *getNode(const std::string &name);
|
||||||
|
|
||||||
|
// Attaches the given object to a bone on this object's base skeleton. If the bone doesn't
|
||||||
|
// exist, the object isn't attached and NULL is returned. The returned TagPoint is only
|
||||||
|
// valid until the next setObjectRoot call.
|
||||||
|
Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj);
|
||||||
|
void detachObjectFromBone(Ogre::MovableObject *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreTagPoint.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -57,10 +58,10 @@ namespace MWRender
|
||||||
|
|
||||||
Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
|
Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
|
||||||
if (!mVanity.enabled && !mPreviewMode) {
|
if (!mVanity.enabled && !mPreviewMode) {
|
||||||
mCameraNode->setOrientation(xr);
|
mCamera->getParentNode()->setOrientation(xr);
|
||||||
} else {
|
} else {
|
||||||
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||||
mCameraNode->setOrientation(zr * xr);
|
mCamera->getParentNode()->setOrientation(zr * xr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,14 +113,12 @@ namespace MWRender
|
||||||
void Camera::toggleViewMode()
|
void Camera::toggleViewMode()
|
||||||
{
|
{
|
||||||
mFirstPersonView = !mFirstPersonView;
|
mFirstPersonView = !mFirstPersonView;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
if (mFirstPersonView) {
|
if (mFirstPersonView) {
|
||||||
mCamera->setPosition(0.f, 0.f, 0.f);
|
mCamera->setPosition(0.f, 0.f, 0.f);
|
||||||
setLowHeight(false);
|
|
||||||
} else {
|
} else {
|
||||||
mCamera->setPosition(0.f, 0.f, mCameraDistance);
|
mCamera->setPosition(0.f, 0.f, mCameraDistance);
|
||||||
setLowHeight(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,21 +138,16 @@ namespace MWRender
|
||||||
return true;
|
return true;
|
||||||
mVanity.enabled = enable;
|
mVanity.enabled = enable;
|
||||||
|
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
|
||||||
float offset = mPreviewCam.offset;
|
float offset = mPreviewCam.offset;
|
||||||
Ogre::Vector3 rot(0.f, 0.f, 0.f);
|
Ogre::Vector3 rot(0.f, 0.f, 0.f);
|
||||||
if (mVanity.enabled) {
|
if (mVanity.enabled) {
|
||||||
rot.x = Ogre::Degree(-30.f).valueRadians();
|
rot.x = Ogre::Degree(-30.f).valueRadians();
|
||||||
mMainCam.offset = mCamera->getPosition().z;
|
mMainCam.offset = mCamera->getPosition().z;
|
||||||
|
|
||||||
setLowHeight(true);
|
|
||||||
} else {
|
} else {
|
||||||
rot.x = getPitch();
|
rot.x = getPitch();
|
||||||
offset = mMainCam.offset;
|
offset = mMainCam.offset;
|
||||||
|
|
||||||
setLowHeight(!mFirstPersonView);
|
|
||||||
}
|
}
|
||||||
rot.z = getYaw();
|
rot.z = getYaw();
|
||||||
|
|
||||||
|
@ -169,20 +163,15 @@ namespace MWRender
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mPreviewMode = enable;
|
mPreviewMode = enable;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
|
||||||
float offset = mCamera->getPosition().z;
|
float offset = mCamera->getPosition().z;
|
||||||
if (mPreviewMode) {
|
if (mPreviewMode) {
|
||||||
mMainCam.offset = offset;
|
mMainCam.offset = offset;
|
||||||
offset = mPreviewCam.offset;
|
offset = mPreviewCam.offset;
|
||||||
|
|
||||||
setLowHeight(true);
|
|
||||||
} else {
|
} else {
|
||||||
mPreviewCam.offset = offset;
|
mPreviewCam.offset = offset;
|
||||||
offset = mMainCam.offset;
|
offset = mMainCam.offset;
|
||||||
|
|
||||||
setLowHeight(!mFirstPersonView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCamera->setPosition(0.f, 0.f, offset);
|
mCamera->setPosition(0.f, 0.f, offset);
|
||||||
|
@ -283,26 +272,48 @@ namespace MWRender
|
||||||
// If we're switching to a new NpcAnimation, ensure the old one is
|
// If we're switching to a new NpcAnimation, ensure the old one is
|
||||||
// using a normal view mode
|
// using a normal view mode
|
||||||
if(mAnimation && mAnimation != anim)
|
if(mAnimation && mAnimation != anim)
|
||||||
|
{
|
||||||
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
||||||
|
mAnimation->setCamera(NULL);
|
||||||
|
mAnimation->detachObjectFromBone(mCamera);
|
||||||
|
}
|
||||||
mAnimation = anim;
|
mAnimation = anim;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
mAnimation->setCamera(this);
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
processViewChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setHeight(float height)
|
void Camera::processViewChange()
|
||||||
{
|
{
|
||||||
mHeight = height;
|
mAnimation->detachObjectFromBone(mCamera);
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight);
|
mCamera->detachFromParent();
|
||||||
|
|
||||||
|
if(isFirstPerson())
|
||||||
|
{
|
||||||
|
mAnimation->setViewMode(NpcAnimation::VM_FirstPerson);
|
||||||
|
Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera);
|
||||||
|
tag->setInheritOrientation(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
||||||
|
mCameraNode->attachObject(mCamera);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Camera::getHeight()
|
float Camera::getHeight()
|
||||||
{
|
{
|
||||||
return mHeight * mTrackingPtr.getRefData().getBaseNode()->getScale().z;
|
if(mCamera->isParentTagPoint())
|
||||||
|
{
|
||||||
|
Ogre::TagPoint *tag = static_cast<Ogre::TagPoint*>(mCamera->getParentNode());
|
||||||
|
return tag->_getFullLocalTransform().getTrans().z;
|
||||||
|
}
|
||||||
|
return mCamera->getParentNode()->getPosition().z;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
|
bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
|
||||||
{
|
{
|
||||||
mCamera->getParentSceneNode ()->needUpdate(true);
|
mCamera->getParentSceneNode()->needUpdate(true);
|
||||||
camera = mCamera->getRealPosition();
|
camera = mCamera->getRealPosition();
|
||||||
player = mTrackingPtr.getRefData().getBaseNode()->getPosition();
|
player = mTrackingPtr.getRefData().getBaseNode()->getPosition();
|
||||||
|
|
||||||
|
@ -325,15 +336,6 @@ namespace MWRender
|
||||||
mFreeLook = enable;
|
mFreeLook = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setLowHeight(bool low)
|
|
||||||
{
|
|
||||||
if (low) {
|
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight * 0.85);
|
|
||||||
} else {
|
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Camera::isVanityOrPreviewModeEnabled()
|
bool Camera::isVanityOrPreviewModeEnabled()
|
||||||
{
|
{
|
||||||
return mPreviewMode || mVanity.enabled;
|
return mPreviewMode || mVanity.enabled;
|
||||||
|
|
|
@ -46,8 +46,6 @@ namespace MWRender
|
||||||
/// Updates sound manager listener data
|
/// Updates sound manager listener data
|
||||||
void updateListener();
|
void updateListener();
|
||||||
|
|
||||||
void setLowHeight(bool low = true);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Camera(Ogre::Camera *camera);
|
Camera(Ogre::Camera *camera);
|
||||||
~Camera();
|
~Camera();
|
||||||
|
@ -80,6 +78,8 @@ namespace MWRender
|
||||||
bool isFirstPerson() const
|
bool isFirstPerson() const
|
||||||
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
||||||
|
|
||||||
|
void processViewChange();
|
||||||
|
|
||||||
void update(float duration);
|
void update(float duration);
|
||||||
|
|
||||||
/// Set camera distance for current mode. Don't work on 1st person view.
|
/// Set camera distance for current mode. Don't work on 1st person view.
|
||||||
|
@ -93,7 +93,6 @@ namespace MWRender
|
||||||
|
|
||||||
void setAnimation(NpcAnimation *anim);
|
void setAnimation(NpcAnimation *anim);
|
||||||
|
|
||||||
void setHeight(float height);
|
|
||||||
float getHeight();
|
float getHeight();
|
||||||
|
|
||||||
/// Stores player and camera world positions in passed arguments
|
/// Stores player and camera world positions in passed arguments
|
||||||
|
|
|
@ -44,9 +44,14 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
||||||
|
|
||||||
/// \todo Read the fallback values from INIImporter (Inventory:Directional*)
|
// This is a dummy light to turn off shadows without having to use a separate set of shaders
|
||||||
Ogre::Light* l = mSceneMgr->createLight();
|
Ogre::Light* l = mSceneMgr->createLight();
|
||||||
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
||||||
|
l->setDiffuseColour (Ogre::ColourValue(0,0,0));
|
||||||
|
|
||||||
|
/// \todo Read the fallback values from INIImporter (Inventory:Directional*)
|
||||||
|
l = mSceneMgr->createLight();
|
||||||
|
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
||||||
l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
|
l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
|
||||||
l->setDiffuseColour (Ogre::ColourValue(1,1,1));
|
l->setDiffuseColour (Ogre::ColourValue(1,1,1));
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -98,17 +99,22 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
Misc::StringUtils::toLower(mBodyPrefix);
|
Misc::StringUtils::toLower(mBodyPrefix);
|
||||||
|
|
||||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||||
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
setObjectRoot(node, smodel, true);
|
setObjectRoot(node, smodel, true);
|
||||||
|
|
||||||
addAnimSource(smodel);
|
if(mViewMode != VM_FirstPerson)
|
||||||
if(mBodyPrefix.find("argonian") != std::string::npos)
|
{
|
||||||
addAnimSource("meshes\\argonian_swimkna.nif");
|
addAnimSource(smodel);
|
||||||
else if(!mNpc->isMale() && !isBeast)
|
if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||||
addAnimSource("meshes\\base_anim_female.nif");
|
addAnimSource("meshes\\argonian_swimkna.nif");
|
||||||
if(mNpc->mModel.length() > 0)
|
else if(!mNpc->isMale() && !isBeast)
|
||||||
addAnimSource("meshes\\"+mNpc->mModel);
|
addAnimSource("meshes\\base_anim_female.nif");
|
||||||
if(mViewMode == VM_FirstPerson)
|
if(mNpc->mModel.length() > 0)
|
||||||
|
addAnimSource("meshes\\"+mNpc->mModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
||||||
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
||||||
|
@ -128,20 +134,28 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
assert(viewMode != VM_HeadOnly);
|
assert(viewMode != VM_HeadOnly);
|
||||||
mViewMode = viewMode;
|
mViewMode = viewMode;
|
||||||
|
|
||||||
|
clearAnimSources();
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
|
const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
|
||||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
|
||||||
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
|
||||||
|
|
||||||
clearAnimSources();
|
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||||
addAnimSource(smodel);
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
if(mBodyPrefix.find("argonian") != std::string::npos)
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
addAnimSource("meshes\\argonian_swimkna.nif");
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
else if(!mNpc->isMale() && !isBeast)
|
setObjectRoot(mInsert->getParentSceneNode(), smodel, true);
|
||||||
addAnimSource("meshes\\base_anim_female.nif");
|
|
||||||
if(mNpc->mModel.length() > 0)
|
if(mViewMode != VM_FirstPerson)
|
||||||
addAnimSource("meshes\\"+mNpc->mModel);
|
{
|
||||||
if(mViewMode == VM_FirstPerson)
|
addAnimSource(smodel);
|
||||||
|
if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||||
|
addAnimSource("meshes\\argonian_swimkna.nif");
|
||||||
|
else if(!mNpc->isMale() && !isBeast)
|
||||||
|
addAnimSource("meshes\\base_anim_female.nif");
|
||||||
|
if(mNpc->mModel.length() > 0)
|
||||||
|
addAnimSource("meshes\\"+mNpc->mModel);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
||||||
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
||||||
|
@ -197,19 +211,11 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
if(!forceupdate)
|
if(!forceupdate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* FIXME: Remove this once we figure out how to show what in first-person */
|
|
||||||
if(mViewMode == VM_FirstPerson)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < slotlistsize;i++)
|
|
||||||
this->*slotlist[i].mPart = inv.getSlot(slotlist[i].mSlot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot);
|
MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot);
|
||||||
|
|
||||||
this->*slotlist[i].mPart = iter;
|
this->*slotlist[i].mPart = store;
|
||||||
removePartGroup(slotlist[i].mSlot);
|
removePartGroup(slotlist[i].mSlot);
|
||||||
|
|
||||||
if(this->*slotlist[i].mPart == inv.end())
|
if(this->*slotlist[i].mPart == inv.end())
|
||||||
|
@ -219,7 +225,6 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
removeIndividualPart(ESM::PRT_Hair);
|
removeIndividualPart(ESM::PRT_Hair);
|
||||||
|
|
||||||
int prio = 1;
|
int prio = 1;
|
||||||
MWWorld::ContainerStoreIterator &store = this->*slotlist[i].mPart;
|
|
||||||
if(store->getTypeName() == typeid(ESM::Clothing).name())
|
if(store->getTypeName() == typeid(ESM::Clothing).name())
|
||||||
{
|
{
|
||||||
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
|
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
|
||||||
|
@ -279,32 +284,34 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
||||||
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
||||||
{
|
{
|
||||||
static std::map<int, int> bodypartMap;
|
typedef std::multimap<ESM::BodyPart::MeshPart,ESM::PartReferenceType> BodyPartMapType;
|
||||||
if(bodypartMap.size() == 0)
|
static BodyPartMapType sBodyPartMap;
|
||||||
|
if(sBodyPartMap.size() == 0)
|
||||||
{
|
{
|
||||||
bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck));
|
||||||
bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass));
|
||||||
bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin));
|
||||||
bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand));
|
||||||
bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand));
|
||||||
bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist));
|
||||||
bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist));
|
||||||
bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm));
|
||||||
bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm));
|
||||||
bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm));
|
||||||
bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm));
|
||||||
bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot));
|
||||||
bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot));
|
||||||
bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle));
|
||||||
bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle));
|
||||||
bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee));
|
||||||
bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee));
|
||||||
bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg));
|
||||||
bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg));
|
||||||
bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail));
|
||||||
}
|
}
|
||||||
|
|
||||||
sRaceMapping[thisCombination].resize(ESM::PRT_Count, NULL);
|
std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||||
|
parts.resize(ESM::PRT_Count, NULL);
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
||||||
|
@ -325,29 +332,55 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
||||||
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
||||||
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
||||||
if (firstPerson != (mViewMode == VM_FirstPerson))
|
if(firstPerson != (mViewMode == VM_FirstPerson))
|
||||||
|
{
|
||||||
|
if(mViewMode == VM_FirstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
{
|
||||||
|
/* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */
|
||||||
|
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||||
|
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||||
|
{
|
||||||
|
if(!parts[bIt->second])
|
||||||
|
parts[bIt->second] = &*it;
|
||||||
|
bIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
for (std::map<int, int>::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt )
|
}
|
||||||
if (bIt->second == bodypart.mData.mPart)
|
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||||
sRaceMapping[thisCombination][bIt->first] = &*it;
|
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||||
|
{
|
||||||
|
parts[bIt->second] = &*it;
|
||||||
|
bIt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
const std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||||
|
for(int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
||||||
{
|
{
|
||||||
const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part];
|
if(mPartPriorities[part] < 1)
|
||||||
if (mPartPriorities[part] < 1 && bodypart)
|
{
|
||||||
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
const ESM::BodyPart* bodypart = parts[part];
|
||||||
|
if(bodypart)
|
||||||
|
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
||||||
{
|
{
|
||||||
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||||
setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha);
|
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
|
||||||
|
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||||
objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
{
|
||||||
|
Ogre::Entity *ent = objects.mEntities[i];
|
||||||
|
ent->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
||||||
|
}
|
||||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
for(size_t i = 0;i < objects.mParticles.size();i++)
|
||||||
objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
||||||
|
|
||||||
|
@ -382,6 +415,13 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
||||||
|
|
||||||
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
||||||
|
if(mViewMode == VM_FirstPerson && mCamera)
|
||||||
|
{
|
||||||
|
float pitch = mCamera->getPitch();
|
||||||
|
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
|
||||||
|
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
|
||||||
|
}
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < sPartListSize;i++)
|
||||||
{
|
{
|
||||||
Ogre::Entity *ent = mObjectParts[i].mSkelBase;
|
Ogre::Entity *ent = mObjectParts[i].mSkelBase;
|
||||||
|
@ -458,9 +498,31 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||||
{
|
{
|
||||||
const ESM::BodyPart *bodypart = 0;
|
const ESM::BodyPart *bodypart = 0;
|
||||||
if(!mNpc->isMale() && !part->mFemale.empty())
|
if(!mNpc->isMale() && !part->mFemale.empty())
|
||||||
|
{
|
||||||
bodypart = partStore.search(part->mFemale+ext);
|
bodypart = partStore.search(part->mFemale+ext);
|
||||||
|
if(!bodypart && mViewMode == VM_FirstPerson)
|
||||||
|
{
|
||||||
|
bodypart = partStore.search(part->mFemale);
|
||||||
|
if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
bodypart = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!bodypart && !part->mMale.empty())
|
if(!bodypart && !part->mMale.empty())
|
||||||
|
{
|
||||||
bodypart = partStore.search(part->mMale+ext);
|
bodypart = partStore.search(part->mMale+ext);
|
||||||
|
if(!bodypart && mViewMode == VM_FirstPerson)
|
||||||
|
{
|
||||||
|
bodypart = partStore.search(part->mMale);
|
||||||
|
if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
bodypart = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(bodypart)
|
if(bodypart)
|
||||||
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||||
|
@ -472,8 +534,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||||
void NpcAnimation::showWeapons(bool showWeapon)
|
void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
{
|
{
|
||||||
mShowWeapons = showWeapon;
|
mShowWeapons = showWeapon;
|
||||||
if(showWeapon &&
|
if(showWeapon)
|
||||||
mViewMode != VM_FirstPerson/* FIXME: Remove this once first-person bodies work */)
|
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
|
|
@ -59,6 +59,9 @@ enum VisibilityFlags
|
||||||
// overlays, we only want these on the main render target
|
// overlays, we only want these on the main render target
|
||||||
RV_Overlay = 1024,
|
RV_Overlay = 1024,
|
||||||
|
|
||||||
|
// First person meshes do not cast shadows
|
||||||
|
RV_FirstPerson = 2048,
|
||||||
|
|
||||||
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water
|
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue