From 6e84d4bcdde03b821c6d880bda2d26b4dfbdf207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 23:19:48 -0800 Subject: [PATCH 001/239] Add a helper method to load entity objects --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 15 +---------- apps/openmw/mwrender/npcanimation.cpp | 17 +----------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2a3b8cf43..4784771a9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,10 +19,34 @@ Animation::Animation() Animation::~Animation() { - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + if(mInsert) + { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + sceneMgr->destroyEntity(mEntityList.mEntities[i]); + } mEntityList.mEntities.clear(); + mEntityList.mSkelBase = NULL; +} + + +void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +{ + mInsert = node; + assert(mInsert); + + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } + } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 07583db78..ebbfb2a7a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -43,6 +43,8 @@ protected: bool findGroupTimes(const std::string &groupname, GroupTimes *times); + void createEntityList(Ogre::SceneNode *node, const std::string &model); + public: Animation(); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7ee361a6f..1ca897c15 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -18,7 +18,6 @@ CreatureAnimation::~CreatureAnimation() CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { - mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->mBase != NULL); @@ -26,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { std::string mesh = "meshes\\" + ref->mBase->mModel; - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); + createEntityList(ptr.getRefData().getBaseNode(), mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,18 +51,6 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } - - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - } - } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e6a8006e2..c76c67425 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -82,13 +82,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mBodyPrefix = "b_n_" + mNpc->mRace; std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); - mInsert = node; - assert(mInsert); - bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); + createEntityList(node, smodel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *base = mEntityList.mEntities[i]; @@ -116,18 +113,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - } - } - float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 818a24cdd6542513d7b3f4133856cdc338b23822 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 00:03:14 -0800 Subject: [PATCH 002/239] Hold on to the AnimationState being used for animating --- apps/openmw/mwrender/animation.cpp | 15 +++++---------- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4784771a9..6b8a3283c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,6 +14,7 @@ Animation::Animation() : mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) + , mAnimState(NULL) { } @@ -45,6 +46,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::AnimationState *state = as.getNext(); state->setEnabled(true); state->setLoop(false); + if(!mAnimState) + mAnimState = state; } } } @@ -155,16 +158,8 @@ void Animation::runAnimation(float timepassed) } } - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setTimePosition(mTime); - } - } + if(mAnimState) + mAnimState->setTimePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ebbfb2a7a..de4778d87 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,6 +40,7 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; + Ogre::AnimationState *mAnimState; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 761914bdaa3d02207afe13fbf36a3d3430fe8226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 03:31:51 -0800 Subject: [PATCH 003/239] Use a separate method to build the animation --- components/nifogre/ogre_nif_loader.cpp | 228 +++++++++++++------------ 1 file changed, 115 insertions(+), 113 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489..61e3a72e9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -162,6 +162,120 @@ static void fail(const std::string &msg) } +static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + /* HACK: Pre-create the node tracks by matching the track IDs with the + * bone IDs. Otherwise, Ogre animates the wrong bones. */ + size_t bonecount = skel->getNumBones(); + for(size_t i = 0;i < bonecount;i++) + anim->createNodeTrack(i, skel->getBone(i)); + + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *kfc = ctrls[i]; + Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); + const Ogre::Quaternion startquat = bone->getInitialOrientation(); + const Ogre::Vector3 starttrans = bone->getInitialPosition(); + const Ogre::Vector3 startscale = bone->getInitialScale(); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = startquat.Inverse() * quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue - starttrans; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + float begTime = std::max(kfc->timeStart, startTime); + float endTime = std::min(kfc->timeStop, stopTime); + bool didlast = false; + + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, begTime); + if(curtime >= endTime) + { + didlast = true; + curtime = endTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = startquat.Inverse() * quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue - starttrans; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) + kframe->setTranslate(curtrans); + else + { + Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) + kframe->setScale(curscale); + else + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) { TextKeyMap textkeys; @@ -279,119 +393,7 @@ void loadResource(Ogre::Resource *resource) return; } - Ogre::Animation *anim = skel->createAnimation(skel->getName(), maxtime); - /* HACK: Pre-create the node tracks by matching the track IDs with the - * bone IDs. Otherwise, Ogre animates the wrong bones. */ - size_t bonecount = skel->getNumBones(); - for(size_t i = 0;i < bonecount;i++) - anim->createNodeTrack(i, skel->getBone(i)); - - for(size_t i = 0;i < ctrls.size();i++) - { - Nif::NiKeyframeController *kfc = ctrls[i]; - Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - Nif::QuaternionKeyList quatkeys = kf->mRotations; - Nif::Vector3KeyList trankeys = kf->mTranslations; - Nif::FloatKeyList scalekeys = kf->mScales; - std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort()); - std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort()); - std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort()); - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - const Ogre::Quaternion startquat = bone->getInitialOrientation(); - const Ogre::Vector3 starttrans = bone->getInitialPosition(); - const Ogre::Vector3 startscale = bone->getInitialScale(); - Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = startquat.Inverse() * quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue - starttrans; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; - bool didlast = false; - - while(!didlast) - { - float curtime = kfc->timeStop; - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, kfc->timeStart); - if(curtime >= kfc->timeStop) - { - didlast = true; - curtime = kfc->timeStop; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - quatiter++; - if(quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue ; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - traniter++; - if(traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - scaleiter++; - if(scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 58d35dbfcfef078f388cdf28dc1bd339df8fb3e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 04:01:11 -0800 Subject: [PATCH 004/239] Have createEntities' caller retrieve the text keys as needed --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++-- apps/openmw/mwrender/objects.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 30 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 4 ++-- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6b8a3283c..d2d253b91 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,6 +1,6 @@ #include "animation.hpp" -#include +#include #include #include #include @@ -36,7 +36,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); @@ -49,6 +49,21 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!mAnimState) mAnimState = state; } + + // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); + while(iter.hasMoreElements()) + { + Ogre::Bone *bone = iter.getNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty()) + { + mTextKeys = Ogre::any_cast(data); + break; + } + } } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 36f09e6d9..ae188c11e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -94,7 +94,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 61e3a72e9..f579b4b93 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -329,7 +329,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny("TextKeyExtraData", Ogre::Any(extractTextKeys(tk))); + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); } e = e->extra; } @@ -1083,7 +1083,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textkeys, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) { EntityList entitylist; @@ -1091,7 +1091,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke if(meshes.size() == 0) return entitylist; - Ogre::SceneManager *sceneMgr = parent->getCreator(); + Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); @@ -1100,34 +1100,16 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke entitylist.mSkelBase = entity; } - if(entitylist.mSkelBase && textkeys) - { - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(entitylist.mSkelBase->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) - { - Ogre::Bone *bone = iter.getNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny("TextKeyExtraData"); - if(!data.isEmpty()) - { - *textkeys = Ogre::any_cast(data); - break; - } - } - } - if(entitylist.mSkelBase) { - parent->attachObject(entitylist.mSkelBase); + parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parent->attachObject(entity); + parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); @@ -1136,7 +1118,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke else { for(size_t i = 0;i < entitylist.mEntities.size();i++) - parent->attachObject(entitylist.mEntities[i]); + parentNode->attachObject(entitylist.mEntities[i]); } return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 3e05c5873..9dcd0bea6 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -43,6 +43,7 @@ namespace NifOgre // FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; +static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; @@ -77,8 +78,7 @@ public: const std::string &name, const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parent, - TextKeyMap *textkeys, + static EntityList createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group="General"); }; From e5ce55b6a4b4a88d75203c5c73b832310b0757aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 06:20:21 -0800 Subject: [PATCH 005/239] Remove a hack --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f579b4b93..870b8df0e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -165,11 +165,6 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { Ogre::Animation *anim = skel->createAnimation(name, stopTime); - /* HACK: Pre-create the node tracks by matching the track IDs with the - * bone IDs. Otherwise, Ogre animates the wrong bones. */ - size_t bonecount = skel->getNumBones(); - for(size_t i = 0;i < bonecount;i++) - anim->createNodeTrack(i, skel->getBone(i)); for(size_t i = 0;i < ctrls.size();i++) { @@ -186,10 +181,12 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); Ogre::Bone *bone = skel->getBone(targets[i]); - Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); - const Ogre::Quaternion startquat = bone->getInitialOrientation(); - const Ogre::Vector3 starttrans = bone->getInitialPosition(); - const Ogre::Vector3 startscale = bone->getInitialScale(); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + const Ogre::Quaternion &startquat = bone->getInitialOrientation(); + const Ogre::Vector3 &starttrans = bone->getInitialPosition(); + const Ogre::Vector3 &startscale = bone->getInitialScale(); Ogre::Quaternion lastquat, curquat; Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); From 18389c7b04213bf56987db8fa9b6d29365a090ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 17:50:22 -0800 Subject: [PATCH 006/239] Set non-bone nodes as manually controlled --- components/nifogre/ogre_nif_loader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 870b8df0e..f1aecf720 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -306,11 +306,12 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorcreateBone(); if(parent) parent->addChild(bone); + if(!node->boneTrafo) + bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); - bone->setInitialState(); Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) From 8ebf49a35b643d61b36b5394203fe8cf5bf6f6b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 20:54:57 -0800 Subject: [PATCH 007/239] Only lower-case the model name The skeleton name will already be lower-case --- components/nifogre/ogre_nif_loader.cpp | 12 +++++------- components/nifogre/ogre_nif_loader.hpp | 8 +++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f1aecf720..04b2822e0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1043,11 +1043,8 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshPairMap; static MeshPairMap sMeshPairMap; -MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) +MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); if(meshiter != sMeshPairMap.end()) return meshiter->second; @@ -1081,10 +1078,11 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; @@ -1124,11 +1122,11 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::str EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, - const std::string &group) + std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 9dcd0bea6..47d1573fe 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -70,21 +70,19 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, std::string skelName, const std::string &group); + static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); static EntityList createEntities(Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); }; } #endif - - From efca5ded472f6ea9a0a86f80257d1ab2191a10eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 21:12:08 -0800 Subject: [PATCH 008/239] Clean up some header includes to reduce nesting --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/creature.hpp | 4 +--- apps/openmw/mwrender/actors.cpp | 13 ++++++++++--- apps/openmw/mwrender/actors.hpp | 16 +++++++++------- apps/openmw/mwrender/animation.hpp | 15 ++++----------- apps/openmw/mwrender/characterpreview.cpp | 1 + apps/openmw/mwrender/creatureanimation.hpp | 17 ++++++++++------- apps/openmw/mwrender/npcanimation.hpp | 9 +++++---- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwworld/scene.cpp | 1 + 11 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc625b306..0c9110ed4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -6,6 +6,7 @@ #include #include "../mwworld/globals.hpp" +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -42,7 +43,6 @@ namespace MWWorld class CellStore; class Player; class LocalScripts; - class Ptr; class TimeStamp; class ESMStore; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index edf5dd25d..7b0f9f728 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -18,6 +18,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/actors.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a158fa743..a96c18a8c 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,9 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwrender/renderinginterface.hpp" -#include "../mwrender/actors.hpp" - +#include "../mwworld/class.hpp" namespace MWClass { diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 05bb030d7..fc5a46d12 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -3,15 +3,20 @@ #include #include +#include "../mwworld/ptr.hpp" + +#include "animation.hpp" +#include "creatureanimation.hpp" +#include "npcanimation.hpp" + #include "renderconst.hpp" +namespace MWRender +{ using namespace Ogre; -using namespace MWRender; -using namespace NifOgre; Actors::~Actors(){ - std::map::iterator it = mAllActors.begin(); for (; it != mAllActors.end(); ++it) { delete it->second; @@ -156,3 +161,5 @@ Actors::updateObjectCell(const MWWorld::Ptr &ptr) mAllActors[ptr] = anim; } } + +} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 073c5d51f..71be0bd7b 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,25 +1,27 @@ #ifndef _GAME_RENDER_ACTORS_H #define _GAME_RENDER_ACTORS_H -#include "npcanimation.hpp" -#include "creatureanimation.hpp" +#include namespace MWWorld { class Ptr; class CellStore; + class InventoryStore; } -namespace MWRender{ - class Actors{ +namespace MWRender +{ + class Animation; + + class Actors + { OEngine::Render::OgreRenderer &mRend; std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; std::map mAllActors; - - - public: + public: Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index de4778d87..633a3f9e7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,20 +1,13 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include - #include -#include -#include "../mwworld/actiontalk.hpp" -#include -#include +namespace MWRender +{ - - -namespace MWRender { - -class Animation { +class Animation +{ struct GroupTimes { float mStart; float mStop; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0a11dc281..b144466c9 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "renderconst.hpp" #include "npcanimation.hpp" diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index e1a7bbb8f..5456f857f 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -3,18 +3,21 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" +namespace MWWorld +{ + class Ptr; +} - -namespace MWRender{ - - class CreatureAnimation: public Animation +namespace MWRender +{ + class CreatureAnimation : public Animation { public: - virtual ~CreatureAnimation(); CreatureAnimation(const MWWorld::Ptr& ptr); - virtual void runAnimation(float timepassed); + virtual ~CreatureAnimation(); + virtual void runAnimation(float timepassed); }; } + #endif diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc22..ff853de71 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,9 +3,7 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -13,9 +11,11 @@ namespace ESM struct NPC; } -namespace MWRender{ +namespace MWRender +{ -class NpcAnimation: public Animation{ +class NpcAnimation : public Animation +{ private: MWWorld::InventoryStore& mInv; int mStateID; @@ -91,4 +91,5 @@ public: }; } + #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8cb8e9fa8..71424aaed 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -19,8 +19,9 @@ #include #include -#include "../mwworld/esmstore.hpp" #include +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6b9abf508..6a6ad92d7 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -10,6 +10,7 @@ #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" +#include "class.hpp" #include "cellfunctors.hpp" From 99769879e30ce15a2eda7765eea6727f01a50b64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 00:32:38 -0800 Subject: [PATCH 009/239] Fix some createEntities calls --- apps/openmw/mwrender/sky.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd4303..c8a6ca0ef 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; From 976b042cca0891e3a21b59af2795b4361e38534a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 01:59:18 -0800 Subject: [PATCH 010/239] Use a list to reduce some repeating code --- apps/openmw/mwrender/npcanimation.cpp | 264 ++++++++------------------ apps/openmw/mwrender/npcanimation.hpp | 12 +- 2 files changed, 88 insertions(+), 188 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c76c67425..37c8aee64 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -14,34 +14,46 @@ using namespace Ogre; using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ + +const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { + { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, + { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, + { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, + { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, + { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, + { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, + { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, + { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, + { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, + { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, + { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, + { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, + { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, + { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, + { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, + { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, + { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, + { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, + { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, + { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, + { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, + { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, + { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, + { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } +}; + NpcAnimation::~NpcAnimation() { - removeEntities(mHead); - removeEntities(mHair); - removeEntities(mNeck); - removeEntities(mChest); - removeEntities(mGroin); - removeEntities(mSkirt); - removeEntities(mHandL); - removeEntities(mHandR); - removeEntities(mWristL); - removeEntities(mWristR); - removeEntities(mForearmL); - removeEntities(mForearmR); - removeEntities(mUpperArmL); - removeEntities(mUpperArmR); - removeEntities(mFootL); - removeEntities(mFootR); - removeEntities(mAnkleL); - removeEntities(mAnkleR); - removeEntities(mKneeL); - removeEntities(mKneeR); - removeEntities(mUpperLegL); - removeEntities(mUpperLegR); - removeEntities(mClavicleL); - removeEntities(mClavicleR); - removeEntities(mTail); + for(size_t i = 0;i < sPartListSize;i++) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + } } @@ -90,9 +102,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { Ogre::Entity *base = mEntityList.mEntities[i]; - base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); - + base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); base->setVisibilityFlags(mVisibilityFlags); + bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -126,29 +138,29 @@ void NpcAnimation::updateParts() { bool apparelChanged = false; - const struct { - MWWorld::ContainerStoreIterator *iter; + static const struct { + MWWorld::ContainerStoreIterator NpcAnimation::*iter; int slot; } slotlist[] = { - { &mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &mPants, MWWorld::InventoryStore::Slot_Pants }, + { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, + { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, + { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, + { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, + { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, + { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, + { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, + { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(*slotlist[i].iter != iter) + if(this->*slotlist[i].iter != iter) { - *slotlist[i].iter = iter; + this->*slotlist[i].iter = iter; removePartGroup(slotlist[i].slot); apparelChanged = true; } @@ -318,21 +330,18 @@ void NpcAnimation::updateParts() if(mPartPriorities[PartTypeList[i].type] < 1) { const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = - store.get(); + const MWWorld::Store &partStore = store.get(); - if (!mNpc->isMale()) { + if(!mNpc->isMale()) + { part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); - } } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); - } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); - } if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -348,7 +357,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int for(size_t i = 0;i < parts.size();i++) { parts[i]->setVisibilityFlags(mVisibilityFlags); - parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); + parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } return entities; } @@ -384,62 +393,15 @@ void NpcAnimation::removeIndividualPart(int type) mPartPriorities[type] = 0; mPartslots[type] = -1; - if(type == ESM::PRT_Head) //0 - removeEntities(mHead); - else if(type == ESM::PRT_Hair) //1 - removeEntities(mHair); - else if(type == ESM::PRT_Neck) //2 - removeEntities(mNeck); - else if(type == ESM::PRT_Cuirass)//3 - removeEntities(mChest); - else if(type == ESM::PRT_Groin)//4 - removeEntities(mGroin); - else if(type == ESM::PRT_Skirt)//5 - removeEntities(mSkirt); - else if(type == ESM::PRT_RHand)//6 - removeEntities(mHandR); - else if(type == ESM::PRT_LHand)//7 - removeEntities(mHandL); - else if(type == ESM::PRT_RWrist)//8 - removeEntities(mWristR); - else if(type == ESM::PRT_LWrist) //9 - removeEntities(mWristL); - else if(type == ESM::PRT_Shield) //10 + for(size_t i = 0;i < sPartListSize;i++) { + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + break; + } } - else if(type == ESM::PRT_RForearm) //11 - removeEntities(mForearmR); - else if(type == ESM::PRT_LForearm) //12 - removeEntities(mForearmL); - else if(type == ESM::PRT_RUpperarm) //13 - removeEntities(mUpperArmR); - else if(type == ESM::PRT_LUpperarm) //14 - removeEntities(mUpperArmL); - else if(type == ESM::PRT_RFoot) //15 - removeEntities(mFootR); - else if(type == ESM::PRT_LFoot) //16 - removeEntities(mFootL); - else if(type == ESM::PRT_RAnkle) //17 - removeEntities(mAnkleR); - else if(type == ESM::PRT_LAnkle) //18 - removeEntities(mAnkleL); - else if(type == ESM::PRT_RKnee) //19 - removeEntities(mKneeR); - else if(type == ESM::PRT_LKnee) //20 - removeEntities(mKneeL); - else if(type == ESM::PRT_RLeg) //21 - removeEntities(mUpperLegR); - else if(type == ESM::PRT_LLeg) //22 - removeEntities(mUpperLegL); - else if(type == ESM::PRT_RPauldron) //23 - removeEntities(mClavicleR); - else if(type == ESM::PRT_LPauldron) //24 - removeEntities(mClavicleL); - else if(type == ESM::PRT_Weapon) //25 - { - } - else if(type == ESM::PRT_Tail) //26 - removeEntities(mTail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -469,87 +431,15 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, removeIndividualPart(type); mPartslots[type] = group; mPartPriorities[type] = priority; - switch(type) + + for(size_t i = 0;i < sPartListSize;i++) { - case ESM::PRT_Head: //0 - mHead = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Hair: //1 - mHair = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Neck: //2 - mNeck = insertBoundedPart(mesh, group, "Neck"); - break; - case ESM::PRT_Cuirass: //3 - mChest = insertBoundedPart(mesh, group, "Chest"); - break; - case ESM::PRT_Groin: //4 - mGroin = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_Skirt: //5 - mSkirt = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_RHand: //6 - mHandR = insertBoundedPart(mesh, group, "Right Hand"); - break; - case ESM::PRT_LHand: //7 - mHandL = insertBoundedPart(mesh, group, "Left Hand"); - break; - case ESM::PRT_RWrist: //8 - mWristR = insertBoundedPart(mesh, group, "Right Wrist"); - break; - case ESM::PRT_LWrist: //9 - mWristL = insertBoundedPart(mesh, group, "Left Wrist"); - break; - case ESM::PRT_Shield: //10 - break; - case ESM::PRT_RForearm: //11 - mForearmR = insertBoundedPart(mesh, group, "Right Forearm"); - break; - case ESM::PRT_LForearm: //12 - mForearmL = insertBoundedPart(mesh, group, "Left Forearm"); - break; - case ESM::PRT_RUpperarm: //13 - mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm"); - break; - case ESM::PRT_LUpperarm: //14 - mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm"); - break; - case ESM::PRT_RFoot: //15 - mFootR = insertBoundedPart(mesh, group, "Right Foot"); - break; - case ESM::PRT_LFoot: //16 - mFootL = insertBoundedPart(mesh, group, "Left Foot"); - break; - case ESM::PRT_RAnkle: //17 - mAnkleR = insertBoundedPart(mesh, group, "Right Ankle"); - break; - case ESM::PRT_LAnkle: //18 - mAnkleL = insertBoundedPart(mesh, group, "Left Ankle"); - break; - case ESM::PRT_RKnee: //19 - mKneeR = insertBoundedPart(mesh, group, "Right Knee"); - break; - case ESM::PRT_LKnee: //20 - mKneeL = insertBoundedPart(mesh, group, "Left Knee"); - break; - case ESM::PRT_RLeg: //21 - mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg"); - break; - case ESM::PRT_LLeg: //22 - mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg"); - break; - case ESM::PRT_RPauldron: //23 - mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle"); - break; - case ESM::PRT_LPauldron: //24 - mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle"); - break; - case ESM::PRT_Weapon: //25 - break; - case ESM::PRT_Tail: //26 - mTail = insertBoundedPart(mesh, group, "Tail"); + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; + } } return true; } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ff853de71..e6eee5491 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,6 +14,14 @@ namespace ESM namespace MWRender { +class NpcAnimation; + +struct PartInfo { + ESM::PartReferenceType type; + NifOgre::EntityList NpcAnimation::*ents; + const char name[32]; +}; + class NpcAnimation : public Animation { private: @@ -55,7 +63,6 @@ private: std::string mHairModel; std::string mBodyPrefix; - float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; MWWorld::ContainerStoreIterator mHelmet; @@ -72,6 +79,9 @@ private: int mVisibilityFlags; + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags); From 2b1fe7dc44652f1531fb9aa70c67a62cb19e6752 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 05:39:39 -0800 Subject: [PATCH 011/239] Add part info for weapons and shields --- apps/openmw/mwrender/npcanimation.cpp | 25 ++++++++++--------------- apps/openmw/mwrender/npcanimation.hpp | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 37c8aee64..b7e93cef2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -17,7 +17,7 @@ using namespace NifOgre; namespace MWRender { -const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { +const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, @@ -28,7 +28,7 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, @@ -43,24 +43,21 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); - } + removeEntities(this->*sPartList[i].ents); } NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), - mStateID(-1), mInv(inv), + mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), mRobe(mInv.end()), @@ -78,10 +75,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { mNpc = ptr.get()->mBase; - for (int init = 0; init < 27; init++) + for(size_t i = 0;i < sPartListSize;i++) { - mPartslots[init] = -1; //each slot is empty - mPartPriorities[init] = 0; + mPartslots[i] = -1; //each slot is empty + mPartPriorities[i] = 0; } const MWWorld::ESMStore &store = @@ -397,8 +394,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); + removeEntities(this->*sPartList[i].ents); break; } } @@ -436,8 +432,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - if(sPartList[i].ents) - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e6eee5491..090366a23 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,23 +14,22 @@ namespace ESM namespace MWRender { -class NpcAnimation; - +class NpcAnimation : public Animation +{ +public: struct PartInfo { ESM::PartReferenceType type; NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; -class NpcAnimation : public Animation -{ private: + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + MWWorld::InventoryStore& mInv; int mStateID; - int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty - int mPartPriorities[27]; - //Bounded Parts NifOgre::EntityList mClavicleL; NifOgre::EntityList mClavicleR; @@ -54,6 +53,8 @@ private: NifOgre::EntityList mHair; NifOgre::EntityList mHandL; NifOgre::EntityList mHandR; + NifOgre::EntityList mShield; + NifOgre::EntityList mWeapon; NifOgre::EntityList mHead; NifOgre::EntityList mChest; NifOgre::EntityList mTail; @@ -79,8 +80,8 @@ private: int mVisibilityFlags; - static const size_t sPartListSize = 27; - static const PartInfo sPartList[sPartListSize]; + int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty + int mPartPriorities[sPartListSize]; public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From b96a9797199d4fa076d6516d59e9a892d744e8c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:05:48 -0800 Subject: [PATCH 012/239] Store an MWWorld::Ptr with the Animation --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 5 ++++- apps/openmw/mwrender/creatureanimation.cpp | 7 ++++--- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d2d253b91..d7f3d52d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,8 +10,9 @@ namespace MWRender { -Animation::Animation() - : mInsert(NULL) +Animation::Animation(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) , mAnimState(NULL) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 633a3f9e7..593538ea6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,6 +3,8 @@ #include +#include "../mwworld/ptr.hpp" + namespace MWRender { @@ -23,6 +25,7 @@ class Animation }; protected: + MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; float mTime; @@ -40,7 +43,7 @@ protected: void createEntityList(Ogre::SceneNode *node, const std::string &model); public: - Animation(); + Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); void playGroup(std::string groupname, int mode, int loops); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 1ca897c15..caa040d95 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,16 +16,17 @@ CreatureAnimation::~CreatureAnimation() { } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) { - MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(ptr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b7e93cef2..5682a86cc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -55,7 +55,7 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) - : Animation(), + : Animation(ptr), mInv(inv), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveR(mInv.end()), mSkirtIter(mInv.end()) { - mNpc = ptr.get()->mBase; + mNpc = mPtr.get()->mBase; for(size_t i = 0;i < sPartListSize;i++) { From 910619eb21c05fc9baa93e139a7d011bce9ea775 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:31:53 -0800 Subject: [PATCH 013/239] Store the NonAccum animation root from the skeleton instance Currently this is assumed to be the node with the animation text keys. --- apps/openmw/mwrender/animation.cpp | 4 +++- apps/openmw/mwrender/animation.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d7f3d52d6..b8be879e5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,8 +14,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) , mTime(0.0f) - , mSkipFrame(false) , mAnimState(NULL) + , mSkipFrame(false) + , mNonAccumRoot(NULL) { } @@ -62,6 +63,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); break; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 593538ea6..3bc173d70 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,12 +31,13 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; bool mSkipFrame; NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::AnimationState *mAnimState; + Ogre::Node *mNonAccumRoot; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 7ba09ff025e07250a88261a1b099f377717a72a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 20:05:50 -0800 Subject: [PATCH 014/239] Catch errors from buildBones --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 04b2822e0..3c8b3067a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -367,7 +367,14 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - buildBones(skel, node, ctrls); + try { + buildBones(skel, node, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file From 5b3a20ef69c23eea4f65b138aca43517c497963c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 21:18:48 -0800 Subject: [PATCH 015/239] Update the object position as the animation moves --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/characterpreview.cpp | 1 - 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8be879e5..b73d35264 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -7,6 +7,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWRender { @@ -16,8 +19,14 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mAnimState(NULL) , mSkipFrame(false) + , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mLastPosition(0.0f) { + mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; + mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; + mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; + mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -52,9 +61,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAnimState = state; } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); while(iter.hasMoreElements()) { @@ -63,7 +73,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mLastPosition = mNonAccumRoot->getPosition(); break; } } @@ -71,6 +84,43 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::updatePosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + /* Update the animation and get the non-accumulation root's difference from the + * last update. */ + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + + /* Translate the accumulation root back to compensate for the move. */ + mAccumRoot->translate(-posdiff); + mLastPosition += posdiff; + + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } +} + +void Animation::resetPosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mLastPosition = mNonAccumRoot->getPosition(); + /* FIXME: This should be set to -mLastPosition, but without proper collision the + * model gets placed halfway into the ground. */ + mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + } +} + + struct checklow { bool operator()(const char &a, const char &b) const { @@ -145,6 +195,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup = times; mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + resetPosition(mTime); } } @@ -155,29 +206,36 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mLoops > 0 && !mSkipFrame) + if(mAnimState && !mSkipFrame) { mTime += timepassed; + recheck: if(mTime >= mCurGroup.mLoopStop) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; + updatePosition(mCurGroup.mLoopStop); mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; + resetPosition(mCurGroup.mLoopStart); + goto recheck; } else if(mTime >= mCurGroup.mStop) { if(mNextGroup.mLoops > 0) + { + updatePosition(mCurGroup.mStop); mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - else - mTime = mCurGroup.mStop; - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + resetPosition(mNextGroup.mStart); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + goto recheck; + } + mTime = mCurGroup.mStop; } } - if(mAnimState) - mAnimState->setTimePosition(mTime); + updatePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3bc173d70..d1ae5af4c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,7 +37,16 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::Node *mNonAccumRoot; + Ogre::Bone *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mLastPosition; + + /* Updates the animation to the specified time, and moves the mPtr object + * based on the change since the last update or reset. */ + void updatePosition(float time); + /* Updates the animation to the specified time, without moving the mPtr + * object. */ + void resetPosition(float time); bool findGroupTimes(const std::string &groupname, GroupTimes *times); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b144466c9..7431c2a61 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -138,7 +138,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->playGroup ("inventoryhandtohand", 0, 1); - mAnimation->runAnimation (0); } // -------------------------------------------------------------------------------------------------- From 648e3331f51e5ee75176b82f72d3860e635548ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 23:20:20 -0800 Subject: [PATCH 016/239] Don't try to move objects that aren't in a cell --- apps/openmw/mwrender/animation.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b73d35264..4cf0db3ed 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,12 +98,15 @@ void Animation::updatePosition(float time) mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; + if(mPtr.isInCell()) + { + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } } } From 14d814d1d310e6dd30ef5c82abfae036af585e94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:21:25 -0800 Subject: [PATCH 017/239] Avoid creating bones for NiTriShape nodes The offset specified for them can be just as easilly handled by the tag point they get connected to, and as such it's just needless extra nodes. --- components/nifogre/ogre_nif_loader.cpp | 55 ++++++++++++++++---------- components/nifogre/ogre_nif_loader.hpp | 19 +++++++-- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 3c8b3067a..e71c57efa 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -169,6 +169,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const for(size_t i = 0;i < ctrls.size();i++) { Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; Nif::NiKeyframeData *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ @@ -183,7 +185,9 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); const Ogre::Quaternion &startquat = bone->getInitialOrientation(); const Ogre::Vector3 &starttrans = bone->getInitialPosition(); const Ogre::Vector3 &startscale = bone->getInitialScale(); @@ -299,6 +303,9 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) { + if(node->recType == Nif::RC_NiTriShape) + return; + Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -403,6 +410,9 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + if(node->recType == Nif::RC_NiTriShape) + return false; + if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -733,7 +743,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); skel = skelMgr->getByName(mSkelName); - skel->touch(); // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to @@ -967,7 +976,7 @@ public: findTriShape(mesh, node); } - void createMeshes(const Nif::Node *node, MeshPairList &meshes, int flags=0) + void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { flags |= node->flags; @@ -1026,7 +1035,8 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(std::make_pair(mesh->getName(), shape->name)); + meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), + shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) @@ -1047,16 +1057,16 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshPairMap; -static MeshPairMap sMeshPairMap; +typedef std::map MeshInfoMap; +static MeshInfoMap sMeshInfoMap; -MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); - if(meshiter != sMeshPairMap.end()) + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; Nif::NIFFile nif(name); if (nif.numRecords() < 1) { @@ -1090,14 +1100,14 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, name, group); + MeshInfoList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); Ogre::Entity *entity = entitylist.mEntities.back(); if(!entitylist.mSkelBase && entity->hasSkeleton()) entitylist.mSkelBase = entity; @@ -1115,7 +1125,12 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } else @@ -1134,22 +1149,22 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "tri "+bonename; - std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower); + std::string filter = bonename; + std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first); + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); + std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), + meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].second.length() < filter.length() || - meshes[i].second.compare(0, filter.length(), filter) != 0) + if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 47d1573fe..4ed52a84a 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,8 +53,21 @@ struct EntityList { }; -/** This holds a list of mesh names along with the names of their parent nodes */ -typedef std::vector< std::pair > MeshPairList; +/* This holds a list of mesh names, the names of their parent nodes, and the offset + * from their parent nodes. */ +struct MeshInfo { + std::string mMeshName; + std::string mTargetNode; + Ogre::Vector3 mPos; + Ogre::Matrix3 mRot; + float mScale; + + MeshInfo(const std::string &name, const std::string &target, + const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) + : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + { } +}; +typedef std::vector MeshInfoList; /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into @@ -70,7 +83,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 5f668976a84cbff41a948314f4e4282a8601b94d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:48:59 -0800 Subject: [PATCH 018/239] Improve resetting the animation position --- apps/openmw/mwrender/animation.cpp | 8 ++++---- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4cf0db3ed..4b8580467 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mStartPosition(0.0f) , mLastPosition(0.0f) { mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; @@ -76,7 +77,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mLastPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; break; } } @@ -117,9 +119,7 @@ void Animation::resetPosition(float time) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); - /* FIXME: This should be set to -mLastPosition, but without proper collision the - * model gets placed halfway into the ground. */ - mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + mAccumRoot->setPosition(mStartPosition - mLastPosition); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d1ae5af4c..73e34befe 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,7 @@ protected: NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; /* Updates the animation to the specified time, and moves the mPtr object From 05dfafa7770d01f988f8d13488ab80df88d3e016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:09:15 -0800 Subject: [PATCH 019/239] Avoid an unnecessary lookup when moving the scene node --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 71424aaed..51f1150ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -249,8 +249,7 @@ void RenderingManager::removeObject (const MWWorld::Ptr& ptr) void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) { /// \todo move this to the rendering-subsystems - mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())-> - setPosition (position); + ptr.getRefData().getBaseNode()->setPosition(position); } void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) From d3e949f5c61e8196da71c48655c67bdbbb8d2356 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:23:44 -0800 Subject: [PATCH 020/239] Make the animation text keys lower case to help lookup --- apps/openmw/mwrender/animation.cpp | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4b8580467..aedc13189 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -82,6 +82,13 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } } + + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + { + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + } } } @@ -124,19 +131,12 @@ void Animation::resetPosition(float time) } -struct checklow { - bool operator()(const char &a, const char &b) const - { - return ::tolower(a) == ::tolower(b); - } -}; - bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { - const std::string &start = groupname+": start"; - const std::string &startloop = groupname+": loop start"; - const std::string &stop = groupname+": stop"; - const std::string &stoploop = groupname+": loop stop"; + const std::string start = groupname+": start"; + const std::string startloop = groupname+": loop start"; + const std::string stop = groupname+": stop"; + const std::string stoploop = groupname+": loop stop"; NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) @@ -144,24 +144,20 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) return true; - std::string::const_iterator strpos = iter->second.begin(); - std::string::const_iterator strend = iter->second.end(); - size_t strlen = strend-strpos; - - if(start.size() <= strlen && std::mismatch(strpos, strend, start.begin(), checklow()).first == strend) + if(start == iter->second) { times->mStart = iter->first; times->mLoopStart = iter->first; } - else if(startloop.size() <= strlen && std::mismatch(strpos, strend, startloop.begin(), checklow()).first == strend) + else if(startloop == iter->second) { times->mLoopStart = iter->first; } - else if(stoploop.size() <= strlen && std::mismatch(strpos, strend, stoploop.begin(), checklow()).first == strend) + else if(stoploop == iter->second) { times->mLoopStop = iter->first; } - else if(stop.size() <= strlen && std::mismatch(strpos, strend, stop.begin(), checklow()).first == strend) + else if(stop == iter->second) { times->mStop = iter->first; if(times->mLoopStop < 0.0f) @@ -179,6 +175,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; times.mLoops = loops; + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); if(groupname == "all") { times.mStart = times.mLoopStart = 0.0f; From d8dbd5e206c8c028c6d52ee72d498bd5d97c5b49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:56:03 -0800 Subject: [PATCH 021/239] Store text key iterators for the start and stop times --- apps/openmw/mwrender/animation.cpp | 84 +++++++++++++++--------------- apps/openmw/mwrender/animation.hpp | 26 ++++----- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index aedc13189..b4bfd0684 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,18 +16,16 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) - , mTime(0.0f) - , mAnimState(NULL) - , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mTime(0.0f) + , mCurGroup(mTextKeys.end()) + , mNextGroup(mTextKeys.end()) + , mAnimState(NULL) + , mSkipFrame(false) { - mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; - mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; - mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; - mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -74,9 +72,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mStartPosition = mNonAccumRoot->getPosition(); mLastPosition = mStartPosition; break; @@ -141,60 +142,57 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) { - if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) - return true; - if(start == iter->second) { - times->mStart = iter->first; - times->mLoopStart = iter->first; + times->mStart = iter; + times->mLoopStart = iter; } else if(startloop == iter->second) - { - times->mLoopStart = iter->first; - } + times->mLoopStart = iter; else if(stoploop == iter->second) - { - times->mLoopStop = iter->first; - } + times->mLoopStop = iter; else if(stop == iter->second) { - times->mStop = iter->first; - if(times->mLoopStop < 0.0f) - times->mLoopStop = iter->first; - break; + times->mStop = iter; + if(times->mLoopStop == mTextKeys.end()) + times->mLoopStop = iter; + return (times->mStart != mTextKeys.end()); } } - return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); + return false; } void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times; + if(mTextKeys.size() == 0) + { + std::cerr<< "Trying to animate an unanimate object" <first; + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); } else if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + { + std::cerr<< "Failed to find animation group "< 0) mNextGroup = times; else { mCurGroup = times; - mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + mNextGroup = GroupTimes(mTextKeys.end()); + mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; resetPosition(mTime); } } @@ -210,28 +208,28 @@ void Animation::runAnimation(float timepassed) { mTime += timepassed; recheck: - if(mTime >= mCurGroup.mLoopStop) + if(mTime >= mCurGroup.mLoopStop->first) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop); - mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; - resetPosition(mCurGroup.mLoopStart); + updatePosition(mCurGroup.mLoopStop->first); + mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; + resetPosition(mCurGroup.mLoopStart->first); goto recheck; } - else if(mTime >= mCurGroup.mStop) + else if(mTime >= mCurGroup.mStop->first) { if(mNextGroup.mLoops > 0) { - updatePosition(mCurGroup.mStop); - mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - resetPosition(mNextGroup.mStart); + updatePosition(mCurGroup.mStop->first); + mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; + resetPosition(mNextGroup.mStart->first); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + mNextGroup = GroupTimes(mTextKeys.end()); goto recheck; } - mTime = mCurGroup.mStop; + mTime = mCurGroup.mStop->first; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73e34befe..44a2eaf3e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -11,15 +11,15 @@ namespace MWRender class Animation { struct GroupTimes { - float mStart; - float mStop; - float mLoopStart; - float mLoopStop; + NifOgre::TextKeyMap::const_iterator mStart; + NifOgre::TextKeyMap::const_iterator mStop; + NifOgre::TextKeyMap::const_iterator mLoopStart; + NifOgre::TextKeyMap::const_iterator mLoopStop; size_t mLoops; - GroupTimes() - : mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f), + GroupTimes(NifOgre::TextKeyMap::const_iterator iter) + : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), mLoops(0) { } }; @@ -28,13 +28,6 @@ protected: MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; - float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; - - bool mSkipFrame; - NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; @@ -42,6 +35,13 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + float mTime; + GroupTimes mCurGroup; + GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; + + bool mSkipFrame; + /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); From 2a9dc5ad94a48353b816f3056ce4c3326e2a7bef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 21:00:21 -0800 Subject: [PATCH 022/239] Ensure mCurGroup always has valid iterators, and only get the animation state when animation keys exist --- apps/openmw/mwrender/animation.cpp | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b4bfd0684..6da3ad583 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,17 +49,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - if(!mAnimState) - mAnimState = state; - } - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -72,7 +61,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -84,11 +73,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } } - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + if(mTextKeys.size() > 0) { - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + if(!mAnimState) + mAnimState = state; + } } } } @@ -179,6 +180,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) { times.mStart = times.mLoopStart = mTextKeys.begin(); times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; } else if(!findGroupTimes(groupname, ×)) { From e44729cd43a98ee35bea3b123f3e021cdc6dceee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 00:17:42 -0800 Subject: [PATCH 023/239] Make the text keys lower-case when extracting them I think it's safe to assume all text keys are treated in a case-insensitive manner. So far the only known NiTextKeyExtraData records are for animation keys, which effectively are. --- apps/openmw/mwrender/animation.cpp | 5 ----- components/nifogre/ogre_nif_loader.cpp | 13 +++++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6da3ad583..4e33873d3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -75,11 +75,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(mTextKeys.size() > 0) { - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); while(as.hasMoreElements()) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e71c57efa..803496bf9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -286,13 +286,18 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) std::string::size_type pos = 0; while(pos < str.length()) { - while(pos < str.length() && ::isspace(str[pos])) + if(::isspace(str[pos])) + { pos++; - if(pos >= str.length()) - break; + continue; + } std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - textkeys.insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos))); + std::string result; + result.reserve(str.length()); + std::transform(str.begin()+pos, str.begin()+std::min(str.length(), nextpos), + std::back_inserter(result), ::tolower); + textkeys.insert(std::make_pair(tk->list[i].time, result)); pos = nextpos; } From bb98542c5a5d16c40713e1a0f847d7735a8c7abe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 01:40:38 -0800 Subject: [PATCH 024/239] Build separate animations for each group --- apps/openmw/mwrender/animation.cpp | 55 ++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 4 +- components/nifogre/ogre_nif_loader.cpp | 38 ++++++++++++++++++ 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e33873d3..4448360bd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mCurGroup(mTextKeys.end()) , mNextGroup(mTextKeys.end()) - , mAnimState(NULL) , mSkipFrame(false) { } @@ -80,10 +79,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(as.hasMoreElements()) { Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); + state->setEnabled(false); state->setLoop(false); - if(!mAnimState) - mAnimState = state; } } } @@ -92,12 +89,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model void Animation::updatePosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -118,10 +115,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -162,24 +159,27 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - if(mTextKeys.size() == 0) - { - std::cerr<< "Trying to animate an unanimate object" <getAnimationState(groupname); + times.mLoops = loops; + + if(groupname == "all") + { + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; + } + else if(!findGroupTimes(groupname, ×)) + throw std::runtime_error("Failed to find animation group "+groupname); } - else if(!findGroupTimes(groupname, ×)) - { - std::cerr<< "Failed to find animation group "<setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(mTextKeys.end()); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } } @@ -201,7 +204,7 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mAnimState && !mSkipFrame) + if(mCurGroup.mAnimState && !mSkipFrame) { mTime += timepassed; recheck: @@ -221,9 +224,11 @@ void Animation::runAnimation(float timepassed) { updatePosition(mCurGroup.mStop->first); mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - resetPosition(mNextGroup.mStart->first); + mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; mNextGroup = GroupTimes(mTextKeys.end()); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mNextGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 44a2eaf3e..e84ebb358 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,11 +16,12 @@ class Animation NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + Ogre::AnimationState *mAnimState; size_t mLoops; GroupTimes(NifOgre::TextKeyMap::const_iterator iter) : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mLoops(0) + mAnimState(NULL), mLoops(0) { } }; @@ -38,7 +39,6 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; bool mSkipFrame; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 803496bf9..c4846cdfd 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -410,7 +410,45 @@ void loadResource(Ogre::Resource *resource) return; } + TextKeyMap textkeys; + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.peekNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); + if(!data.isEmpty()) + { + textkeys = Ogre::any_cast(data); + break; + } + boneiter.moveNext(); + } + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); + while(lastkeyiter->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + lastkeyiter++; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + } } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 4054934f1699affd865977148f45b4137d8e7b16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 02:51:25 -0800 Subject: [PATCH 025/239] Store text keys for each animation --- components/nifogre/ogre_nif_loader.cpp | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c4846cdfd..1b0d3168c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -431,23 +431,29 @@ void loadResource(Ogre::Resource *resource) for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) { std::string::size_type sep = keyiter->second.find(':'); - if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) continue; currentgroup = keyiter->second.substr(0, sep); if(skel->hasAnimation(currentgroup)) continue; - TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); - while(lastkeyiter->first > keyiter->first) + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) { if(lastkeyiter->second.find(':') == currentgroup.length() && lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) break; - lastkeyiter++; } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap groupkeys; + groupkeys.insert(keyiter, ++lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } @@ -459,12 +465,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) - { - NIFSkeletonLoader *loader = &sLoaders[name]; - skel = skelMgr.create(name, group, true, loader); - } + skelMgr.create(name, group, true, &sLoaders[name]); return true; } @@ -1129,8 +1130,12 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } - NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(name, group, node); + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + { + NIFSkeletonLoader skelldr; + hasSkel = skelldr.createSkeleton(name, group, node); + } NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From 1e38e381a4344210872ea8f86d5347c1ac5b3fa0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 03:30:55 -0800 Subject: [PATCH 026/239] Use text keys for each animation --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 7 ++- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4448360bd..59dcd451b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,8 +21,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mCurGroup(mTextKeys.end()) - , mNextGroup(mTextKeys.end()) , mSkipFrame(false) { } @@ -48,19 +46,27 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = iter.getNext(); + Ogre::Bone *bone = boneiter.peekNext(); const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); if(!data.isEmpty()) { - mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); + mTextKeys["all"] = Ogre::any_cast(data); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -70,17 +76,19 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mLastPosition = mStartPosition; break; } + boneiter.moveNext(); } - if(mTextKeys.size() > 0) + if(boneiter.hasMoreElements()) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) + asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(false); - state->setLoop(false); + Ogre::AnimationState *state = asiter.getNext(); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); + if(!data.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); } } } @@ -127,13 +135,28 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { + const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + if(textkeys.size() == 0) + return false; + + if(groupname == "all") + { + times->mStart = times->mLoopStart = textkeys.begin(); + times->mLoopStop = times->mStop = textkeys.end(); + times->mLoopStop--; times->mStop--; + return true; + } + const std::string start = groupname+": start"; const std::string startloop = groupname+": loop start"; const std::string stop = groupname+": stop"; const std::string stoploop = groupname+": loop stop"; + times->mStart = times->mLoopStart = + times->mStop = times->mLoopStop = textkeys.end(); + NifOgre::TextKeyMap::const_iterator iter; - for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) + for(iter = textkeys.begin();iter != textkeys.end();iter++) { if(start == iter->second) { @@ -147,9 +170,9 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim else if(stop == iter->second) { times->mStop = iter; - if(times->mLoopStop == mTextKeys.end()) + if(times->mLoopStop == textkeys.end()) times->mLoopStop = iter; - return (times->mStart != mTextKeys.end()); + return (times->mStart != textkeys.end()); } } @@ -159,23 +182,14 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times(mTextKeys.end()); + GroupTimes times; try { - if(mTextKeys.size() == 0) - throw std::runtime_error("Trying to animate an unanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; - if(groupname == "all") - { - times.mStart = times.mLoopStart = mTextKeys.begin(); - times.mLoopStop = times.mStop = mTextKeys.end(); - times.mLoopStop--; times.mStop--; - } - else if(!findGroupTimes(groupname, ×)) + if(!findGroupTimes(groupname, ×)) throw std::runtime_error("Failed to find animation group "+groupname); } catch(std::exception &e) { @@ -190,7 +204,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) if(mCurGroup.mAnimState) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); @@ -226,9 +240,9 @@ void Animation::runAnimation(float timepassed) mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mCurGroup.mAnimState->setEnabled(true); - resetPosition(mNextGroup.mStart->first); + resetPosition(mCurGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e84ebb358..859d2b989 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -19,9 +19,8 @@ class Animation Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes(NifOgre::TextKeyMap::const_iterator iter) - : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mAnimState(NULL), mLoops(0) + GroupTimes() + : mAnimState(NULL), mLoops(0) { } }; @@ -30,7 +29,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; - NifOgre::TextKeyMap mTextKeys; + std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mStartPosition; From 465fd9c8afbce80590fd8b48d244cd6bbd344e52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:10:02 -0800 Subject: [PATCH 027/239] Offset animation times to start at 0 --- components/nifogre/ogre_nif_loader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1b0d3168c..b065e5fd3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -164,7 +164,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); + kframe = nodetrack->createNodeKeyFrame(curtime-startTime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -450,8 +450,12 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + TextKeyMap::const_iterator insiter = keyiter; TextKeyMap groupkeys; - groupkeys.insert(keyiter, ++lastkeyiter); + do { + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } From 015bb0bf1f309fcff7b61a4e23cdb8484fb97c45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:30:32 -0800 Subject: [PATCH 028/239] Use the calculated max time for the "all" animation --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b065e5fd3..b37b989c7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -424,7 +424,7 @@ void loadResource(Ogre::Resource *resource) boneiter.moveNext(); } - buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); From a9bcbfd8d364210c75120e36f258792d45e90edd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 05:11:32 -0800 Subject: [PATCH 029/239] Use Node::_getFullTransform instead of building the matrix manually --- components/nifogre/ogre_nif_loader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b37b989c7..08a5855ed 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -803,12 +803,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t b = 0;b < bones.length();b++) { Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat, mat2; + Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat2.makeTransform(bone->_getDerivedPosition(), bone->_getDerivedScale(), - bone->_getDerivedOrientation()); - mat = mat2 * mat; + mat = bone->_getFullTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) From 4b7cc1372f4d2500effee6fb3482a1e8fc56b9f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 06:32:31 -0800 Subject: [PATCH 030/239] Some cleanup --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 08a5855ed..cfc0d8397 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1008,7 +1008,7 @@ public: virtual void loadResource(Ogre::Resource *resource) { Ogre::Mesh *mesh = dynamic_cast(resource); - assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); if(!mShapeName.length()) { @@ -1116,7 +1116,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam Nif::NIFFile nif(name); if (nif.numRecords() < 1) { - nif.warn("Found no records in NIF."); + nif.warn("Found no NIF records in "+name+"."); return meshes; } @@ -1127,8 +1127,8 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in file was not a node, but a "+ - r->recName+". Skipping file."); + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); return meshes; } @@ -1204,16 +1204,13 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; - std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); + std::string filter; filter.resize(bonename.length()); + std::transform(bonename.begin(), bonename.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), - meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); From 625a538f03e9d88adbd3431bb7c8810bc3d6c564 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:43:10 -0800 Subject: [PATCH 031/239] Combine part selection into a single loop --- apps/openmw/mwrender/npcanimation.cpp | 239 +++++++++++--------------- 1 file changed, 96 insertions(+), 143 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5682a86cc..e4eea6c71 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,161 +133,114 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor void NpcAnimation::updateParts() { - bool apparelChanged = false; - static const struct { - MWWorld::ContainerStoreIterator NpcAnimation::*iter; + int numRemoveParts; // Max: 1 + ESM::PartReferenceType removeParts[1]; + + MWWorld::ContainerStoreIterator NpcAnimation::*part; int slot; + + int numReserveParts; // Max: 12 + ESM::PartReferenceType reserveParts[12]; } slotlist[] = { - { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, + { 0, { }, + &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe, + 12, { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, + ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, + ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron } + }, + + { 0, { }, + &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt, + 3, { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg } + }, + + { 1, { ESM::PRT_Hair }, + &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, + 0, { } + }, }; - for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) + static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].iter != iter) - { - this->*slotlist[i].iter = iter; - removePartGroup(slotlist[i].slot); - apparelChanged = true; - } - } + if(this->*slotlist[i].part == iter) + continue; - if(apparelChanged) - { - if(mRobe != mInv.end()) - { - MWWorld::Ptr ptr = *mRobe; + this->*slotlist[i].part = iter; + removePartGroup(slotlist[i].slot); - const ESM::Clothing *clothes = (ptr.get())->mBase; + if(this->*slotlist[i].part == mInv.end()) + continue; + + for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) + removeIndividualPart(slotlist[i].removeParts[rem]); + + int prio = 1; + MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part; + if(store->getTypeName() == typeid(ESM::Clothing).name()) + { + prio = ((slotlist[i].numReserveParts+1)<<1) + 0; + const ESM::Clothing *clothes = store->get()->mBase; std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + addPartGroup(slotlist[i].slot, prio, parts); } - if(mSkirtIter != mInv.end()) + else if(store->getTypeName() == typeid(ESM::Armor).name()) { - MWWorld::Ptr ptr = *mSkirtIter; - - const ESM::Clothing *clothes = (ptr.get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + prio = ((slotlist[i].numReserveParts+1)<<1) + 1; + const ESM::Armor *armor = store->get()->mBase; + std::vector parts = armor->mParts.mParts; + addPartGroup(slotlist[i].slot, prio, parts); } - if(mHelmet != mInv.end()) - { - removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (mHelmet->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); - } - if(mCuirass != mInv.end()) - { - const ESM::Armor *armor = (mCuirass->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); - } - if(mGreaves != mInv.end()) - { - const ESM::Armor *armor = (mGreaves->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); - } - - if(mPauldronL != mInv.end()) - { - const ESM::Armor *armor = (mPauldronL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); - } - if(mPauldronR != mInv.end()) - { - const ESM::Armor *armor = (mPauldronR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); - } - if(mBoots != mInv.end()) - { - if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mBoots->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); - } - else if(mBoots->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = (mBoots->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); - } - } - if(mGloveL != mInv.end()) - { - if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveL->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); - } - } - if(mGloveR != mInv.end()) - { - if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveR->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); - } - - } - - if(mShirt != mInv.end()) - { - const ESM::Clothing *clothes = (mShirt->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); - } - if(mPants != mInv.end()) - { - const ESM::Clothing *clothes = (mPants->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); - } + for(int res = 0;res < slotlist[i].numReserveParts;res++) + reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } if(mPartPriorities[ESM::PRT_Head] < 1) @@ -455,7 +408,7 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vectormModel); + addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); else reserveIndividualPart(part.mPart, group, priority); } From 9fedaf18d6d724156910e23be9325882c79787a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:55:55 -0800 Subject: [PATCH 032/239] Make some methods private --- apps/openmw/mwrender/npcanimation.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 090366a23..1a121be07 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -83,12 +83,7 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; -public: - NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags); - virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); - virtual void runAnimation(float timepassed); void updateParts(); void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); @@ -98,6 +93,13 @@ public: void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); +public: + NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, + MWWorld::InventoryStore& inv, int visibilityFlags); + virtual ~NpcAnimation(); + + virtual void runAnimation(float timepassed); + void forceUpdate(); }; From be74859f05257b0cbf3ba8884b39df8570a2d14d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 08:03:28 -0800 Subject: [PATCH 033/239] Avoid some unnecessary copying when calling addPartGroup --- apps/openmw/mwrender/npcanimation.cpp | 10 ++++------ apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e4eea6c71..4fddb2020 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -228,15 +228,13 @@ void NpcAnimation::updateParts() { prio = ((slotlist[i].numReserveParts+1)<<1) + 0; const ESM::Clothing *clothes = store->get()->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, clothes->mParts.mParts); } else if(store->getTypeName() == typeid(ESM::Armor).name()) { prio = ((slotlist[i].numReserveParts+1)<<1) + 1; const ESM::Armor *armor = store->get()->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts); } for(int res = 0;res < slotlist[i].numReserveParts;res++) @@ -392,11 +390,11 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, return true; } -void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts) +void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { for(std::size_t i = 0; i < parts.size(); i++) { - ESM::PartReference &part = parts[i]; + const ESM::PartReference &part = parts[i]; const MWWorld::Store &partStore = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1a121be07..161091317 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -91,7 +91,7 @@ private: bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); - void addPartGroup(int group, int priority, std::vector& parts); + void addPartGroup(int group, int priority, const std::vector &parts); public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From c4c8295e0b0144adc8ba3f1f77b55594c553bbe0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 09:10:59 -0800 Subject: [PATCH 034/239] Rename NIFLoader to Loader, and update some comments --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 6 ++---- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 6 +++--- components/nifogre/ogre_nif_loader.cpp | 22 +++++++++++++++------- components/nifogre/ogre_nif_loader.hpp | 23 +++-------------------- 6 files changed, 25 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 59dcd451b..b8016d087 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -43,7 +43,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); + mEntityList = NifOgre::Loader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4fddb2020..ab4c7fa7c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -11,8 +11,6 @@ #include "renderconst.hpp" -using namespace Ogre; -using namespace NifOgre; namespace MWRender { @@ -299,8 +297,8 @@ void NpcAnimation::updateParts() NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) { - NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, + mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4c3b1166b..d0087e8dc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -93,7 +93,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c8a6ca0ef..0602fc8bb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index cfc0d8397..f078d90c9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -148,8 +148,12 @@ public: }; -class NIFSkeletonLoader : public Ogre::ManualResourceLoader { - +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class NIFSkeletonLoader : public Ogre::ManualResourceLoader +{ static void warn(const std::string &msg) { std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; @@ -754,6 +758,10 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String std::map NIFMaterialLoader::MaterialMap; +/** Manual resource loader for NIF meshes. This is the main class + responsible for translating the internal NIF mesh structure into + something Ogre can use. + */ class NIFMeshLoader : Ogre::ManualResourceLoader { std::string mName; @@ -1106,7 +1114,7 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) { MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); if(meshiter != sMeshInfoMap.end()) @@ -1145,7 +1153,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; @@ -1192,9 +1200,9 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na return entitylist; } -EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { EntityList entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 4ed52a84a..f87d7d3c2 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -31,17 +31,12 @@ #include #include -namespace Nif -{ - class Node; - class Transformation; - class NiTriShape; -} +// FIXME: This namespace really doesn't do anything Nif-specific. Any supportable +// model format should go through this. namespace NifOgre { -// FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { @@ -69,19 +64,7 @@ struct MeshInfo { }; typedef std::vector MeshInfoList; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. - - You have to insert meshes manually into Ogre like this: - - NIFLoader::load("somemesh.nif"); - - This returns a list of meshes used by the model, as well as the names of - their parent nodes (as they pertain to the skeleton, which is optionally - returned in the second argument if it exists). - */ -class NIFLoader +class Loader { static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); From 7f2d71554eea9067e3077534e17f04817f0ed47c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 04:16:18 -0800 Subject: [PATCH 035/239] Use the correct offset when building static geometry from an entity --- apps/openmw/mwrender/objects.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d0087e8dc..bd5f95c24 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -193,13 +193,15 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - for(size_t i = 0;i < entities.mEntities.size();i++) + std::vector::reverse_iterator iter = entities.mEntities.rbegin(); + while(iter != entities.mEntities.rend()) { - Ogre::Entity *ent = entities.mEntities[i]; - insert->detachObject(ent); - sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + Ogre::Node *node = (*iter)->getParentNode(); + sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); - mRenderer.getScene()->destroyEntity(ent); + (*iter)->detachFromParent(); + mRenderer.getScene()->destroyEntity(*iter); + iter++; } } } From e8ac3976b58e9d93cb5f8fe9c78aae391d88e05a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 06:35:06 -0800 Subject: [PATCH 036/239] Fix some subentity assumptions --- apps/openmw/mwrender/sky.cpp | 74 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0602fc8bb..3592eb46e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -205,44 +205,48 @@ unsigned int Moon::getPhaseInt() const void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) { - // Get the vertex colour buffer of this mesh - const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); - HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - - // Lock - void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); - - // Iterate over all vertices - int vertex_size = colourBuffer->getVertexSize(); - float * currentVertex = NULL; - for (unsigned int i=0; igetNumVertices(); ++i) + for(unsigned int idx = 0;idx < ent->getNumSubEntities();idx++) { - // Get a pointer to the vertex colour - ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + Ogre::SubMesh *submesh = ent->getSubEntity(idx)->getSubMesh(); + // Get the vertex colour buffer of this mesh + const Ogre::VertexElement* ves_diffuse = submesh->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); + HardwareVertexBufferSharedPtr colourBuffer = submesh->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - unsigned char alpha=0; - if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (meshType == 1) + // Lock + void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); + + // Iterate over all vertices + int vertex_size = colourBuffer->getVertexSize(); + for (unsigned int i=0; igetNumVertices(); ++i) { - if (i>= 49 && i <= 64) alpha = 0; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row - else alpha = 255; + // Get a pointer to the vertex colour + float *currentVertex = NULL; + ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + + unsigned char alpha=0; + if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (meshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row + else alpha = 255; + } + // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 + uint8 tmpR = static_cast(255); + uint8 tmpG = static_cast(255); + uint8 tmpB = static_cast(255); + uint8 tmpA = static_cast(alpha); + + // Modify + *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); + + // Move to the next vertex + pData = static_cast (pData) + vertex_size; } - // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 - uint8 tmpR = static_cast(255); - uint8 tmpG = static_cast(255); - uint8 tmpB = static_cast(255); - uint8 tmpA = static_cast(alpha); - // Modify - *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); - - // Move to the next vertex - pData = static_cast (pData) + vertex_size; + // Unlock + colourBuffer->unlock(); } - - // Unlock - ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) @@ -356,7 +360,8 @@ void SkyManager::create() atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); - atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) + atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); ModVertexAlpha(atmosphere_ent, 0); } @@ -369,7 +374,8 @@ void SkyManager::create() Entity* clouds_ent = entities.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); + for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) + clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); clouds_ent->setCastShadows(false); ModVertexAlpha(clouds_ent, 1); From 771a5f73166d53c219cfe35763d487cda62be1df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 08:35:24 -0800 Subject: [PATCH 037/239] Add the beginnings of a character controller --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/character.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/character.cpp create mode 100644 apps/openmw/mwmechanics/character.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090..563c9e422 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells + mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp new file mode 100644 index 000000000..319c4fe9b --- /dev/null +++ b/apps/openmw/mwmechanics/character.cpp @@ -0,0 +1,26 @@ +/* + * OpenMW - The completely unofficial reimplementation of Morrowind + * + * This file (character.cpp) is part of the OpenMW package. + * + * OpenMW is distributed as free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * version 3, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 3 along with this program. If not, see + * http://www.gnu.org/licenses/ . + */ + +#include "character.hpp" + + +namespace MWMechanics +{ + +} diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp new file mode 100644 index 000000000..cab269112 --- /dev/null +++ b/apps/openmw/mwmechanics/character.hpp @@ -0,0 +1,9 @@ +#ifndef GAME_MWMECHANICS_CHARACTER_HPP +#define GAME_MWMECHANICS_CHARACTER_HPP + +namespace MWMechanics +{ + +} + +#endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 97f8c73d91a01f9682539aa0cee44b08f585caeb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 11:09:33 -0800 Subject: [PATCH 038/239] Remove some useless parameters SceneNode::setVisibility merely passes the value to its attached object, of which there are none at the point it would be called. Additionally, the method is always called with enabled=true anyway. --- apps/openmw/mwrender/actors.cpp | 33 +++++++++++++++------------------ apps/openmw/mwrender/actors.hpp | 2 +- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index fc5a46d12..ec7c9d073 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -27,14 +27,9 @@ Actors::~Actors(){ void Actors::setMwRoot(Ogre::SceneNode* root){ mMwRoot = root; } -void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ - insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); - - mAllActors[ptr] = anim; -} -void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ +void Actors::insertBegin (const MWWorld::Ptr& ptr) +{ Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -66,26 +61,28 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); - if (!enabled) - insert->setVisible (false); ptr.getRefData().setBaseNode(insert); - - } -void Actors::insertCreature (const MWWorld::Ptr& ptr){ - insertBegin(ptr, true, true); - CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); - //mAllActors.insert(std::pair(ptr,anim)); +void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) +{ + insertBegin(ptr); + NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} +void Actors::insertCreature (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; - //mAllActors.push_back(&anim);*/ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { - delete mAllActors[ptr]; - mAllActors.erase(ptr); + delete mAllActors[ptr]; + mAllActors.erase(ptr); if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode()) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 71be0bd7b..6ea6a8137 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -25,7 +25,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); - void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); + void insertBegin (const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); bool deleteObject (const MWWorld::Ptr& ptr); From 35d17fdaf65b37b48fc92edcda0d6334cd1c20b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 07:12:12 -0800 Subject: [PATCH 039/239] Associate a character controller with each MWWorld::Ptr --- apps/openmw/mwmechanics/actors.cpp | 115 ++++++++++++-------------- apps/openmw/mwmechanics/actors.hpp | 9 +- apps/openmw/mwmechanics/character.hpp | 5 ++ 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d541baea9..a7e8f0db1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,30 +166,28 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert (ptr); + mActors[ptr] = CharacterController(); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } void Actors::removeActor (const MWWorld::Ptr& ptr) { - std::set::iterator iter = mActors.find (ptr); - - if (iter!=mActors.end()) - mActors.erase (iter); + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + mActors.erase(iter); } void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { - std::set::iterator iter = mActors.begin(); - - while (iter!=mActors.end()) - if (iter->getCell()==cellStore) - { - mActors.erase (iter++); - } + PtrControllerMap::iterator iter = mActors.begin(); + while(iter != mActors.end()) + { + if(iter->first.getCell()==cellStore) + mActors.erase(iter++); else ++iter; + } } void Actors::update (std::vector >& movement, float duration, @@ -201,79 +199,72 @@ namespace MWMechanics { float totalDuration = mDuration; mDuration = 0; - - std::set::iterator iter (mActors.begin()); - while (iter!=mActors.end()) + PtrControllerMap::iterator iter(mActors.begin()); + while(iter != mActors.end()) { - if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - updateActor (*iter, totalDuration); + updateActor(iter->first, totalDuration); + if(iter->first.getTypeName() == typeid(ESM::NPC).name()) + updateNpc(iter->first, totalDuration, paused); - if (iter->getTypeName()==typeid (ESM::NPC).name()) - updateNpc (*iter, totalDuration, paused); - } - - if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) - { - // workaround: always keep player alive for now - // \todo remove workaround, once player death can be handled - if (iter->getRefData().getHandle()=="player") + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - MWMechanics::DynamicStat stat ( - MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth()); - - if (stat.getModified()<1) - { - stat.setModified (1, 0); - MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat); - } - - MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect(); - ++iter; + iter++; continue; } - - ++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)]; - - MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0); - - if (MWWorld::Class::get (*iter).isEssential (*iter)) - MWBase::Environment::get().getWindowManager()->messageBox ( - "#{sKilledEssential}", std::vector()); - - mActors.erase (iter++); } - else + + // workaround: always keep player alive for now + // \todo remove workaround, once player death can be handled + if(iter->first.getRefData().getHandle()=="player") + { + MWMechanics::DynamicStat stat ( + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).getHealth()); + + if (stat.getModified()<1) + { + stat.setModified (1, 0); + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).setHealth(stat); + } + + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); ++iter; + continue; + } + + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + + MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox( + "#{sKilledEssential}", std::vector()); + + mActors.erase(iter++); } } - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); - ++iter) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); - - if (vector!=Ogre::Vector3::ZERO) - movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } } void Actors::restoreDynamicStats() { - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) - { - calculateRestoration (*iter, 3600); - } + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const { - std::map::const_iterator iter = mDeathCount.find (id); - - if (iter!=mDeathCount.end()) + std::map::const_iterator iter = mDeathCount.find(id); + if(iter != mDeathCount.end()) return iter->second; - return 0; } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 79ae16fc3..f1e5ab437 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -6,6 +6,8 @@ #include #include +#include "character.hpp" + namespace Ogre { class Vector3; @@ -21,9 +23,10 @@ namespace MWMechanics { class Actors { - std::set mActors; - float mDuration; - std::map mDeathCount; + typedef std::map PtrControllerMap; + PtrControllerMap mActors; + float mDuration; + std::map mDeathCount; void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cab269112..c7638970d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -4,6 +4,11 @@ namespace MWMechanics { +class CharacterController +{ + +}; + } #endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 4890d901a28ff26c93fcc9a7c16f3ee2d9751718 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 08:49:08 -0800 Subject: [PATCH 040/239] Store an MWWorld::Ptr in the character controller --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a7e8f0db1..aa5119dba 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors[ptr] = CharacterController(); + mActors.insert(std::make_pair(ptr, CharacterController(ptr))); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c7638970d..1b5320375 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,12 +1,19 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include "../mwworld/ptr.hpp" + namespace MWMechanics { class CharacterController { + MWWorld::Ptr mPtr; +public: + CharacterController(const MWWorld::Ptr &ptr) + : mPtr(ptr) + { } }; } From 94b24f07e1581fbb0f3310a77537e274887f4844 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 10:10:27 -0800 Subject: [PATCH 041/239] Keep track of the state in the character controller, and don't remove dead actors from the map --- apps/openmw/mwmechanics/actors.cpp | 21 ++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa5119dba..4eae6e213 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,10 +165,13 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { - if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr))); + if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); else + { + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); + } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -205,6 +208,9 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { + if(iter->second.getState() == CharState_Dead) + iter->second.setState(CharState_Idle); + updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) updateNpc(iter->first, totalDuration, paused); @@ -234,15 +240,20 @@ namespace MWMechanics continue; } - ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(iter->second.getState() == CharState_Dead) + { + iter++; + continue; + } + iter->second.setState(CharState_Dead); MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox( "#{sKilledEssential}", std::vector()); - - mActors.erase(iter++); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1b5320375..206f6e737 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -6,14 +6,27 @@ namespace MWMechanics { +enum CharacterState { + CharState_Idle, + CharState_Dead +}; + class CharacterController { MWWorld::Ptr mPtr; + CharacterState mState; + public: - CharacterController(const MWWorld::Ptr &ptr) - : mPtr(ptr) + CharacterController(const MWWorld::Ptr &ptr, CharacterState state) + : mPtr(ptr), mState(state) { } + + CharacterState getState() const + { return mState; } + + void setState(CharacterState state) + { mState = state; } }; } From 3c02e1ccc9f82a7ede31a0634a5688aec359216a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:22:38 -0800 Subject: [PATCH 042/239] Run physics right after updating the actors --- apps/openmw/engine.cpp | 6 +----- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 3 +-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +-- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e6296ab96..b1554fc75 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -96,13 +96,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - std::vector > movement; - MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), MWBase::Environment::get().getWindowManager()->isGuiMode()); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); - // update world MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a1023c986..55eb729a4 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -52,8 +52,7 @@ namespace MWBase ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused) = 0; + virtual void update (float duration, bool paused) = 0; ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4eae6e213..485d7448b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -193,8 +193,7 @@ namespace MWMechanics } } - void Actors::update (std::vector >& movement, float duration, - bool paused) + void Actors::update (float duration, bool paused) { mDuration += duration; @@ -257,12 +256,15 @@ namespace MWMechanics } } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } + if (!paused) + MWBase::Environment::get().getWorld()->doPhysics (movement, duration); } void Actors::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f1e5ab437..faf21a12f 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -56,8 +56,7 @@ namespace MWMechanics void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. - void update (std::vector >& movement, - float duration, bool paused); + void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement void updateActor (const MWWorld::Ptr& ptr, float duration); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dae417d44..3b57c3485 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -201,8 +201,7 @@ namespace MWMechanics mWatched = ptr; } - void MechanicsManager::update (std::vector >& movement, - float duration, bool paused) + void MechanicsManager::update (float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -298,7 +297,7 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (movement, duration, paused); + mActors.update (duration, paused); } void MechanicsManager::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d3a97db36..0efe12f32 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -54,8 +54,7 @@ namespace MWMechanics ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused); + virtual void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI From c1b32d6006adb35d989808e6eb2248cce431409f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:24:20 -0800 Subject: [PATCH 043/239] Remove outdated comments --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 -- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 55eb729a4..401e360d7 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -39,8 +39,6 @@ namespace MWBase virtual void addActor (const MWWorld::Ptr& ptr) = 0; ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr) = 0; ///< Deregister an actor for stats management diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 0efe12f32..549807285 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -41,8 +41,6 @@ namespace MWMechanics virtual void addActor (const MWWorld::Ptr& ptr); ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr); ///< Deregister an actor for stats management From 63e685ea39d30fc2892166841c7776553a0548d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 09:59:19 -0800 Subject: [PATCH 044/239] Add a method to get the Animation from a Ptr --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwrender/actors.cpp | 8 ++++++++ apps/openmw/mwrender/actors.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 8 ++++++++ apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 4 ++++ 7 files changed, 34 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index b8557368d..f846c51ba 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -36,6 +36,7 @@ namespace ESM namespace MWRender { class ExternalRendering; + class Animation; } namespace MWWorld @@ -308,6 +309,9 @@ namespace MWBase /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index c36248aaf..10b654834 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -145,6 +145,14 @@ void Actors::update (float duration) iter->second->runAnimation(duration); } +Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + return iter->second; + return NULL; +} + void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 53829000c..92965a059 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -54,6 +54,8 @@ namespace MWRender /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &ptr); + + Animation* getAnimation(const MWWorld::Ptr &ptr); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fdad152e6..d1f0b17aa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -929,6 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } +Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) +{ + Animation *anim = mActors.getAnimation(ptr); + // TODO: Check mObjects too. + return anim; +} + + void RenderingManager::playVideo(const std::string& name, bool allowSkipping) { mVideoPlayer->playVideo ("video/" + name, allowSkipping); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68f2d79c3..1a7d213f3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -46,6 +46,7 @@ namespace MWRender class ExternalRendering; class GlobalMap; class VideoPlayer; + class Animation; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -196,6 +197,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); + Animation* getAnimation(const MWWorld::Ptr &ptr); + void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b..b855bab8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,6 +1374,11 @@ namespace MWWorld } + MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) + { + return mRendering->getAnimation(ptr); + } + void World::playVideo (const std::string &name, bool allowSkipping) { mRendering->playVideo(name, allowSkipping); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d87..f622144b2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -37,6 +37,7 @@ namespace MWRender { class SkyManager; class CellRender; + class Animation; } namespace MWWorld @@ -352,6 +353,9 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); From b378bc92a06422c55290be5cb9dbac6f295b145a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:16:37 -0800 Subject: [PATCH 045/239] Store an animation object in the character controller --- apps/openmw/mwmechanics/actors.cpp | 5 +++-- apps/openmw/mwmechanics/character.hpp | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 485d7448b..bd7a9cef2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,11 +165,12 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else { - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 206f6e737..8a0986117 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,6 +3,11 @@ #include "../mwworld/ptr.hpp" +namespace MWRender +{ + class Animation; +} + namespace MWMechanics { @@ -14,12 +19,13 @@ enum CharacterState { class CharacterController { MWWorld::Ptr mPtr; + MWRender::Animation *mAnimation; CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, CharacterState state) - : mPtr(ptr), mState(state) + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) { } CharacterState getState() const From 3c487e601934b7422da4683fe5953d99298da7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:45:18 -0800 Subject: [PATCH 046/239] Play an animation when changing states --- apps/openmw/mwmechanics/actors.cpp | 4 ---- apps/openmw/mwmechanics/character.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 8 ++----- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bd7a9cef2..d9a3b6878 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,10 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else - { mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); - } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -247,7 +244,6 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); - MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 319c4fe9b..6d5b92860 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,8 +19,41 @@ #include "character.hpp" +#include "../mwrender/animation.hpp" namespace MWMechanics { +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) +{ + if(!mAnimation) + return; + + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + + +void CharacterController::setState(CharacterState state) +{ + mState = state; + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a0986117..9bb3a1bfc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -24,15 +24,11 @@ class CharacterController CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) - { } + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + void setState(CharacterState state); CharacterState getState() const { return mState; } - - void setState(CharacterState state) - { mState = state; } }; } From f46587c3836d040809cd6105b3a9ef3f5b45f7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:01:08 -0800 Subject: [PATCH 047/239] Store an character controller in the animation --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/animation.cpp | 6 ++++++ apps/openmw/mwrender/animation.hpp | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6d5b92860..21ebd255a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,6 +30,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; + mAnimation->setController(this); switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8016d087..4f32de364 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -95,6 +95,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::setController(MWMechanics::CharacterController *controller) +{ + mController = controller; +} + + void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 859d2b989..ed9e4f585 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,11 @@ #include "../mwworld/ptr.hpp" +namespace MWMechanics +{ + class CharacterController; +} + namespace MWRender { @@ -26,8 +31,9 @@ class Animation protected: MWWorld::Ptr mPtr; - Ogre::SceneNode* mInsert; + MWMechanics::CharacterController *mController; + Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; Ogre::Bone *mAccumRoot; @@ -56,6 +62,7 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); + void setController(MWMechanics::CharacterController *controller); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 0a2f92f67901c06c80d9750cf40b197fd173a51d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:57:08 -0800 Subject: [PATCH 048/239] Keep track of the current text key in the animation --- apps/openmw/mwrender/animation.cpp | 27 +++++++++++++++++++++++++-- apps/openmw/mwrender/animation.hpp | 7 +++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4f32de364..69bd01e2b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -130,6 +130,11 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + + mCurGroup.mNext = mCurGroup.mStart; + while(mCurGroup.mNext->first < time) + mCurGroup.mNext++; + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); @@ -141,7 +146,8 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { - const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + times->mTextKeys = &mTextKeys[groupname]; + const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; if(textkeys.size() == 0) return false; @@ -202,6 +208,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) std::cerr<< e.what() < 0) mNextGroup = times; @@ -211,7 +218,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } @@ -230,6 +237,12 @@ void Animation::runAnimation(float timepassed) recheck: if(mTime >= mCurGroup.mLoopStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) + { + mCurGroup.mNext++; + } + if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; @@ -240,6 +253,11 @@ void Animation::runAnimation(float timepassed) } else if(mTime >= mCurGroup.mStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mStop->first) + { + mCurGroup.mNext++; + } if(mNextGroup.mLoops > 0) { updatePosition(mCurGroup.mStop->first); @@ -254,6 +272,11 @@ void Animation::runAnimation(float timepassed) mTime = mCurGroup.mStop->first; } } + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mTime) + { + mCurGroup.mNext++; + } updatePosition(mTime); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9e4f585..43cce0c02 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,16 +16,19 @@ namespace MWRender class Animation { struct GroupTimes { + NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStart; NifOgre::TextKeyMap::const_iterator mStop; NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + NifOgre::TextKeyMap::const_iterator mNext; + Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes() - : mAnimState(NULL), mLoops(0) + GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) { } }; From d2fc3c7b333f7dedd605b073dcd5a22eb853e3b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 13:09:21 -0800 Subject: [PATCH 049/239] Add a method to tell the character controller of new text keys --- apps/openmw/mwmechanics/character.cpp | 21 +++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 7 +++++++ apps/openmw/mwrender/animation.cpp | 9 +++++++++ 3 files changed, 37 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21ebd255a..6496ba9f2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" + namespace MWMechanics { @@ -42,6 +43,26 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } } +CharacterController::CharacterController(const CharacterController &rhs) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) +{ + if(!mAnimation) + return; + /* We've been copied. Update the animation with the new controller. */ + mAnimation->setController(this); +} + + +void CharacterController::markerEvent(const std::string &evt) +{ + std::string::size_type gp = evt.find(':'); + if(gp >= evt.length()-2) + { + std::cerr<< "Unexpected animation marker: \""<end() && mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } @@ -256,6 +261,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mCurGroup.mStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } if(mNextGroup.mLoops > 0) @@ -275,6 +282,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mTime) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } From 94b93227d32a9753447985a1fbc78af3c8c7230a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 14:37:32 -0800 Subject: [PATCH 050/239] Treat activators as actors for rendering and mechanics Kinda hacky, but it's the only way to get animated activators (flags, silt striders, etc) to work properly. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/activator.cpp | 9 +-- apps/openmw/mwmechanics/actors.cpp | 14 ++++- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/activatoranimation.cpp | 64 +++++++++++++++++++++ apps/openmw/mwrender/activatoranimation.hpp | 23 ++++++++ apps/openmw/mwrender/actors.cpp | 8 +++ apps/openmw/mwrender/actors.hpp | 3 +- apps/openmw/mwrender/animation.cpp | 3 + 9 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwrender/activatoranimation.cpp create mode 100644 apps/openmw/mwrender/activatoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 563c9e422..ec7700bee 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -14,8 +14,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky player animation npcanimation creatureanimation actors objects - renderinginterface localmap occlusionquery terrain terrainmaterial water shadows + renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation + actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows compositors characterpreview externalrendering globalmap videoplayer ) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 26d286aa1..292627286 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -5,12 +5,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld//cellstore.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/physicssystem.hpp" -#include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -21,9 +22,8 @@ namespace MWClass { const std::string model = getModel(ptr); if (!model.empty()) { - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, model); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr); } } @@ -32,6 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); + MWBase::Environment::get().getMechanicsManager()->addActor(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a3b6878..23272e674 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,9 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + /* Kind of a hack. Activators need a character controller to manage an idle state. */ + if(ptr.getTypeName() == typeid(ESM::Activator).name() || + !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); @@ -203,6 +205,11 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { + if(iter->first.getTypeName() == typeid(ESM::Activator).name()) + { + iter++; + continue; + } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -267,7 +274,10 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - calculateRestoration(iter->first, 3600); + { + if(iter->first.getTypeName() != typeid(ESM::Activator).name()) + calculateRestoration(iter->first, 3600); + } } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6496ba9f2..5bf468ffb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" +#include "../mwworld/class.hpp" namespace MWMechanics { diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp new file mode 100644 index 000000000..18ae31865 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -0,0 +1,64 @@ +#include "activatoranimation.hpp" + +#include +#include +#include + +#include "renderconst.hpp" + +#include "../mwbase/world.hpp" + +namespace MWRender +{ + +ActivatorAnimation::~ActivatorAnimation() +{ +} + +ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) +{ + MWWorld::LiveCellRef *ref = mPtr.get(); + + assert (ref->mBase != NULL); + if(!ref->mBase->mModel.empty()) + { + std::string mesh = "meshes\\" + ref->mBase->mModel; + + createEntityList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + { + Ogre::Entity *ent = mEntityList.mEntities[i]; + + bool transparent = false; + for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + { + Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements() && !transparent) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements() && !transparent) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } + } + } + ent->setVisibilityFlags(RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } + } +} + +void ActivatorAnimation::runAnimation(float timepassed) +{ + // Placeholder + + Animation::runAnimation(timepassed); +} + +} diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp new file mode 100644 index 000000000..f3d8d86c8 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -0,0 +1,23 @@ +#ifndef _GAME_RENDER_ACTIVATORANIMATION_H +#define _GAME_RENDER_ACTIVATORANIMATION_H + +#include "animation.hpp" + +namespace MWWorld +{ + class Ptr; +} + +namespace MWRender +{ + class ActivatorAnimation : public Animation + { + public: + ActivatorAnimation(const MWWorld::Ptr& ptr); + virtual ~ActivatorAnimation(); + + virtual void runAnimation(float timepassed); + }; +} + +#endif diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 10b654834..d62e16fa2 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include "animation.hpp" +#include "activatoranimation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" @@ -78,6 +79,13 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) delete mAllActors[ptr]; mAllActors[ptr] = anim; } +void Actors::insertActivator (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + ActivatorAnimation* anim = new ActivatorAnimation(ptr); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} bool Actors::deleteObject (const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 92965a059..4ef78c577 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -31,8 +31,9 @@ namespace MWRender void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); + void insertCreature (const MWWorld::Ptr& ptr); + void insertActivator (const MWWorld::Ptr& ptr); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5341ffd7a..978419845 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -200,6 +200,9 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; try { + if(!mEntityList.mSkelBase) + throw std::runtime_error("Attempting to animate an inanimate object"); + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; From 3c32385e17f878e72a631d976cf3ae17fb8a6cef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:00:06 -0800 Subject: [PATCH 051/239] Avoid trying to animate things that don't have animations --- apps/openmw/mwmechanics/character.cpp | 7 +++++-- apps/openmw/mwrender/animation.cpp | 17 +++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5bf468ffb..47288b0c1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,7 +29,7 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; mAnimation->setController(this); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -68,6 +68,9 @@ void CharacterController::markerEvent(const std::string &evt) void CharacterController::setState(CharacterState state) { mState = state; + + if(!mAnimation || mAnimation->getAnimationCount() == 0) + return; switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 978419845..66d64f9d4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,6 +98,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +int Animation::getAnimationCount() +{ + int num = 0; + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); + while(ai.hasMoreElements()) + { + num++; + ai.moveNext(); + } + } + return num; +} + + void Animation::setController(MWMechanics::CharacterController *controller) { mController = controller; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 43cce0c02..0e5c7e66e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,6 +66,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); + int getAnimationCount(); + void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 46728ab27ff387b46fd8b0893400218c8af10be2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:52:03 -0800 Subject: [PATCH 052/239] Handle "sound:" animation events --- apps/openmw/mwmechanics/character.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 47288b0c1..6acd9a7cf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,9 @@ #include "../mwrender/animation.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + #include "../mwworld/class.hpp" namespace MWMechanics @@ -56,11 +59,10 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - std::string::size_type gp = evt.find(':'); - if(gp >= evt.length()-2) + if(evt.compare(0, 6, "sound:") == 0) { - std::cerr<< "Unexpected animation marker: \""<playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); } } From 46fc61a4c19877a883f44d161fd95c31fc023015 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 16:31:09 -0800 Subject: [PATCH 053/239] Run animations from the character controller --- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 15 ++++++++++++--- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/actors.cpp | 3 +-- apps/openmw/mwrender/player.cpp | 3 --- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 23272e674..7205e7d54 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -263,6 +263,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + iter->second.update(duration); Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6acd9a7cf..87ed8a9e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,7 +32,9 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(mAnimation && mAnimation->getAnimationCount() == 0) + mAnimation = NULL; + if(!mAnimation) return; mAnimation->setController(this); @@ -50,7 +52,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -67,11 +69,18 @@ void CharacterController::markerEvent(const std::string &evt) } +void CharacterController::update(float duration) +{ + if(mAnimation) + mAnimation->runAnimation(duration); +} + + void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c09cb8e42..3a59ae4bb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,6 +33,8 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); + void update(float duration); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d62e16fa2..91395277b 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,8 +149,7 @@ void Actors::skipAnimation (const MWWorld::Ptr& ptr) } void Actors::update (float duration) { - for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) - iter->second->runAnimation(duration); + // Nothing to do } Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 0e4c76b0e..8f3e13039 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,9 +129,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - if (mAnimation) { - mAnimation->runAnimation(duration); - } mPlayerNode->setVisible( mVanity.enabled || mPreviewMode || !mFirstPersonView, false From d2f5a886c731fe9d20ce176f81a5b20bb80c5077 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 17:53:18 -0800 Subject: [PATCH 054/239] Handle playgroup and skipanim through mwmechanics --- apps/openmw/mwbase/mechanicsmanager.hpp | 11 +++++++++++ apps/openmw/mwbase/world.hpp | 12 ------------ apps/openmw/mwmechanics/actors.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 ++++++++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwrender/actors.cpp | 12 ------------ apps/openmw/mwrender/actors.hpp | 12 ------------ apps/openmw/mwrender/renderingmanager.cpp | 11 ----------- apps/openmw/mwrender/renderingmanager.hpp | 12 ------------ apps/openmw/mwscript/animationextensions.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.cpp | 11 ----------- apps/openmw/mwworld/worldimp.hpp | 12 ------------ 15 files changed, 61 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 401e360d7..f7bbd6a9f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -95,6 +95,17 @@ namespace MWBase virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are currently not + /// in the scene should be ignored. + /// + /// \param mode 0 normal, 1 immediate start, 2 immediate loop + /// \param count How many times the animation should be run + + virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the scene should be ignored. }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f846c51ba..c75e96a6e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -260,18 +260,6 @@ namespace MWBase ///< Create a new recrod (of type npc) in the ESM store. /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1) = 0; - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr) = 0; - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused) = 0; virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7205e7d54..749fb2665 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -288,4 +288,17 @@ namespace MWMechanics return iter->second; return 0; } + + void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.playGroup(groupName, mode, number); + } + void Actors::skipAnimation(const MWWorld::Ptr& ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.skipAnim(); + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index faf21a12f..6fed9eff7 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -68,6 +68,9 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 87ed8a9e6..21697f996 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -76,6 +76,20 @@ void CharacterController::update(float duration) } +void CharacterController::playGroup(const std::string &groupname, int mode, int count) +{ + // set mState = CharState_Idle? + if(mAnimation) + mAnimation->playGroup(groupname, mode, count); +} + +void CharacterController::skipAnim() +{ + if(mAnimation) + mAnimation->skipAnim(); +} + + void CharacterController::setState(CharacterState state) { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3a59ae4bb..24e129e38 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,9 @@ public: void update(float duration); + void playGroup(const std::string &groupname, int mode, int count); + void skipAnim(); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3b57c3485..84145eb08 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -628,4 +628,14 @@ namespace MWMechanics permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; } } + + void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + mActors.playAnimationGroup(ptr, groupName, mode, number); + } + void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) + { + mActors.skipAnimation(ptr); + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 549807285..c2bbd96cf 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -89,6 +89,9 @@ namespace MWMechanics float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 91395277b..12ebdab61 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -135,18 +135,6 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) } } -void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->playGroup(groupName, mode, number); -} -void Actors::skipAnimation (const MWWorld::Ptr& ptr) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->skipAnim(); -} void Actors::update (float duration) { // Nothing to do diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 4ef78c577..fc9fa4fbb 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -39,18 +39,6 @@ namespace MWRender void removeCell(MWWorld::CellStore* store); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - void update (float duration); /// Updates containing cell for object rendering data diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1f0b17aa..ea898e1fa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -580,17 +580,6 @@ void RenderingManager::toggleLight() setAmbientMode(); } -void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number) -{ - mActors.playAnimationGroup(ptr, groupName, mode, number); -} - -void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) -{ - mActors.skipAnimation(ptr); -} - void RenderingManager::setSunColour(const Ogre::ColourValue& colour) { if (!mSunEnabled) return; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1a7d213f3..b6c33f9c0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -167,18 +167,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList /// configure fog manually void configureFog(const float density, const Ogre::ColourValue& colour); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); ///< transform the specified bounding box (in world coordinates) into screen coordinates. /// @return packed vector4 (min_x, min_y, max_x, max_y) diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 6f9253e5d..fc52e5e16 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -9,7 +9,7 @@ #include #include -#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -27,7 +27,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->skipAnimation (ptr); + MWBase::Environment::get().getMechanicsManager()->skipAnimation (ptr); } }; @@ -54,7 +54,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, 1); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, 1); } }; @@ -87,7 +87,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b855bab8f..de4cb84ef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -903,17 +903,6 @@ namespace MWWorld return ret; } - void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number) - { - mRendering->playAnimationGroup (ptr, groupName, mode, number); - } - - void World::skipAnimation (const MWWorld::Ptr& ptr) - { - mRendering->skipAnimation (ptr); - } - void World::update (float duration, bool paused) { mWorldScene->update (duration, paused); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f622144b2..67185833f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -291,18 +291,6 @@ namespace MWWorld /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused); virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); From daad8d985963786242782bd72c7527aa02059006 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:03:39 -0800 Subject: [PATCH 055/239] Don't update the character controller while paused --- apps/openmw/mwmechanics/actors.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 749fb2665..101a0a51d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -260,16 +260,18 @@ namespace MWMechanics } } - std::vector > movement; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + if(!paused) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); - } - if (!paused) + std::vector > movement; + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + iter->second.update(duration); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + } MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + } } void Actors::restoreDynamicStats() From 685f21956001e5eeb64b5b200748ec89f6e195af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:56:13 -0800 Subject: [PATCH 056/239] Return a movement vector from the character controller update --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 101a0a51d..35bca441a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,8 +265,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + Ogre::Vector3 vector = iter->second.update(duration); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21697f996..8e5ac0a4a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -69,10 +69,11 @@ void CharacterController::markerEvent(const std::string &evt) } -void CharacterController::update(float duration) +Ogre::Vector3 CharacterController::update(float duration) { if(mAnimation) mAnimation->runAnimation(duration); + return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 24e129e38..83f42887d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,7 +33,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); - void update(float duration); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); From 4dd01b81c6cd63aa0153f2a6efb742e3b0c06a56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:14:49 -0800 Subject: [PATCH 057/239] Update mTime when updating or reseting the animation, and refactor the animation loop --- apps/openmw/mwrender/animation.cpp | 90 +++++++++++++----------------- 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 66d64f9d4..30532b624 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -124,6 +124,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; + if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the @@ -150,9 +152,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext->first < time) + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) mCurGroup.mNext++; if(mNonAccumRoot) @@ -233,7 +236,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } times.mNext = ((mode==2) ? times.mLoopStart : times.mStart); - if(mode == 0 && mCurGroup.mLoops > 0) + if(mode == 0 && mCurGroup.mAnimState) mNextGroup = times; else { @@ -241,9 +244,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); - resetPosition(mTime); + resetPosition(mCurGroup.mNext->first); } } @@ -254,62 +256,46 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mAnimState && !mSkipFrame) - { - mTime += timepassed; - recheck: - if(mTime >= mCurGroup.mLoopStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } + if(mSkipFrame) + timepassed = 0.0f; + mSkipFrame = false; - if(mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop->first); - mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; - resetPosition(mCurGroup.mLoopStart->first); - goto recheck; - } - else if(mTime >= mCurGroup.mStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } - if(mNextGroup.mLoops > 0) - { - updatePosition(mCurGroup.mStop->first); - mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - goto recheck; - } - mTime = mCurGroup.mStop->first; - } - } - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mTime) + while(mCurGroup.mAnimState && timepassed > 0.0f) + { + float targetTime = mTime + timepassed; + if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= targetTime) { + updatePosition(mCurGroup.mNext->first); + timepassed = targetTime - mTime; + if(mController) mController->markerEvent(mCurGroup.mNext->second); + if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) + { + mCurGroup.mLoops--; + resetPosition(mCurGroup.mLoopStart->first); + continue; + } + else if(mCurGroup.mNext == mCurGroup.mStop) + { + if(!mNextGroup.mAnimState) + break; + + mCurGroup.mAnimState->setEnabled(false); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mCurGroup.mStart->first); + continue; + } mCurGroup.mNext++; + continue; } - updatePosition(mTime); + updatePosition(targetTime); + timepassed = targetTime - mTime; } - mSkipFrame = false; } } From afbc9f3e41cad0dcc1c29e8ecc36af7facc27c4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:44:37 -0800 Subject: [PATCH 058/239] Keep track of the animation group currently playing --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8e5ac0a4a..8786c42e1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,10 +41,12 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } @@ -100,10 +102,12 @@ void CharacterController::setState(CharacterState state) switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 83f42887d..9070cbe29 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::string mCurrentGroup; CharacterState mState; protected: From 852aa214cc6562c6f259277fa350f99be8167906 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:16:22 -0800 Subject: [PATCH 059/239] Store the available animation names in the character controller --- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 11 ++++------- apps/openmw/mwrender/animation.hpp | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8786c42e1..c347312c2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,10 +32,13 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(mAnimation && mAnimation->getAnimationCount() == 0) + if(mAnimation) + mAnimNames = mAnimation->getAnimationNames(); + if(mAnimNames.size() == 0) + { mAnimation = NULL; - if(!mAnimation) return; + } mAnimation->setController(this); switch(mState) @@ -52,9 +55,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) + , mState(rhs.mState) { - if(!mAnimation) + if(mAnimNames.size() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -82,7 +86,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { // set mState = CharState_Idle? - if(mAnimation) + if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) mAnimation->playGroup(groupname, mode, count); } @@ -97,7 +101,7 @@ void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation) + if(mAnimNames.size() == 0) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9070cbe29..c29c39acd 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,8 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::vector mAnimNames; + std::string mCurrentGroup; CharacterState mState; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30532b624..1d628aefa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,20 +98,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -int Animation::getAnimationCount() +std::vector Animation::getAnimationNames() { - int num = 0; + std::vector anims; if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); while(ai.hasMoreElements()) - { - num++; - ai.moveNext(); - } + anims.push_back(ai.getNext()->getAnimationName()); } - return num; + return anims; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0e5c7e66e..3afe32a4b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,7 +66,7 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - int getAnimationCount(); + std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); From 7ee389f3b2006bb05aee871e5774c32d64a65b6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:25:50 -0800 Subject: [PATCH 060/239] Handle animation skipping in the character controller --- apps/openmw/mwmechanics/character.cpp | 10 +++++----- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 3 --- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c347312c2..547d9e0a5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -77,8 +77,9 @@ void CharacterController::markerEvent(const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { - if(mAnimation) + if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); + mSkipAnim = false; return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } @@ -92,8 +93,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int void CharacterController::skipAnim() { - if(mAnimation) - mAnimation->skipAnim(); + mSkipAnim = true; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c29c39acd..202e10578 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -25,6 +25,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; + bool mSkipAnim; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d628aefa..c0b6a6e1c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -24,7 +24,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mSkipFrame(false) { } @@ -246,17 +245,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } } -void Animation::skipAnim() -{ - mSkipFrame = true; -} - void Animation::runAnimation(float timepassed) { - if(mSkipFrame) - timepassed = 0.0f; - mSkipFrame = false; - while(mCurGroup.mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3afe32a4b..5dbe7b510 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,8 +48,6 @@ protected: GroupTimes mCurGroup; GroupTimes mNextGroup; - bool mSkipFrame; - /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); @@ -69,7 +67,6 @@ public: std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); - void skipAnim(); virtual void runAnimation(float timepassed); }; From 82d549e22fc1e97794c31892172263fedc792c69 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:39:14 -0800 Subject: [PATCH 061/239] Don't update the animation if time is the same --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0b6a6e1c..d10accab7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -119,6 +119,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { + if(time == mTime) + return; mCurGroup.mAnimState->setTimePosition(time); mTime = time; From da4f17859e12016cf62371ae87730c7f32b20e50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 10:16:36 -0800 Subject: [PATCH 062/239] Recognize soundgen animation markers --- apps/openmw/mwmechanics/character.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 547d9e0a5..7e5f15a9f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -67,10 +67,17 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - if(evt.compare(0, 6, "sound:") == 0) + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return; } } From 47c157303ac64e2fc1df34b1f87a4fe3fff28192 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 11:03:58 -0800 Subject: [PATCH 063/239] Filter events that do not belong to the current group --- apps/openmw/mwmechanics/character.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e5f15a9f..4385d0b9d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,6 +79,12 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } + if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + { + std::cerr<< "Event \""< Date: Thu, 17 Jan 2013 13:18:40 -0800 Subject: [PATCH 064/239] Handle the animation queue in mwmechanics --- apps/openmw/mwmechanics/character.cpp | 55 ++++++++-- apps/openmw/mwmechanics/character.hpp | 3 + apps/openmw/mwrender/animation.cpp | 123 ++++++---------------- apps/openmw/mwrender/animation.hpp | 26 +---- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 91 insertions(+), 118 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4385d0b9d..9fa2c74be 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -45,18 +45,19 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "stop"); break; } } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,12 +80,33 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } - if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + std::string::size_type ms = mCurrentGroup.length()+2; + if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) { std::cerr<< "Event \""<= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + } + else if(mAnimQueue.size() > 0) + { + if(evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front(); + mAnimation->play(mCurrentGroup, "start"); + } + } + } } @@ -101,7 +123,23 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int { // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) - mAnimation->playGroup(groupname, mode, count); + { + count = std::max(count, 1); + if(mode != 0 || mAnimQueue.size() == 0) + { + mAnimQueue.clear(); + while(count-- > 0) + mAnimQueue.push_back(groupname); + mCurrentGroup = groupname; + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + } + else if(mode == 0) + { + mAnimQueue.resize(1); + while(count-- > 0) + mAnimQueue.push_back(groupname); + } + } } void CharacterController::skipAnim() @@ -116,15 +154,16 @@ void CharacterController::setState(CharacterState state) if(mAnimNames.size() == 0) return; + mAnimQueue.clear(); switch(mState) { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 202e10578..992cb8f1f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,6 +23,9 @@ class CharacterController std::vector mAnimNames; + typedef std::deque AnimationQueue; + AnimationQueue mAnimQueue; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d10accab7..4d9ee108c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,6 +23,8 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mCurrentKeys(NULL) + , mAnimState(NULL) , mTime(0.0f) { } @@ -121,14 +123,14 @@ void Animation::updatePosition(float time) { if(time == mTime) return; - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -149,136 +151,81 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; - mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) - mCurGroup.mNext++; + mNextKey = mCurrentKeys->begin(); + while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + mNextKey++; if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } } -bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) +float Animation::findStart(const std::string &groupname, const std::string &start) { - times->mTextKeys = &mTextKeys[groupname]; - const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; - if(textkeys.size() == 0) - return false; + mNextKey = mCurrentKeys->end(); + if(mCurrentKeys->size() == 0) + return 0.0f; if(groupname == "all") { - times->mStart = times->mLoopStart = textkeys.begin(); - times->mLoopStop = times->mStop = textkeys.end(); - times->mLoopStop--; times->mStop--; - return true; + mNextKey = mCurrentKeys->begin(); + return 0.0f; } - const std::string start = groupname+": start"; - const std::string startloop = groupname+": loop start"; - const std::string stop = groupname+": stop"; - const std::string stoploop = groupname+": loop stop"; - - times->mStart = times->mLoopStart = - times->mStop = times->mLoopStop = textkeys.end(); - + std::string startmarker = groupname+": "+start; NifOgre::TextKeyMap::const_iterator iter; - for(iter = textkeys.begin();iter != textkeys.end();iter++) + for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) { - if(start == iter->second) - { - times->mStart = iter; - times->mLoopStart = iter; - } - else if(startloop == iter->second) - times->mLoopStart = iter; - else if(stoploop == iter->second) - times->mLoopStop = iter; - else if(stop == iter->second) - { - times->mStop = iter; - if(times->mLoopStop == textkeys.end()) - times->mLoopStop = iter; - return (times->mStart != textkeys.end()); - } + if(iter->second == startmarker) + return iter->first; } - - return false; + return 0.0f; } -void Animation::playGroup(std::string groupname, int mode, int loops) +void Animation::play(const std::string &groupname, const std::string &start) { - GroupTimes times; - + float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); - times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - times.mLoops = loops; + if(mAnimState) + mAnimState->setEnabled(false); + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); + mCurrentKeys = &mTextKeys[groupname]; + mAnimState->setEnabled(true); - if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + time = findStart(groupname, start); } catch(std::exception &e) { std::cerr<< e.what() <setEnabled(false); - mCurGroup = times; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mNext->first); - } + resetPosition(time); } void Animation::runAnimation(float timepassed) { - while(mCurGroup.mAnimState && timepassed > 0.0f) + while(mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; - if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= targetTime) + if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) { - updatePosition(mCurGroup.mNext->first); + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + mNextKey++; timepassed = targetTime - mTime; if(mController) - mController->markerEvent(mCurGroup.mNext->second); - if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - resetPosition(mCurGroup.mLoopStart->first); - continue; - } - else if(mCurGroup.mNext == mCurGroup.mStop) - { - if(!mNextGroup.mAnimState) - break; - - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - continue; - } - mCurGroup.mNext++; + mController->markerEvent(evt); continue; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5dbe7b510..722eccc30 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,23 +15,6 @@ namespace MWRender class Animation { - struct GroupTimes { - NifOgre::TextKeyMap *mTextKeys; - - NifOgre::TextKeyMap::const_iterator mStart; - NifOgre::TextKeyMap::const_iterator mStop; - NifOgre::TextKeyMap::const_iterator mLoopStart; - NifOgre::TextKeyMap::const_iterator mLoopStop; - - NifOgre::TextKeyMap::const_iterator mNext; - - Ogre::AnimationState *mAnimState; - size_t mLoops; - - GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) - { } - }; - protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; @@ -44,9 +27,10 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mNextKey; + Ogre::AnimationState *mAnimState; float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ @@ -55,7 +39,7 @@ protected: * object. */ void resetPosition(float time); - bool findGroupTimes(const std::string &groupname, GroupTimes *times); + float findStart(const std::string &groupname, const std::string &start); void createEntityList(Ogre::SceneNode *node, const std::string &model); @@ -66,7 +50,7 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); - void playGroup(std::string groupname, int mode, int loops); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb9954df6..cbee9c865 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->playGroup ("inventoryhandtohand", 0, 1); + mAnimation->play("inventoryhandtohand", "start"); } // -------------------------------------------------------------------------------------------------- From fc0f9e215909e15b5a09eb7edafdda4ce9dceada Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 14:49:42 -0800 Subject: [PATCH 065/239] The animation state tracks the animation time for us --- apps/openmw/mwrender/animation.cpp | 28 +++++++++++----------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d9ee108c..18aa98215 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,7 +25,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) - , mTime(0.0f) { } @@ -121,10 +120,7 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { - if(time == mTime) - return; mAnimState->setTimePosition(time); - mTime = time; if(mNonAccumRoot) { @@ -152,7 +148,6 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mAnimState->setTimePosition(time); - mTime = time; mNextKey = mCurrentKeys->begin(); while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) @@ -216,21 +211,20 @@ void Animation::runAnimation(float timepassed) { while(mAnimState && timepassed > 0.0f) { - float targetTime = mTime + timepassed; - if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) + float targetTime = mAnimState->getTimePosition() + timepassed; + if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - mNextKey++; - timepassed = targetTime - mTime; - - if(mController) - mController->markerEvent(evt); - continue; + updatePosition(targetTime); + break; } - updatePosition(targetTime); - timepassed = targetTime - mTime; + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + timepassed = targetTime - mNextKey->first; + mNextKey++; + + if(mController) + mController->markerEvent(evt); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 722eccc30..726d0cf38 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,7 +30,6 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - float mTime; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ From fef6284f15ebf7cafcfed1e3bb7e4a3727cddafe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 15:47:25 -0800 Subject: [PATCH 066/239] Only reset the animation time if a new state was set --- apps/openmw/mwrender/animation.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 18aa98215..1a464f5d8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -187,24 +187,22 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { - float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); + Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mAnimState = newstate; mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; - time = findStart(groupname, start); + resetPosition(findStart(groupname, start)); } catch(std::exception &e) { std::cerr<< e.what() < Date: Thu, 17 Jan 2013 15:48:09 -0800 Subject: [PATCH 067/239] Fix player rendering --- apps/openmw/mwrender/player.hpp | 4 +++- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 29a68ca69..e24f44d68 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -95,7 +95,9 @@ namespace MWRender /// Restore default camera distance for current mode. void setCameraDistance(); - void setAnimation(MWRender::NpcAnimation *anim); + void setAnimation(NpcAnimation *anim); + NpcAnimation *getAnimation() const + { return mAnimation; } void setHeight(float height); float getHeight(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ea898e1fa..082b561ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -921,7 +921,7 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - // TODO: Check mObjects too. + if(!anim) anim = mPlayer->getAnimation(); return anim; } From 8fa1b56efcbfc9869c9b22d14f0c1bfb72853de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 16:34:26 -0800 Subject: [PATCH 068/239] Loop the current animation if there's nothing more queued --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9fa2c74be..a42771e0b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,6 +107,11 @@ void CharacterController::markerEvent(const std::string &evt) } } } + else + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + mAnimation->play(mCurrentGroup, "loop start"); + } } @@ -130,6 +135,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,6 +144,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); } } } From 8720433fa9e171c1776db6845f93ad4c4986256b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 17:38:05 -0800 Subject: [PATCH 069/239] Do not automatically loop animations There are 0 length idle animations that break this --- apps/openmw/mwmechanics/character.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a42771e0b..0b8eff733 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,11 +107,6 @@ void CharacterController::markerEvent(const std::string &evt) } } } - else - { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) - mAnimation->play(mCurrentGroup, "loop start"); - } } From 9d7ccfda1ffa7edd79b52cc777466c55181296a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 21:07:36 -0800 Subject: [PATCH 070/239] Rename CharState_Idle to CharState_Alive --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 5 ++--- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441a..00350fcc2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Alive); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0b8eff733..4e861f35c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -121,7 +121,6 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) { count = std::max(count, 1); @@ -159,7 +158,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1f..cdbe439a4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Idle, + CharState_Alive, CharState_Dead }; From a94947029e41e0337c5163dc1d1fd7d1496fde1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 00:59:48 -0800 Subject: [PATCH 071/239] Check the marker name before deciding what to do with it Also, don't force 'idle' after a playgroup --- apps/openmw/mwmechanics/character.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4e861f35c..0767df130 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -87,17 +87,24 @@ void CharacterController::markerEvent(const std::string &evt) return; } - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); } + return; } - else if(mAnimQueue.size() > 0) + + if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) @@ -106,6 +113,7 @@ void CharacterController::markerEvent(const std::string &evt) mAnimation->play(mCurrentGroup, "start"); } } + return; } } @@ -129,7 +137,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,7 +145,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); } } } From 5cafc24ee2b619898afdda0914e4da6b79f77464 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 13:43:45 -0800 Subject: [PATCH 072/239] Rename CharState_Alive back to CharState_Idle --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00350fcc2..35bca441a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Alive); + iter->second.setState(CharState_Idle); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0767df130..96221cbb8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -164,7 +164,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cdbe439a4..992cb8f1f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Alive, + CharState_Idle, CharState_Dead }; From 3e9b0a333cea79ba76b684bdb83b086c89028432 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:25:32 -0800 Subject: [PATCH 073/239] Allow specifying the accumulation for animations Animations that move a character may do so either visually or physically. An axis' accumuluation value specifies whether the movement is visual (0) or physical (1). Idle animations, for instance, typically don't physically move a character, while death animations may physically move them along the X and Y planes, but not along Z (the vertical movement is purely visual). --- apps/openmw/mwmechanics/character.cpp | 15 ++++----------- apps/openmw/mwrender/animation.cpp | 9 ++++++++- apps/openmw/mwrender/animation.hpp | 6 ++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 96221cbb8..f5b6301a2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,17 +41,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - switch(mState) - { - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->play(mCurrentGroup, "stop"); - break; - } + setState(mState); } CharacterController::CharacterController(const CharacterController &rhs) @@ -138,6 +128,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } else if(mode == 0) @@ -166,10 +157,12 @@ void CharacterController::setState(CharacterState state) { case CharState_Idle: mCurrentGroup = "idle"; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->play(mCurrentGroup, "start"); break; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a464f5d8..b6c712522 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mInsert(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mAccumulate(Ogre::Vector3::ZERO) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) @@ -118,6 +119,12 @@ void Animation::setController(MWMechanics::CharacterController *controller) } +void Animation::setAccumulation(const Ogre::Vector3 &accum) +{ + mAccumulate = accum; +} + + void Animation::updatePosition(float time) { mAnimState->setTimePosition(time); @@ -127,7 +134,7 @@ void Animation::updatePosition(float time) /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 726d0cf38..32d51775a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -24,6 +24,7 @@ protected: std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; @@ -49,6 +50,11 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); + // Specifies the axis' to accumulate on. Non-accumulated axis will just + // move visually, but not affect the actual movement. Each x/y/z value + // should be on the scale of 0 to 1. + void setAccumulation(const Ogre::Vector3 &accum); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; From c7684cb979bc0c4791d6e88bb9cf626764ed3417 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:50:55 -0800 Subject: [PATCH 074/239] Pass the key time to markerEvent --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5b6301a2..241033802 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const CharacterController &rhs) } -void CharacterController::markerEvent(const std::string &evt) +void CharacterController::markerEvent(float time, const std::string &evt) { if(evt.compare(0, 7, "sound: ") == 0) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1f..902b8cc36 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,7 +32,7 @@ class CharacterController protected: /* Called by the animation whenever a new text key is reached. */ - void markerEvent(const std::string &evt); + void markerEvent(float time, const std::string &evt); friend class MWRender::Animation; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b6c712522..cfc72de37 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -223,13 +223,15 @@ void Animation::runAnimation(float timepassed) break; } + float time = mNextKey->first; const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - timepassed = targetTime - mNextKey->first; mNextKey++; + updatePosition(time); + timepassed = targetTime - time; + if(mController) - mController->markerEvent(evt); + mController->markerEvent(time, evt); } } From a527cb8349fd1b4e6b0fa12ac70ab83bb78d4449 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:22:14 -0800 Subject: [PATCH 075/239] Loop the current animation when not dead This should be better, but it's not perfect. It misses the case where start < loop start == loop stop <= stop --- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 241033802..97cdf3f49 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); @@ -89,7 +94,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); From 40f8e757637927d631ff97aa4a14d0b7c911bddf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:39:28 -0800 Subject: [PATCH 076/239] Use a SpecialIdle state for PlayGroup/LoopGroup invoked animations Note that actors will *not* automatically resume a normal idle state afterward. Their AI will need to control what to do when the special idle is finished. --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 97cdf3f49..73a6f2c9c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -138,6 +138,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mState = CharState_SpecialIdle; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -165,6 +166,8 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { + case CharState_SpecialIdle: + break; case CharState_Idle: mCurrentGroup = "idle"; mAnimation->setAccumulation(Ogre::Vector3::ZERO); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 902b8cc36..47bb27e83 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,6 +12,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_Dead }; From 9235fba77058e5ade49e5b64f988694ecfde2c2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:00:51 -0800 Subject: [PATCH 077/239] Store the movement vector in the character controller --- apps/openmw/mwmechanics/actors.cpp | 6 ++++++ apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441a..396f34eab 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,6 +262,12 @@ namespace MWMechanics if(!paused) { + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setDirection(dir); + } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 73a6f2c9c..ff400b9d1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); mSkipAnim = false; - return MWWorld::Class::get(mPtr).getMovementVector(mPtr); + return mDirection; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 47bb27e83..c151b3b9f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include + #include "../mwworld/ptr.hpp" namespace MWRender @@ -27,6 +29,8 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; + Ogre::Vector3 mDirection; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; @@ -46,6 +50,9 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + void setState(CharacterState state); CharacterState getState() const { return mState; } From 9123f4f2afdc7738087dadf59ee5ddee342ea9e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:21:29 -0800 Subject: [PATCH 078/239] Return the movement vector from runAnimation --- apps/openmw/mwrender/activatoranimation.cpp | 7 ------- apps/openmw/mwrender/activatoranimation.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 14 +++++++++----- apps/openmw/mwrender/animation.hpp | 4 ++-- apps/openmw/mwrender/creatureanimation.cpp | 12 ++---------- apps/openmw/mwrender/creatureanimation.hpp | 2 -- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.hpp | 2 +- 8 files changed, 16 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 18ae31865..f951307b6 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -54,11 +54,4 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) } } -void ActivatorAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index f3d8d86c8..f3ea38f44 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: ActivatorAnimation(const MWWorld::Ptr& ptr); virtual ~ActivatorAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cfc72de37..f9fa6e14c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -125,16 +125,17 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } -void Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition(float time) { mAnimState->setTimePosition(time); + Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); @@ -150,6 +151,7 @@ void Animation::updatePosition(float time) world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); } } + return posdiff; } void Animation::resetPosition(float time) @@ -212,14 +214,15 @@ void Animation::play(const std::string &groupname, const std::string &start) } } -void Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float timepassed) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - updatePosition(targetTime); + movement += updatePosition(targetTime); break; } @@ -227,12 +230,13 @@ void Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - updatePosition(time); + movement += updatePosition(time); timepassed = targetTime - time; if(mController) mController->markerEvent(time, evt); } + return movement; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32d51775a..dfa2950f3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -34,7 +34,7 @@ protected: /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ - void updatePosition(float time); + Ogre::Vector3 updatePosition(float time); /* Updates the animation to the specified time, without moving the mPtr * object. */ void resetPosition(float time); @@ -56,7 +56,7 @@ public: void setAccumulation(const Ogre::Vector3 &accum); void play(const std::string &groupname, const std::string &start); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index caa040d95..34b09c0d0 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -8,9 +8,8 @@ #include "../mwbase/world.hpp" -using namespace Ogre; -using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ CreatureAnimation::~CreatureAnimation() { @@ -55,11 +54,4 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } } -void CreatureAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 5456f857f..0c277d198 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: CreatureAnimation(const MWWorld::Ptr& ptr); virtual ~CreatureAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f309ee899..432a2f526 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -308,7 +308,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int return entities; } -void NpcAnimation::runAnimation(float timepassed) +Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { if(mTimeToChange > .2) { @@ -317,7 +317,7 @@ void NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - Animation::runAnimation(timepassed); + return Animation::runAnimation(timepassed); } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 161091317..a4e87e722 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -98,7 +98,7 @@ public: MWWorld::InventoryStore& inv, int visibilityFlags); virtual ~NpcAnimation(); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); void forceUpdate(); }; From 1cdd64cd9b0c90cc8b0c78e4e21a3cd90c525df3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:05:58 -0800 Subject: [PATCH 079/239] Return the animation movement from the character controller. Consequently, dead actors don't move anymore. The doPhysics call apparently isn't moving them. --- apps/openmw/mwmechanics/character.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 7 +++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ff400b9d1..226f00069 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -120,10 +120,25 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) - mAnimation->runAnimation(duration); + movement += mAnimation->runAnimation(duration); mSkipAnim = false; - return mDirection; + + if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead) + { + // FIXME: mDirection shouldn't influence the movement here. + movement += mDirection; + } + else + { + // FIXME: mDirection should be normalized after setting the speed of + // the animation in setDirection, rather than here. + movement = mDirection.normalisedCopy() * movement.length(); + } + + return movement; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f9fa6e14c..4d8f9586f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -140,16 +140,6 @@ Ogre::Vector3 Animation::updatePosition(float time) /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - - if(mPtr.isInCell()) - { - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); - } } return posdiff; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dfa2950f3..349871f0a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,11 +32,10 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - /* Updates the animation to the specified time, and moves the mPtr object - * based on the change since the last update or reset. */ + /* Updates the animation to the specified time, and returns the movement + * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving the mPtr - * object. */ + /* Updates the animation to the specified time, without moving anything. */ void resetPosition(float time); float findStart(const std::string &groupname, const std::string &start); From e33f59e0feb124b5436f9ed1b34bbf43bf5f933f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:41:36 -0800 Subject: [PATCH 080/239] Ensure the direction vector is initialized and copied properly --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 226f00069..b6adec068 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; From aecfc0829a70a5539b6e86af91fd73a305888e9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 18:04:00 -0800 Subject: [PATCH 081/239] Implement WalkForward and WalkBack character states --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++++++++++ apps/openmw/mwmechanics/character.cpp | 12 ++++++++++++ apps/openmw/mwmechanics/character.hpp | 4 ++++ 3 files changed, 32 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 396f34eab..b09bcac4d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -251,6 +251,7 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); + iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -264,7 +265,22 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + if(iter->second.getState() == CharState_Dead) + continue; + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + CharacterState newstate = CharState_Idle; + + if(dir.length() >= 0.1f) + { + if(dir.y < 0.0f) + newstate = CharState_WalkBack; + else + newstate = CharState_WalkForward; + } + + if(iter->second.getState() != newstate) + iter->second.setState(newstate); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6adec068..f3a1f2fba 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -188,6 +188,18 @@ void CharacterController::setState(CharacterState state) mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; + + case CharState_WalkForward: + mCurrentGroup = "walkforward"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_WalkBack: + mCurrentGroup = "walkback"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_Dead: mCurrentGroup = "death1"; mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c151b3b9f..f2651b4cf 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -16,6 +16,10 @@ namespace MWMechanics enum CharacterState { CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, + + CharState_WalkForward, + CharState_WalkBack, + CharState_Dead }; From 0b68953f0d7b4c60e83c2be4e3c3cb4715c0178c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 21:40:47 -0800 Subject: [PATCH 082/239] Scale animation speed using the direction length The direction length doesn't currently give a good speed, but it's something. --- apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 3 +-- apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 4 ++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f3a1f2fba..ad784d34f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -118,6 +118,17 @@ void CharacterController::markerEvent(float time, const std::string &evt) } +void CharacterController::setDirection(const Ogre::Vector3 &dir) +{ + // HACK: The direction length we get is too large. + float mult = dir.length() / 32.0f; + mult = std::max(1.0f, mult); + if(mAnimation) + mAnimation->setSpeedMult(mult); + mDirection = dir.normalisedCopy(); +} + + Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; @@ -125,17 +136,10 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead) + if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead)) { - // FIXME: mDirection shouldn't influence the movement here. - movement += mDirection; - } - else - { - // FIXME: mDirection should be normalized after setting the speed of - // the animation in setDirection, rather than here. - movement = mDirection.normalisedCopy() * movement.length(); + movement = mDirection * movement.length(); } return movement; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f2651b4cf..9a82f890d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -54,8 +54,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir) - { mDirection = dir; } + void setDirection(const Ogre::Vector3 &dir); void setState(CharacterState state); CharacterState getState() const diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d8f9586f..a86e14c83 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mAnimSpeedMult(1.0f) { } @@ -207,6 +208,7 @@ void Animation::play(const std::string &groupname, const std::string &start) Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 349871f0a..6c8357d59 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ @@ -54,6 +55,9 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); + void setSpeedMult(float speedmult) + { mAnimSpeedMult = speedmult; } + void play(const std::string &groupname, const std::string &start); virtual Ogre::Vector3 runAnimation(float timepassed); }; From de2d084e6182b5c9ff328491f32a43f28b6624a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:22:15 -0800 Subject: [PATCH 083/239] Add a looping property to handle if an animation should loop --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ apps/openmw/mwmechanics/character.hpp | 5 +++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b09bcac4d..76e02ed36 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,9 +169,9 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) @@ -250,7 +250,7 @@ namespace MWMechanics continue; } - iter->second.setState(CharState_Dead); + iter->second.setState(CharState_Dead, false); iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -280,7 +280,7 @@ namespace MWMechanics } if(iter->second.getState() != newstate) - iter->second.setState(newstate); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ad784d34f..5127b6564 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,8 @@ namespace MWMechanics { -CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -41,13 +41,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState); + setState(mState, loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mLoop(rhs.mLoop) { if(mAnimNames.size() == 0) return; @@ -81,7 +82,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -96,7 +97,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -158,6 +159,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; + mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -176,9 +178,10 @@ void CharacterController::skipAnim() } -void CharacterController::setState(CharacterState state) +void CharacterController::setState(CharacterState state, bool loop) { mState = state; + mLoop = loop; if(mAnimNames.size() == 0) return; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9a82f890d..d773c85b2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -38,6 +38,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; + bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ @@ -46,7 +47,7 @@ protected: friend class MWRender::Animation; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); Ogre::Vector3 update(float duration); @@ -56,7 +57,7 @@ public: void setDirection(const Ogre::Vector3 &dir); - void setState(CharacterState state); + void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } }; From e0541b52c4321a8535516590de0df40ec0d98436 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:56:24 -0800 Subject: [PATCH 084/239] Use a list to store and get state information --- apps/openmw/mwmechanics/character.cpp | 67 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5127b6564..a49400823 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,6 +19,8 @@ #include "character.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" @@ -29,6 +31,35 @@ namespace MWMechanics { +static const struct { + CharacterState state; + const char groupname[32]; + Ogre::Vector3 accumulate; +} sStateList[] = { + { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + + { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + + { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, +}; +static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); + +static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +{ + for(size_t i = 0;i < sStateListSize;i++) + { + if(sStateList[i].state == state) + { + *group = sStateList[i].groupname; + *accum = sStateList[i].accumulate; + return; + } + } + throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); +} + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { @@ -41,7 +72,11 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState, loop); + + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) @@ -186,33 +221,11 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimNames.size() == 0) return; mAnimQueue.clear(); - switch(mState) - { - case CharState_SpecialIdle: - break; - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkForward: - mCurrentGroup = "walkforward"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkBack: - mCurrentGroup = "walkback"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - } + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); } } From a7b07ee5cf2ed697ce43dbe0283ac7554c106010 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 15:44:57 -0800 Subject: [PATCH 085/239] Don't reset the animation when setting the same state Unless looping is being toggled on. --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76e02ed36..8c6da4a31 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -279,8 +279,7 @@ namespace MWMechanics newstate = CharState_WalkForward; } - if(iter->second.getState() != newstate) - iter->second.setState(newstate, true); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a49400823..7e52ef3d8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -215,8 +215,18 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { - mState = state; - mLoop = loop; + if(mState == state) + { + // If setting the same state again, only reset the animation if looping + // is being turned on. + if(mLoop == loop || !(mLoop=loop)) + return; + } + else + { + mState = state; + mLoop = loop; + } if(mAnimNames.size() == 0) return; From 68779375b2aa6dd1e722d2460c15d37a17403aed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 16:19:47 -0800 Subject: [PATCH 086/239] Implement WalkLeft and WalkRight character states --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++++- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwmechanics/character.hpp | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8c6da4a31..6c69c457b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -273,7 +273,14 @@ namespace MWMechanics if(dir.length() >= 0.1f) { - if(dir.y < 0.0f) + if(std::abs(dir.x/2.0f) > std::abs(dir.y)) + { + if(dir.x > 0.0f) + newstate = CharState_WalkRight; + else if(dir.x < 0.0f) + newstate = CharState_WalkLeft; + } + else if(dir.y < 0.0f) newstate = CharState_WalkBack; else newstate = CharState_WalkForward; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e52ef3d8..262945c02 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,6 +41,8 @@ static const struct { { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d773c85b2..6d8b3386c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -19,6 +19,8 @@ enum CharacterState { CharState_WalkForward, CharState_WalkBack, + CharState_WalkLeft, + CharState_WalkRight, CharState_Dead }; From 85ca1e993f312594f4e0a77b12d3be625f218f46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 21:55:04 -0800 Subject: [PATCH 087/239] Properly check if an animation exists before playing it --- apps/openmw/mwmechanics/character.cpp | 34 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 18 +++----------- apps/openmw/mwrender/animation.hpp | 3 ++- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 262945c02..ea934a284 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -65,29 +65,24 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { - if(mAnimation) - mAnimNames = mAnimation->getAnimationNames(); - if(mAnimNames.size() == 0) - { - mAnimation = NULL; + if(!mAnimation) return; - } mAnimation->setController(this); Ogre::Vector3 accum; getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "stop"); + if(mAnimation->hasAnimation(mCurrentGroup)) + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) - , mLoop(rhs.mLoop) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) + , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) { - if(mAnimNames.size() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -186,7 +181,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) + if(mAnimation && mAnimation->hasAnimation(groupname)) { count = std::max(count, 1); if(mode != 0 || mAnimQueue.size() == 0) @@ -230,14 +225,19 @@ void CharacterController::setState(CharacterState state, bool loop) mLoop = loop; } - if(mAnimNames.size() == 0) + if(!mAnimation) return; mAnimQueue.clear(); + std::string anim; Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + getStateInfo(mState, &anim, &accum); + if(mAnimation->hasAnimation(anim)) + { + mCurrentGroup = anim; + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); + } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6d8b3386c..43ff21dfb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -30,8 +30,6 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - std::vector mAnimNames; - typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a86e14c83..67be0bf0c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -100,17 +100,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -std::vector Animation::getAnimationNames() +bool Animation::hasAnimation(const std::string &anim) { - std::vector anims; - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); - while(ai.hasMoreElements()) - anims.push_back(ai.getNext()->getAnimationName()); - } - return anims; + return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); } @@ -188,13 +180,9 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { try { - if(!mEntityList.mSkelBase) - throw std::runtime_error("Attempting to animate an inanimate object"); - - Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = newstate; + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6c8357d59..50ddc34d5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,7 +48,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - std::vector getAnimationNames(); + + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value From e1e76bde76fd441f867d20d412c9bfd2e53808aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 15:39:43 -0800 Subject: [PATCH 088/239] Combine a loop into another where it's used --- apps/openmw/mwrender/animation.cpp | 38 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 67be0bf0c..4884712c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -67,34 +67,32 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty()) - { - mTextKeys["all"] = Ogre::any_cast(data); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty()) + continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mTextKeys["all"] = Ogre::any_cast(data); - mStartPosition = mNonAccumRoot->getPosition(); - mLastPosition = mStartPosition; - break; - } - boneiter.moveNext(); - } + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; - if(boneiter.hasMoreElements()) - { asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { Ogre::AnimationState *state = asiter.getNext(); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); - if(!data.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+state->getAnimationName()); + if(!groupdata.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); } + + break; } } } From 536f8104e687d04d38fcee4c1f7b9b3218d56630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 17:24:43 -0800 Subject: [PATCH 089/239] Do not create an 'all' animation. --- apps/openmw/mwrender/animation.cpp | 4 +--- components/nifogre/ogre_nif_loader.cpp | 29 ++++++++------------------ 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4884712c3..75a441a9c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -70,11 +70,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) + if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mTextKeys["all"] = Ogre::any_cast(data); - mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 372c38e0f..357866c7c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -308,7 +308,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -341,7 +341,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); + textkeys = extractTextKeys(tk); + nonaccum = bone; } e = e->extra; } @@ -353,7 +354,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector(nif.getRecord(0)); std::vector ctrls; + Ogre::Bone *nonaccum = NULL; + TextKeyMap textkeys; try { - buildBones(skel, node, ctrls); + buildBones(skel, node, nonaccum, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); - if(!data.isEmpty()) - { - textkeys = Ogre::any_cast(data); - break; - } - boneiter.moveNext(); - } - - buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); @@ -459,7 +449,6 @@ void loadResource(Ogre::Resource *resource) groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 8e8900e4221d015aa10f69344584f139dc00a86f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 22:51:39 -0800 Subject: [PATCH 090/239] Use the first bone with text keys as the nonaccum root. --- components/nifogre/ogre_nif_loader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 357866c7c..890dcf7e9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -320,8 +320,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc bone = skel->createBone(); if(parent) parent->addChild(bone); - if(!node->boneTrafo) - bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); @@ -338,7 +336,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); From 6905bd18ba09abc64a3a9b157d9309a36fd34d17 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 02:59:12 -0800 Subject: [PATCH 091/239] Filter out the group name from the text keys It's already in the animation name, and the text keys are animation-specific anyway. --- apps/openmw/mwmechanics/character.cpp | 10 ++-------- components/nifogre/ogre_nif_loader.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea934a284..bc065d9d6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,14 +103,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) // to this actor type return; } - std::string::size_type ms = mCurrentGroup.length()+2; - if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) - { - std::cerr<< "Event \""<first - keyiter->first, insiter->second)); + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, + insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From e956a1cbc0e9c28aef893cedde957dc41c744f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 03:24:52 -0800 Subject: [PATCH 092/239] Merge SpecialIdle character state into Idle --- apps/openmw/mwmechanics/character.cpp | 19 +++++++------------ apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bc065d9d6..d0cbf0477 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -36,8 +36,7 @@ static const struct { const char groupname[32]; Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, @@ -163,8 +162,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() == CharState_Dead)) { movement = mDirection * movement.length(); } @@ -175,7 +173,9 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(mAnimation && mAnimation->hasAnimation(groupname)) + if(!mAnimation || !mAnimation->hasAnimation(groupname)) + std::cerr<< "Animation "< 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_SpecialIdle; + mState = CharState_Idle; mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); @@ -207,12 +207,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - // If setting the same state again, only reset the animation if looping - // is being turned on. - if(mLoop == loop || !(mLoop=loop)) - return; - } + return; else { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 43ff21dfb..ec9102f9f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,7 +14,6 @@ namespace MWMechanics { enum CharacterState { - CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_WalkForward, From 37fe1bd3f0f6e254501dca6c644bc2f69cac7c3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 22:51:13 -0800 Subject: [PATCH 093/239] Handle looping in the Animation object --- apps/openmw/mwmechanics/character.cpp | 44 ++++++----------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 31 +++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 ++- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d0cbf0477..83326d25a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -61,8 +61,9 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); } + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(!mAnimation) return; @@ -73,13 +74,13 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop"); + mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -103,32 +104,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) return; } - if(evt == "loop stop") - { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); - } - return; - } - if(evt == "stop") { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); + mAnimation->play(mCurrentGroup, "loop start", false); } else if(mAnimQueue.size() > 0) { @@ -136,7 +117,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", false); } } return; @@ -185,9 +166,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) { @@ -208,11 +188,7 @@ void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) return; - else - { - mState = state; - mLoop = loop; - } + mState = state; if(!mAnimation) return; @@ -225,7 +201,7 @@ void CharacterController::setState(CharacterState state, bool loop) { mCurrentGroup = anim; mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index ec9102f9f..53349c841 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -37,7 +37,6 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; - bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 75a441a9c..45f7ab2e4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -173,7 +174,7 @@ float Animation::findStart(const std::string &groupname, const std::string &star } -void Animation::play(const std::string &groupname, const std::string &start) +void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { if(mAnimState) @@ -181,6 +182,7 @@ void Animation::play(const std::string &groupname, const std::string &start) mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; + mLooping = loop; resetPosition(findStart(groupname, start)); } @@ -209,6 +211,33 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) movement += updatePosition(time); timepassed = targetTime - time; + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + continue; + } + if(evt == "loop stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + continue; + } + if(evt == "stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + else if(mController) + mController->markerEvent(time, evt); + continue; + } if(mController) mController->markerEvent(time, evt); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 50ddc34d5..839813576 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,8 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mLooping; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement @@ -59,7 +61,7 @@ public: void setSpeedMult(float speedmult) { mAnimSpeedMult = speedmult; } - void play(const std::string &groupname, const std::string &start); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cbee9c865..5a1a93311 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start"); + mAnimation->play("inventoryhandtohand", "start", false); } // -------------------------------------------------------------------------------------------------- From d836b3d0ffbd9085bf06724b0aa59967982d627e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:24:57 -0800 Subject: [PATCH 094/239] Don't try to create animations if there's no text keys and nonaccum node. Such meshes apparently use NiBSAnimationNode, a Bethesda-specific extension which has animation-related info in its flags (values currently unknown). --- components/nifogre/ogre_nif_loader.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4ae9c79f3..adc05f7e7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -414,6 +414,13 @@ void loadResource(Ogre::Resource *resource) return; } + if(!nonaccum) + { + warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ + skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + return; + } + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From 05f8b8c28383dd21eb60d1042a0ba353c6503830 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:31:45 -0800 Subject: [PATCH 095/239] Specify the text key to reset animations to --- apps/openmw/mwrender/animation.cpp | 45 ++++++++++-------------------- apps/openmw/mwrender/animation.hpp | 6 ++-- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f7ab2e4..5a5761faa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -134,14 +134,20 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::resetPosition(float time) +void Animation::reset(const std::string &marker) { - mAnimState->setTimePosition(time); - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mAnimState->setTimePosition(mNextKey->first); + else + { + mNextKey = mCurrentKeys->begin(); + mAnimState->setTimePosition(0.0f); + } + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); @@ -151,29 +157,6 @@ void Animation::resetPosition(float time) } -float Animation::findStart(const std::string &groupname, const std::string &start) -{ - mNextKey = mCurrentKeys->end(); - if(mCurrentKeys->size() == 0) - return 0.0f; - - if(groupname == "all") - { - mNextKey = mCurrentKeys->begin(); - return 0.0f; - } - - std::string startmarker = groupname+": "+start; - NifOgre::TextKeyMap::const_iterator iter; - for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) - { - if(iter->second == startmarker) - return iter->first; - } - return 0.0f; -} - - void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { @@ -181,10 +164,10 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; - - resetPosition(findStart(groupname, start)); + reset(start); } catch(std::exception &e) { std::cerr<< e.what() <getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } @@ -230,7 +213,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 839813576..ed9c6eb19 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,10 +38,10 @@ protected: /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving anything. */ - void resetPosition(float time); - float findStart(const std::string &groupname, const std::string &start); + /* Resets the animation to the time of the specified marker, without moving + * anything. If the marker is not found, it resets to the beginning. */ + void reset(const std::string &marker); void createEntityList(Ogre::SceneNode *node, const std::string &model); From b1ffdf855fbab4df838a86e3f310c876261dc000 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Jan 2013 04:48:53 -0800 Subject: [PATCH 096/239] Reset the initial state of animated nodes on the skeleton instances This is so the animation specifies node keyframe data based on the node's parent. This will also be necessary for applying animations from different skeleton sources, as they can have different binding positions (even native .skeleton resources will need to specify animation data this way). --- apps/openmw/mwrender/animation.cpp | 22 +++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5a5761faa..a36155dbe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,7 +78,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mStartPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; asiter = aset->getAnimationStateIterator(); @@ -93,6 +93,26 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } + + // Reset initial state of bones that are animated, so the animation correctly applies. + if(skelinst->getNumAnimations() > 0) + { + Ogre::Animation *anim = skelinst->getAnimation(0); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) + { + const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); + const Ogre::Node *srcbone = dynamic_cast(srcnode); + if(!srcbone || !skelinst->hasBone(srcbone->getName())) + continue; + + Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3(1.0f)); + bone->setInitialState(); + } + } } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index adc05f7e7..ce0fb00fc 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -193,19 +193,16 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - const Ogre::Quaternion &startquat = bone->getInitialOrientation(); - const Ogre::Vector3 &starttrans = bone->getInitialPosition(); - const Ogre::Vector3 &startscale = bone->getInitialScale(); Ogre::Quaternion lastquat, curquat; Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); Ogre::Vector3 lastscale(1.0f), curscale(1.0f); if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = startquat.Inverse() * quatiter->mValue; + lastquat = curquat = quatiter->mValue; if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue - starttrans; + lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); float begTime = std::max(kfc->timeStart, startTime); float endTime = std::min(kfc->timeStop, stopTime); bool didlast = false; @@ -235,19 +232,19 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const { lastquat = curquat; if(++quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue; + curquat = quatiter->mValue; } while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) { lasttrans = curtrans; if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; + curtrans = traniter->mValue; } while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) { lastscale = curscale; if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + curscale = Ogre::Vector3(scaleiter->mValue); } Ogre::TransformKeyFrame *kframe; From 7b71b4eb31c53beaa13fd369d3d831b3508810c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Jan 2013 03:03:48 -0800 Subject: [PATCH 097/239] Add a missing include --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5d9250ab6..0888a4522 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,6 +16,7 @@ #include "player.hpp" #include "manualref.hpp" #include "cellfunctors.hpp" +#include "containerstore.hpp" using namespace Ogre; From e1d39331454e5839e4248941f7b4037e0755b69e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 01:27:12 -0800 Subject: [PATCH 098/239] Remove an unused struct --- components/nifogre/ogre_nif_loader.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ce0fb00fc..e5e949d0e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -355,15 +355,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc } -/* Comparitor to help sort Key<> vectors */ -template -struct KeyTimeSort -{ - bool operator()(const Nif::KeyT &lhs, const Nif::KeyT &rhs) const - { return lhs.mTime < rhs.mTime; } -}; - - typedef std::map LoaderMap; static LoaderMap sLoaders; From 7df4d0d19fdb081fb6e813c7c327ad38695a8da1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 21:41:51 -0800 Subject: [PATCH 099/239] Remove an unnecessary cast --- apps/openmw/mwrender/animation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a36155dbe..c4439841f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -102,11 +102,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(trackiter.hasMoreElements()) { const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - const Ogre::Node *srcbone = dynamic_cast(srcnode); - if(!srcbone || !skelinst->hasBone(srcbone->getName())) + if(!skelinst->hasBone(srcnode->getName())) continue; - Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); bone->setOrientation(Ogre::Quaternion::IDENTITY); bone->setPosition(Ogre::Vector3::ZERO); bone->setScale(Ogre::Vector3(1.0f)); From 487c83e94305efb7becf4682feb9c80e9998f99d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 22:09:41 -0800 Subject: [PATCH 100/239] Rename nonaccum to animroot --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e5e949d0e..8dbfbff5a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -305,7 +305,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -326,18 +326,18 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc while(!ctrl.empty()) { if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); + ctrls.push_back(static_cast(ctrl.getPtr())); ctrl = ctrl->next; } Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); - nonaccum = bone; + animroot = bone; } e = e->extra; } @@ -349,7 +349,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), nonaccum, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); } } } @@ -369,10 +369,10 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - Ogre::Bone *nonaccum = NULL; + Ogre::Bone *animroot = NULL; TextKeyMap textkeys; try { - buildBones(skel, node, nonaccum, textkeys, ctrls); + buildBones(skel, node, animroot, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getName()+", but no text keys. Uses NiBSAnimationNode?"); return; } - Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; From 8d98f3649c356dd0e88fba1397d0ccb5cca47f22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 23:39:11 -0800 Subject: [PATCH 101/239] Use a separate class to handle activator mechanics --- apps/openmw/CMakeLists.txt | 5 +- apps/openmw/mwbase/mechanicsmanager.hpp | 14 ++--- apps/openmw/mwclass/activator.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 62 +++++++++++++++++++ apps/openmw/mwmechanics/activators.hpp | 42 +++++++++++++ apps/openmw/mwmechanics/actors.cpp | 14 +---- .../mwmechanics/mechanicsmanagerimp.cpp | 45 +++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 19 +++--- apps/openmw/mwworld/scene.cpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 9 ++- 12 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 apps/openmw/mwmechanics/activators.cpp create mode 100644 apps/openmw/mwmechanics/activators.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ec7700bee..73baa4e72 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,8 +62,9 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate + mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f7bbd6a9f..ec616fcaf 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -37,21 +37,21 @@ namespace MWBase virtual ~MechanicsManager() {} - virtual void addActor (const MWWorld::Ptr& ptr) = 0; - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr) = 0; + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr) = 0; - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr) = 0; + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore) = 0; - ///< Deregister all actors in the given cell. + virtual void drop (const MWWorld::CellStore *cellStore) = 0; + ///< Deregister all objects in the given cell. virtual void watchActor (const MWWorld::Ptr& ptr) = 0; ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused) = 0; - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 292627286..3a60d9c39 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -32,7 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7b0f9f728..90dc70715 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -97,7 +97,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cfbc64b87..6069e3b7c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -142,7 +142,7 @@ namespace MWClass void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Npc::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp new file mode 100644 index 000000000..799d7ecd5 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.cpp @@ -0,0 +1,62 @@ +#include "activators.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Activators::Activators() +{ +} + +void Activators::addActivator (const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Activators::removeActivator (const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + mActivators.erase(iter); +} + +void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mActivators.begin(); + while(iter != mActivators.end()) + { + if(iter->first.getCell()==cellStore) + mActivators.erase(iter++); + else + ++iter; + } +} + +void Activators::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) + iter->second.update(duration); + } +} + +void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.playGroup(groupName, mode, number); +} +void Activators::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp new file mode 100644 index 000000000..3ddb0f843 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.hpp @@ -0,0 +1,42 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Activators + { + typedef std::map PtrControllerMap; + PtrControllerMap mActivators; + + public: + Activators(); + + void addActivator (const MWWorld::Ptr& ptr); + ///< Register an activator + + void removeActivator (const MWWorld::Ptr& ptr); + ///< Deregister an activator + + void dropActivators (const MWWorld::CellStore *cellStore); + ///< Deregister all activators in the given cell. + + void update (float duration, bool paused); + ///< Update activator animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6c69c457b..98ae3e755 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,9 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - /* Kind of a hack. Activators need a character controller to manage an idle state. */ - if(ptr.getTypeName() == typeid(ESM::Activator).name() || - !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, true))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); @@ -205,11 +203,6 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { - if(iter->first.getTypeName() == typeid(ESM::Activator).name()) - { - iter++; - continue; - } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -304,10 +297,7 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->first.getTypeName() != typeid(ESM::Activator).name()) - calculateRestoration(iter->first, 3600); - } + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 84145eb08..3e56cbcb1 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -175,33 +175,37 @@ namespace MWMechanics buildPlayer(); } - void MechanicsManager::addActor (const MWWorld::Ptr& ptr) + void MechanicsManager::add(const MWWorld::Ptr& ptr) { - mActors.addActor (ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.addActivator(ptr); + else + mActors.addActor(ptr); } - void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) + void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - if (ptr==mWatched) + if(ptr == mWatched) + mWatched = MWWorld::Ptr(); + mActors.removeActor(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) + { + if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) mWatched = MWWorld::Ptr(); - mActors.removeActor (ptr); + mActors.dropActors(cellStore); + mActivators.dropActivators(cellStore); } - void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore) - { - if (!mWatched.isEmpty() && mWatched.getCell()==cellStore) - mWatched = MWWorld::Ptr(); - mActors.dropActors (cellStore); - } - - void MechanicsManager::watchActor (const MWWorld::Ptr& ptr) + void MechanicsManager::watchActor(const MWWorld::Ptr& ptr) { mWatched = ptr; } - void MechanicsManager::update (float duration, bool paused) + void MechanicsManager::update(float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -297,7 +301,8 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (duration, paused); + mActors.update(duration, paused); + mActivators.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -631,11 +636,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - mActors.playAnimationGroup(ptr, groupName, mode, number); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.playAnimationGroup(ptr, groupName, mode, number); + else + mActors.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - mActors.skipAnimation(ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.skipAnimation(ptr); + else + mActors.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index c2bbd96cf..f70242bb9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "activators.hpp" #include "actors.hpp" namespace Ogre @@ -29,6 +30,8 @@ namespace MWMechanics bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; + + Activators mActivators; Actors mActors; void buildPlayer(); @@ -39,21 +42,21 @@ namespace MWMechanics MechanicsManager(); - virtual void addActor (const MWWorld::Ptr& ptr); - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr); + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr); - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr); + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore); - ///< Deregister all actors in the given cell. + virtual void drop(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. - virtual void watchActor (const MWWorld::Ptr& ptr); + virtual void watchActor(const MWWorld::Ptr& ptr); ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused); - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e116dca57..47751acb3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -100,7 +100,7 @@ namespace MWWorld //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); - MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); + MWBase::Environment::get().getMechanicsManager()->drop (*iter); MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); } @@ -166,7 +166,7 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->addActor(player); + mechMgr->add(player); mechMgr->watchActor(player); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); @@ -179,7 +179,7 @@ namespace MWWorld mRendering.preCellChange(mCurrentCell); // remove active - MWBase::Environment::get().getMechanicsManager()->removeActor (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -443,7 +443,7 @@ namespace MWWorld void Scene::removeObjectFromScene (const Ptr& ptr) { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); + MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->removeObject (ptr.getRefData().getHandle()); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0888a4522..a1d713a8a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -700,6 +700,7 @@ namespace MWWorld if (*currCell != newCell) { if (isPlayer) + { if (!newCell.isExterior()) changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); else @@ -708,7 +709,9 @@ namespace MWWorld int cellY = newCell.mCell->getGridY(); mWorldScene->changeCell(cellX, cellY, pos, false); } - else { + } + else + { if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) @@ -732,8 +735,8 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->removeActor(ptr); - mechMgr->addActor(copy); + mechMgr->remove(ptr); + mechMgr->add(copy); } else { From fdabef65a1ccae23007a720a224d6e76dfd3ea12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:19:24 -0800 Subject: [PATCH 102/239] Use a method to update an object's cell in the mechanics manager This prevents destroying and recreating the object's character controller (and messing up the current animation) when moving between cells. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwmechanics/activators.cpp | 11 ++++++++++ apps/openmw/mwmechanics/activators.hpp | 3 +++ apps/openmw/mwmechanics/actors.cpp | 11 ++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 9 ++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 22 +++++-------------- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index ec616fcaf..cb9539ef6 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,6 +43,9 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + ///< Moves an object to a new cell + virtual void drop (const MWWorld::CellStore *cellStore) = 0; ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 799d7ecd5..20b7865f5 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -25,6 +25,17 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } +void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + { + CharacterController ctrl = iter->second; + mActivators.erase(iter); + mActivators.insert(std::make_pair(ptr, ctrl)); + } +} + void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActivators.begin(); diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 3ddb0f843..5c3eba220 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,6 +28,9 @@ namespace MWMechanics void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator + void updateActivatorCell(const MWWorld::Ptr& ptr); + ///< Updates an activator with a new cell store + void dropActivators (const MWWorld::CellStore *cellStore); ///< Deregister all activators in the given cell. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 98ae3e755..27b7ad14e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,6 +179,17 @@ namespace MWMechanics mActors.erase(iter); } + void Actors::updateActorCell(const MWWorld::Ptr &ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + { + CharacterController ctrl = iter->second; + mActors.erase(iter); + mActors.insert(std::make_pair(ptr, ctrl)); + } + } + void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActors.begin(); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6fed9eff7..8c3df6c28 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -53,6 +53,9 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. + void updateActorCell(const MWWorld::Ptr& ptr); + ///< Updates an actor with a new cell store + void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3e56cbcb1..9e76084f5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -190,6 +190,15 @@ namespace MWMechanics mActors.removeActor(ptr); } + void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + { + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.updateActivatorCell(ptr); + else + mActors.updateActorCell(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f70242bb9..99010b7ff 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,6 +48,9 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr); + ///< Moves an object to a new cell + virtual void drop(const MWWorld::CellStore *cellStore); ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a1d713a8a..84a6b1b3d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -729,24 +729,14 @@ namespace MWWorld addContainerScripts(copy, &newCell); mRendering->moveObjectToCell(copy, vec, currCell); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); + mechMgr->updateCell(copy); - if (MWWorld::Class::get(ptr).isActor()) + std::string script = MWWorld::Class::get(ptr).getScript(ptr); + if(!script.empty()) { - MWBase::MechanicsManager *mechMgr = - MWBase::Environment::get().getMechanicsManager(); - - mechMgr->remove(ptr); - mechMgr->add(copy); - } - else - { - std::string script = - MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) - { - mLocalScripts.remove(ptr); - mLocalScripts.add(script, copy); - } + mLocalScripts.remove(ptr); + mLocalScripts.add(script, copy); } } ptr.getRefData().setCount(0); From 92d0c55f32bf9e2ee8d6a850bdd4b2d4e4fff82c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:43:42 -0800 Subject: [PATCH 103/239] Add a flag to specify if an animation should be playing --- apps/openmw/mwrender/animation.cpp | 13 ++++++++++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c4439841f..b0f21da84 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mPlaying(false) , mLooping(false) , mAnimSpeedMult(1.0f) { @@ -187,6 +188,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; reset(start); + mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mAnimState && mPlaying && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); + mPlaying = (targetTime < mAnimState->getLength() || mLooping); break; } @@ -236,8 +239,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mAnimState->getTimePosition() >= time) break; } - else if(mController) - mController->markerEvent(time, evt); + else + { + mPlaying = false; + if(mController) + mController->markerEvent(time, evt); + } continue; } if(mController) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9c6eb19..091c2f227 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mPlaying; bool mLooping; float mAnimSpeedMult; From 879359f39d35cc88724b251231543bc76bda0bd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:50:52 -0800 Subject: [PATCH 104/239] Set the animation state loop flag as appropriate --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b0f21da84..9666e62f4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -184,6 +184,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; From 99efe4e494f449950877e08ca93a9d43a99adc1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:02:55 -0800 Subject: [PATCH 105/239] Remove an unnecessary class member --- apps/openmw/mwrender/animation.cpp | 8 +++----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9666e62f4..778efc813 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,7 +27,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mAnimState(NULL) , mPlaying(false) - , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -187,7 +186,6 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; - mLooping = loop; reset(start); mPlaying = true; } @@ -206,7 +204,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (targetTime < mAnimState->getLength() || mLooping); + mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); break; } @@ -224,7 +222,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) @@ -234,7 +232,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 091c2f227..5fa1bd85c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,7 +32,6 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; bool mPlaying; - bool mLooping; float mAnimSpeedMult; From d4ddaa3d9585411c9f7c7a8a90e12de2ce517db0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:08:52 -0800 Subject: [PATCH 106/239] Only register activators that have a MWRender::Animation object --- apps/openmw/mwmechanics/activators.cpp | 5 +++-- apps/openmw/mwmechanics/activators.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 20b7865f5..1a743cad5 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -12,10 +12,11 @@ Activators::Activators() { } -void Activators::addActivator (const MWWorld::Ptr& ptr) +void Activators::addActivator(const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); + if(anim != NULL) + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); } void Activators::removeActivator (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 5c3eba220..0b9e984aa 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -23,7 +23,7 @@ namespace MWMechanics Activators(); void addActivator (const MWWorld::Ptr& ptr); - ///< Register an activator + ///< Register an animated activator void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator From 0853fa335c2545a7ada380315b18078736d72ed6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:36:17 -0800 Subject: [PATCH 107/239] Avoid redundant string concatenations --- components/nifogre/ogre_nif_loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8dbfbff5a..d1bf803f1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,14 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; + std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) + if(meshes[i].mMeshName.find(filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; From 04d4c125ba85775c8ca8e1c17e5f7122fbab444c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 02:00:42 -0800 Subject: [PATCH 108/239] Print when an animation event is unhandled --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83326d25a..6e78adfa4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -122,6 +122,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) } return; } + + std::cerr<< "Unhandled animation event: "< Date: Wed, 30 Jan 2013 02:38:50 -0800 Subject: [PATCH 109/239] Make sure the player node's visibility cascades --- apps/openmw/mwrender/player.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 8f3e13039..9ab8a7de3 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,11 +129,8 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); - + /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -310,10 +307,7 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); } void Player::setHeight(float height) From 360f7bfac88a3d1346691eb8d6896b61125bf9ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:04:18 -0800 Subject: [PATCH 110/239] Apply animations to bones manually Couple reasons for this: * This paves the way for allowing animations specified in other skeletons to be applied to the character (NPCs and certain creatures can have multiple animation sources, but Ogre is incredibly strict when it comes to sharing animations between skeletons). * It will allow for entities to be animated based on the character's skeleton, without having to duplicate the mesh for each skeleton it can be used on. This doesn't impact Ogre's ability to efficiently deform skinned meshes, nor does it get in the way of hardware skinning. --- apps/openmw/mwrender/animation.cpp | 61 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 778efc813..03bc92e96 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -94,24 +94,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } - // Reset initial state of bones that are animated, so the animation correctly applies. - if(skelinst->getNumAnimations() > 0) - { - Ogre::Animation *anim = skelinst->getAnimation(0); - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - if(!skelinst->hasBone(srcnode->getName())) - continue; - - Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3(1.0f)); - bone->setInitialState(); - } - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); } } @@ -134,16 +122,39 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } +void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) +{ + Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); + Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); + while(tracks.hasMoreElements()) + { + Ogre::NodeAnimationTrack *track = tracks.getNext(); + const Ogre::String &targetname = track->getAssociatedNode()->getName(); + if(!skel->hasBone(targetname)) + continue; + Ogre::Bone *bone = skel->getBone(targetname); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + track->applyToNode(bone, timeindex); + } + + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); +} + + Ogre::Vector3 Animation::updatePosition(float time) { + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); mAnimState->setTimePosition(time); + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { - /* Update the animation and get the non-accumulation root's difference from the - * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + /* Get the non-accumulation root's difference from the last update. */ posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ @@ -159,6 +170,7 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) mAnimState->setTimePosition(mNextKey->first); else @@ -166,10 +178,10 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mAnimState->setTimePosition(0.0f); } + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -179,10 +191,7 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - if(mAnimState) - mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setEnabled(true); mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; @@ -197,6 +206,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && mPlaying && timepassed > 0.0f) { @@ -249,6 +259,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mController) mController->markerEvent(time, evt); } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5fa1bd85c..c281551c7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -35,6 +35,8 @@ protected: float mAnimSpeedMult; + void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); From 5c3a7f7d523192c95380f9ec92e51ea25eb09213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:34:07 -0800 Subject: [PATCH 111/239] Avoid handling animation states We don't need them anymore --- apps/openmw/mwrender/animation.cpp | 41 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 4 ++- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 03bc92e96..73780a7f0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,8 +25,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) - , mAnimState(NULL) + , mCurrentAnim(NULL) + , mCurrentTime(0.0f) , mPlaying(false) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -106,7 +108,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); + return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); } @@ -147,9 +149,11 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk Ogre::Vector3 Animation::updatePosition(float time) { - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); - mAnimState->setTimePosition(time); - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + if(mLooping) + mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); + else + mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -170,15 +174,14 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) - mAnimState->setTimePosition(mNextKey->first); + mCurrentTime = mNextKey->first; else { mNextKey = mCurrentKeys->begin(); - mAnimState->setTimePosition(0.0f); + mCurrentTime = 0.0f; } - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { @@ -191,12 +194,12 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setLoop(loop); - + mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + reset(start); mPlaying = true; + mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mCurrentAnim && mPlaying && timepassed > 0.0f) { - float targetTime = mAnimState->getTimePosition() + timepassed; + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); + mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); break; } @@ -232,20 +235,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } continue; } if(evt == "stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } else diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c281551c7..886d967ab 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,8 +30,10 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::AnimationState *mAnimState; + Ogre::Animation *mCurrentAnim; + float mCurrentTime; bool mPlaying; + bool mLooping; float mAnimSpeedMult; From b6354c6282785feba4106a919242c491dcea3380 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 09:29:16 -0800 Subject: [PATCH 112/239] Don't share skeleton instances between bounded parts on an NPC However, a skeleton instance will still be shared between entities in an entity list. --- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++++ apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 5 ++--- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 73780a7f0..b63de2f16 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -146,6 +146,21 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) +{ + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + if(!skelsrc->hasBone(bone->getName())) + continue; + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } +} + Ogre::Vector3 Animation::updatePosition(float time) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 886d967ab..60e524d28 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,8 +37,13 @@ protected: float mAnimSpeedMult; + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates a skeleton instance so that all bones matching the source skeleton (based on + * bone names) are positioned identically. */ + void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 432a2f526..03fda8982 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,6 +305,21 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } + if(entities.mSkelBase) + { + Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); + } return entities; } @@ -317,7 +332,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - return Animation::runAnimation(timepassed); + Ogre::Vector3 ret = Animation::runAnimation(timepassed); + const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + for(size_t i = 0;i < sPartListSize;i++) + { + Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + if(!ent) continue; + updateSkeletonInstance(skelsrc, ent->getSkeleton()); + ent->getAllAnimationStates()->_notifyDirty(); + } + return ret; } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d1bf803f1..5444c803b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1228,19 +1228,18 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(entitylist.mSkelBase) { - entitylist.mSkelBase->shareSkeletonInstanceWith(parent); parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(parent); + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); tag->setScale(scale); } } From d6f923f2743afd4bd781e5a31bc5f897f3f18785 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:28:18 -0800 Subject: [PATCH 113/239] Use a child scene node for the accumulation root --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f16..b81104067 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d28..165a6525c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c6a9ea50076765f26eee02616a9531ff95815133 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:37:39 -0800 Subject: [PATCH 114/239] Use the skeleton as defined in the NIF model The avoids having to duplicate models that get attached to different character skeletons. --- components/nifogre/ogre_nif_loader.cpp | 59 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5444c803b..9c9fd3b22 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -754,7 +754,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; size_t mShapeIndex; - std::string mSkelName; std::string mMaterialName; std::string mShapeName; @@ -782,11 +781,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. - mesh->setSkeletonName(mSkelName); + mesh->setSkeletonName(mName); // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mSkelName); + skel = skelMgr->getByName(mName); // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to @@ -823,22 +822,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcVerts = newVerts; srcNorms = newNorms; } - else if(mSkelName.length() == 0) + else { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } } } @@ -998,8 +1001,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader public: NIFMeshLoader() { } - NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0), mSkelName(skelName) + NIFMeshLoader(const std::string &name, const std::string &group) + : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } virtual void loadResource(Ogre::Resource *resource) @@ -1010,7 +1013,9 @@ public: Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); if(mShapeIndex >= nif->numRecords()) { - mesh->setSkeletonName(mSkelName); + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); return; } @@ -1061,8 +1066,6 @@ public: std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(mShapeName.length() > 0) fullname += "@shape="+mShapeName; - if(mSkelName.length() > 0 && mName != mSkelName) - fullname += "@skel="+mSkelName; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); @@ -1105,13 +1108,13 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &group) { - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name]; Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); if(nif.numRecords() < 1) @@ -1139,7 +1142,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &skelName, hasSkel = skelldr.createSkeleton(name, group, node); } - NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); + NIFMeshLoader meshldr(name, group); meshldr.createMeshes(node, meshes); return meshes; @@ -1150,7 +1153,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, name, group); + MeshInfoList meshes = load(name, group); if(meshes.size() == 0) return entitylist; @@ -1199,7 +1202,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList meshes = load(name, group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index f87d7d3c2..13a76d472 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -66,7 +66,7 @@ typedef std::vector MeshInfoList; class Loader { - static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 376dfed15ba01cee8d24d122dfafc797a86fd303 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Feb 2013 08:50:32 -0800 Subject: [PATCH 115/239] Revert "Use a child scene node for the accumulation root" This reverts commit d6f923f2743afd4bd781e5a31bc5f897f3f18785. We don't need it for any of the NIFs we're currently handling. As long as there's no NIF files that would break it, we should require a stationary root if an animation wants to accumulate. If we must, a better idea may be to inject an extra bone into the skeleton instance and make that the accumulation root. --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b81104067..b63de2f16 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node->createChildSceneNode(); + mInsert = node; assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,7 +76,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = mInsert; + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c..60e524d28 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Node *mAccumRoot; + Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From 7f87c1873b4fbd4b27590d1313f8a15bd1ba55cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 02:53:22 -0800 Subject: [PATCH 116/239] Use an array to store the entity parts --- apps/openmw/mwrender/npcanimation.cpp | 62 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 31 +------------- 2 files changed, 33 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03fda8982..18f44c87c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,39 +16,39 @@ namespace MWRender { const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { - { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, - { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, - { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, - { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, - { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, - { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, - { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, - { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, - { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, - { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, - { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, - { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, - { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, - { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, - { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, - { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, - { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, - { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, - { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, - { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, - { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, - { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, - { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, - { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, - { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } + { ESM::PRT_Head, "Head" }, + { ESM::PRT_Hair, "Head" }, + { ESM::PRT_Neck, "Neck" }, + { ESM::PRT_Cuirass, "Chest" }, + { ESM::PRT_Groin, "Groin" }, + { ESM::PRT_Skirt, "Groin" }, + { ESM::PRT_RHand, "Right Hand" }, + { ESM::PRT_LHand, "Left Hand" }, + { ESM::PRT_RWrist, "Right Wrist" }, + { ESM::PRT_LWrist, "Left Wrist" }, + { ESM::PRT_Shield, "Shield" }, + { ESM::PRT_RForearm, "Right Forearm" }, + { ESM::PRT_LForearm, "Left Forearm" }, + { ESM::PRT_RUpperarm, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, "Left Upper Arm" }, + { ESM::PRT_RFoot, "Right Foot" }, + { ESM::PRT_LFoot, "Left Foot" }, + { ESM::PRT_RAnkle, "Right Ankle" }, + { ESM::PRT_LAnkle, "Left Ankle" }, + { ESM::PRT_RKnee, "Right Knee" }, + { ESM::PRT_LKnee, "Left Knee" }, + { ESM::PRT_RLeg, "Right Upper Leg" }, + { ESM::PRT_LLeg, "Left Upper Leg" }, + { ESM::PRT_RPauldron, "Right Clavicle" }, + { ESM::PRT_LPauldron, "Left Clavicle" }, + { ESM::PRT_Weapon, "Weapon" }, + { ESM::PRT_Tail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); } @@ -336,7 +336,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + Ogre::Entity *ent = mEntityParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -367,7 +367,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); break; } } @@ -405,7 +405,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a4e87e722..513741d03 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -19,7 +19,6 @@ class NpcAnimation : public Animation public: struct PartInfo { ESM::PartReferenceType type; - NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; @@ -30,34 +29,8 @@ private: MWWorld::InventoryStore& mInv; int mStateID; - //Bounded Parts - NifOgre::EntityList mClavicleL; - NifOgre::EntityList mClavicleR; - NifOgre::EntityList mUpperArmL; - NifOgre::EntityList mUpperArmR; - NifOgre::EntityList mUpperLegL; - NifOgre::EntityList mUpperLegR; - NifOgre::EntityList mForearmL; - NifOgre::EntityList mForearmR; - NifOgre::EntityList mWristL; - NifOgre::EntityList mWristR; - NifOgre::EntityList mKneeR; - NifOgre::EntityList mKneeL; - NifOgre::EntityList mNeck; - NifOgre::EntityList mAnkleL; - NifOgre::EntityList mAnkleR; - NifOgre::EntityList mGroin; - NifOgre::EntityList mSkirt; - NifOgre::EntityList mFootL; - NifOgre::EntityList mFootR; - NifOgre::EntityList mHair; - NifOgre::EntityList mHandL; - NifOgre::EntityList mHandR; - NifOgre::EntityList mShield; - NifOgre::EntityList mWeapon; - NifOgre::EntityList mHead; - NifOgre::EntityList mChest; - NifOgre::EntityList mTail; + // Bounded Parts + NifOgre::EntityList mEntityParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; From e6e7c69013070bd1c76f13a5d98739a9fc850fdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:26:52 -0800 Subject: [PATCH 117/239] Fix handling of filtered entities --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9c9fd3b22..2da8033e6 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1212,16 +1213,8 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(ent->hasSkeleton()) - { - if(meshes[i].mMeshName.find(filter) == std::string::npos) - { - sceneMgr->destroyEntity(ent); - continue; - } - if(!entitylist.mSkelBase) - entitylist.mSkelBase = ent; - } + if(!entitylist.mSkelBase && ent->hasSkeleton()) + entitylist.mSkelBase = ent; entitylist.mEntities.push_back(ent); } @@ -1231,19 +1224,25 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(entitylist.mSkelBase) { - parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; - if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + if(entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parentNode->attachObject(entity); + if(entity != entitylist.mSkelBase) + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + parentNode->attachObject(entity); } - else if(entity != entitylist.mSkelBase) + else { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); - tag->setScale(scale); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } } From fc7590694d11a1e6281fa203102ef1e0074d645a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:43:37 -0800 Subject: [PATCH 118/239] Revert "Revert "Use a child scene node for the accumulation root"" This reverts commit 376dfed15ba01cee8d24d122dfafc797a86fd303. I was wrong. It's needed at least for NPCs since they're attaching multiple animated skeletons to an object, and they all need to be offset correctly. Would be nice to use a Node, Bone, or TagPoint instead of a hefty SceneNode, though. --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f16..b81104067 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d28..165a6525c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c23a96d6065ae0ca8a452624be8711bff0985f8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 06:08:03 -0800 Subject: [PATCH 119/239] Run an aniamtion update after "playing" the inventory idle This is so all the NPC parts get updated correctly. --- apps/openmw/mwrender/characterpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 5a1a93311..8f0440b11 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,6 +145,7 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From c45b4d6072cf5c2fc043089dd1d4c309621d1596 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 22:27:08 -0800 Subject: [PATCH 120/239] Clean up some NIF warning reports --- components/nifogre/ogre_nif_loader.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2da8033e6..8175279d0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,9 +328,14 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); + else + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } + if(!(node->recType == Nif::RC_NiNode)) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ExtraPtr e = node->extra; while(!e.empty()) { @@ -365,9 +370,8 @@ void loadResource(Ogre::Resource *resource) Ogre::Skeleton *skel = dynamic_cast(resource); OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - Nif::NIFFile::ptr pnif(Nif::NIFFile::create (skel->getName())); - Nif::NIFFile & nif = *pnif.get (); - const Nif::Node *node = dynamic_cast(nif.getRecord(0)); + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRecord(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -406,7 +410,7 @@ void loadResource(Ogre::Resource *resource) if(!animroot) { warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + skel->getName()+", but no text keys."); return; } @@ -1037,7 +1041,6 @@ public: while(!e.empty()) { Nif::NiStringExtraData *sd; - Nif::NiTextKeyExtraData *td; if((sd=dynamic_cast(e.getPtr())) != NULL) { // String markers may contain important information @@ -1049,12 +1052,6 @@ public: flags |= 0x01; } } - else if((td=dynamic_cast(e.getPtr())) != NULL) - { - // TODO: Read and store text keys somewhere - } - else - warn("Unhandled extra data type "+e->recName); e = e->extra; } @@ -1087,9 +1084,6 @@ public: meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } - else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && - node->recType != Nif::RC_NiRotatingParticles) - warn("Unhandled mesh node type: "+node->recName); const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) From 007a5963de20e6a123e4d1519e62397a6d385b67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 23:39:43 -0800 Subject: [PATCH 121/239] Handle most state changes in the character controller when setting the movement vector --- apps/openmw/mwmechanics/actors.cpp | 34 ++++----------------------- apps/openmw/mwmechanics/character.cpp | 29 ++++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 27b7ad14e..2466b8a86 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -211,8 +211,7 @@ namespace MWMechanics float totalDuration = mDuration; mDuration = 0; - PtrControllerMap::iterator iter(mActors.begin()); - while(iter != mActors.end()) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { @@ -224,10 +223,7 @@ namespace MWMechanics updateNpc(iter->first, totalDuration, paused); if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) - { - iter++; continue; - } } // workaround: always keep player alive for now @@ -244,18 +240,14 @@ namespace MWMechanics } MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); - ++iter; continue; } if(iter->second.getState() == CharState_Dead) - { - iter++; continue; - } + iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Dead, false); - iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -272,26 +264,8 @@ namespace MWMechanics if(iter->second.getState() == CharState_Dead) continue; - Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - CharacterState newstate = CharState_Idle; - - if(dir.length() >= 0.1f) - { - if(std::abs(dir.x/2.0f) > std::abs(dir.y)) - { - if(dir.x > 0.0f) - newstate = CharState_WalkRight; - else if(dir.x < 0.0f) - newstate = CharState_WalkLeft; - } - else if(dir.y < 0.0f) - newstate = CharState_WalkBack; - else - newstate = CharState_WalkForward; - } - - iter->second.setState(newstate, true); - iter->second.setDirection(dir); + Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setMovementVector(movement); } std::vector > movement; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e78adfa4..677ffcf23 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -127,14 +127,31 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setDirection(const Ogre::Vector3 &dir) +void CharacterController::setMovementVector(const Ogre::Vector3 &vec) { - // HACK: The direction length we get is too large. - float mult = dir.length() / 32.0f; - mult = std::max(1.0f, mult); + // HACK: The length we get is too large. + float speed = std::max(1.0f, vec.length() / 32.0f); + + if(vec.length() >= 0.1f) + { + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); + } + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); + else + setState(CharState_WalkForward, true); + } + else + setState(CharState_Idle, true); + if(mAnimation) - mAnimation->setSpeedMult(mult); - mDirection = dir.normalisedCopy(); + mAnimation->setSpeedMult(speed); + mDirection = vec.normalisedCopy(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 53349c841..e5c7a4b8c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -53,7 +53,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir); + void setMovementVector(const Ogre::Vector3 &vec); void setState(CharacterState state, bool loop); CharacterState getState() const From 7fe877d8eab4a53dc70f23de52b0fb26493b0d7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:19:22 -0800 Subject: [PATCH 122/239] Add a couple more character states --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++++++-- apps/openmw/mwmechanics/character.hpp | 15 ++++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2466b8a86..df0d6a5e8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -215,7 +215,7 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); @@ -243,11 +243,11 @@ namespace MWMechanics continue; } - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; iter->second.setMovementVector(Ogre::Vector3::ZERO); - iter->second.setState(CharState_Dead, false); + iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -261,7 +261,7 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 677ffcf23..4f8525eca 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -37,13 +37,25 @@ static const struct { Ogre::Vector3 accumulate; } sStateList[] = { { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); @@ -162,7 +174,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) { movement = mDirection * movement.length(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index e5c7a4b8c..c8e92f7a9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -15,13 +15,26 @@ namespace MWMechanics enum CharacterState { CharState_Idle, + CharState_Idle2, + CharState_Idle3, + CharState_Idle4, + CharState_Idle5, + CharState_Idle6, + CharState_Idle7, + CharState_Idle8, + CharState_Idle9, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, - CharState_Dead + /* Must be last! */ + CharState_Death1, + CharState_Death2, + CharState_Death3, + CharState_Death4, + CharState_Death5 }; class CharacterController From 60a75cb5ee77453d7d33db421bee3cf2d0eb61f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:54:50 -0800 Subject: [PATCH 123/239] Make sure to keep the character preview animation updated --- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8f0440b11..24df30556 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,7 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->forceUpdate (); + mAnimation->runAnimation(0.0f); + mAnimation->forceUpdate(); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); @@ -145,7 +146,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); - mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From 23acf4b130e10213403b3655dca97eeb13f5808b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 01:38:42 -0800 Subject: [PATCH 124/239] Don't break right away when the animation time remaining is 0 --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b81104067..0e906181c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -225,7 +225,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement = Ogre::Vector3::ZERO; timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying && timepassed > 0.0f) + while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c..46a1ed88d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,6 +44,7 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -52,6 +53,7 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + void createEntityList(Ogre::SceneNode *node, const std::string &model); public: From 51d5efeeb2df6a4be1b0c94df9a54011e60ddb2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 07:15:34 -0800 Subject: [PATCH 125/239] Work out the state in the character controller update method --- apps/openmw/mwmechanics/actors.cpp | 10 -------- apps/openmw/mwmechanics/character.cpp | 35 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index df0d6a5e8..c1f552ae4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -246,7 +246,6 @@ namespace MWMechanics if(iter->second.getState() >= CharState_Death1) continue; - iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -259,15 +258,6 @@ namespace MWMechanics if(!paused) { - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->second.getState() >= CharState_Death1) - continue; - - Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - iter->second.setMovementVector(movement); - } - std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4f8525eca..f5a4dda51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -139,36 +139,35 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setMovementVector(const Ogre::Vector3 &vec) +Ogre::Vector3 CharacterController::update(float duration) { + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + // HACK: The length we get is too large. float speed = std::max(1.0f, vec.length() / 32.0f); - if(vec.length() >= 0.1f) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(CharState_WalkRight, true); - else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); - } - else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); - else - setState(CharState_WalkForward, true); + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); } + else if(vec.y > 0.0f) + setState(CharState_WalkForward, true); + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); else - setState(CharState_Idle, true); + { + if(!(getState() >= CharState_Death1)) + setState(CharState_Idle, true); + } if(mAnimation) mAnimation->setSpeedMult(speed); mDirection = vec.normalisedCopy(); -} - -Ogre::Vector3 CharacterController::update(float duration) -{ Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c8e92f7a9..69d73263b 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -66,8 +66,6 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setMovementVector(const Ogre::Vector3 &vec); - void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } From 91513206a01e5aa482d582f61179da93c9411ae1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 12:02:51 -0800 Subject: [PATCH 126/239] Don't use per-animation accumulation values This breaks walking diagonally and "jumping" (which technically wasn't jumping anyway). --- apps/openmw/mwmechanics/character.cpp | 70 ++++++++++++--------------- apps/openmw/mwmechanics/character.hpp | 2 - 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5a4dda51..fed6e3e3e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -34,39 +34,37 @@ namespace MWMechanics static const struct { CharacterState state; const char groupname[32]; - Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle" }, + { CharState_Idle2, "idle2" }, + { CharState_Idle3, "idle3" }, + { CharState_Idle4, "idle4" }, + { CharState_Idle5, "idle5" }, + { CharState_Idle6, "idle6" }, + { CharState_Idle7, "idle7" }, + { CharState_Idle8, "idle8" }, + { CharState_Idle9, "idle9" }, - { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkForward, "walkforward" }, + { CharState_WalkBack, "walkback" }, + { CharState_WalkLeft, "walkleft" }, + { CharState_WalkRight, "walkright" }, - { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1" }, + { CharState_Death2, "death2" }, + { CharState_Death3, "death3" }, + { CharState_Death4, "death4" }, + { CharState_Death5, "death5" }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); -static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +static void getStateInfo(CharacterState state, std::string *group) { for(size_t i = 0;i < sStateListSize;i++) { if(sStateList[i].state == state) { *group = sStateList[i].groupname; - *accum = sStateList[i].accumulate; return; } } @@ -75,24 +73,25 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(!mAnimation) return; mAnimation->setController(this); - Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); + getStateInfo(mState, &mCurrentGroup); + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) + , mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -144,9 +143,6 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - // HACK: The length we get is too large. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) @@ -164,20 +160,17 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } + // FIXME: The speed should actually be determined by the character's stance + // (running, sneaking, etc) and stats, rather than the length of the vector. + float speed = std::max(1.0f, vec.length() / 32.0f); if(mAnimation) mAnimation->setSpeedMult(speed); - mDirection = vec.normalisedCopy(); Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) - { - movement = mDirection * movement.length(); - } - return movement; } @@ -196,7 +189,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) @@ -225,12 +217,10 @@ void CharacterController::setState(CharacterState state, bool loop) mAnimQueue.clear(); std::string anim; - Ogre::Vector3 accum; - getStateInfo(mState, &anim, &accum); + getStateInfo(mState, &anim); if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->setAccumulation(accum); mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 69d73263b..c5f29beef 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,8 +45,6 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; - Ogre::Vector3 mDirection; - std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; From 1747c1e01ac4729a37b328a89972c9143ab05e96 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 07:10:14 -0800 Subject: [PATCH 127/239] Integrate a new movement solver to handle object movement and collisions Temporary, and pretty breoken. Needs some serious integration fixes. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 7 + apps/openmw/mwmechanics/character.cpp | 32 ++++- apps/openmw/mwmechanics/character.hpp | 5 + apps/openmw/mwmechanics/movementsolver.cpp | 154 +++++++++++++++++++++ apps/openmw/mwmechanics/movementsolver.hpp | 37 +++++ apps/openmw/mwworld/worldimp.hpp | 4 + 7 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 apps/openmw/mwmechanics/movementsolver.cpp create mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 73baa4e72..5f425f7a0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate movementsolver ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a426e3454..5f6e27867 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -20,6 +20,11 @@ namespace OEngine { class Fader; } + + namespace Physic + { + class PhysicEngine; + } } namespace ESM @@ -300,6 +305,8 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index fed6e3e3e..7962e197e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -25,9 +25,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" +#include "movementsolver.hpp" + + namespace MWMechanics { @@ -75,6 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; @@ -93,12 +98,18 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); } +CharacterController::~CharacterController() +{ + delete mMovementSolver; +} + void CharacterController::markerEvent(float time, const std::string &evt) { @@ -160,18 +171,25 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } - // FIXME: The speed should actually be determined by the character's stance - // (running, sneaking, etc) and stats, rather than the length of the vector. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(mAnimation) - mAnimation->setSpeedMult(speed); - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) + { + // FIXME: The speed should actually be determined by the character's + // stance (running, sneaking, etc) and stats + mAnimation->setSpeedMult(1.0f); movement += mAnimation->runAnimation(duration); + } mSkipAnim = false; - return movement; + if(duration > 0.0f) + { + Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? + Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); + } + + return Ogre::Vector3(0.0f); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c5f29beef..efd90ca19 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,6 +13,8 @@ namespace MWRender namespace MWMechanics { +class MovementSolver; + enum CharacterState { CharState_Idle, CharState_Idle2, @@ -49,6 +51,8 @@ class CharacterController CharacterState mState; bool mSkipAnim; + MovementSolver *mMovementSolver; + protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); @@ -58,6 +62,7 @@ protected: public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); + virtual ~CharacterController(); Ogre::Vector3 update(float duration); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp new file mode 100644 index 000000000..219f077e4 --- /dev/null +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -0,0 +1,154 @@ +#include "movementsolver.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +{ +} + +MovementSolver::~MovementSolver() +{ + // nothing to do +} + +void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) +{ + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); +} + +void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) +{ + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); +} + +bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) +{ + static const float maxslope = 45.0f; + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); + if(getSlope(trace.planenormal) < maxslope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; +} + +float MovementSolver::getSlope(const Ogre::Vector3 &normal) +{ + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); +} + + +Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +{ + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + + /* Anything to collide with? */ + if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) + return position+movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + float maxslope=45; + + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !mPtr.getCell()->isExterior(); + float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > maxslope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) + std::cout<< "stepped" < + +namespace MWMechanics +{ + class MovementSolver + { + public: + MovementSolver(const MWWorld::Ptr &ptr); + virtual ~MovementSolver(); + + Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + + private: + bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); + + void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); + void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); + + float getSlope(const Ogre::Vector3 &normal); + + MWWorld::Ptr mPtr; + OEngine::Physic::PhysicEngine *mEngine; + OEngine::Physic::PhysicActor *mPhysicActor; + + float verticalVelocity; + }; +} + +#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4899a8807..062387e92 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -347,6 +347,10 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const + { return mPhysEngine; } + /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From bec538bfa155717b04287aed98c4e6b86b99a73c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:19:59 -0800 Subject: [PATCH 128/239] Always declare operator<< for using a TextKeyMap with Ogre::Any --- components/nifogre/ogre_nif_loader.cpp | 3 --- components/nifogre/ogre_nif_loader.hpp | 10 ++++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8175279d0..b878c29f4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -54,9 +54,6 @@ typedef unsigned char ubyte; namespace std { -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - // TODO: Do something useful ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) { return o; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 13a76d472..12be52233 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -81,4 +81,14 @@ public: } +namespace std +{ + +// These operators allow extra data types to be stored in an Ogre::Any +// object, which can then be stored in user object bindings on the nodes + +ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); + +} + #endif From 6b32fa7999b3bd6f0341cef088b616b547395907 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:48:21 -0800 Subject: [PATCH 129/239] Use the correct position for the actor --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7962e197e..29ea723ed 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); From 1a5cb8760d6047ee57cb2b4333248ece3cad9d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:04:20 -0800 Subject: [PATCH 130/239] Rotate movement vector to world space before passing to the movement solver --- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/movementsolver.cpp | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 29ea723ed..8eb0caf58 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,16 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; + + Ogre::Vector3 pos(refpos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 219f077e4..a758c76f3 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -9,6 +9,7 @@ namespace MWMechanics MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) : mPtr(ptr) , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) + , verticalVelocity(0.0f) { } @@ -71,11 +72,10 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); - /* Anything to collide with? */ - if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) - return position+movement; + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. From 39cf7b0b42f32e98e9cb2864eb7361d30a4ad979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:17:48 -0800 Subject: [PATCH 131/239] Pass the Ptr of the object being moved to the move method This prevents having to store another copy of it, which risks getting out of sync. --- apps/openmw/mwmechanics/character.cpp | 8 +++----- apps/openmw/mwmechanics/movementsolver.cpp | 20 ++++++++++++++------ apps/openmw/mwmechanics/movementsolver.hpp | 22 +++++++++++++++------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8eb0caf58..b98a863ae 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +98,7 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -191,10 +191,8 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - Ogre::Vector3 pos(refpos.pos); - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index a758c76f3..4a7a59cb3 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -1,14 +1,20 @@ #include "movementsolver.hpp" +#include "libs/openengine/bullet/trace.h" +#include "libs/openengine/bullet/physic.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include + + namespace MWMechanics { -MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) - : mPtr(ptr) - , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +MovementSolver::MovementSolver() + : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) , verticalVelocity(0.0f) { } @@ -70,10 +76,12 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); if(!mPhysicActor || !mPhysicActor->getCollisionMode()) return position + movement; @@ -86,7 +94,7 @@ Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Ve Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; - bool isInterior = !mPtr.getCell()->isExterior(); + bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 lastNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 8bd05fa15..450bc055e 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -1,22 +1,31 @@ #ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H #define GAME_MWMECHANICS_MOVEMENTSOLVER_H -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" +#include -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} -#include +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + class PhysicActor; + } +} namespace MWMechanics { class MovementSolver { public: - MovementSolver(const MWWorld::Ptr &ptr); + MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); @@ -26,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); - MWWorld::Ptr mPtr; OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; From ee9b19d2ed92c1d9bdb03f9216d398cb42b1fb03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:04:06 -0800 Subject: [PATCH 132/239] Make sure to remove a Ptr from the activators when requested --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9e76084f5..085cb6653 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -188,6 +188,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); + mActivators.removeActivator(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) From 2f8affc95507e5f7264a91da06e5ff440e9b0c21 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:58:06 -0800 Subject: [PATCH 133/239] Make sure the player's controller is properly updated when they change --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 085cb6653..eee72f880 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -309,6 +309,12 @@ namespace MWMechanics } winMgr->configureSkills (majorSkills, minorSkills); + + // HACK? The player has been changed, so a new Animation object may + // have been made for them. Make sure they're properly updated. + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + mActors.removeActor(ptr); + mActors.addActor(ptr); } mActors.update(duration, paused); From 5ee298cdc14c0f653c377fa4c676a2487e877d54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 14:08:38 -0800 Subject: [PATCH 134/239] Make sure the player updates last --- apps/openmw/mwmechanics/actors.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c1f552ae4..e829d4679 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,14 +258,19 @@ namespace MWMechanics if(!paused) { - std::vector > movement; + PtrControllerMap::iterator player(mActors.end()); for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = iter->second.update(duration); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + if(iter->first.getRefData().getHandle() == "player") + { + /* Make sure player updates last (in case a cell transition occurs) */ + player = iter; + continue; + } + iter->second.update(duration); } - MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + if(player != mActors.end()) + player->second.update(duration); } } From 1c604445ba4f25f4ed2cf92e105e2a57e291bfcf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 06:59:01 -0800 Subject: [PATCH 135/239] Store movement vectors as they get returned --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++---------- apps/openmw/mwmechanics/actors.hpp | 7 ++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e829d4679..e01303c02 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,19 +258,15 @@ namespace MWMechanics if(!paused) { - PtrControllerMap::iterator player(mActors.end()); + mMovement.reserve(mActors.size()); + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") - { - /* Make sure player updates last (in case a cell transition occurs) */ - player = iter; - continue; - } - iter->second.update(duration); + Ogre::Vector3 movement = iter->second.update(duration); + mMovement.push_back(std::make_pair(iter->first, movement)); } - if(player != mActors.end()) - player->second.update(duration); + + mMovement.clear(); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 8c3df6c28..6968f3401 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,9 +25,14 @@ namespace MWMechanics { typedef std::map PtrControllerMap; PtrControllerMap mActors; - float mDuration; + + typedef std::vector > PtrMovementList; + PtrMovementList mMovement; + std::map mDeathCount; + float mDuration; + void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); void adjustMagicEffects (const MWWorld::Ptr& creature); From 82e4da4e6455249ca402bf886382bd0263e17c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 07:41:57 -0800 Subject: [PATCH 136/239] Get the half-extents from the physicactor --- apps/openmw/mwmechanics/character.cpp | 3 +-- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++++++++ libs/openengine/bullet/physic.hpp | 5 +++++ 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b98a863ae..27c1dc851 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -191,8 +191,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 4a7a59cb3..f17671a61 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -76,7 +76,7 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) { Ogre::Vector3 position(ptr.getRefData().getPosition().pos); @@ -96,6 +96,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 450bc055e..a8b9bf144 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -25,7 +25,7 @@ namespace MWMechanics MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b39ba53a2..7f0f6e2f9 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -156,6 +156,20 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getHalfExtents() const + { + if(mBody) + { + btBoxShape *box = static_cast(mBody->getCollisionShape()); + if(box != NULL) + { + btVector3 size = box->getHalfExtentsWithMargin(); + return Ogre::Vector3(size.getX(), size.getY(), size.getZ()); + } + } + return Ogre::Vector3(0.0f); + } + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 76bdb491d..d98625c0a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -117,6 +117,11 @@ namespace Physic */ void setScale(float scale); + /** + * Returns the half extents for this PhysiActor + */ + Ogre::Vector3 getHalfExtents() const; + /** * Runs pmove for this PhysicActor */ From a782a9109b131c04da01a0052afcbf8d7c208d97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:24:22 -0800 Subject: [PATCH 137/239] Store the vertical velocity in the physic actor --- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- libs/openengine/bullet/physic.cpp | 13 ++++++++++++- libs/openengine/bullet/physic.hpp | 11 +++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index f17671a61..3fddb28fe 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -15,7 +15,6 @@ namespace MWMechanics MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) - , verticalVelocity(0.0f) { } @@ -89,6 +88,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. float maxslope=45; + float verticalVelocity = mPhysicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -156,6 +156,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 verticalVelocity = clippedVelocity.z; verticalVelocity -= time*400; + mPhysicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index a8b9bf144..6a965b56a 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -37,8 +37,6 @@ namespace MWMechanics OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; - - float verticalVelocity; }; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7f0f6e2f9..1ae916f81 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -170,6 +170,17 @@ namespace Physic return Ogre::Vector3(0.0f); } + void PhysicActor::setVerticalForce(float force) + { + verticalForce = force; + } + + float PhysicActor::getVerticalForce() const + { + return verticalForce; + } + + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index d98625c0a..daf1c09f2 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -122,6 +122,16 @@ namespace Physic */ Ogre::Vector3 getHalfExtents() const; + /** + * Sets the current amount of vertical force (gravity) affecting this physic actor + */ + void setVerticalForce(float force); + + /** + * Gets the current amount of vertical force (gravity) affecting this physic actor + */ + float getVerticalForce() const; + /** * Runs pmove for this PhysicActor */ @@ -141,6 +151,7 @@ namespace Physic Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; + float verticalForce; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From d50832081cddc2f1238d41de85c62657ace1f3f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:37:02 -0800 Subject: [PATCH 138/239] Remove the unneeded PhysicActor field from MovementSolver --- apps/openmw/mwmechanics/movementsolver.cpp | 24 +++++++++++----------- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 3fddb28fe..544cb2ab8 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -13,6 +13,8 @@ namespace MWMechanics { +static const float sMaxSlope = 45.0f; + MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) { @@ -49,17 +51,16 @@ void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) { - static const float maxslope = 45.0f; traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < maxslope) + if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -80,23 +81,22 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 Ogre::Vector3 position(ptr.getRefData().getPosition().pos); /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float maxslope=45; - float verticalVelocity = mPhysicActor->getVerticalForce(); + float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); @@ -106,7 +106,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); if(trace.fraction < 1.0f) { - if(getSlope(trace.planenormal) > maxslope) + if(getSlope(trace.planenormal) > sMaxSlope) { // if we're on a really steep slope, don't listen to user input clippedVelocity.x = clippedVelocity.y = 0.0f; @@ -129,7 +129,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 if(trace.fraction != 1.0f) { //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) std::cout<< "stepped" <setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 6a965b56a..1c56df036 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -13,7 +13,6 @@ namespace OEngine namespace Physic { class PhysicEngine; - class PhysicActor; } } @@ -36,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); OEngine::Physic::PhysicEngine *mEngine; - OEngine::Physic::PhysicActor *mPhysicActor; }; } From 3251796ba04b513881658f693b14b7762d11ae77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:57:08 -0800 Subject: [PATCH 139/239] Fix left/right movement --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8b..991cf4f51 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -271,12 +271,12 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (1); + mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (-1); + mPlayer.setLeftRight (1); } else mPlayer.setLeftRight (0); From 2cdda967980acf429ab05d64358c8100e5813795 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 10:23:26 -0800 Subject: [PATCH 140/239] Clear out some unneeded doPhysics stuff --- apps/openmw/mwworld/physicssystem.cpp | 58 --------------------------- apps/openmw/mwworld/physicssystem.hpp | 3 -- apps/openmw/mwworld/worldimp.cpp | 43 -------------------- 3 files changed, 104 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9e2e94143..7d77718a3 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,66 +190,8 @@ namespace MWWorld //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - //set the movement keys to 0 (no movement) for every actor) - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - OEngine::Physic::PhysicActor* act = it->second; - act->setMovement(0,0,0); - } - - playerMove::playercmd& pm_ref = playerphysics->cmd; - - - pm_ref.rightmove = 0; - pm_ref.forwardmove = 0; - pm_ref.upmove = 0; - - - //playerphysics->ps.move_type = PM_NOCLIP; - for (std::vector >::const_iterator iter (actors.begin()); - iter!=actors.end(); ++iter) - { - //dirty stuff to get the camera orientation. Must be changed! - if (iter->first == "player") { - playerphysics->ps.viewangles.x = - Ogre::Radian(mPlayerData.pitch).valueDegrees(); - - - - playerphysics->ps.viewangles.y = - Ogre::Radian(mPlayerData.yaw).valueDegrees() + 90; - - pm_ref.rightmove = iter->second.x; - pm_ref.forwardmove = -iter->second.y; - pm_ref.upmove = iter->second.z; - } - } - mEngine->stepSimulation(dt); } - std::vector< std::pair > PhysicsSystem::doPhysicsFixed ( - const std::vector >& actors) - { - Pmove(playerphysics); - - - std::vector< std::pair > response; - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - - Ogre::Vector3 coord = it->second->getPosition(); - if(it->first == "player"){ - - coord = playerphysics->ps.origin ; - - } - - - response.push_back(std::pair(it->first, coord)); - } - - return response; - } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 81715c31e..b28f651f6 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -17,9 +17,6 @@ namespace MWWorld void doPhysics(float duration, const std::vector >& actors); ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - std::vector< std::pair > doPhysicsFixed (const std::vector >& actors); - ///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 246467fb0..5f6a2f4a7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -838,49 +838,6 @@ namespace MWWorld float duration) { mPhysics->doPhysics(duration, actors); - - const int tick = 16; // 16 ms ^= 60 Hz - - // Game clock part of the loop, contains everything that has to be executed in a fixed timestep - long long dt = mTimer.getMilliseconds() - lastTick; - if (dt >= 100) - { - // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps - lastTick += (dt - 100); - dt = 100; - } - while (dt >= tick) - { - dt -= tick; - lastTick += tick; - - std::vector< std::pair > vectors = mPhysics->doPhysicsFixed (actors); - - std::vector< std::pair >::iterator player = vectors.end(); - - for (std::vector< std::pair >::iterator it = vectors.begin(); - it!= vectors.end(); ++it) - { - if (it->first=="player") - { - player = it; - } - else - { - MWWorld::Ptr ptr = getPtrViaHandle (it->first); - moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); - } - } - - // Make sure player is moved last (otherwise the cell might change in the middle of an update - // loop) - if (player!=vectors.end()) - { - if (moveObjectImp (getPtrViaHandle (player->first), - player->second.x, player->second.y, player->second.z) == true) - return; // abort the current loop if the cell has changed - } - } } bool World::toggleCollisionMode() From 0a4568bd11cf6d6a7e9f4f7cbd3e96d7d691faae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 11:03:39 -0800 Subject: [PATCH 141/239] Move the PtrMovementList typedef to MWWorld Use it for the doPhysics parameter, too --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 7 ------- apps/openmw/mwworld/physicssystem.hpp | 3 --- apps/openmw/mwworld/worldimp.cpp | 4 +--- apps/openmw/mwworld/worldimp.hpp | 3 +-- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5f6e27867..b5d8aec9c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -52,6 +52,8 @@ namespace MWWorld class TimeStamp; class ESMStore; class RefData; + + typedef std::vector > PtrMovementList; } namespace MWBase @@ -233,8 +235,7 @@ namespace MWBase virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration) = 0; + virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0; ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode() = 0; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6968f3401..fbd787e83 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,7 @@ #include #include "character.hpp" +#include "../mwbase/world.hpp" namespace Ogre { @@ -26,8 +27,7 @@ namespace MWMechanics typedef std::map PtrControllerMap; PtrControllerMap mActors; - typedef std::vector > PtrMovementList; - PtrMovementList mMovement; + MWWorld::PtrMovementList mMovement; std::map mDeathCount; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7d77718a3..c95abc5a0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -185,13 +185,6 @@ namespace MWWorld } } - void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) - { - //set the DebugRenderingMode. To disable it,set it to 0 - //eng->setDebugRenderingMode(1); - - } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index b28f651f6..06b29d290 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -14,9 +14,6 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - void doPhysics(float duration, const std::vector >& actors); - ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5f6a2f4a7..d900f555c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -834,10 +834,8 @@ namespace MWWorld --cellY; } - void World::doPhysics (const std::vector >& actors, - float duration) + void World::doPhysics(const PtrMovementList &actors, float duration) { - mPhysics->doPhysics(duration, actors); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 062387e92..597766469 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -263,8 +263,7 @@ namespace MWWorld virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration); + virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode(); From 2c39760bd50284a809ba9fc091d01929e23eb3f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:45:10 -0800 Subject: [PATCH 142/239] Move the movement solver code to mwworld's physics system --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 26 +--- apps/openmw/mwmechanics/character.hpp | 4 - apps/openmw/mwmechanics/movementsolver.cpp | 164 --------------------- apps/openmw/mwmechanics/movementsolver.hpp | 41 ------ apps/openmw/mwworld/physicssystem.cpp | 152 +++++++++++++++++++ apps/openmw/mwworld/physicssystem.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 21 +++ 9 files changed, 184 insertions(+), 229 deletions(-) delete mode 100644 apps/openmw/mwmechanics/movementsolver.cpp delete mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 184a00d50..a491ea5ce 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate movementsolver + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e01303c02..a8c05f17e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,6 +265,7 @@ namespace MWMechanics Ogre::Vector3 movement = iter->second.update(duration); mMovement.push_back(std::make_pair(iter->first, movement)); } + MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration); mMovement.clear(); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27c1dc851..3899b05ab 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,6 @@ #include "../mwworld/class.hpp" -#include "movementsolver.hpp" - namespace MWMechanics { @@ -79,7 +77,6 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +95,6 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -107,7 +103,6 @@ CharacterController::CharacterController(const CharacterController &rhs) CharacterController::~CharacterController() { - delete mMovementSolver; } @@ -181,21 +176,14 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - if(duration > 0.0f) - { - const ESM::Position &refpos = mPtr.getRefData().getPosition(); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); - MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); - } - - return Ogre::Vector3(0.0f); + return movement; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index efd90ca19..adb6364a0 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,8 +13,6 @@ namespace MWRender namespace MWMechanics { -class MovementSolver; - enum CharacterState { CharState_Idle, CharState_Idle2, @@ -51,8 +49,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; - MovementSolver *mMovementSolver; - protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp deleted file mode 100644 index 544cb2ab8..000000000 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "movementsolver.hpp" - -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" - -#include "../mwworld/ptr.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include - - -namespace MWMechanics -{ - -static const float sMaxSlope = 45.0f; - -MovementSolver::MovementSolver() - : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) -{ -} - -MovementSolver::~MovementSolver() -{ - // nothing to do -} - -void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. - //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); - if(backoff < 0.0f) - backoff *= overbounce; - else - backoff /= overbounce; - - out = in - (normal*backoff); -} - -void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) -{ - Ogre::Vector3 normalizedDirection(direction); - normalizedDirection.normalise(); - - // no divide by normalizedDirection.length necessary because it's normalized - velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); -} - -bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) -{ - traceResults trace; // no initialization needed - - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) - return false; - - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < sMaxSlope) - { - // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. - position = trace.endpos; - return true; - } - - return false; -} - -float MovementSolver::getSlope(const Ogre::Vector3 &normal) -{ - return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); -} - - -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) -{ - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); - - /* Anything to collide with? */ - OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; - - traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - float verticalVelocity = physicActor->getVerticalForce(); - Ogre::Vector3 horizontalVelocity = movement/time; - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - - float remainingTime = time; - bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; - - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction < 1.0f) - { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } - } - - do { - // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - newPosition = trace.endpos; - currentNormal = trace.planenormal; - remainingTime = remainingTime * (1.0f-trace.fraction); - - // check for obstructions - if(trace.fraction != 1.0f) - { - //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) - { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) - std::cout<< "stepped" <setVerticalForce(verticalVelocity); - - return newPosition; -} - -} diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp deleted file mode 100644 index 1c56df036..000000000 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H -#define GAME_MWMECHANICS_MOVEMENTSOLVER_H - -#include - -namespace MWWorld -{ - class Ptr; -} - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -namespace MWMechanics -{ - class MovementSolver - { - public: - MovementSolver(); - virtual ~MovementSolver(); - - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); - - private: - bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); - - void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); - void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); - - float getSlope(const Ogre::Vector3 &normal); - - OEngine::Physic::PhysicEngine *mEngine; - }; -} - -#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c95abc5a0..2d83c9a04 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,6 +21,153 @@ using namespace Ogre; namespace MWWorld { + static const float sMaxSlope = 45.0f; + + class MovementSolver + { + private: + static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, + float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + OEngine::Physic::PhysicEngine *engine) + { + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + if(getSlope(trace.planenormal) < sMaxSlope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; + } + + static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, + const float overbounce) + { + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); + } + + static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) + { + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); + } + + static float getSlope(const Ogre::Vector3 &normal) + { + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); + } + + public: + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + OEngine::Physic::PhysicEngine *engine) + { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + + /* Anything to collide with? */ + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) + return position + movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + + float verticalVelocity = physicActor->getVerticalForce(); + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !ptr.getCell()->isExterior(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + std::cout<< "stepped" <setVerticalForce(verticalVelocity); + + return newPosition; + } + }; + + PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { @@ -185,6 +332,11 @@ namespace MWWorld } } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + { + return MovementSolver::move(ptr, movement, time, mEngine); + } + void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 06b29d290..d897c78e9 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,6 +35,8 @@ namespace MWWorld bool toggleCollisionMode(); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d900f555c..fb31c54ab 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -836,6 +836,27 @@ namespace MWWorld void World::doPhysics(const PtrMovementList &actors, float duration) { + /* No duration? Shouldn't be any movement, then. */ + if(duration <= 0.0f) + return; + + PtrMovementList::const_iterator player(actors.end()); + for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) + { + if(iter->first.getRefData().getHandle() == "player") + { + /* Handle player last, in case a cell transition occurs */ + player = iter; + continue; + } + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + moveObjectImp(iter->first, vec.x, vec.y, vec.z); + } + if(player != actors.end()) + { + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + moveObjectImp(player->first, vec.x, vec.y, vec.z); + } } bool World::toggleCollisionMode() From f7f1adfb9d6265d95804c3df2793e47aeed5280d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:55:06 -0800 Subject: [PATCH 143/239] Don't accumulate animations with activators --- apps/openmw/mwmechanics/character.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3899b05ab..42ab78d4f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -83,9 +83,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - /* Accumulate along X/Y only for now, until we can figure out how we should - * handle knockout and death which moves the character down. */ - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + { + /* Don't accumulate with activators (they don't get moved). */ + mAnimation->setAccumulation(Ogre::Vector3::ZERO); + } + else + { + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } From 8c0bb1ff4d26567ff4eb1a96a5e70e0f9c5ec227 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 14:02:14 -0800 Subject: [PATCH 144/239] Rotate movement in the movement solver --- apps/openmw/mwmechanics/character.cpp | 7 ------- apps/openmw/mwworld/physicssystem.cpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 42ab78d4f..f1f6280e5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -184,13 +184,6 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - const ESM::Position &refpos = mPtr.getRefData().getPosition(); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - return movement; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 2d83c9a04..7020c8fb2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,10 +80,17 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, OEngine::Physic::PhysicEngine *engine) { - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); From ee3764e9b34c1da280fc48a65a08225ffca0060f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:07:48 -0800 Subject: [PATCH 145/239] Increase max slope to 60. 45 is too low. --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7020c8fb2..9517715b6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,7 +21,7 @@ using namespace Ogre; namespace MWWorld { - static const float sMaxSlope = 45.0f; + static const float sMaxSlope = 60.0f; class MovementSolver { From e217a3d25c1a7720d672ce748186db3ab09832ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:51:26 -0800 Subject: [PATCH 146/239] Silence some console spam --- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9517715b6..e6e4dd676 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -143,9 +143,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) - std::cout<< "stepped" < Date: Tue, 5 Feb 2013 16:29:51 -0800 Subject: [PATCH 147/239] Use a vector of skeletons to handle animation sources --- apps/openmw/mwrender/animation.cpp | 96 ++++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 5 ++ 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0e906181c..ad98efb14 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,42 @@ Animation::~Animation() } +Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +{ + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(name); + if(skel.isNull()) + { + std::cerr<< "Failed to get skeleton source "<touch(); + mSkeletonSources.push_back(skel); + + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + return bone; + } + + return NULL; +} + void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); @@ -63,51 +99,35 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model state->setLoop(false); } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + boneiter.getNext()->setManuallyControlled(true); + Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(bone) + { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; - - asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+state->getAnimationName()); - if(!groupdata.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); - } - - break; } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); } } bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); + for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + { + if((*iter)->hasAnimation(anim)) + return true; + } + return false; } @@ -208,8 +228,20 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + bool found = false; + /* Look in reverse; last-inserted source has priority. */ + for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + { + if((*iter)->hasAnimation(groupname)) + { + mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentKeys = &mTextKeys[groupname]; + found = true; + break; + } + } + if(!found) + throw std::runtime_error("Failed to find animation "+groupname); reset(start); mPlaying = true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 46a1ed88d..62e93f110 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -28,6 +28,8 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + std::vector mSkeletonSources; + NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; @@ -53,6 +55,9 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + /* Inserts an additional skeleton into the animation source chain. Returns + * the bone representing the non-accum root from the base skeleton. */ + Ogre::Bone *insertSkeletonSource(const std::string &name); void createEntityList(Ogre::SceneNode *node, const std::string &model); From 16933e3926c368a575ee39e10d58cd65247c2d3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 16:59:20 -0800 Subject: [PATCH 148/239] Scale the accumulation root translation --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ad98efb14..63bd07bee 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -196,7 +196,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); + mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); mLastPosition += posdiff; } return posdiff; @@ -220,7 +220,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition - mLastPosition); + mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); } } From 054ef3113a8c28fd3cd59c19a60309d4cd1098ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:15:40 -0800 Subject: [PATCH 149/239] Check existing skeleton sources if the current one has no animation root --- apps/openmw/mwrender/animation.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 63bd07bee..baca70e37 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -108,10 +108,28 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model boneiter.getNext()->setManuallyControlled(true); Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(!bone) + { + for(std::vector::const_iterator iter(mSkeletonSources.begin()); + !bone && iter != mSkeletonSources.end();iter++) + { + Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty() && Ogre::any_cast(data)) + break; + + bone = NULL; + } + } + } if(bone) { mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mNonAccumRoot = skelinst->getBone(bone->getName()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; From c839502743697f9caa67ee60aec8e90e6f47f6d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:16:45 -0800 Subject: [PATCH 150/239] Setup base_anim.nif as an initial skeleton source for biped creatures --- apps/openmw/mwrender/creatureanimation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 34b09c0d0..094281c46 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,9 +23,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + insertSkeletonSource("meshes\\base_anim.nif"); - createEntityList(mPtr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; From 8b1e7b95ba4637cf01b65a1254f3e76b0cd55c77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:55:12 -0800 Subject: [PATCH 151/239] Attempt to load the skeleton source if it doesn't yet exist --- apps/openmw/mwrender/animation.cpp | 9 +++++++-- components/nifogre/ogre_nif_loader.cpp | 27 ++++++++++++++++++++++++++ components/nifogre/ogre_nif_loader.hpp | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index baca70e37..f0ba8d654 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -52,8 +52,13 @@ Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) Ogre::SkeletonPtr skel = skelMgr.getByName(name); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); mSkeletonSources.push_back(skel); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b878c29f4..c7f6ac50d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1250,6 +1250,33 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } +bool Loader::createSkeleton(const std::string &name, const std::string &group) +{ + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return false; + } + + // The first record is assumed to be the root node + Nif::Record const *r = nif.getRecord(0); + assert(r != NULL); + + Nif::Node const *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return false; + } + + NIFSkeletonLoader skelldr; + return skelldr.createSkeleton(name, group, node); +} + + /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh in the file was given a separate bone in a skeleton. Unfortunately diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 12be52233..0064defe2 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -77,6 +77,8 @@ public: static EntityList createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); + + static bool createSkeleton(const std::string &name, const std::string &group="General"); }; } From 535cd8360fd49ac805b7574529267e20559bbfb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:09:43 -0800 Subject: [PATCH 152/239] Load extra animations for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 18f44c87c..74b3945fa 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -120,6 +120,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + if(!mNpc->isMale() && !isBeast) + insertSkeletonSource("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + insertSkeletonSource("meshes\\argonian_swimkna.nif"); + + if(mNpc->mModel.length() > 0) + insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 18b70084095facb95a25011a891f167f6a9966cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:25:09 -0800 Subject: [PATCH 153/239] Better fix some scaling issues --- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f0ba8d654..019217ca6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); + mAccumRoot->translate(-posdiff); mLastPosition += posdiff; } return posdiff; @@ -243,7 +243,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); + mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 74b3945fa..120996a70 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -83,6 +83,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); + float scale = race->mData.mHeight.mMale; + if(!mNpc->isMale()) + scale = race->mData.mHeight.mFemale; + node->scale(Ogre::Vector3(scale)); + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; @@ -128,12 +133,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - float scale = race->mData.mHeight.mMale; - if (!mNpc->isMale()) { - scale = race->mData.mHeight.mFemale; - } - mInsert->scale(scale, scale, scale); - updateParts(); } From fc307e64b03d47e38f91cdcb4ac181f7fdfb0d6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:05:07 -0800 Subject: [PATCH 154/239] Add swimming states --- apps/openmw/mwmechanics/character.cpp | 18 +++++++++++++----- apps/openmw/mwmechanics/character.hpp | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1f6280e5..f119ceb69 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -46,12 +46,18 @@ static const struct { { CharState_Idle7, "idle7" }, { CharState_Idle8, "idle8" }, { CharState_Idle9, "idle9" }, + { CharState_IdleSwim, "idleswim" }, { CharState_WalkForward, "walkforward" }, { CharState_WalkBack, "walkback" }, { CharState_WalkLeft, "walkleft" }, { CharState_WalkRight, "walkright" }, + { CharState_SwimWalkForward, "swimwalkforward" }, + { CharState_SwimWalkBack, "swimwalkback" }, + { CharState_SwimWalkLeft, "swimwalkleft" }, + { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -157,21 +163,23 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState(CharState_WalkRight, true); + setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); + setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState(CharState_WalkForward, true); + setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); + setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) - setState(CharState_Idle, true); + setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } Ogre::Vector3 movement = Ogre::Vector3::ZERO; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index adb6364a0..535680fa1 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,12 +23,18 @@ enum CharacterState { CharState_Idle7, CharState_Idle8, CharState_Idle9, + CharState_IdleSwim, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, + CharState_SwimWalkForward, + CharState_SwimWalkBack, + CharState_SwimWalkLeft, + CharState_SwimWalkRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From 9cf30f39bd1d3b1c17450d2929c75e98b76318de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:45:51 -0800 Subject: [PATCH 155/239] Don't apply gravity when swimming --- apps/openmw/mwworld/physicssystem.cpp | 32 +++++++++++++++------------ apps/openmw/mwworld/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index e6e4dd676..b30d9a7b2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -81,7 +81,7 @@ namespace MWWorld public: static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, - OEngine::Physic::PhysicEngine *engine) + bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); @@ -100,8 +100,9 @@ namespace MWWorld traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; + float verticalVelocity = (gravity ? physicActor->getVerticalForce() : + horizontalVelocity.z); Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -115,18 +116,21 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(gravity) { - if(getSlope(trace.planenormal) > sMaxSlope) + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } } } @@ -339,9 +343,9 @@ namespace MWWorld } } - Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { - return MovementSolver::move(ptr, movement, time, mEngine); + return MovementSolver::move(ptr, movement, time, gravity, mEngine); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index d897c78e9..c1f70f2ca 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,7 +35,7 @@ namespace MWWorld bool toggleCollisionMode(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb31c54ab..b59907683 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -849,12 +849,12 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } } From dfd16c44245c6577fca1e05522974fbdb9a6bde5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:39:26 -0800 Subject: [PATCH 156/239] Fix movement rotations --- apps/openmw/mwworld/physicssystem.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b30d9a7b2..c42214fb2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -86,20 +86,33 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; + { + // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? + return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + if(!gravity) + { + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } + else + { + movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement; + } + Ogre::Vector3 horizontalVelocity = movement/time; float verticalVelocity = (gravity ? physicActor->getVerticalForce() : horizontalVelocity.z); From bdda7278c4acf52b9d23950d64314d39d3f86f2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:56:30 -0800 Subject: [PATCH 157/239] Use 3/4ths of the physic actor's height to test if swimming --- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b59907683..55270280d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1336,8 +1336,9 @@ namespace MWWorld float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme should rely on object height - pos.z += 30; + /// \fixme 3/4ths submerged? + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + if(actor) pos.z += actor->getHalfExtents().z * 1.5; return isUnderwater(*object.getCell()->mCell, pos); } From 04524fbf92fd639751daf75a0724b6aed9881249 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 15:23:52 -0800 Subject: [PATCH 158/239] Don't scale the movement vector up --- apps/openmw/mwclass/npc.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6069e3b7c..3666d9d6b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -311,14 +311,10 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - Ogre::Vector3 vector (0, 0, 0); - - vector.x = getMovementSettings (ptr).mLeftRight * 127; - vector.y = getMovementSettings (ptr).mForwardBackward * 127; - vector.z = getMovementSettings(ptr).mUpDown * 127; - - //if (getStance (ptr, Run, false)) - // vector *= 2; + Ogre::Vector3 vector; + vector.x = getMovementSettings(ptr).mLeftRight; + vector.y = getMovementSettings(ptr).mForwardBackward; + vector.z = getMovementSettings(ptr).mUpDown; return vector; } From cbaf489eb6436681d4cb2893749f68a9d4510009 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 16:53:52 -0800 Subject: [PATCH 159/239] Add running states --- apps/openmw/mwmechanics/character.cpp | 27 +++++++++++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 10 ++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f119ceb69..b6e96bdf5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -58,6 +58,16 @@ static const struct { { CharState_SwimWalkLeft, "swimwalkleft" }, { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_RunForward, "runforward" }, + { CharState_RunBack, "runback" }, + { CharState_RunLeft, "runleft" }, + { CharState_RunRight, "runright" }, + + { CharState_SwimRunForward, "swimrunforward" }, + { CharState_SwimRunBack, "swimrunback" }, + { CharState_SwimRunLeft, "swimrunleft" }, + { CharState_SwimRunRight, "swimrunright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -164,18 +174,27 @@ Ogre::Vector3 CharacterController::update(float duration) const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 535680fa1..d67964b84 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,16 @@ enum CharacterState { CharState_SwimWalkLeft, CharState_SwimWalkRight, + CharState_RunForward, + CharState_RunBack, + CharState_RunLeft, + CharState_RunRight, + + CharState_SwimRunForward, + CharState_SwimRunBack, + CharState_SwimRunLeft, + CharState_SwimRunRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From a8f0ce43a5e1d6f50758c8fb8663ac6082f892d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 17:51:47 -0800 Subject: [PATCH 160/239] Add a run key --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ apps/openmw/mwworld/player.cpp | 6 ++++++ apps/openmw/mwworld/player.hpp | 1 + 4 files changed, 17 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 991cf4f51..4868eedae 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,11 @@ namespace MWInput else mPlayer.setUpDown (0); + if(actionIsActive(A_Run)) + mPlayer.setRunState(true); + else + mPlayer.setRunState(false); + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab @@ -690,6 +695,7 @@ namespace MWInput defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_Console] = OIS::KC_F2; + defaultKeyBindings[A_Run] = OIS::KC_LSHIFT; defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_Jump] = OIS::KC_E; @@ -756,6 +762,7 @@ namespace MWInput descriptions[A_ToggleWeapon] = "sReady_Weapon"; descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_Console] = "sConsoleTitle"; + descriptions[A_Run] = "sRun"; descriptions[A_Crouch] = "sCrouch_Sneak"; descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_Jump] = "sJump"; @@ -804,6 +811,7 @@ namespace MWInput ret.push_back(A_MoveLeft); ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); + ret.push_back(A_Run); ret.push_back(A_Crouch); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f28..6fd6441da 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -239,6 +239,8 @@ namespace MWInput A_ToggleHUD, + A_Run, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 3414ba448..76d44a5d7 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -71,6 +71,12 @@ namespace MWWorld MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; } + void Player::setRunState(bool run) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); + } + void Player::toggleRunning() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 1c1ef76cf..4ef4d6771 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -65,6 +65,7 @@ namespace MWWorld void setForwardBackward (int value); void setUpDown(int value); + void setRunState(bool run); void toggleRunning(); }; } From ebc7bc9427da101a1b71223706d74fde1a56a845 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 18:22:16 -0800 Subject: [PATCH 161/239] Rename A_AlwaysRun to A_Run Note that there is an "always run" key, but its functionality is handled by A_ToggleWalk. --- apps/openmw/mwinput/inputmanagerimp.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 6fd6441da..3af39911c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -207,7 +207,7 @@ namespace MWInput A_Journal, //Journal A_Weapon, //Draw/Sheath weapon A_Spell, //Ready/Unready Casting - A_AlwaysRun, //Toggle Always Run + A_Run, //Run when held A_CycleSpellLeft, //cycling through spells A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons @@ -239,8 +239,6 @@ namespace MWInput A_ToggleHUD, - A_Run, - A_Last // Marker for the last item }; }; From e577ee2de815d9880ab66cf208c03c6c259cec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:44:58 -0800 Subject: [PATCH 162/239] Add a method to set/retrieve being on the ground --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++++++---- apps/openmw/mwworld/worldimp.cpp | 18 +++++++----------- libs/openengine/bullet/physic.cpp | 11 ++++++++++- libs/openengine/bullet/physic.hpp | 5 +++++ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c42214fb2..c5c634d79 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,6 +9,9 @@ #include #include +#include +#include + #include //#include "../mwbase/world.hpp" // FIXME @@ -129,6 +132,7 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; + bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -155,10 +159,11 @@ namespace MWWorld remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions - if(trace.fraction != 1.0f) + if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + onground = getSlope(currentNormal) <= sMaxSlope; + if(!onground || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -184,8 +189,8 @@ namespace MWWorld } while(iterations < maxIterations && remainingTime != 0.0f); verticalVelocity = clippedVelocity.z; - verticalVelocity -= time*400; - physicActor->setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 55270280d..085add7c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,5 +1,7 @@ #include "worldimp.hpp" +#include + #include #include @@ -1366,20 +1368,14 @@ namespace MWWorld { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); - Ogre::Vector3 playerPos; - float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos; - playerPos.x = pos[0]; - playerPos.y = pos[1]; - playerPos.z = pos[2]; + RefData &refdata = mPlayer->getPlayer().getRefData(); + const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); + Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = - mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos)) + if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep) + if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ae916f81..95313cdba 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -180,6 +180,15 @@ namespace Physic return verticalForce; } + void PhysicActor::setOnGround(bool grounded) + { + onGround = grounded; + } + + bool PhysicActor::getOnGround() const + { + return collisionMode && onGround; + } void PhysicActor::runPmove(){ Pmove(pmove); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index daf1c09f2..4bc926b8a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -132,6 +132,10 @@ namespace Physic */ float getVerticalForce() const; + void setOnGround(bool grounded); + + bool getOnGround() const; + /** * Runs pmove for this PhysicActor */ @@ -152,6 +156,7 @@ namespace Physic btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; float verticalForce; + bool onGround; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From 923d0d6eb4030cac4a1198b85a70ebcc62f58788 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:47:09 -0800 Subject: [PATCH 163/239] Fix up some header includes --- apps/openmw/mwrender/debugging.cpp | 2 ++ apps/openmw/mwrender/debugging.hpp | 9 ++++++++- apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwworld/physicssystem.hpp | 5 ++++- libs/openengine/bullet/pmove.cpp | 4 ++-- libs/openengine/bullet/pmove.h | 10 ++++++++-- libs/openengine/bullet/trace.cpp | 8 ++------ libs/openengine/bullet/trace.h | 14 +++++++++++--- 9 files changed, 40 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 1548cc1b0..2061b74d7 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index d312b6d54..07e5f0a3f 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -13,6 +12,14 @@ namespace ESM struct Pathgrid; } +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + namespace Ogre { class Camera; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 48632dba8..b2bdac683 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -2,6 +2,7 @@ #define _GAME_RENDER_OBJECTS_H #include +#include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 082b561ef..1551f73b8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c1f70f2ca..0b4ccd52f 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,12 +1,15 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include "ptr.hpp" #include +#include "ptr.hpp" namespace MWWorld { + class World; class PhysicsSystem { diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8d98a482e..9cd76968a 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -7,8 +7,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include "pmove.h" - - //#include "bprintf.h" //#include "..\..\ESMParser\ESMParser\CELL.h" @@ -22,6 +20,8 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include +#include "trace.h" + //SceneInstance* global_lastscene = NULL; // Forward declaration: diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index fa303184e..29a050471 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -8,8 +8,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include #include -#include "trace.h" -#include "physic.hpp" #include @@ -18,6 +16,14 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. // Forwards-declare it! +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + /*#ifndef COMPILING_PMOVE #include "Scene.h" extern SceneInstance* global_lastscene; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 9f5398574..847059530 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -1,14 +1,10 @@ #include "trace.h" - - #include - - - - +#include "physic.hpp" +#include "pmove.h" void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 1bfe0c717..462d062eb 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -4,9 +4,17 @@ #include #include -#include -#include -#include "pmove.h" + +#include + + +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} enum traceWorldType From 8de2d24d0ef2094174ee0ad77b928519012a9ba9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:57:59 -0800 Subject: [PATCH 164/239] Restore old ground check --- apps/openmw/mwworld/physicssystem.cpp | 5 +---- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c5c634d79..9262aa3c5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -132,7 +132,6 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -162,8 +161,7 @@ namespace MWWorld if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -190,7 +188,6 @@ namespace MWWorld verticalVelocity = clippedVelocity.z; physicActor->setVerticalForce(verticalVelocity - time*400.0f); - physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 085add7c9..6e063e1fe 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1369,10 +1369,12 @@ namespace MWWorld Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); RefData &refdata = mPlayer->getPlayer().getRefData(); - const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); Ogre::Vector3 playerPos(refdata.getPosition().pos); - if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); + bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); + + if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) From fe0e6c452d300cb288e5174b41ea498462d4ccc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 12:11:10 -0800 Subject: [PATCH 165/239] Remove the unneeded playerMove object from PhysicsSystem --- apps/openmw/mwworld/physicssystem.cpp | 34 +++++++-------------------- apps/openmw/mwworld/physicssystem.hpp | 19 +++++++++++---- apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/scene.hpp | 4 ++-- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9262aa3c5..6c41d56e6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,8 +9,9 @@ #include #include -#include -#include +#include +#include +#include #include @@ -25,6 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; + static const float sStepSize = 9.0f; class MovementSolver { @@ -35,13 +37,13 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -197,20 +199,16 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { - - playerphysics = new playerMove; // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - playerphysics->mEngine = mEngine; } PhysicsSystem::~PhysicsSystem() { delete mEngine; - delete playerphysics; - } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; @@ -279,15 +277,8 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - playerphysics->hasWater = hasWater; - if(hasWater){ - playerphysics->waterHeight = waterHeight; - } for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { it->second->setCurrentWater(hasWater, waterHeight); - } - } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -428,14 +419,8 @@ namespace MWWorld { // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // start positions others than 0, 0, 0 - if (handle == "player") - { - playerphysics->ps.origin = position; - } - else - { + if (handle != "player") act->setPosition(position); - } } } @@ -474,7 +459,6 @@ namespace MWWorld bool PhysicsSystem::toggleCollisionMode() { - playerphysics->ps.move_type = (playerphysics->ps.move_type == PM_NOCLIP ? PM_NORMAL : PM_NOCLIP); for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { if (it->first=="player") diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 0b4ccd52f..cbdd9935e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,15 +1,27 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include -#include -#include "ptr.hpp" + +namespace OEngine +{ + namespace Render + { + class OgreRenderer; + } + namespace Physic + { + class PhysicEngine; + } +} namespace MWWorld { class World; + class Ptr; class PhysicsSystem { @@ -74,7 +86,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; - playerMove* playerphysics; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 47751acb3..1966603fe 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -8,6 +8,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ad6ad1559..2333a95ab 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -3,7 +3,7 @@ #include "../mwrender/renderingmanager.hpp" -#include "physicssystem.hpp" +#include "ptr.hpp" #include "globals.hpp" namespace Ogre @@ -34,9 +34,9 @@ namespace MWRender namespace MWWorld { + class PhysicsSystem; class Player; class CellStore; - class Ptr; class Scene { From ca6f8b6d88f8abf2f58386691eb3d0e86b3a3769 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 13:18:16 -0800 Subject: [PATCH 166/239] Reorganize a bit of code in the movement solver --- apps/openmw/mwworld/physicssystem.cpp | 70 ++++++++++++--------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 6c41d56e6..b6d507da9 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -27,6 +27,8 @@ namespace MWWorld static const float sMaxSlope = 60.0f; static const float sStepSize = 9.0f; + // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + static const int sMaxIterations = 50; class MovementSolver { @@ -85,7 +87,7 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); @@ -103,55 +105,44 @@ namespace MWWorld } traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - if(!gravity) - { - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * - movement; - } - else - { - movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * - movement; - } - - Ogre::Vector3 horizontalVelocity = movement/time; - float verticalVelocity = (gravity ? physicActor->getVerticalForce() : - horizontalVelocity.z); - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; + Ogre::Vector3 velocity; + if(!gravity) + { + velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement / time; + } + else + { + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement / time; + velocity.z = physicActor->getVerticalForce(); + } + + // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(velocity); if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); } } + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); @@ -186,10 +177,9 @@ namespace MWWorld lastNormal = currentNormal; iterations++; - } while(iterations < maxIterations && remainingTime != 0.0f); + } while(iterations < sMaxIterations && remainingTime > 0.0f); - verticalVelocity = clippedVelocity.z; - physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; } From cbdd459500cd2c164f633e11d2173d21e9ec4cb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 15:48:41 -0800 Subject: [PATCH 167/239] Remove unneeded playerMove from PhysicActor --- apps/openmw/mwworld/physicssystem.cpp | 10 +--- libs/openengine/bullet/physic.cpp | 71 +-------------------------- libs/openengine/bullet/physic.hpp | 35 +------------ 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b6d507da9..cb8eb2a02 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -267,8 +267,7 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - it->second->setCurrentWater(hasWater, waterHeight); + // TODO: store and use } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -405,13 +404,6 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - if (handle != "player") - act->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 95313cdba..06f952305 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -34,14 +34,6 @@ namespace Physic Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - pmove = new playerMove; - pmove->mEngine = mEngine; - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } PhysicActor::~PhysicActor() @@ -50,38 +42,11 @@ namespace Physic mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } - delete pmove; - } - - void PhysicActor::setCurrentWater(bool hasWater, int waterHeight){ - pmove->hasWater = hasWater; - if(hasWater){ - pmove->waterHeight = waterHeight; - } - } - - void PhysicActor::setGravity(float gravity) - { - pmove->ps.gravity = gravity; - } - - void PhysicActor::setSpeed(float speed) - { - pmove->ps.speed = speed; } void PhysicActor::enableCollisions(bool collision) { collisionMode = collision; - if(collisionMode) - pmove->ps.move_type=PM_NORMAL; - else - pmove->ps.move_type=PM_NOCLIP; - } - - void PhysicActor::setJumpVelocity(float velocity) - { - pmove->ps.jump_velocity = velocity; } bool PhysicActor::getCollisionMode() @@ -89,23 +54,8 @@ namespace Physic return collisionMode; } - void PhysicActor::setMovement(signed char rightmove, signed char forwardmove, signed char upmove) - { - playerMove::playercmd& pm_ref = pmove->cmd; - pm_ref.rightmove = rightmove; - pm_ref.forwardmove = forwardmove; - pm_ref.upmove = upmove; - } - void PhysicActor::setPmoveViewAngles(float pitch, float yaw, float roll){ - pmove->ps.viewangles.x = pitch; - pmove->ps.viewangles.y = yaw; - pmove->ps.viewangles.z = roll; - } - - - - void PhysicActor::setRotation(const Ogre::Quaternion quat) + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -128,13 +78,6 @@ namespace Physic return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } - void PhysicActor::setPosition(const Ogre::Vector3 pos) - { - mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); - btVector3 vec = mBody->getWorldTransform().getOrigin(); - pmove->ps.origin = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()); - } - void PhysicActor::setScale(float scale){ Ogre::Vector3 position = getPosition(); Ogre::Quaternion rotation = getRotation(); @@ -148,12 +91,6 @@ namespace Physic //Create the newly scaled rigid body mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } Ogre::Vector3 PhysicActor::getHalfExtents() const @@ -190,12 +127,6 @@ namespace Physic return collisionMode && onGround; } - void PhysicActor::runPmove(){ - Pmove(pmove); - Ogre::Vector3 newpos = pmove->ps.origin; - mBody->getWorldTransform().setOrigin(btVector3(newpos.x, newpos.y, newpos.z)); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 4bc926b8a..aa832ddcc 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -18,7 +18,6 @@ class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; class btHeightfieldTerrainShape; -struct playerMove; namespace BtOgre { @@ -65,25 +64,12 @@ namespace Physic ~PhysicActor(); - void setCurrentWater(bool hasWater, int waterHeight); - - /** - * This function sets the movement keys for pmove - */ - void setMovement(signed char rightmove, signed char forwardmove, signed char upmove); - /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it * from setting the visual orientation to setting the orientation of the rigid body directly. */ - void setRotation(const Ogre::Quaternion quat); - - void setGravity(float gravity); - - void setSpeed(float speed); - - void setJumpVelocity(float velocity); + void setRotation(const Ogre::Quaternion &quat); void enableCollisions(bool collision); @@ -100,18 +86,6 @@ namespace Physic */ Ogre::Quaternion getRotation(); - /** - * Sets the position of mBody from a visual position input. - * For most cases this should not be used. We should instead let pmove move the PhysicActor around for us - */ - void setPosition(const Ogre::Vector3 pos); - - /** - * Sets the view angles for pmove directly. - * Remember, add 90 for yaw. Set roll to 0. - */ - void setPmoveViewAngles(float pitch, float yaw, float roll); - /** * Sets the scale of the PhysicActor */ @@ -136,11 +110,6 @@ namespace Physic bool getOnGround() const; - /** - * Runs pmove for this PhysicActor - */ - void runPmove(); - //HACK: in Visual Studio 2010 and presumably above, this structures alignment // must be 16, but the built in operator new & delete don't properly // perform this alignment. @@ -161,8 +130,6 @@ namespace Physic std::string mMesh; PhysicEngine* mEngine; std::string mName; - playerMove* pmove; - }; /** From d47d2216f2c9494d6a1b4e48df658485ea568bdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 16:18:29 -0800 Subject: [PATCH 168/239] Use some const references where appropriate --- apps/openmw/mwworld/physicssystem.cpp | 6 ++-- libs/openengine/bullet/physic.cpp | 42 +++++++++++++++------------ libs/openengine/bullet/physic.hpp | 27 ++++++++--------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index cb8eb2a02..8bf852f42 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -409,8 +409,8 @@ namespace MWWorld void PhysicsSystem::rotateObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Quaternion rotation = node->getOrientation(); + const std::string &handle = node->getName(); + const Ogre::Quaternion &rotation = node->getOrientation(); if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { //Needs to be changed @@ -428,7 +428,7 @@ namespace MWWorld void PhysicsSystem::scaleObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); + const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { removeObject(handle); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 06f952305..2b26c3a48 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -27,8 +27,9 @@ namespace Physic COL_RAYCASTING = BIT(3) }; - PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) + : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) + , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -38,7 +39,8 @@ namespace Physic PhysicActor::~PhysicActor() { - if(mBody){ + if(mBody) + { mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } @@ -321,18 +323,21 @@ namespace Physic mHeightFieldMap.erase(name); } - void PhysicEngine::adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation, Ogre::Quaternion boxRotation){ + void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation) + { btTransform tr; - rotation = rotation * boxRotation; - Ogre::Vector3 transrot = rotation * scaledBoxTranslation; + Ogre::Quaternion boxrot = rotation * boxRotation; + Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; Ogre::Vector3 newPosition = transrot + position; - + tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); + tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); body->setWorldTransform(tr); } - void PhysicEngine::boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation){ + void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) + { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; //std::cout << "The string" << outputstring << "\n"; @@ -345,7 +350,8 @@ namespace Physic adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); } - RigidBody* PhysicEngine::createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) { std::string sid = (boost::format("%07.3f") % scale).str(); @@ -406,7 +412,7 @@ namespace Physic } } - void PhysicEngine::removeRigidBody(std::string name) + void PhysicEngine::removeRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -426,7 +432,7 @@ namespace Physic } } - void PhysicEngine::deleteRigidBody(std::string name) + void PhysicEngine::deleteRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -446,7 +452,7 @@ namespace Physic } } - RigidBody* PhysicEngine::getRigidBody(std::string name) + RigidBody* PhysicEngine::getRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -469,8 +475,8 @@ namespace Physic } } - void PhysicEngine::addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation) + void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation) { // Remove character with given name, so we don't make memory // leak when character would be added twice @@ -483,7 +489,7 @@ namespace Physic PhysicActorMap[name] = newActor; } - void PhysicEngine::removeCharacter(std::string name) + void PhysicEngine::removeCharacter(const std::string &name) { //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); @@ -499,7 +505,7 @@ namespace Physic } } - PhysicActor* PhysicEngine::getCharacter(std::string name) + PhysicActor* PhysicEngine::getCharacter(const std::string &name) { PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index aa832ddcc..1a28023a9 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -60,7 +60,7 @@ namespace Physic class PhysicActor { public: - PhysicActor(std::string name, std::string mesh, PhysicEngine *engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale); + PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale); ~PhysicActor(); @@ -178,19 +178,21 @@ namespace Physic * Creates a RigidBody. It does not add it to the simulation. * After created, the body is set to the correct rotation, position, and scale */ - RigidBody* createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); /** * Adjusts a rigid body to the right position and rotation */ - void adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation = Ogre::Vector3::ZERO, Ogre::Quaternion boxRotation = Ogre::Quaternion::IDENTITY); + void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO, + const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY); /** Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. */ - void boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation); + void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); /** * Add a HeightField to the simulation */ @@ -211,35 +213,35 @@ namespace Physic /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. */ - void removeRigidBody(std::string name); + void removeRigidBody(const std::string &name); /** * Delete a RigidBody, and remove it from RigidBodyMap. */ - void deleteRigidBody(std::string name); + void deleteRigidBody(const std::string &name); /** * Return a pointer to a given rigid body. * TODO:check if exist */ - RigidBody* getRigidBody(std::string name); + RigidBody* getRigidBody(const std::string &name); /** * Create and add a character to the scene, and add it to the ActorMap. */ - void addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation); + void addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? */ - void removeCharacter(std::string name); + void removeCharacter(const std::string &name); /** * Return a pointer to a character * TODO:check if the actor exist... */ - PhysicActor* getCharacter(std::string name); + PhysicActor* getCharacter(const std::string &name); /** * This step the simulation of a given time. @@ -307,7 +309,6 @@ namespace Physic BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; bool mDebugActive; - }; From f5afa43db5037f4e8f4343db6ef933c7bb7279a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 17:45:41 -0800 Subject: [PATCH 169/239] Remove an unneeded parameter --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 8bf852f42..a5dd7f369 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -56,20 +56,17 @@ namespace MWWorld return false; } - static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, - const float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); + float backoff = inout.dotProduct(normal); if(backoff < 0.0f) backoff *= overbounce; else backoff /= overbounce; - out = in - (normal*backoff); + inout -= normal*backoff; } static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) @@ -134,7 +131,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } } @@ -171,7 +168,7 @@ namespace MWWorld // std::cout<< "stepped" < Date: Fri, 8 Feb 2013 13:12:34 -0800 Subject: [PATCH 170/239] Cleanup trace.cpp/h --- libs/openengine/bullet/trace.cpp | 256 +++++++++++-------------------- libs/openengine/bullet/trace.h | 51 +----- 2 files changed, 99 insertions(+), 208 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 847059530..138411e11 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -3,190 +3,116 @@ #include +#include +#include + #include "physic.hpp" #include "pmove.h" -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +enum traceWorldType { - //static float lastyaw = 0.0f; - //static float lastpitch = 0.0f; - //if (!traceobj) - // return; - - //if (!traceobj->incellptr) - // return; - - - const Ogre::Vector3 rayDir = end - start; - - - - - - - - NewPhysTraceResults out; - //std::cout << "Starting trace\n"; - //Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); - //Ogre::Vector3 endReplace = startReplace; - //endReplace.z -= .25; - - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), isInterior, enginePass); - - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - - - //results->allsolid = out.startSolid; - - // If outside and underground, we're solid - /*if (isInterior) - { - const Ogre::Vector3 height = GetGroundPosition(start, CellCoords(traceCell->data->gridX, traceCell->data->gridY) ); - if (start.yPos - height.yPos < (-2.0f * BBHalfExtents.yPos) ) - { - results->allsolid = true; - } - else - results->allsolid = false; - }*/ - - // If inside and out of the tree, we're solid - //else - //{ - results->allsolid = out.startSolid; - //std::cout << "allsolid" << results->allsolid << "\n"; - //} - - if (!hasHit) - { - results->endpos = end; - results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; - results->fraction = 1.0f; - } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = rayDir * results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; - /*bprintf("Start: (%f, %f, %f) End: (%f, %f, %f) TraceDir: (%f, %f, %f) HitNormal: (%f, %f, %f) Fraction: %f Hitpos: (%f, %f, %f) CompensatedHitpos: (%f, %f, %f)\n", - start.xPos, start.yPos, start.zPos, - end.xPos, end.yPos, end.zPos, - rayDir.xPos, rayDir.yPos, rayDir.zPos, - results->planenormal.xPos, results->planenormal.yPos, results->planenormal.zPos, results->fraction, - out.endPos.xPos, out.endPos.yPos, out.endPos.zPos, - results->endpos.xPos, results->endpos.yPos, results->endpos.zPos);*/ - } -} + collisionWorldTrace = 1, + pickWorldTrace = 2, + bothWorldTrace = collisionWorldTrace | pickWorldTrace +}; +enum collaborativePhysicsType +{ + No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) + Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) + Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) + Both_Physics = 3 // This object has both kinds of physics (example: activators) +}; +struct NewPhysTraceResults +{ + Ogre::Vector3 endPos; + Ogre::Vector3 hitNormal; + float fraction; + bool startSolid; + //const Object* hitObj; +}; template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) +static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { - //if (!traceobj->incellptr) - // return false; - //if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex()) - // std::cout << "It's convex\n"; - - - - const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); - const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); + const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); + const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); - //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); - const btTransform from(btrot, btstart); - const btTransform to(btrot, btend); + //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); + const btTransform from(btrot, btstart); + const btTransform to(btrot, btend); - // warning: unused variable ... - /* - float x = from.getOrigin().getX(); - float y = from.getOrigin().getY(); - float z = from.getOrigin().getZ(); - float x2 = to.getOrigin().getX(); - float y2 = to.getOrigin().getY(); - float z2 = to.getOrigin().getZ(); - */ - - //std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; - //std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; - //std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n"; + btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); + newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - btCollisionWorld::ClosestConvexResultCallback - newTraceCallback(btstart, btend); + enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - - - enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - //newTraceCallback. - - - //std::cout << "NUM: " << enginePass->dynamicsWorld->getNumCollisionObjects() << "\n"; + // Copy the hit data over to our trace results struct: + out->fraction = newTraceCallback.m_closestHitFraction; - // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + out->hitNormal.x = tracehitnormal.x(); + out->hitNormal.y = tracehitnormal.y(); + out->hitNormal.z = tracehitnormal.z(); - Ogre::Vector3& outhitnormal = out->hitNormal; - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; + out->endPos.x = tracehitpos.x(); + out->endPos.y = tracehitpos.y(); + out->endPos.z = tracehitpos.z(); - outhitnormal.x = tracehitnormal.x(); - outhitnormal.y = tracehitnormal.y(); - outhitnormal.z = tracehitnormal.z(); - - Ogre::Vector3& outhitpos = out->endPos; - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - - outhitpos.x = tracehitpos.x(); - outhitpos.y = tracehitpos.y(); - outhitpos.z= tracehitpos.z(); - - // StartSolid test: - { - out->startSolid = false; - //btCollisionObject collision; - //collision.setCollisionShape(const_cast(&newshape) ); - - //CustomContactCallback crb; - - //world.world->contactTest(&collision, crb); - //out->startSolid = crb.hit; - - // If outside and underground, we're solid - if (!isInterior) //Check if we are interior - { - } - - // If inside and out of the tree, we're solid - else - { - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - //std::cout << "AABBMIN" << aabbMin.getX() <<"," <startSolid = false; + if(isInterior) + { + // If inside and out of the tree, we're solid + btVector3 aabbMin, aabbMax; + enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); + btVector3 point(start.x, start.y, start.z); + if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) + { + //We're solid + //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! //out->startSolid = true; - } - } - } + } + } + } - const bool hasHit = newTraceCallback.hasHit(); - - - - - return hasHit; + return newTraceCallback.hasHit(); +} + + +void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +{ + NewPhysTraceResults out; + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, + Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); + if (out.fraction < 0.001f) + results->startsolid = true; + else + results->startsolid = false; + results->allsolid = out.startSolid; + + if(!hasHit) + { + results->endpos = end; + results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); + results->entityNum = ENTITYNUM_NONE; + results->fraction = 1.0f; + } + else + { + results->fraction = out.fraction; + results->planenormal = out.hitNormal; + results->endpos = (end-start)*results->fraction + start; + results->entityNum = ENTITYNUM_WORLD; + } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 462d062eb..94708d403 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -1,10 +1,6 @@ #ifndef OENGINE_BULLET_TRACE_H #define OENGINE_BULLET_TRACE_H - -#include -#include - #include @@ -17,52 +13,21 @@ namespace OEngine } -enum traceWorldType -{ - collisionWorldTrace = 1, - pickWorldTrace = 2, - bothWorldTrace = collisionWorldTrace | pickWorldTrace -}; - -enum collaborativePhysicsType -{ - No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) - Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) - Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) - Both_Physics = 3 // This object has both kinds of physics (example: activators) -}; - -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - bool startSolid; - //const Object* hitObj; -}; struct traceResults { - Ogre::Vector3 endpos; - Ogre::Vector3 planenormal; + Ogre::Vector3 endpos; + Ogre::Vector3 planenormal; - float fraction; + float fraction; - int surfaceFlags; - int contents; - int entityNum; + int surfaceFlags; + int contents; + int entityNum; - bool allsolid; - bool startsolid; + bool allsolid; + bool startsolid; }; - - -template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - #endif From f197c67e95ac189b141ee65bf336b80648f9f3e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 12:46:20 -0800 Subject: [PATCH 171/239] Fix a circular include --- components/esm/loadcell.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce..a811cab1c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -3,17 +3,17 @@ #include #include +#include #include "esmcommon.hpp" #include "defs.hpp" -#include "apps/openmw/mwbase/world.hpp" -/* -namespace MWWorld { - class ESMStore; - class CellStore; + +namespace MWWorld +{ + class ESMStore; } -*/ + namespace ESM { From 8d6f017f171950ddcf64cfdf835677a519407f59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 13:25:39 -0800 Subject: [PATCH 172/239] Remove an unneeded Animation field --- apps/openmw/mwrender/animation.cpp | 6 +----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 019217ca6..e157afc83 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -22,7 +22,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) - , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mCurrentAnim(NULL) @@ -135,9 +134,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getName()); - - mStartPosition = mNonAccumRoot->getInitialPosition(); - mLastPosition = mStartPosition; } } } @@ -243,7 +239,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); + mAccumRoot->setPosition(-mLastPosition * mAccumulate); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 62e93f110..ee73193bf 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,7 +25,6 @@ protected: Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; - Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; std::vector mSkeletonSources; From f4e587c72c9019b388890d2da0a386bcd54228a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 17:48:23 -0800 Subject: [PATCH 173/239] Always create a skeleton from a NIF when there's more than one NiNode --- components/nifogre/ogre_nif_loader.cpp | 72 ++++++++++++++++---------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c7f6ac50d..5f7e686a0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -21,8 +21,6 @@ */ -//loadResource->handleNode->handleNiTriShape->createSubMesh - #include "ogre_nif_loader.hpp" #include @@ -456,30 +454,28 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do + * not create a skeleton. */ if(node->recType == Nif::RC_NiTriShape) return false; - if(node->boneTrafo != NULL) + if(node->recType == Nif::RC_NiNode) { - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + bool alltrishapes = true; + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length() && alltrishapes;i++) + { + if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) + alltrishapes = false; + } + if(alltrishapes) + return false; } - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(createSkeleton(name, group, children[i].getPtr())) - return true; - } - } - } - return false; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + skelMgr.create(name, group, true, &sLoaders[name]); + return true; } }; @@ -1052,7 +1048,7 @@ public: e = e->extra; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); mShapeName = shape->name; @@ -1068,11 +1064,8 @@ public: { NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; - if(!(flags&0x01)) // Not hidden - { - loader->mShapeIndex = shape->recIndex; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); - } + loader->mShapeIndex = shape->recIndex; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); @@ -1093,6 +1086,29 @@ public: } } } + + void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + { + /* This creates an empty mesh to which a skeleton gets attached. This + * is to ensure we have an entity with a skeleton instance, even if all + * other meshes are hidden or entities attached to a specific node + * instead of skinned. */ + std::string fullname = mName; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFMeshLoader *loader = &sLoaders[fullname]; + *loader = *this; + + mesh = meshMgr.createManual(fullname, mGroup, loader); + mesh->setAutoBuildEdgeLists(false); + } + meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), + node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1135,7 +1151,9 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) } NIFMeshLoader meshldr(name, group); - meshldr.createMeshes(node, meshes); + if(hasSkel) + meshldr.createEmptyMesh(node, meshes); + meshldr.createMeshes(node, meshes, 0); return meshes; } From 4ee5857bae1285a9334430e140b617ec37d4e05d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 19:09:56 -0800 Subject: [PATCH 174/239] Filter accumulation axis for mLastPosition as needed --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e157afc83..9d9631ece 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -238,8 +238,8 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(-mLastPosition * mAccumulate); + mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; + mAccumRoot->setPosition(-mLastPosition); } } From 5b2ca6fa7d3a6f61f6a5b60bb1cd1144ffd04a8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:43:29 -0800 Subject: [PATCH 175/239] Don't complain about RootCollisionNode, it's handled in nifbullet --- components/nifogre/ogre_nif_loader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5f7e686a0..e276092c7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,7 +328,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode)) + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); Nif::ExtraPtr e = node->extra; From da5f11700f8e6603d09a04f868fe3de112beacc4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:45:00 -0800 Subject: [PATCH 176/239] Warn about unhandled node types before the controllers --- components/nifogre/ogre_nif_loader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e276092c7..c52a73e1c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -318,6 +318,11 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { @@ -328,11 +333,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - Nif::ExtraPtr e = node->extra; while(!e.empty()) { From a729b1b12a6502e7382c8a2bb3f79ed1e808bce1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:34:51 -0800 Subject: [PATCH 177/239] Snap to the ground after moving Depends on two factors: * End up close enough above to a walkable plane (it's within sMaxStep units down and is angled sMaxSlope or less) * Started out on the ground without any upward movement This also reduces the distance needed to be to the ground to 4 (from 10), and ensures the actor is 2 units above the ground when on it. Downward force is also removed when starting on the ground. --- apps/openmw/mwworld/physicssystem.cpp | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a5dd7f369..7a343604c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -102,6 +102,7 @@ namespace MWWorld } traceResults trace; //no initialization needed + bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); @@ -117,22 +118,24 @@ namespace MWWorld } else { + if(!(movement.z > 0.0f)) + { + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + onground = true; + } + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * movement / time; - velocity.z = physicActor->getVerticalForce(); + velocity.z += physicActor->getVerticalForce(); } - // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(velocity); - - if(gravity) + if(onground) { - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); - } + // if we're on the ground, force velocity to track it + clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } Ogre::Vector3 lastNormal(0.0f); @@ -176,6 +179,14 @@ namespace MWWorld iterations++; } while(iterations < sMaxIterations && remainingTime > 0.0f); + if(onground) + { + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + newPosition.z = trace.endpos.z + 2.0f; + else + onground = false; + } physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; From 15dc82f4545d78318ec7d3655df22fd569615800 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:59:05 -0800 Subject: [PATCH 178/239] Increase step size to 15 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7a343604c..447c1fa2a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 9.0f; + static const float sStepSize = 15.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 18b606fddff13307d1b9700e548de5dddb0e550a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 20:10:04 -0800 Subject: [PATCH 179/239] Use the PhysicActor's set/getOnGround method --- apps/openmw/mwworld/physicssystem.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 447c1fa2a..423666563 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -187,6 +187,7 @@ namespace MWWorld else onground = false; } + physicActor->setOnGround(onground); physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2b42e6f06..77e29f9be 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1418,17 +1418,13 @@ namespace MWWorld RefData &refdata = mPlayer->getPlayer().getRefData(); Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; - } MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) From ac717373b1a47618a0392cd33da7c1bd836fc630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:35:15 -0800 Subject: [PATCH 180/239] Add a method to check if an object is on the ground --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++-- apps/openmw/mwworld/worldimp.hpp | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3b71d421c..278c0d0a9 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,8 +286,9 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; - virtual bool isSwimming(const MWWorld::Ptr &object) = 0; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; + virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; virtual void togglePreviewMode(bool enable) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77e29f9be..f2d2e2c00 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1379,7 +1379,7 @@ namespace MWWorld } bool - World::isSwimming(const MWWorld::Ptr &object) + World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim float *fpos = object.getRefData().getPosition().pos; @@ -1393,7 +1393,7 @@ namespace MWWorld } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) + World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const { if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { return false; @@ -1401,6 +1401,13 @@ namespace MWWorld return pos.z < cell.mWater; } + bool World::isOnGround(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + return physactor && physactor->getOnGround(); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7b20ba17..39c87fce7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,8 +314,9 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); - virtual bool isSwimming(const MWWorld::Ptr &object); - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); + virtual bool isSwimming(const MWWorld::Ptr &object) const; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { mRendering->togglePOV(); From 3348e8a436081c4ebbfbe39fd8296056be3c75d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:41:14 -0800 Subject: [PATCH 181/239] Clarify a comment --- apps/openmw/mwmechanics/character.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d67964b84..eb3907041 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,7 +45,7 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, - /* Must be last! */ + /* Death states must be last! */ CharState_Death1, CharState_Death2, CharState_Death3, From e1a1530774bdb21bd2314b9bd2e48947cf198933 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 01:27:57 -0800 Subject: [PATCH 182/239] Better implement Npc::getSpeed --- apps/openmw/mwclass/npc.cpp | 84 +++++++++++++++++++++++++++++++++++-- apps/openmw/mwclass/npc.hpp | 17 ++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3666d9d6b..d135d2683 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -55,9 +55,30 @@ namespace MWClass { void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const { + static bool inited = false; + if(!inited) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + fMinWalkSpeed = gmst.find("fMinWalkSpeed"); + fMaxWalkSpeed = gmst.find("fMaxWalkSpeed"); + fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect"); + fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier"); + fAthleticsRunBonus = gmst.find("fAthleticsRunBonus"); + fBaseRunMultiplier = gmst.find("fBaseRunMultiplier"); + fMinFlySpeed = gmst.find("fMinFlySpeed"); + fMaxFlySpeed = gmst.find("fMaxFlySpeed"); + fSwimRunBase = gmst.find("fSwimRunBase"); + fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + // Added in Tribunal/Bloodmoon, may not exist + fWereWolfRunMult = gmst.search("fWereWolfRunMult"); + + inited = true; + } if (!ptr.getRefData().getCustomData()) { - std::auto_ptr data (new CustomData); + std::auto_ptr data(new CustomData); MWWorld::LiveCellRef *ref = ptr.get(); @@ -297,9 +318,54 @@ namespace MWClass return false; } - float Npc::getSpeed (const MWWorld::Ptr& ptr) const + float Npc::getSpeed(const MWWorld::Ptr& ptr) const { - return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); + + float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* + (fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat()); + walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance; + walkSpeed = std::max(0.0f, walkSpeed); + if(Npc::getStance(ptr, Sneak, false)) + walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * + fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + + float moveSpeed; + if(normalizedEncumbrance > 1.0f) + moveSpeed = 0.0f; + else if(0/*world->isFlying(ptr)*/) + { + float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + + 0.0f/*levitationBonus*/); + flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); + flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; + flySpeed = std::max(0.0f, flySpeed); + moveSpeed = flySpeed; + } + else if(world->isSwimming(ptr)) + { + float swimSpeed = walkSpeed; + if(Npc::getStance(ptr, Run, false)) + swimSpeed = runSpeed; + swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* + fSwimRunAthleticsMult->getFloat(); + moveSpeed = swimSpeed; + } + else if(Npc::getStance(ptr, Run, false)) + moveSpeed = runSpeed; + else + moveSpeed = walkSpeed; + + if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) + moveSpeed *= 0.75f; + if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) + moveSpeed *= fWereWolfRunMult->getFloat(); + + return moveSpeed; } MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const @@ -416,4 +482,16 @@ namespace MWClass return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); } + + const ESM::GameSetting *Npc::fMinWalkSpeed; + const ESM::GameSetting *Npc::fMaxWalkSpeed; + const ESM::GameSetting *Npc::fEncumberedMoveEffect; + const ESM::GameSetting *Npc::fSneakSpeedMultiplier; + const ESM::GameSetting *Npc::fAthleticsRunBonus; + const ESM::GameSetting *Npc::fBaseRunMultiplier; + const ESM::GameSetting *Npc::fMinFlySpeed; + const ESM::GameSetting *Npc::fMaxFlySpeed; + const ESM::GameSetting *Npc::fSwimRunBase; + const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 20c2da4b1..a97e4c42e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -3,6 +3,11 @@ #include "../mwworld/class.hpp" +namespace ESM +{ + class GameSetting; +} + namespace MWClass { class Npc : public MWWorld::Class @@ -12,6 +17,18 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + static const ESM::GameSetting *fMinWalkSpeed; + static const ESM::GameSetting *fMaxWalkSpeed; + static const ESM::GameSetting *fEncumberedMoveEffect; + static const ESM::GameSetting *fSneakSpeedMultiplier; + static const ESM::GameSetting *fAthleticsRunBonus; + static const ESM::GameSetting *fBaseRunMultiplier; + static const ESM::GameSetting *fMinFlySpeed; + static const ESM::GameSetting *fMaxFlySpeed; + static const ESM::GameSetting *fSwimRunBase; + static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fWereWolfRunMult; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; From ff0099fa6e89c97f5f269d2f25adc66a5540edfc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 02:15:39 -0800 Subject: [PATCH 183/239] Scale the animation speed based on the animation velocity and movement speed This may not be totoally correct since it takes the whole animation into account, rather than just the looping portion. But it's good enough for now. --- apps/openmw/mwmechanics/character.cpp | 5 ++-- apps/openmw/mwrender/animation.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 4 ++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6e96bdf5..c40fac40a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,7 @@ Ogre::Vector3 CharacterController::update(float duration) { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + const float speed = cls.getSpeed(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); @@ -204,9 +205,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { - // FIXME: The speed should actually be determined by the character's - // stance (running, sneaking, etc) and stats - mAnimation->setSpeedMult(1.0f); + mAnimation->setSpeed(speed); movement += mAnimation->runAnimation(duration); } mSkipAnim = false; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9d9631ece..1a606992a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -28,6 +28,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { } @@ -161,6 +162,13 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) mAccumulate = accum; } +void Animation::setSpeed(float speed) +{ + mAnimSpeedMult = 1.0f; + if(mAnimVelocity > 1.0f && speed > 0.0f) + mAnimSpeedMult = speed / mAnimVelocity; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { @@ -255,6 +263,31 @@ void Animation::play(const std::string &groupname, const std::string &start, boo { mCurrentAnim = (*iter)->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mAnimVelocity = 0.0f; + + if(mNonAccumRoot) + { + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + const Ogre::TransformKeyFrame *startkf, *endkf; + startkf = static_cast(track->getKeyFrame(0)); + endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + + mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / + mCurrentAnim->getLength(); + } + } + found = true; break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ee73193bf..fc35c06be 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -36,6 +36,7 @@ protected: bool mPlaying; bool mLooping; + float mAnimVelocity; float mAnimSpeedMult; /* Applies the given animation to the given skeleton instance, using the specified time. */ @@ -73,8 +74,7 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); - void setSpeedMult(float speedmult) - { mAnimSpeedMult = speedmult; } + void setSpeed(float speed); void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e4341525c859a94250de4c09165737cdd81b64e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 04:45:28 -0800 Subject: [PATCH 184/239] Add a jump state Currently unused --- apps/openmw/mwmechanics/character.cpp | 5 ++++- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c40fac40a..376092256 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -68,6 +68,8 @@ static const struct { { CharState_SwimRunLeft, "swimrunleft" }, { CharState_SwimRunRight, "swimrunright" }, + { CharState_Jump, "jump" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -170,11 +172,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); const float speed = cls.getSpeed(mPtr); - bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index eb3907041..996687a3e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,6 +45,8 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, + CharState_Jump, + /* Death states must be last! */ CharState_Death1, CharState_Death2, From c57001e3bdda8a0b60eef303a49c4cf3eddd5f70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 05:11:06 -0800 Subject: [PATCH 185/239] Remove an unused field --- apps/openmw/mwworld/physicssystem.cpp | 4 +--- apps/openmw/mwworld/physicssystem.hpp | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 423666563..240f1c435 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -196,7 +196,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mFreeFly (true) + mRender(_rend), mEngine(0) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); @@ -460,12 +460,10 @@ namespace MWWorld if(cmode) { act->enableCollisions(false); - mFreeFly = true; return false; } else { - mFreeFly = false; act->enableCollisions(true); return true; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index cbdd9935e..60c8246ae 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -85,7 +85,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; - bool mFreeFly; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); From c965bd8e181b0bf9a81df51b11770e97f49711ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 17:22:55 -0800 Subject: [PATCH 186/239] Increase step size to 30 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 240f1c435..058160595 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 15.0f; + static const float sStepSize = 30.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 158e18b98d879b4ba9d87c8a1bc6d72d5320db65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Feb 2013 00:30:07 -0800 Subject: [PATCH 187/239] Remove an unused method --- apps/openmw/mwbase/world.hpp | 3 --- apps/openmw/mwworld/worldimp.hpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 278c0d0a9..da670cf23 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -307,9 +307,6 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 39c87fce7..8b9b39617 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,10 +349,6 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const - { return mPhysEngine; } - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From 6356d3a385c7f1a1df5ce25267021f4d6833be45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Feb 2013 06:02:57 -0800 Subject: [PATCH 188/239] Start actors with collision enabled NPCs are now affected by gravity. The player still starts in no-collision mode though, since they start in the void rather than a door marker. --- libs/openengine/bullet/physic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 2b26c3a48..7ffe07189 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -29,8 +29,11 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { + // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. + if(name == "player") + collisionMode = false; mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); From f2948ced2366d126cd8a9870e26a08f9268f974c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 03:07:31 -0800 Subject: [PATCH 189/239] Allow diagonal movement --- apps/openmw/mwmechanics/character.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 376092256..672ab2e9a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement(0.0f); + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); @@ -190,22 +192,28 @@ Ogre::Vector3 CharacterController::update(float duration) setState(isrunning ? (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); } - else if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { mAnimation->setSpeed(speed); From 627b866744b20524027eca4911e43b9c48e2df25 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 06:29:16 -0800 Subject: [PATCH 190/239] Don't try to set a new state when dead --- apps/openmw/mwmechanics/character.cpp | 71 ++++++++++++++------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 672ab2e9a..27bc62d07 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -174,43 +174,44 @@ Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement(0.0f); - const MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - const float speed = cls.getSpeed(mPtr); + float speed = 0.0f; + if(!(getState() >= CharState_Death1)) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - bool inwater = world->isSwimming(mPtr); - bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + bool inwater = world->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunRight : CharState_RunRight) : - (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); - else if(vec.x < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : - (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); - // Apply any forward/backward movement manually - movement.y += vec.y * (speed*duration); - } - else if(vec.y != 0.0f) - { - if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); - // Apply any sideways movement manually - movement.x += vec.x * (speed*duration); - } - else - { - if(!(getState() >= CharState_Death1)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + else if(vec.x < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); + } + else setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } From 5d403ebdd34ec1c616c4221b5af04a35261662ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 04:03:24 +0100 Subject: [PATCH 191/239] Fix collision debug drawer (tcg) --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ libs/openengine/bullet/BtOgreExtras.h | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++------ libs/openengine/bullet/physic.hpp | 9 +++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f2d2e2c00..a80f083b5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -186,6 +186,8 @@ namespace MWWorld mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mPhysEngine->setSceneManager(renderer.getScene()); + mWeatherManager = new MWWorld::WeatherManager(mRendering); int idx = 0; @@ -892,6 +894,8 @@ namespace MWWorld Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } + // the only purpose this has currently is to update the debug drawer + mPhysEngine->stepSimulation (duration); } bool World::toggleCollisionMode() diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h index 423924eda..b20a3ff98 100644 --- a/libs/openengine/bullet/BtOgreExtras.h +++ b/libs/openengine/bullet/BtOgreExtras.h @@ -207,7 +207,7 @@ public: mLineDrawer->setMaterial("BtOgre/DebugLines"); - mLineDrawer->setVisibilityFlags (1024); + //mLineDrawer->setVisibilityFlags (1024); } ~DebugDrawer() diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7ffe07189..220ba5d51 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -191,10 +191,7 @@ namespace Physic { if(!isDebugCreated) { - Ogre::SceneManagerEnumerator::SceneManagerIterator iter = Ogre::Root::getSingleton().getSceneManagerIterator(); - iter.begin(); - Ogre::SceneManager* scn = iter.getNext(); - Ogre::SceneNode* node = scn->getRootSceneNode()->createChildSceneNode(); + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); @@ -219,6 +216,11 @@ namespace Physic return mDebugActive; } + void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr) + { + mSceneMgr = sceneMgr; + } + PhysicEngine::~PhysicEngine() { HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); @@ -471,7 +473,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This isn't needed as there are no dynamic objects at this point + //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); @@ -494,7 +497,6 @@ namespace Physic void PhysicEngine::removeCharacter(const std::string &name) { - //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 1a28023a9..559bf032e 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -24,6 +24,11 @@ namespace BtOgre class DebugDrawer; } +namespace Ogre +{ + class SceneManager; +} + namespace MWWorld { class World; @@ -269,6 +274,8 @@ namespace Physic void getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max); + void setSceneManager(Ogre::SceneManager* sceneMgr); + /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). */ @@ -305,6 +312,8 @@ namespace Physic typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; + Ogre::SceneManager* mSceneMgr; + //debug rendering BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; From 17200cb226a8ea95a940e7093f14170098b80d34 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 20:43:55 -0800 Subject: [PATCH 192/239] Don't try to move when there's no speed --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27bc62d07..00a58523d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -185,7 +185,7 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) setState(isrunning ? @@ -198,7 +198,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any forward/backward movement manually movement.y += vec.y * (speed*duration); } - else if(vec.y != 0.0f) + else if(vec.y != 0.0f && speed > 0.0f) { if(vec.y > 0.0f) setState(isrunning ? From 5a1a0b7338f9c4f8bafb2b65d82c649c95c12a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 22:39:43 -0800 Subject: [PATCH 193/239] Add and use an MWWorld::isFlying method --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + libs/openengine/bullet/physic.cpp | 5 ----- libs/openengine/bullet/physic.hpp | 6 +++++- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index da670cf23..cc23e035e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,6 +286,7 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d135d2683..998b90e19 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -336,7 +336,7 @@ namespace MWClass float moveSpeed; if(normalizedEncumbrance > 1.0f) moveSpeed = 0.0f; - else if(0/*world->isFlying(ptr)*/) + else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + 0.0f/*levitationBonus*/); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a80f083b5..1a6630232 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1382,6 +1382,17 @@ namespace MWWorld mRendering->getTriangleBatchCount(triangles, batches); } + bool + World::isFlying(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + /// \todo check for levitation effects + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(physactor && physactor->getCollisionMode()) + return false; + return true; + } + bool World::isSwimming(const MWWorld::Ptr &object) const { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8b9b39617..d347570fe 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,6 +314,7 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 220ba5d51..e5045eee6 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -54,11 +54,6 @@ namespace Physic collisionMode = collision; } - bool PhysicActor::getCollisionMode() - { - return collisionMode; - } - void PhysicActor::setRotation(const Ogre::Quaternion &quat) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 559bf032e..8ea9657e6 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -78,7 +78,11 @@ namespace Physic void enableCollisions(bool collision); - bool getCollisionMode(); + bool getCollisionMode() const + { + return collisionMode; + } + /** * This returns the visual position of the PhysicActor (used to position a scenenode). From c694161272e61abecd4c429a59c90b8cc05cc03b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 01:28:02 -0800 Subject: [PATCH 194/239] Don't try to step if not on the ground --- apps/openmw/mwworld/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 058160595..dc290ec28 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,8 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + if(!onground || + !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); From 8255a64bfe9038f0aae9df3925ff3f9e6c7c827d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:10:36 -0800 Subject: [PATCH 195/239] Handle levitate and swift swim effects --- apps/openmw/mwclass/npc.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 998b90e19..4a31334ad 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,6 +322,8 @@ namespace MWClass { const MWBase::World *world = MWBase::Environment::get().getWorld(); const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* @@ -330,16 +332,17 @@ namespace MWClass walkSpeed = std::max(0.0f, walkSpeed); if(Npc::getStance(ptr, Sneak, false)) walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); float moveSpeed; - if(normalizedEncumbrance > 1.0f) + if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - 0.0f/*levitationBonus*/); + mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -350,7 +353,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; From a510adc57279f227cfa26af7b45df2921556236c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:25:57 -0800 Subject: [PATCH 196/239] Allow stepping when not being affected by gravity --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index dc290ec28..63f9cb949 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!onground || + if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); From 1399a06c76708c438ea4a3f47a59f267be84c7ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:01:33 -0800 Subject: [PATCH 197/239] Update animation looping when setting the same state --- apps/openmw/mwmechanics/character.cpp | 4 ++++ apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 11 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 00a58523d..713f1bb3b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -260,7 +260,11 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) + { + if(mAnimation) + mAnimation->setLooping(loop); return; + } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a606992a..da91af005 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } +void Animation::setLooping(bool loop) +{ + mLooping = loop; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index fc35c06be..2f930e9ad 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -76,6 +76,8 @@ public: void setSpeed(float speed); + void setLooping(bool loop); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; From 89fabdb3a935a9512df98d91cbe20fabc24332cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:18:15 -0800 Subject: [PATCH 198/239] Update the PhysicActor's RigidBody when moving This works, but is less than ideal. As it is now, the rigid body gets updated twice as the position and rotation are set separately. They should instead be updated together. --- apps/openmw/mwworld/physicssystem.cpp | 4 ++++ libs/openengine/bullet/physic.cpp | 7 +++++++ libs/openengine/bullet/physic.hpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 63f9cb949..ec867326d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -414,6 +414,10 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } + else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) + { + physact->setPosition(position); + } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e5045eee6..4a1c33fb8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -55,6 +55,12 @@ namespace Physic } + void PhysicActor::setPosition(const Ogre::Vector3 &pos) + { + if(pos != getPosition()) + mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + } + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ @@ -62,6 +68,7 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getPosition() { btVector3 vec = mBody->getWorldTransform().getOrigin(); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 8ea9657e6..bd5d3d50a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -69,6 +69,8 @@ namespace Physic ~PhysicActor(); + void setPosition(const Ogre::Vector3 &pos); + /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it From 5d55b41714dfec738b71f5a0c0988d6021b9cb27 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:59:38 -0800 Subject: [PATCH 199/239] Remove a now-unneeded(?) hack --- apps/openmw/mwworld/physicssystem.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ec867326d..5552bd749 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -394,30 +394,13 @@ namespace MWWorld void PhysicsSystem::moveObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Vector3 position = node->getPosition(); - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - - - if(dynamic_cast(body->getCollisionShape()) == NULL){ - btTransform tr = body->getWorldTransform(); - tr.setOrigin(btVector3(position.x,position.y,position.z)); - body->setWorldTransform(tr); - } - else{ - //For objects that contain a box shape. - //Do any such objects exist? Perhaps animated objects? - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); - } - } + Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); + const std::string &handle = node->getName(); + const Ogre::Vector3 &position = node->getPosition(); + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) + body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) - { physact->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) From f8349a04bf95033b8ba4119f460cedb8216c16c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 05:26:58 -0800 Subject: [PATCH 200/239] Use the looping portion of the animation to calculate the velocity --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index da91af005..d63e30247 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -284,12 +284,32 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(track && track->getNumKeyFrames() > 1) { - const Ogre::TransformKeyFrame *startkf, *endkf; - startkf = static_cast(track->getKeyFrame(0)); - endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } - mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / - mCurrentAnim->getLength(); + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } } } From 8196694c08580aece938d644f2f011ad17a08584 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:04:25 -0800 Subject: [PATCH 201/239] Avoid applying the animation when resetting it --- apps/openmw/mwrender/animation.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d63e30247..330045423 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,8 +228,8 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); } return posdiff; } @@ -247,12 +247,24 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mCurrentTime = 0.0f; } - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = 0; + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track) + { + Ogre::TransformKeyFrame kf(0, mCurrentTime); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + mLastPosition = kf.getTranslate() * mAccumulate; + } } } From 86f6491bc8e15782e23f369bf1ff6c0453b04f1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:38:48 -0800 Subject: [PATCH 202/239] Remove unused pmove code --- CMakeLists.txt | 2 - libs/openengine/bullet/physic.cpp | 1 - libs/openengine/bullet/pmove.cpp | 2115 ----------------------------- libs/openengine/bullet/pmove.h | 206 --- libs/openengine/bullet/trace.cpp | 3 - libs/openengine/bullet/trace.h | 4 - 6 files changed, 2331 deletions(-) delete mode 100644 libs/openengine/bullet/pmove.cpp delete mode 100644 libs/openengine/bullet/pmove.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1c7dd3..fac7bb41e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,8 +94,6 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h - ${LIBDIR}/openengine/bullet/pmove.cpp - ${LIBDIR}/openengine/bullet/pmove.h ${LIBDIR}/openengine/bullet/trace.cpp ${LIBDIR}/openengine/bullet/trace.h diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 4a1c33fb8..5d5749d5d 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,7 +2,6 @@ #include #include #include -#include "pmove.h" #include #include "CMotionState.h" #include "OgreRoot.h" diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp deleted file mode 100644 index 9cd76968a..000000000 --- a/libs/openengine/bullet/pmove.cpp +++ /dev/null @@ -1,2115 +0,0 @@ -/* -This source file is a *modified* version of bg_pmove.c from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - - -#include "pmove.h" - -//#include "bprintf.h" - -//#include "..\..\ESMParser\ESMParser\CELL.h" - -//#include "GameTime.h" - -//#include "Sound.h" - -//#include "..\..\ESMParser\ESMParser\SNDG.h" -//#include "..\..\ESMParser\ESMParser\SOUN.h" - -#include - -#include "trace.h" - -//SceneInstance* global_lastscene = NULL; - -// Forward declaration: -void PM_AirMove(); - -static playerMove* pm = NULL; - -//extern std::map ExtCellLookup; - -static struct playermoveLocal -{ - playermoveLocal() : frametime(1.0f / 20.0f), groundPlane(true), walking(true), msec(50) - { - forward = Ogre::Vector3(0.0f, 0.0f, 0.0f); - right = Ogre::Vector3(0.0f, 0.0f, 0.0f); - up = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - previous_origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - previous_velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - } - - traceResults groundTrace; - - //SceneInstance* scene; - - float frametime; // in seconds (usually something like 0.01f) - float impactSpeed; - - Ogre::Vector3 forward; - Ogre::Vector3 right; - Ogre::Vector3 up; - - int msec; - - Ogre::Vector3 previous_origin, previous_velocity; - - int previous_waterlevel; // the waterlevel before this pmove - - bool groundPlane; // if we're standing on a groundplane this frame - - bool walking; - int waterHeight; - bool hasWater; - bool isInterior; - -} pml; - -static inline void PM_ClipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - float backoff; - //float change; - //int i; - - // backoff = in dot normal - //backoff = DotProduct (in, normal); - backoff = in.dotProduct(normal); - - if ( backoff < 0 ) - backoff *= overbounce; - else - backoff /= overbounce; - - // change = normal * backoff - // out = in - change - /*for ( i=0 ; i<3 ; i++ ) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - - }*/ - float changex = normal.x * backoff; - out.x = in.x - changex; - float changey = normal.y * backoff; - out.y = in.y - changey; - float changez = normal.z * backoff; - out.z = in.z - changez; -} - -float VectorNormalize2( const Ogre::Vector3& v, Ogre::Vector3& out) -{ - float length, ilength; - - length = v.x * v.x+ v.y * v.y + v.z * v.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x= v.x * ilength; - out.y = v.y * ilength; - out.z = v.z * ilength; - } else - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) ); -#endif - //VectorClear( out ); - out.x = 0; out.y = 0; out.z = 0; - } - - return length; - -} - - -float VectorNormalize(Ogre::Vector3& out) -{ - float length, ilength; - - length = out.x * out.x + out.y * out.y + out.z * out.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x = out.x * ilength; - out.y = out.y * ilength; - out.z = out.z * ilength; - } - - return length; - -} - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ - -bool PM_SlideMove( bool gravity ) -{ - int bumpcount, numbumps; - Ogre::Vector3 dir; - float d; - int numplanes; - Ogre::Vector3 planes[MAX_CLIP_PLANES]; - Ogre::Vector3 primal_velocity; - Ogre::Vector3 clipVelocity; - int i, j, k; - struct traceResults trace; - Ogre::Vector3 end(0,0,0); - float time_left; - float into; - Ogre::Vector3 endVelocity(0,0,0); - Ogre::Vector3 endClipVelocity(0,0,0); - - numbumps = 4; - - // primal_velocity = pm->ps->velocity - //VectorCopy (pm->ps->velocity, primal_velocity); - primal_velocity = pm->ps.velocity; - - if ( gravity ) - { - // endVelocity = pm->ps->velocity - vec3(0, 0, pm->ps->gravity * pml.frametime) - //VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity = pm->ps.velocity; - //endVelocity[2] -= pm->ps->gravity * pml.frametime; - endVelocity.z -= pm->ps.gravity * pml.frametime; - - // pm->ps->velocity = avg(pm->ps->velocity.z, endVelocity.z) - //pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - pm->ps.velocity.z= (pm->ps.velocity.z + endVelocity.z) * 0.5f; - - //primal_velocity[2] = endVelocity[2]; - primal_velocity.z = endVelocity.z; - - if ( pml.groundPlane ) - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) - { - numplanes = 1; - - // planes[0] = pml.groundTrace.plane.normal - //VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - planes[0] = pml.groundTrace.planenormal; - } else - numplanes = 0; - - // never turn against original velocity - VectorNormalize2( pm->ps.velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) - { - - // calculate position we are trying to move to - //VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - end = pm->ps.origin + pm->ps.velocity * time_left; - - // see if we can make it there - //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, end, pm->ps.halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if (trace.allsolid) - { - // entity is completely trapped in another solid - //pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - if (trace.fraction > 0) - // actually covered some distance - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact8 - //PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) - { - // this shouldn't really happen - //VectorClear( pm->ps->velocity ); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) - { - if (trace.planenormal.dotProduct(planes[i]) > 0.99) //OGRE::VECTOR3 ? - //if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) - { - // pm->ps->velocity += (trace.plane.normal + pm->ps->velocity) - //VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - pm->ps.velocity = trace.planenormal + pm->ps.velocity; - break; - } - } - - if ( i < numplanes ) - continue; - - //VectorCopy (trace.plane.normal, planes[numplanes]); - planes[numplanes] = trace.planenormal; - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) - { - //into = DotProduct( pm->ps->velocity, planes[i] ); - into = pm->ps.velocity.dotProduct(planes[i]); - if ( into >= 0.1 ) - continue; // move doesn't interact with the plane - - - if(planes[i].x >= .70) - { - pm->ps.velocity.z = 0; - return true; - } - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) - pml.impactSpeed = -into; - - // slide along the plane - //PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, planes[i], clipVelocity, OVERCLIP); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) - { - if ( j == i ) - continue; - - if (clipVelocity.dotProduct(planes[j]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - - - - //pm->ps.velocity = Ogre::Vector3(0,0,0); - //return true; - - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if (clipVelocity.dotProduct(planes[i]) >= 0) - //if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) - continue; - - - // slide the original velocity along the crease - //dProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, pm->ps->velocity ); - d = dir.dotProduct(pm->ps.velocity); - - //VectorScale( dir, d, clipVelocity ); - clipVelocity = dir * d; - - //CrossProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, endVelocity ); - d = dir.dotProduct(endVelocity); - - //VectorScale( dir, d, endClipVelocity ); - endClipVelocity = dir * d; - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) - { - - if ( k == i || k == j ) - continue; - - if (clipVelocity.dotProduct(planes[k]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - // stop dead at a tripple plane interaction - //VectorClear( pm->ps->velocity ); - //printf("Stop dead at a triple plane interaction\n"); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - } - - // if we have fixed all interactions, try another move - //VectorCopy( clipVelocity, pm->ps->velocity ); - pm->ps.velocity = clipVelocity; - - //VectorCopy( endClipVelocity, endVelocity ); - endVelocity = endClipVelocity; - break; - } - } - - if ( gravity ) - //VectorCopy( endVelocity, pm->ps->velocity ); - pm->ps.velocity = endVelocity; - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps.pm_time ) - //VectorCopy( primal_velocity, pm->ps->velocity ); - pm->ps.velocity = primal_velocity; - - //return ( (qboolean)(bumpcount != 0) ); - return bumpcount != 0; -} - -/* -================== -PM_StepSlideMove - -================== -*/ -int PM_StepSlideMove( bool gravity ) -{ - Ogre::Vector3 start_o, start_v; - Ogre::Vector3 down_o, down_v; - traceResults trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - Ogre::Vector3 up, down; - float stepSize; - - //std::cout << "StepSlideMove\n"; - // start_o = pm->ps->origin - //VectorCopy (pm->ps->origin, start_o); - start_o = pm->ps.origin; - - // start_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, start_v); - start_v = pm->ps.velocity; - - if ( PM_SlideMove( gravity ) == false ) - return 1; // we got exactly where we wanted to go first try - - - // down = start_o - vec3(0, 0, STEPSIZE) - //VectorCopy(start_o, down); - down = start_o; - down.z -= STEPSIZE; - - //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, start_o, down, , 0, pml.scene); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, down, start_o, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - // up = vec3(0, 0, 1) - //VectorSet(up, 0, 0, 1); - up = Ogre::Vector3(0.0f, 0.0f, 1.0f); - - // never step up when you still have up velocity - //if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) - if (pm->ps.velocity.z > 0 && ( - trace.fraction == 1.0 || trace.planenormal.dotProduct(up) < 0.7 - ) ) - return 2; - - // down_o = pm->ps->origin - //VectorCopy (pm->ps->origin, down_o); - down_o = pm->ps.origin; - - // down_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, down_v); - down_v = pm->ps.velocity; - - // up = start_o + vec3(0, 0, STEPSIZE) - //VectorCopy (start_o, up); - up = start_o; - //up[2] += STEPSIZE; - up.z += STEPSIZE; - - // test the player position if they were a stepheight higher - //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&up, D3DXVECTOR3(0.0f, STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, up, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.allsolid ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:bend can't step\n", c_pmove); - //bprintf("bend can't step\n"); - return 3; // can't step up - } - - //stepSize = trace.endpos[2] - start_o[2]; - stepSize = trace.endpos.z - start_o.z; - - // try slidemove from this position - //VectorCopy (trace.endpos, pm->ps->origin); // pm->ps->origin = trace.endpos - pm->ps.origin = trace.endpos; - //VectorCopy (start_v, pm->ps->velocity); // pm->ps->velocity = start_v - pm->ps.velocity = start_v; - - PM_SlideMove( gravity ); - - // push down the final amount - - // down = pm->ps->origin - vec3(0, 0, stepSize) - //VectorCopy (pm->ps->origin, down); - down = pm->ps.origin; - //down[2] -= stepSize; - down.z -= stepSize; - - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, down, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( !trace.allsolid ) - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if ( trace.fraction < 1.0 ) - //PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, trace.planenormal, pm->ps.velocity, OVERCLIP); - - { - // use the step move - float delta; - - //delta = pm->ps->origin[2] - start_o[2]; - delta = pm->ps.origin.z - start_o.z; - if ( delta > 2 ) - { - pm->ps.counter = 10; - - /* - if (gravity) - printf("g on: %f ", delta); - else - printf("g off: %f ", delta); - - if ( delta < 7 ) - printf("stepped 3 < x < 7\n"); - //PM_AddEvent( EV_STEP_4 ); - else if ( delta < 11 ) - printf("stepped 7 < x < 11\n"); - //PM_AddEvent( EV_STEP_8 ); - else if ( delta < 15 ) - printf("stepped 11 < x < 15\n"); - //PM_AddEvent( EV_STEP_12 ); - else - printf("stepped 15+\n"); - //PM_AddEvent( EV_STEP_16 ); - */ - } - /*if ( pm->debugLevel ) - Com_Printf("%i:stepped\n", c_pmove);*/ - } - - return 4; -} - -void PM_Friction(void) -{ - - Ogre::Vector3 vec; - float* vel; - float speed, newspeed, control; - float drop; - - vel = &(pm->ps.velocity.x); - - // vec = vel - //VectorCopy( vel, vec ); - vec = pm->ps.velocity; - - if ( pml.walking ) - //vec[2] = 0; // ignore slope movement - vec.z = 0; - - //speed = VectorLength(vec); - speed = vec.length(); - if (speed < 1) - { - vel[0] = 0; - vel[1] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - //bprintf("Static friction (vec = [%f, %f, %f]) (vec.length = %f)\n", vec.x, vec.y, vec.z, speed); - return; - } - - drop = 0; - - // apply ground friction - if ( pm->ps.waterlevel <= 1 ) - { - if ( pml.walking )//&& !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) - { - // if getting knocked back, no friction - //if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) - { - control = (speed < pm_stopspeed) ? pm_stopspeed : speed; - drop += control * pm_friction * pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->ps.waterlevel ) - drop += speed * pm_waterfriction * pm->ps.waterlevel * pml.frametime; - - // apply flying friction - /*if ( pm->ps->powerups[PW_FLIGHT]) - drop += speed * pm_flightfriction * pml.frametime; - - if ( pm->ps->pm_type == PM_SPECTATOR) - drop += speed * pm_spectatorfriction * pml.frametime;*/ - if (pm->ps.move_type == PM_SPECTATOR) - drop += speed * pm_flightfriction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - newspeed /= speed; - - // vel *= newspeed - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; -} - -float PM_CmdScale(playerMove::playercmd* const cmd) -{ - int max; - float total; - float scale; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) - max = abs( cmd->rightmove ); - - if ( abs( cmd->upmove ) > max ) - max = abs( cmd->upmove ); - - if ( !max ) - return 0; - - total = sqrtf( (const float)(cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); - scale = (float)pm->ps.speed * max / ( 127.0f * total ); - if(pm->ps.move_type == PM_NOCLIP) - scale *= 10; - - return scale; -} - -static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel ) -{ -// int i; - float addspeed, accelspeed, currentspeed; - - - // currentspeed = pm->ps->velocity dot wishdir - //currentspeed = DotProduct (pm->ps->velocity, wishdir); - currentspeed = pm->ps.velocity.dotProduct(wishdir); - - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = accel * pml.frametime * wishspeed; - - // Clamp accelspeed at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // pm->ps->velocity += accelspeed * wishdir - //for (i=0 ; i<3 ; i++) - //pm->ps->velocity[i] += accelspeed * wishdir[i]; - pm->ps.velocity += (wishdir * accelspeed); - //pm->ps.velocity = wishdir * wishspeed; //New, for instant acceleration - -} - -static bool PM_CheckJump(void) -{ - //if ( pm->ps->pm_flags & PMF_RESPAWNED ) - //return qfalse; // don't allow jump until all buttons are up - - if ( pm->cmd.upmove < 10 ) - // not holding jump - return false; - - pm->cmd.upmove = 0; - - // must wait for jump to be released - /*if ( pm->ps->pm_flags & PMF_JUMP_HELD ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return false; - }*/ - - pml.groundPlane = false; // jumping away - pml.walking = false; - //pm->ps->pm_flags |= PMF_JUMP_HELD; - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.z = pm->ps.jump_velocity; - pm->ps.bSnap = false; - //PM_AddEvent( EV_JUMP ); - - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - - return true; -} - -static void PM_WaterMove( playerMove* const pm ) -{ - //int i; - //vec3_t wishvel; - Ogre::Vector3 wishvel; - float wishspeed; - //vec3_t wishdir; - Ogre::Vector3 wishdir; - float scale; - float vel; - - pm->ps.bSnap = false; - - /*if ( PM_CheckWaterJump() ) - { - PM_WaterJumpMove(); - return; - }*/ -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - if (pm->cmd.forwardmove || pm->cmd.rightmove) - { - //NEEDS TO BE REWRITTEN FOR OGRE TIME--------------------------------------------------- - /* - static const TimeTicks footstep_duration = GetTimeFreq(); // make each splash last 1.0s - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pm->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // splashes while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - //-----------------jhooks1 - - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_swim : SNDG::l_swim); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - //Sound, ignore for now -- jhooks1 - //} - } - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - */ - wishvel.x = 0; - wishvel.z = -60; - wishvel.y = 0; - } - else - { - /*for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;*/ - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps.speed * pm_swimScale ) - wishspeed = pm->ps.speed * pm_swimScale; - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - //if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) - if (pml.groundPlane && pm->ps.velocity.dotProduct(pml.groundTrace.planenormal) < 0.0f) - { - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - - VectorNormalize(pm->ps.velocity); - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - } - - PM_SlideMove( false ); -} - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( playerMove* const pmove ) -{ -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - float accelerate; - float vel; - //pm->ps.gravity = 4000; - - //std::cout << "Player is walking\n"; - - if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) - { - // begin swimming - PM_WaterMove(pmove); - return; - } - - - if ( PM_CheckJump () ) - { - - // jumped away - if ( pm->ps.waterlevel > 1 ) - PM_WaterMove(pmove); - else - PM_AirMove(); - //printf("Jumped away\n"); - return; - } - - // Footsteps time - if (pmove->cmd.forwardmove || pmove->cmd.rightmove) - { - bool step_underwater = false; - //if (pmove->traceObj) - //{ - - - //jhooks1 - Water handling, deal with later - - - - if (pmove->hasWater) - { - if (pmove->hasWater ) - { - const float waterHeight = pmove->waterHeight; - const float waterSoundStepHeight = waterHeight + pm->ps.halfExtents.y; - if (pmove->ps.origin.y < waterSoundStepHeight) - step_underwater = true; - } - } - //} - - /* - static const TimeTicks footstep_duration = GetTimeFreq() / 2; // make each footstep last 500ms - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pmove->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // footsteps while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - - if (step_underwater) - { - /* - const namestruct ns(lastWasLeft ? "FootWaterRight" : "FootWaterLeft"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - else - { - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_foot : SNDG::l_foot); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - - PM_Friction (); - - - //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; - - //pml.right[2] = 0; - pml.right.z = 0; - //std::cout << "Further down" << pm->ps.velocity << "\n"; - - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); - //std::cout << "Clip velocity" << pm->ps.velocity << "\n"; - // - - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - //pml.forward = pml.forward.normalise(); - //pml.right = pml.right.normalise(); - //std::cout << "forward2" << pml.forward << "\n"; - //std::cout << "right2" << pml.right << "\n"; - - - // wishvel = (pml.forward * fmove) + (pml.right * smove); - //for ( i = 0 ; i < 3 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - - //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); - - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - // wishdir = wishvel - //VectorCopy (wishvel, wishdir); - //wishvel = wishdir; - wishdir = wishvel; - - wishspeed = VectorNormalize(wishdir); - //std::cout << "Wishspeed: " << wishspeed << "\n"; - wishspeed *= scale; - //std::cout << "Wishspeed scaled:" << wishspeed << "\n"; - - // clamp the speed lower if ducking - if ( pm->cmd.ducking ) - if ( wishspeed > pm->ps.speed * pm_duckScale ) - wishspeed = pm->ps.speed * pm_duckScale; - - // clamp the speed lower if wading or walking on the bottom - if ( pm->ps.waterlevel ) - { - float waterScale; - - waterScale = pm->ps.waterlevel / 3.0f; - waterScale = 1.0f - ( 1.0f - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps.speed * waterScale ) - wishspeed = pm->ps.speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //accelerate = pm_airaccelerate; - //else - accelerate = pm_accelerate; - - - PM_Accelerate (wishdir, wishspeed, accelerate); - //std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - //else - //{ - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - //} - - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - //std::cout << "The length" << vel << "\n"; - - // slide along the ground plane - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, - pm->ps.velocity, OVERCLIP ); - //std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps.velocity); - //pm->ps.velocity = pm->ps.velocity.normalise(); - - //std::cout << "Final:" << pm->ps.velocity << "\n"; - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - - // don't do anything if standing still - //if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) - if (!pm->ps.velocity.x && !pm->ps.velocity.z) - return; - - PM_StepSlideMove( false ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - - -} - -void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::playercmd* const cmd ) -{ - short temp; - int i; - - //while(1); - - //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) - //return; // no view changes at all - - //if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) - //return; // no view changes at all - - // circularly clamp the angles with deltas - //bprintf("View angles: %i, %i, %i\n", cmd->angles[0], cmd->angles[1], cmd->angles[2]); - for (i = 0 ; i < 3 ; i++) - { - temp = cmd->angles[i];// + ps->delta_angles[i]; - //if ( i == PITCH ) - { - // don't let the player look up or down more than 90 degrees - /*if ( temp > 16000 ) - { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp = 16000; - } - else if ( temp < -16000 ) - { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp = -16000; - }*/ - } - (&(ps->viewangles.x) )[i] = SHORT2ANGLE(temp); - //cmd->angles[i] += ps->delta_angles[i]; - } - //ps->delta_angles[0] = ps->delta_angles[1] = ps->delta_angles[2] = 0; - -} - -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) -{ - float angle; - static float sr, sp, sy, cr, cp, cy; - // static to help MS compiler fp bugs - - //angle = angles[YAW] * (M_PI*2 / 360); - angle = angles.x * (M_PI * 2.0f / 360.0f); - sp = sinf(angle); - cp = cosf(angle); - - //angle = angles[PITCH] * (M_PI*2 / 360); - angle = angles.y * (-M_PI * 2.0f / 360.0f); - sy = sinf(angle); - cy = cosf(angle); - - //angle = angles[ROLL] * (M_PI*2 / 360); - angle = angles.z * (M_PI * 2.0f / 360.0f); - sr = sinf(angle); - cr = cosf(angle); - - if (forward) - { - forward->x = cp * cy; - forward->y = cp * sy; - forward->z = -sp; - } - if (right) - { - right->x = (-1 * sr * sp * cy + -1 * cr * -sy); - right->y = (-1 * sr * sp * sy + -1 * cr * cy); - right->z = 0; - } - if (up) - { - up->x =(cr * sp * cy + -sr * -sy); - up->y=(cr * sp * sy + -sr * cy); - up->z = cr * cp; - } - -} - -void PM_GroundTraceMissed() -{ - traceResults trace; - Ogre::Vector3 point; - //We should not have significant upwards velocity when in the air, unless we jumped. - //This code protects against flying into the air when moving at high speeds. - //Z velocity is set to 50, instead of 0, to help move up certain steps. - - //std::cout << "Ground trace missed\n"; - // we just transitioned into freefall - //if ( pm->debugLevel ) - //Com_Printf("%i:lift\n", c_pmove); - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - //VectorCopy( pm->ps->origin, point ); - point = pm->ps.origin; - //point[2] -= 64; - point.z -= 32; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - //It hit the ground below - if ( trace.fraction < 1.0 && pm->ps.origin.z > trace.endpos.z) - { - pm->ps.origin = trace.endpos; - pml.walking = true; - pml.groundPlane = true; - pm->ps.groundEntityNum = trace.entityNum; - - } - else{ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - pm->ps.bSnap = false; - } - - -} - -static bool PM_CorrectAllSolid(traceResults* const trace) -{ - int i, j, k; - Ogre::Vector3 point; - - //if ( pm->debugLevel ) - //Com_Printf("%i:allsolid\n", c_pmove); - //bprintf("allsolid\n"); - - // jitter around - for (i = -1; i <= 1; i++) - { - for (j = -1; j <= 1; j++) - { - for (k = -1; k <= 1; k++) - { - //VectorCopy(pm->ps->origin, point); - point = pm->ps.origin; - - /*point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k;*/ - point += Ogre::Vector3( (const float)i, (const float)j, (const float)k); - - //pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&point, *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0, pml.traceObj); - newtrace(trace, point, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if ( !trace->allsolid ) - { - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = *trace; - return true; - } - } - } - } - - //pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - - return false; -} - -static void PM_CrashLand( void ) -{ - float delta; - float dist ; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) - PM_ForceLegsAnim( LEGS_LANDB ); - else - PM_ForceLegsAnim( LEGS_LAND ); - - pm->ps->legsTimer = TIMER_LAND;*/ - - // calculate the exact velocity on landing - //dist = pm->ps->origin[2] - pml.previous_origin[2]; - - dist = pm->ps.origin.z - pml.previous_origin.z; - - //vel = pml.previous_velocity[2]; - vel = pml.previous_velocity.z; - - //acc = -pm->ps->gravity; - acc = -pm->ps.gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) - return; - - t = (-b - sqrtf( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta * delta * 0.0001f; - - // ducking while falling doubles damage - /*if ( pm->ps->pm_flags & PMF_DUCKED ) - delta *= 2;*/ - if (pm->cmd.upmove < -20) - delta *= 2; - - // never take falling damage if completely underwater - if ( pm->ps.waterlevel == 3 ) - return; - - // reduce falling damage if there is standing water - if ( pm->ps.waterlevel == 2 ) - delta *= 0.25; - if ( pm->ps.waterlevel == 1 ) - delta *= 0.5; - - if ( delta < 1 ) - return; -/* - if (delta > 60) - printf("Far crashland: %f\n", delta); - else if (delta > 40) - printf("Medium crashland: %f\n", delta); - else if (delta > 4) - printf("Short crashland: %f\n", delta); -*/ - if (delta > 60) - { - /* - static const namestruct healthDamage("Health Damage"); - const SOUN* const soun = SOUN::GetSound(healthDamage); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - - if (delta > 3) // We need at least a short crashland to proc the sound effects: - { - bool splashSound = false; - - if (pm->hasWater) - { - - const float waterHeight = pm->waterHeight; - const float waterHeightSplash = waterHeight + pm->ps.halfExtents.y; - if (pm->ps.origin.z < waterHeightSplash) - { - splashSound = true; - } - - } - - - if (splashSound) - { - //Change this later----------------------------------- - /* - const namestruct ns("DefaultLandWater"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundDatga->GetVolumeFloat() ); - }*/ - } - else - { - //Change this later--------------------------------- - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, SNDG::land); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - //if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) - { - /*if ( delta > 60 ) - PM_AddEvent( EV_FALL_FAR ); - else if ( delta > 40 ) - { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) - PM_AddEvent( EV_FALL_MEDIUM ); - } - else if ( delta > 7 ) - PM_AddEvent( EV_FALL_SHORT ); - else - PM_AddEvent( PM_FootstepForSurface() );*/ - } - - // start footstep cycle over - //pm->ps->bobCycle = 0; -} - -static void PM_GroundTrace( void ) -{ - Ogre::Vector3 point; - traceResults trace; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - //std::cout << "ALL SOLID\n"; - if ( !PM_CorrectAllSolid(&trace) ){ - //std::cout << "Returning after correct all solid\n"; - return; - } - } - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0) - { - if(pm->ps.velocity.z > 50.0f && pm->ps.bSnap && pm->ps.speed > 1000.0f) - pm->ps.velocity.z = 50.0f; - if(pm->ps.snappingImplemented){ - if(pm->ps.bSnap && pm->ps.counter <= 0) - PM_GroundTraceMissed(); - } - - - - return; - } - else - { - //It hit something, so we are on the ground - pm->ps.bSnap = true; - - } - // check if getting thrown off the ground - //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:kickoff\n", c_pmove); - - // go into jump animation - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - if(!pm->ps.bSnap){ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - } - else - { - pml.groundPlane = true; - pml.walking = true; - } - return; - } - - - - - // slopes that are too steep will not be considered onground - //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) - //std::cout << "MinWalkNormal" << trace.planenormal.z; - if (trace.planenormal.z < MIN_WALK_NORMAL) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:steep\n", c_pmove); - - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = true; - pml.walking = false; - return; - } - - pml.groundPlane = true; - pml.walking = true; - - // hitting solid ground will end a waterjump - /*if (pm->ps.pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - }*/ - - if ( pm->ps.groundEntityNum == ENTITYNUM_NONE ) - { - // just hit the ground - /*if ( pm->debugLevel ) - Com_Printf("%i:Land\n", c_pmove);*/ - //bprintf("Land\n"); - - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - //if ( pml.previous_velocity[2] < -200 ) - if (pml.previous_velocity.z < -200) - { - // don't allow another jump for a little while - //pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps.pm_time = 250; - } - } - - pm->ps.groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - //PM_AddTouchEnt( trace.entityNum ); -} - -void PM_AirMove() -{ - //int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - //pm->ps.gravity = 800; - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; //Z or Y? - //pml.right[2] = 0; - pml.right.z = 0; - //VectorNormalize (pml.forward); - VectorNormalize(pml.forward); - VectorNormalize(pml.right); - //VectorNormalize (pml.right); - - //for ( i = 0 ; i < 2 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - //wishvel[2] = 0; - wishvel.z = 0; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); - -/*#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif*/ - //std::cout << "Moving in the air" << pm->ps.velocity << "\n"; - - /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; - - -} - -static void PM_NoclipMove( void ) -{ - float speed, drop, friction, control, newspeed; -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - - //pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - //speed = VectorLength (pm->ps->velocity); - speed = pm->ps.velocity.length(); - if (speed < 1) - //VectorCopy (vec3_origin, pm->ps->velocity); - pm->ps.velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - //VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * newspeed; - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - //for (i=0 ; i<3 ; i++) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - - wishvel = pml.forward * fmove + pml.right * smove; - //wishvel[2] += pm->cmd.upmove; - wishvel.z += pm->cmd.upmove; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - //VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); - pm->ps.origin = pm->ps.origin + pm->ps.velocity * pml.frametime; -} - -static void PM_DropTimers( void ) -{ - // drop misc timing counter - if ( pm->ps.pm_time ) - { - if ( pml.msec >= pm->ps.pm_time ) - { - //pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps.pm_time = 0; - } - else - pm->ps.pm_time -= pml.msec; - } - - //bprintf("Time: %i\n", pm->ps.pm_time); - - // drop animation counter - /*if ( pm->ps->legsTimer > 0 ) - { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) - pm->ps->legsTimer = 0; - } - - if ( pm->ps->torsoTimer > 0 ) - { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) - pm->ps->torsoTimer = 0; - }*/ -} - -static void PM_FlyMove( void ) -{ - //int i; - Ogre::Vector3 wishvel; - float wishspeed; - Ogre::Vector3 wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0;*/ - wishvel = Ogre::Vector3(0,0,0); - } - else - { - //for (i=0 ; i<3 ; i++) - //wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += /*6.35f * */pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( false ); -} - - -void PM_SetWaterLevel( playerMove* const pm ) -{ - Ogre::Vector3 point; - //int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - - pm->ps.waterlevel = WL_DRYLAND; - pm->ps.watertype = 0; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; */ - point.x = pm->ps.origin.x; - point.y = pm->ps.origin.y; - point.z = pm->ps.origin.z + MINS_Z + 1; - - //cont = pm->pointcontents( point, pm->ps->clientNum ); - bool checkWater = (pml.hasWater && pml.waterHeight > point.z); - //if ( cont & MASK_WATER ) - if ( checkWater) - { - sample2 = /*pm->ps.viewheight*/DEFAULT_VIEWHEIGHT - MINS_Z; - sample1 = sample2 / 2; - - pm->ps.watertype = CONTENTS_WATER;//cont; - pm->ps.waterlevel = WL_ANKLE; - //point[2] = pm->ps->origin[2] + MINS_Z + sample1; - point.z = pm->ps.origin.z + MINS_Z + sample1; - checkWater = (pml.hasWater && pml.waterHeight > point.z); - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - if (checkWater) - { - pm->ps.waterlevel = WL_WAIST; - //point[2] = pm->ps->origin[2] + MINS_Z + sample2; - point.z = pm->ps.origin.z + MINS_Z + sample2; - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - checkWater = (pml.hasWater && pml.waterHeight > point.z); - if (checkWater ) - pm->ps.waterlevel = WL_UNDERWATER; - } - } -} - -void PmoveSingle (playerMove* const pmove) -{ - pmove->ps.counter--; - //pm = pmove; - - // Aedra doesn't support Q3-style VM traps D: //while(1); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - //c_pmove++; - - // clear results - //pm->numtouch = 0; - pm->ps.watertype = 0; - pm->ps.waterlevel = WL_DRYLAND; - - //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) - //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - //if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) - //pm->cmd.buttons &= ~BUTTON_WALKING; - - - // set the talk balloon flag - //if ( pm->cmd.buttons & BUTTON_TALK ) - //pm->ps->eFlags |= EF_TALK; - //else - //pm->ps->eFlags &= ~EF_TALK; - - // set the firing flag for continuous beam weapons - /*if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) - pm->ps->eFlags |= EF_FIRING; - else - pm->ps->eFlags &= ~EF_FIRING;*/ - - // clear the respawned flag if attack and use are cleared - /*if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) - pm->ps->pm_flags &= ~PMF_RESPAWNED;*/ - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - /*if ( pmove->cmd.buttons & BUTTON_TALK ) - { - // keep the talk button set tho for when the cmd.serverTime > 66 msec - // and the same cmd is used multiple times in Pmove - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - }*/ - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml) ); - - // Aedra-specific code: - //pml.scene = global_lastscene; - - - // End Aedra-specific code - pml.hasWater = pmove->hasWater; - pml.isInterior = pmove->isInterior; - pml.waterHeight = pmove->waterHeight; - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; - if ( pml.msec < 1 ) - pml.msec = 1; - else if ( pml.msec > 200 ) - pml.msec = 200; - - //pm->ps->commandTime = pmove->cmd.serverTime; - - // Commented out as a hack - pm->ps.commandTime = pmove->cmd.serverTime; - - // Handle state change procs: - if (pm->cmd.activating != pm->cmd.lastActivatingState) - { - if (!pm->cmd.lastActivatingState && pm->cmd.activating) - pm->cmd.procActivating = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procActivating = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procActivating = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastActivatingState = pm->cmd.activating; - - if (pm->cmd.dropping != pm->cmd.lastDroppingState) - { - if (!pm->cmd.lastDroppingState && pm->cmd.dropping) - pm->cmd.procDropping = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procDropping = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procDropping = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastDroppingState = pm->cmd.dropping; - - // save old org in case we get stuck - //VectorCopy (pm->ps->origin, pml.previous_origin); - pml.previous_origin = pm->ps.origin; - - // Copy over the lastframe origin - pmove->ps.lastframe_origin = pmove->ps.origin; - - //pmove->ps.lastframe_origin = pmove->ps.origin; - - // save old velocity for crashlanding - //VectorCopy (pm->ps->velocity, pml.previous_velocity); - pml.previous_velocity = pm->ps.velocity; - - pml.frametime = pml.msec * 0.001f; - - // update the viewangles - //PM_UpdateViewAngles( &(pm->ps), &(pm->cmd) ); - - AngleVectors (pm->ps.viewangles, &(pml.forward), &(pml.right), &(pml.up) ); - - //if ( pm->cmd.upmove < 10 ) - // not holding jump - //pm->ps->pm_flags &= ~PMF_JUMP_HELD; - - // decide if backpedaling animations should be used - /*if ( pm->cmd.forwardmove < 0 ) - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;*/ - - /*if ( pm->ps->pm_type >= PM_DEAD ) - { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - }*/ - - if ( pm->ps.move_type == PM_SPECTATOR ) - { - - //PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps.move_type == PM_NOCLIP ) - { - - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps.move_type == PM_FREEZE){ - - return; // no movement at all - - } - - if ( pm->ps.move_type == PM_INTERMISSION || pm->ps.move_type == PM_SPINTERMISSION){ - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(pmove); - pml.previous_waterlevel = pmove->ps.waterlevel; - - // set mins, maxs, and viewheight - //PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - - /*if ( pm->ps->pm_type == PM_DEAD ) - PM_DeadMove (); - - PM_DropTimers();*/ - - PM_DropTimers(); - -/*#ifdef MISSIONPACK - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_InvulnerabilityMove(); - } else -#endif*/ - /*if ( pm->ps->powerups[PW_FLIGHT] ) - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } - else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - PM_WaterJumpMove();*/ - if ( pmove->ps.waterlevel > 1 ) - // swimming - PM_WaterMove(pmove); - else if ( pml.walking ) - { - - // walking on ground - PM_WalkMove(pmove); - //bprintf("WalkMove\n"); - } - else - { - // airborne - //std::cout << "AIRMOVE\n"; - PM_AirMove(); - //bprintf("AirMove\n"); - } - - //PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - PM_SetWaterLevel(pmove); - - // weapons - /*PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity );*/ -} - -void Ext_UpdateViewAngles(playerMove* const pm) -{ - playerMove::playerStruct* const ps = &(pm->ps); - playerMove::playercmd* const cmd = &(pm->cmd); - PM_UpdateViewAngles(ps, cmd); -} - -void Pmove (playerMove* const pmove) -{ - // warning: unused variable ‘fmove’ - //int fmove = pmove->cmd.forwardmove; - - pm = pmove; - - int finalTime; - - finalTime = pmove->cmd.serverTime; - - pmove->ps.commandTime = 40; - - if ( finalTime < pmove->ps.commandTime ) - return; // should not happen - - if ( finalTime > pmove->ps.commandTime + 1000 ) - pmove->ps.commandTime = finalTime - 1000; - - pmove->ps.pmove_framecount = (pmove->ps.pmove_framecount + 1) & ( (1 << PS_PMOVEFRAMECOUNTBITS) - 1); - - // chop the move up if it is too long, to prevent framerate - // dependent behavior - while ( pmove->ps.commandTime != finalTime ) - { - int msec; - - msec = finalTime - pmove->ps.commandTime; - - if ( pmove->pmove_fixed ) - { - if ( msec > pmove->pmove_msec ) - msec = pmove->pmove_msec; - } - else - { - if ( msec > 66 ) - msec = 66; - } - - pmove->cmd.serverTime = pmove->ps.commandTime + msec; - - if (pmove->isInterior) - { - PmoveSingle( pmove ); - } - else - { - PmoveSingle( pmove ); - /* - std::map::const_iterator it = ExtCellLookup.find(PositionToCell(pmove->ps.origin) ); - if (it != ExtCellLookup.end() ) - { - pmove->traceObj->incellptr = it->second; - }*/ - } - - //if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) - //pmove->cmd.upmove = 20; - } - - //pmove->ps.last_compute_time = GetTimeQPC(); - //pmove->ps.lerp_multiplier = (pmove->ps.origin - pmove->ps.lastframe_origin);// * (1.000 / 31.0); - - //PM_CheckStuck(); - -} - - diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h deleted file mode 100644 index 29a050471..000000000 --- a/libs/openengine/bullet/pmove.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef OENGINE_BULLET_PMOVE_H -#define OENGINE_BULLET_PMOVE_H -/* -This source file is a *modified* version of various header files from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - -#include -#include - -#include - -//#include "GameMath.h" -//#include "GameTime.h" - -// Forwards-declare it! - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -/*#ifndef COMPILING_PMOVE -#include "Scene.h" -extern SceneInstance* global_lastscene; -#endif*/ - -static const Ogre::Vector3 halfExtentsDefault(14.64f * 2, 14.24f * 2, 33.25f * 2); - -#define MAX_CLIP_PLANES 5 -#define OVERCLIP 1.001f -//#define STEPSIZE 18 // 18 is way too much -#define STEPSIZE (9) -#ifndef M_PI - #define M_PI 3.14159265358979323846f -#endif -#define YAW 0 -#define PITCH /*1*/2 -#define ROLL /*2*/1 -#define SHORT2ANGLE(x) ( (x) * (360.0f / 65536.0f) ) -#define ANGLE2SHORT(x) ( (const short)( (x) / (360.0f / 65536.0f) ) ) -#define GENTITYNUM_BITS 10 // don't need to send any more -#define MAX_GENTITIES (1 << GENTITYNUM_BITS) -#define ENTITYNUM_NONE (MAX_GENTITIES - 1) -#define ENTITYNUM_WORLD (MAX_GENTITIES - 2) -#define MIN_WALK_NORMAL .7f // can't walk on very steep slopes -#define PS_PMOVEFRAMECOUNTBITS 6 -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT (-16) -#define CONTENTS_SOLID 1 // an eye is never valid in a solid -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_FOG 64 -static const float pm_accelerate = 10.0f; -static const float pm_stopspeed = 100.0f; -static const float pm_friction = 12.0f; -static const float pm_flightfriction = 3.0f; -static const float pm_waterfriction = 1.0f; -static const float pm_airaccelerate = 1.0f; -static const float pm_swimScale = 0.50f; -static const float pm_duckScale = 0.25f; -static const float pm_flyaccelerate = 8.0f; -static const float pm_wateraccelerate = 4.0f; - -enum pmtype_t -{ - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -}; - -enum waterlevel_t -{ - WL_DRYLAND = 0, - WL_ANKLE, - WL_WAIST, - WL_UNDERWATER -}; - - -//#include "bprintf.h" - -struct playerMove -{ - struct playerStruct - { - playerStruct() : gravity(800.0f), speed(480.0f), jump_velocity(270), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1), halfExtents(halfExtentsDefault) - { - origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - delta_angles[0] = delta_angles[1] = delta_angles[2] = 0; - - lastframe_origin.x = lastframe_origin.y = lastframe_origin.z = 0; - lerp_multiplier.x = lerp_multiplier.y = lerp_multiplier.z = 0; - } - - inline void SpeedUp(void) - { - //printf("speed up to: %f\n", speed); - speed *= 1.25f; - } - - inline void SpeedDown(void) - { - //printf("speed down to %f\n", speed); - speed /= 1.25f; - } - - Ogre::Vector3 velocity; - Ogre::Vector3 origin; - Ogre::Vector3 halfExtents; - bool bSnap; - bool snappingImplemented; - int counter; - float gravity; // default = 800 - float speed; // default = 320 - float jump_velocity; //default = 270 - - int commandTime; // the time at which this command was issued (in milliseconds) - - int pm_time; - - Ogre::Vector3 viewangles; - - int groundEntityNum; - - int pmove_framecount; - - int watertype; - waterlevel_t waterlevel; - - signed short delta_angles[3]; - - pmtype_t move_type; - - float last_compute_time; - Ogre::Vector3 lastframe_origin; - Ogre::Vector3 lerp_multiplier; - } ps; - - struct playercmd - { - enum CMDstateChange - { - NO_CHANGE, - KEYDOWN, - KEYUP - }; - - playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), - activating(false), lastActivatingState(false), procActivating(NO_CHANGE), - dropping(false), lastDroppingState(false), procDropping(NO_CHANGE) - { - angles[0] = angles[1] = angles[2] = 0; - } - - int serverTime; - - short angles[3]; - - signed char forwardmove; - signed char rightmove; - signed char upmove; - - bool ducking; - bool activating; // if the user is holding down the activate button - bool dropping; // if the user is dropping an item - - bool lastActivatingState; - bool lastDroppingState; - - CMDstateChange procActivating; - CMDstateChange procDropping; - } cmd; - - playerMove() : msec(50), pmove_fixed(false), pmove_msec(50), waterHeight(0), isInterior(true), hasWater(false) - { - } - - int msec; - int pmove_msec; - bool pmove_fixed; - int waterHeight; - bool hasWater; - bool isInterior; - OEngine::Physic::PhysicEngine* mEngine; -}; - -void Pmove (playerMove* const pmove); -void Ext_UpdateViewAngles(playerMove* const pm); -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) ; -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 138411e11..618f6ee65 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -7,7 +7,6 @@ #include #include "physic.hpp" -#include "pmove.h" enum traceWorldType @@ -105,7 +104,6 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; results->fraction = 1.0f; } else @@ -113,6 +111,5 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr results->fraction = out.fraction; results->planenormal = out.hitNormal; results->endpos = (end-start)*results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 94708d403..7b17da178 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -20,10 +20,6 @@ struct traceResults float fraction; - int surfaceFlags; - int contents; - int entityNum; - bool allsolid; bool startsolid; }; From 66743ecee70623d2d97291af7268fdcbf3a614e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 07:00:22 -0800 Subject: [PATCH 203/239] Remove some unused trace fields --- libs/openengine/bullet/trace.cpp | 39 +++++--------------------------- libs/openengine/bullet/trace.h | 3 --- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 618f6ee65..2f52d669a 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -29,14 +29,12 @@ struct NewPhysTraceResults Ogre::Vector3 endPos; Ogre::Vector3 hitNormal; float fraction; - bool startSolid; //const Object* hitObj; }; -template -static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); @@ -49,7 +47,7 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; + newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); @@ -66,24 +64,6 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve out->endPos.y = tracehitpos.y(); out->endPos.z = tracehitpos.z(); - // StartSolid test: - { - out->startSolid = false; - if(isInterior) - { - // If inside and out of the tree, we're solid - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - btVector3 point(start.x, start.y, start.z); - if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) - { - //We're solid - //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! - //out->startSolid = true; - } - } - } - return newTraceCallback.hasHit(); } @@ -91,15 +71,8 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object { NewPhysTraceResults out; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, - Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - results->allsolid = out.startSolid; - + bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); if(!hasHit) { results->endpos = end; diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 7b17da178..34ecb7454 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -19,9 +19,6 @@ struct traceResults Ogre::Vector3 planenormal; float fraction; - - bool allsolid; - bool startsolid; }; void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); From 6ae00be8a32966c2f7a9f433464e565a70f488db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 22:28:15 -0800 Subject: [PATCH 204/239] Fix nifbullet shape transformation --- components/nifbullet/bullet_nif_loader.cpp | 134 ++++++--------------- components/nifbullet/bullet_nif_loader.hpp | 18 +-- 2 files changed, 46 insertions(+), 106 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 9c6dafa34..a619bdda2 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace NifBullet; - +namespace NifBullet +{ ManualBulletShapeLoader::~ManualBulletShapeLoader() { } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) -{ - Ogre::Quaternion oquat(m); - btQuaternion quat; - quat.setW(oquat.w); - quat.setX(oquat.x); - quat.setY(oquat.y); - quat.setZ(oquat.z); - return quat; -} - btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); @@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - // The first record is assumed to be the root node Nif::Record *r = nif.getRecord(0); assert(r != NULL); @@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,NULL,hasCollisionNode,false,false); + handleNode(node,0,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->mCollide == false) - { - handleNode(node,0,NULL,hasCollisionNode,false,true); - } + handleNode(node,0,hasCollisionNode,false,true); //cShape->collide = hasCollisionNode&&cShape->collide; @@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) cShape->Shape = mBoundingBox; - else { currentShape = new TriangleMeshShape(mTriMesh,true); @@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { - if (node->recType == Nif::RC_NiNode) + if(node->recType == Nif::RC_RootCollisionNode) + return true; + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; ichildren; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) + if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) return true;; + if(hasRootCollisionNode(list[i].getPtr())) + return true; } } } - else if (node->recType == Nif::RC_NiTriShape) - { - return false; - } - else if(node->recType == Nif::RC_RootCollisionNode) - { - return true; - } return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, + bool hasCollisionNode, bool isCollisionNode, + bool raycastingOnly) { - // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; @@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, } } - Nif::Transformation childTrafo = node->trafo; - - if (parentTrafo) - { - - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; - - // Merge the rotations together - childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; - - // Scale - childTrafo.scale *= parentTrafo->scale; - - } - if(node->hasBounds) { - - - btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; - - mBoundingBox = new btBoxShape(boxsize); + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } - - // For NiNodes, loop through children - if (node->recType == Nif::RC_NiNode) - { - Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); } - else if(node->recType == Nif::RC_RootCollisionNode) + + // For NiNodes, loop through children + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_RootCollisionNode); + + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) - handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); + if(!list[i].empty()) + handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycastingOnly) { assert(shape != NULL); @@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int return; - Nif::NiTriShapeData *data = shape->data.getPtr(); - + const Nif::NiTriShapeData *data = shape->data.getPtr(); const std::vector &vertices = data->vertices; - const Ogre::Matrix3 &rot = shape->trafo.rotation; - const Ogre::Vector3 &pos = shape->trafo.pos; - float scale = shape->trafo.scale * parentScale; - short* triangles = &data->triangles[0]; + const short *triangles = &data->triangles[0]; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; - Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; - Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; + Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; + Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; + Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } @@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr return; OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); } + +} // namespace NifBullet diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 520878ce1..0629b208d 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -51,19 +51,18 @@ namespace NifBullet class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); - void warn(std::string msg) + void warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; } - void fail(std::string msg) + void fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } /** @@ -79,31 +78,26 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node const * node); + bool hasRootCollisionNode(const Nif::Node *node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); std::string resourceName; std::string resourceGroup; - - OEngine::Physic::BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; From cfdc820a1f6382be2c78c0a71f20fa2e7f893cd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 01:55:12 -0800 Subject: [PATCH 205/239] Make an actor fly when it has a levitate effect --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1a6630232..e75bd1677 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -886,12 +888,14 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, + !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, + !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } // the only purpose this has currently is to update the debug drawer @@ -1386,11 +1390,15 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - /// \todo check for levitation effects const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(physactor && physactor->getCollisionMode()) - return false; - return true; + if(!physactor || !physactor->getCollisionMode()) + return true; + + const MWWorld::Class &cls = MWWorld::Class::get(ptr); + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + return true; + + return false; } bool From 617158afcd43efc533fb49e07e736df60fcf6696 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 02:32:48 -0800 Subject: [PATCH 206/239] Ensure updated skeleton bone placement matches in world space Objects attached to actors (shirts, robes, etc) do not require the same node hierarchy as the character root. So to ensure proper placement, we need to set the bone target's derived transformation using the source bone's derived transformation (which in turn means we need to work up from the root, to ensure the bone's parents are properly placed). --- apps/openmw/mwrender/animation.cpp | 42 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 330045423..f4b618866 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -197,19 +197,41 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) +{ + if(skelsrc->hasBone(bone->getName())) + { + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + if(!srcbone->getParent() || !bone->getParent()) + { + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } + else + { + bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); + bone->_setDerivedPosition(srcbone->_getDerivedPosition()); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + } + } + else + { + // No matching bone in the source. Make sure it stays properly offset + // from its parent. + bone->resetToInitialState(); + } + + Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator(); + while(boneiter.hasMoreElements()) + updateBoneTree(skelsrc, static_cast(boneiter.getNext())); +} + void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) { - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - if(!skelsrc->hasBone(bone->getName())) - continue; - Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); - bone->setOrientation(srcbone->getOrientation()); - bone->setPosition(srcbone->getPosition()); - bone->setScale(srcbone->getScale()); - } + updateBoneTree(skelsrc, boneiter.getNext()); } From fe6fa9ebe745ca2bb2cbe2b70e82eb150a50575d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 04:14:52 -0800 Subject: [PATCH 207/239] Simplify newtrace a bit --- apps/openmw/mwworld/physicssystem.cpp | 15 ++++---- libs/openengine/bullet/trace.cpp | 51 ++++++--------------------- libs/openengine/bullet/trace.h | 2 +- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5552bd749..0b9e13fb7 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -34,18 +34,18 @@ namespace MWWorld { private: static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, - float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + const Ogre::Vector3 &halfExtents, bool isInterior, OEngine::Physic::PhysicEngine *engine) { traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, engine); + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -105,7 +105,6 @@ namespace MWWorld bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 velocity; @@ -120,7 +119,7 @@ namespace MWWorld { if(!(movement.z > 0.0f)) { - newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } @@ -145,7 +144,7 @@ namespace MWWorld int iterations = 0; do { // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); @@ -157,7 +156,7 @@ namespace MWWorld if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if((gravity && !onground) || - !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); @@ -182,7 +181,7 @@ namespace MWWorld if(onground) { - newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) newPosition.z = trace.endpos.z + 2.0f; else diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 2f52d669a..7664eb418 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -24,21 +24,11 @@ enum collaborativePhysicsType Both_Physics = 3 // This object has both kinds of physics (example: activators) }; -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - //const Object* hitObj; -}; - -static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine *enginePass) //Traceobj was a Aedra Object { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btQuaternion btrot(0.0f, 0.0f, 0.0f); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); @@ -46,43 +36,22 @@ static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const btTransform to(btrot, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; - - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - out->hitNormal.x = tracehitnormal.x(); - out->hitNormal.y = tracehitnormal.y(); - out->hitNormal.z = tracehitnormal.z(); - - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - out->endPos.x = tracehitpos.x(); - out->endPos.y = tracehitpos.y(); - out->endPos.z = tracehitpos.z(); - - return newTraceCallback.hasHit(); -} - - -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object -{ - NewPhysTraceResults out; - bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if(!hasHit) + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + results->fraction = newTraceCallback.m_closestHitFraction; + results->planenormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + results->endpos = (end-start)*results->fraction + start; + } + else { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); results->fraction = 1.0f; } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = (end-start)*results->fraction + start; - } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 34ecb7454..f484497d9 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -21,6 +21,6 @@ struct traceResults float fraction; }; -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); #endif From b14def7c0951fc17eff0394be34304dcf6223ad2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 05:24:38 -0800 Subject: [PATCH 208/239] Set the character as being on the ground when colliding with a shallow enough slope --- apps/openmw/mwworld/physicssystem.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0b9e13fb7..a61eebe2f 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -137,45 +137,43 @@ namespace MWWorld clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; - currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + if(getSlope(trace.planenormal) <= sMaxSlope) { + // We hit a slope we can walk on. Update velocity accordingly. + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + // We're only on the ground if gravity is affecting us + onground = gravity; + } + else + { + // Can't walk on this. Try to step up onto it. if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { - Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); + Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up); resultantDirection.normalise(); clippedVelocity = velocity; projectVelocity(clippedVelocity, resultantDirection); // just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain. - clippedVelocity += currentNormal*clippedVelocity.length()/50.0f; - //std::cout<< "clipped velocity: "< 0.0f); From 4eb8ea0c954740e2287c1c6c81b2a11fc2e11eca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 07:51:36 -0800 Subject: [PATCH 209/239] Fix stepping and vertical force accumulation --- apps/openmw/mwworld/physicssystem.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a61eebe2f..9b9c9afea 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -39,14 +39,18 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), - position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, isInterior, engine); + newtrace(&trace, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + halfExtents, isInterior, engine); + if(trace.fraction == 0.0f) + return false; + + newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime, + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); - if(getSlope(trace.planenormal) < sMaxSlope) + if(getSlope(trace.planenormal) <= sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -56,7 +60,7 @@ namespace MWWorld return false; } - static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce=1.0f) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. @@ -134,7 +138,7 @@ namespace MWWorld { // if we're on the ground, force velocity to track it clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); } const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); @@ -153,7 +157,7 @@ namespace MWWorld if(getSlope(trace.planenormal) <= sMaxSlope) { // We hit a slope we can walk on. Update velocity accordingly. - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); // We're only on the ground if gravity is affecting us onground = gravity; } @@ -186,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); return newPosition; } From 7fcca180b6751249ae61c13660659501af5317cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 20:08:04 -0800 Subject: [PATCH 210/239] Implement rudimentary jumping --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 713f1bb3b..6c8d558a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -181,10 +181,17 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); + // This jump is all kinds of wrong. The speed is incorrect, the state should be set to + // Jump, and X/Y movement should be disallowed except for the initial thrust (which would + // be carried by "physics" until landing). + if(onground) + movement.z += vec.z * (500.0f*duration); + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) From 9c3af5f344497ebdacc2477565a1df78a3996f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:26:30 -0800 Subject: [PATCH 211/239] Do not interpret noclip mode as flying --- apps/openmw/mwworld/worldimp.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e75bd1677..bfc313caa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1389,15 +1389,9 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { - RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor || !physactor->getCollisionMode()) - return true; - const MWWorld::Class &cls = MWWorld::Class::get(ptr); if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) return true; - return false; } From 7ec73c29f2ff1af05df4f3aac9f86907a805fbf2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:27:26 -0800 Subject: [PATCH 212/239] Do not return the player's Animation object for non-players --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1551f73b8..0b9730dea 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -923,7 +923,8 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - if(!anim) anim = mPlayer->getAnimation(); + if(!anim && ptr.getRefData().getHandle() == "player") + anim = mPlayer->getAnimation(); return anim; } From 84227caa0c715922b8f3984beed92b141de23fd8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:30:06 -0800 Subject: [PATCH 213/239] Cleanup Npc::getSpeed a little --- apps/openmw/mwclass/npc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4a31334ad..642c7f645 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -335,14 +335,16 @@ namespace MWClass float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + if(npcdata->mNpcStats.isWerewolf()) + runSpeed *= fWereWolfRunMult->getFloat(); float moveSpeed; if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; - else if(world->isFlying(ptr)) + else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); + mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -353,7 +355,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; @@ -365,8 +367,6 @@ namespace MWClass if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) moveSpeed *= 0.75f; - if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) - moveSpeed *= fWereWolfRunMult->getFloat(); return moveSpeed; } From 9dee2a72cd732bc302074f9ecf7e317704da3704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 09:22:06 -0800 Subject: [PATCH 214/239] Use a separate method to calculate animation velocity --- apps/openmw/mwrender/animation.cpp | 85 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f4b618866..707aedcd9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,6 +175,49 @@ void Animation::setLooping(bool loop) } +void Animation::calcAnimVelocity() +{ + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } + + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } + } +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); @@ -305,47 +348,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimVelocity = 0.0f; if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track && track->getNumKeyFrames() > 1) - { - float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) - { - if(keyiter->second == "loop start") - loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } - - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); - - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } - } - } + calcAnimVelocity(); found = true; break; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2f930e9ad..c6e230670 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; + void calcAnimVelocity(); + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); From ecbf1568a1c1a1e37507b5fdd8acdfe7f38ea784 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 10:15:29 -0800 Subject: [PATCH 215/239] Fix NPC part attachment --- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----------- apps/openmw/mwrender/npcanimation.hpp | 5 +++-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 120996a70..4d8119c72 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,10 +133,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - updateParts(); + updateParts(true); } -void NpcAnimation::updateParts() +void NpcAnimation::updateParts(bool forceupdate) { static const struct { int numRemoveParts; // Max: 1 @@ -212,11 +212,21 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + for(size_t i = 0;!forceupdate && i < slotlistsize;i++) + { + MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + if(this->*slotlist[i].part != iter) + { + forceupdate = true; + break; + } + } + if(!forceupdate) + return; + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].part == iter) - continue; this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); @@ -332,12 +342,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { - if(mTimeToChange > .2) + if(mTimeToChange <= 0.0f) { - mTimeToChange = 0; + mTimeToChange = 0.2f; updateParts(); } - mTimeToChange += timepassed; + mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); @@ -441,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector Date: Fri, 22 Feb 2013 11:16:00 -0800 Subject: [PATCH 216/239] Fix character preview --- apps/openmw/mwrender/characterpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 24df30556..9f8962d7c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,8 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->runAnimation(0.0f); mAnimation->forceUpdate(); + mAnimation->runAnimation(0.0f); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); From f17ea109ca653a92da910141640a48ff440cb44f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 04:06:05 +0100 Subject: [PATCH 217/239] Fix light positions --- apps/openmw/mwclass/light.cpp | 9 +------- apps/openmw/mwrender/objects.cpp | 39 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/objects.hpp | 4 ++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 235e57d37..094ae5b16 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -36,14 +36,7 @@ namespace MWClass objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); if (!model.empty()) - objects.insertMesh(ptr, "meshes\\" + model); - - const int color = ref->mBase->mData.mColor; - const float r = ((color >> 0) & 0xFF) / 255.0f; - const float g = ((color >> 8) & 0xFF) / 255.0f; - const float b = ((color >> 16) & 0xFF) / 255.0f; - const float radius = float (ref->mBase->mData.mRadius); - objects.insertLight (ptr, r, g, b, radius); + objects.insertMesh(ptr, "meshes\\" + model, true); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bd5f95c24..c51cafc0e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -34,6 +34,18 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) for (int i=node->numAttachedObjects()-1; i>=0; --i) { Ogre::MovableObject *object = node->getAttachedObject (i); + + // for entities, destroy any objects attached to bones + if (object->getTypeFlags () == Ogre::SceneManager::ENTITY_TYPE_MASK) + { + Ogre::Entity* ent = static_cast(object); + Ogre::Entity::ChildObjectListIterator children = ent->getAttachedObjectIterator (); + while (children.hasMoreElements()) + { + mRenderer.getScene ()->destroyMovableObject (children.getNext ()); + } + } + node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } @@ -87,7 +99,7 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) mIsStatic = static_; } -void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) +void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light) { Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); @@ -204,17 +216,29 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) iter++; } } + + if (light) + { + insertLight(ptr, entities.mSkelBase); + } } -void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); - Ogre::Light *light = mRenderer.getScene()->createLight(); - light->setDiffuseColour (r, g, b); MWWorld::LiveCellRef *ref = ptr.get(); + const int color = ref->mBase->mData.mColor; + const float r = ((color >> 0) & 0xFF) / 255.0f; + const float g = ((color >> 8) & 0xFF) / 255.0f; + const float b = ((color >> 16) & 0xFF) / 255.0f; + const float radius = float (ref->mBase->mData.mRadius); + + Ogre::Light *light = mRenderer.getScene()->createLight(); + light->setDiffuseColour (r, g, b); + LightInfo info; info.name = light->getName(); info.radius = radius; @@ -265,7 +289,12 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f light->setAttenuation(r*10, 0, 0, attenuation); } - insert->attachObject(light); + // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node + if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + skelBase->attachObjectToBone ("AttachLight", light); + else + insert->attachObject(light); + mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b2bdac683..283c05388 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -73,8 +73,8 @@ public: Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); - void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); - void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius); + void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); void enableLights(); void disableLights(); From 7e816c826bf6c642fee570c099aa29485b0b3ecb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 09:17:12 +0100 Subject: [PATCH 218/239] Fix lights without a mesh --- apps/openmw/mwclass/light.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 094ae5b16..9d0fe298b 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -37,6 +37,8 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); + else + objects.insertLight(ptr, NULL); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const From f841576bba22b7e8b0f2b2ddb61878b64c0c33db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 01:54:46 -0800 Subject: [PATCH 219/239] Don't override animations played with playgroup --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6c8d558a4..7b166ba91 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -218,7 +218,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any sideways movement manually movement.x += vec.x * (speed*duration); } - else + else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } @@ -246,7 +246,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_Idle; + mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 996687a3e..2465aea98 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,6 +14,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, CharState_Idle, CharState_Idle2, CharState_Idle3, From b8f5813609f0c32705d95f83106e2c5005fee19e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 03:34:03 -0800 Subject: [PATCH 220/239] Set all animation sources at once --- apps/openmw/mwrender/activatoranimation.cpp | 1 + apps/openmw/mwrender/animation.cpp | 100 +++++++++----------- apps/openmw/mwrender/animation.hpp | 12 ++- apps/openmw/mwrender/creatureanimation.cpp | 11 ++- apps/openmw/mwrender/npcanimation.cpp | 9 +- 5 files changed, 70 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index f951307b6..7bc89b917 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -51,6 +51,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Misc); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 707aedcd9..160641eb0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,45 +46,64 @@ Animation::~Animation() } -Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +void Animation::setAnimationSources(const std::vector &names) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) + + mCurrentAnim = NULL; + mCurrentKeys = NULL; + mAnimVelocity = 0.0f; + mAccumRoot = NULL; + mNonAccumRoot = NULL; + mSkeletonSources.clear(); + + std::vector::const_iterator nameiter = names.begin(); + while(nameiter != names.end()) { - NifOgre::Loader::createSkeleton(name); - skel = skelMgr.getByName(name); + Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); - mSkeletonSources.push_back(skel); + skel->touch(); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; - - for(int i = 0;i < skel->getNumAnimations();i++) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + if(!mNonAccumRoot && mEntityList.mSkelBase) + { + mAccumRoot = mInsert; + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + } + + mSkeletonSources.push_back(skel); + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + break; } - return bone; + nameiter++; } - - return NULL; } void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) @@ -111,31 +130,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); - - Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); - if(!bone) - { - for(std::vector::const_iterator iter(mSkeletonSources.begin()); - !bone && iter != mSkeletonSources.end();iter++) - { - Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty() && Ogre::any_cast(data)) - break; - - bone = NULL; - } - } - } - if(bone) - { - mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getName()); - } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c6e230670..130805a50 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -57,9 +57,15 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); - /* Inserts an additional skeleton into the animation source chain. Returns - * the bone representing the non-accum root from the base skeleton. */ - Ogre::Bone *insertSkeletonSource(const std::string &name); + /* Specifies a list of skeleton names to use as animation sources. */ + void setAnimationSources(const std::vector &names); + + /* Specifies a single skeleton name to use as an animation source. */ + void setAnimationSource(const std::string &name) + { + std::vector names(1, name); + setAnimationSources(names); + } void createEntityList(Ogre::SceneNode *node, const std::string &model); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 094281c46..b85c4dbbd 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,10 +23,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - if((ref->mBase->mFlags&ESM::Creature::Biped)) - insertSkeletonSource("meshes\\base_anim.nif"); + std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); + createEntityList(mPtr.getRefData().getBaseNode(), model); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,6 +51,12 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4d8119c72..3f135b7f6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -125,13 +125,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) - insertSkeletonSource("meshes\\base_anim_female.nif"); + skelnames.push_back("meshes\\base_anim_female.nif"); else if(mBodyPrefix.find("argonian") != std::string::npos) - insertSkeletonSource("meshes\\argonian_swimkna.nif"); - + skelnames.push_back("meshes\\argonian_swimkna.nif"); if(mNpc->mModel.length() > 0) - insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + setAnimationSources(skelnames); updateParts(true); } From e6da9dfae533065a4c258007160b3269c3407a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 05:15:10 -0800 Subject: [PATCH 221/239] Specify the animation key to stop playing at --- apps/openmw/mwmechanics/character.cpp | 10 +++--- apps/openmw/mwrender/animation.cpp | 43 ++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 11 +++--- apps/openmw/mwrender/characterpreview.cpp | 2 +- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7b166ba91..5598e0e56 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -113,7 +113,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", loop); + mAnimation->play(mCurrentGroup, "stop", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) @@ -152,7 +152,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); } else if(mAnimQueue.size() > 0) { @@ -160,7 +160,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", false); + mAnimation->play(mCurrentGroup, "start", "stop", false); } } return; @@ -247,7 +247,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); } else if(mode == 0) { @@ -283,7 +283,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 160641eb0..1dd46365b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) + , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -293,12 +294,12 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::reset(const std::string &marker) +void Animation::reset(const std::string &start, const std::string &stop) { mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) - mNextKey++; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) + mNextKey++; if(mNextKey != mCurrentKeys->end()) mCurrentTime = mNextKey->first; else @@ -307,6 +308,17 @@ void Animation::reset(const std::string &marker) mCurrentTime = 0.0f; } + if(stop.length() > 0) + { + NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; + while(stopKey != mCurrentKeys->end() && stopKey->second != stop) + stopKey++; + if(stopKey != mCurrentKeys->end()) + mStopTime = stopKey->first; + else + mStopTime = mCurrentAnim->getLength(); + } + if(mNonAccumRoot) { const Ogre::NodeAnimationTrack *track = 0; @@ -328,7 +340,7 @@ void Animation::reset(const std::string &marker) } -void Animation::play(const std::string &groupname, const std::string &start, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { bool found = false; @@ -351,9 +363,9 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start); + reset(start, stop); + setLooping(loop); mPlaying = true; - mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() <end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); + mPlaying = (mLooping || mStopTime > targetTime); break; } @@ -380,6 +392,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mNextKey++; movement += updatePosition(time); + mPlaying = (mLooping || mStopTime > time); + timepassed = targetTime - time; if(evt == "start" || evt == "loop start") @@ -391,7 +405,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; } @@ -401,17 +415,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; + continue; } - else - { - mPlaying = false; - if(mController) - mController->markerEvent(time, evt); - } - continue; + // fall-through } if(mController) mController->markerEvent(time, evt); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 130805a50..47bc8c390 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,6 +33,7 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; float mCurrentTime; + float mStopTime; bool mPlaying; bool mLooping; @@ -53,9 +54,11 @@ protected: * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Resets the animation to the time of the specified marker, without moving - * anything. If the marker is not found, it resets to the beginning. */ - void reset(const std::string &marker); + /* Resets the animation to the time of the specified start marker, without + * moving anything, and set the end time to the specified stop marker. If + * the marker is not found, it resets to the beginning or end respectively. + */ + void reset(const std::string &start, const std::string &stop); /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); @@ -86,7 +89,7 @@ public: void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 9f8962d7c..36cac2155 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,7 +145,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->play("inventoryhandtohand", "start", "stop", false); } // -------------------------------------------------------------------------------------------------- From 0d0e75fe0b74c265e6ae31a5dccfa2e240fc196e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 07:36:11 -0800 Subject: [PATCH 222/239] Don't set animation sources for models that don't have a skeleton --- apps/openmw/mwrender/animation.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1dd46365b..29652ca6a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,6 +49,9 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { + if(!mEntityList.mSkelBase) + return; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); mCurrentAnim = NULL; @@ -59,7 +62,7 @@ void Animation::setAnimationSources(const std::vector &names) mSkeletonSources.clear(); std::vector::const_iterator nameiter = names.begin(); - while(nameiter != names.end()) + for(nameiter = names.begin();nameiter != names.end();nameiter++) { Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) @@ -69,7 +72,6 @@ void Animation::setAnimationSources(const std::vector &names) if(skel.isNull()) { std::cerr<< "Failed to get skeleton source "<<*nameiter < &names) if(data.isEmpty() || !Ogre::any_cast(data)) continue; - if(!mNonAccumRoot && mEntityList.mSkelBase) + if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); @@ -102,8 +104,6 @@ void Animation::setAnimationSources(const std::vector &names) break; } - - nameiter++; } } From a2eaec787802d80f62917e13037b75e696d04213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 08:03:52 -0800 Subject: [PATCH 223/239] Avoiding holding the InventoryStore in the NpcAnimation class --- apps/openmw/mwrender/actors.cpp | 6 +---- apps/openmw/mwrender/npcanimation.cpp | 34 ++++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 12 ++++------ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 3f3145900..d356d922e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -167,11 +167,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) PtrAnimationMap::iterator iter = mAllActors.find(ptr); if(iter != mAllActors.end()) { - /// \note Update key (Ptr's are compared only with refdata so mCell - /// on key is outdated), maybe redundant - NpcAnimation *anim = static_cast(iter->second); - anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); - + Animation *anim = iter->second; mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index dcaee55f9..809e3f6d2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,8 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -54,22 +56,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(ptr), - mInv(&inv), mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), - mRobe(mInv->end()), - mHelmet(mInv->end()), - mShirt(mInv->end()), - mCuirass(mInv->end()), - mGreaves(mInv->end()), - mPauldronL(mInv->end()), - mPauldronR(mInv->end()), - mBoots(mInv->end()), - mPants(mInv->end()), - mGloveL(mInv->end()), - mGloveR(mInv->end()), - mSkirtIter(mInv->end()) + mRobe(inv.end()), + mHelmet(inv.end()), + mShirt(inv.end()), + mCuirass(inv.end()), + mGreaves(inv.end()), + mPauldronL(inv.end()), + mPauldronR(inv.end()), + mBoots(inv.end()), + mPants(inv.end()), + mGloveL(inv.end()), + mGloveR(inv.end()), + mSkirtIter(inv.end()) { mNpc = mPtr.get()->mBase; @@ -213,9 +214,10 @@ void NpcAnimation::updateParts(bool forceupdate) }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for(size_t i = 0;!forceupdate && i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); if(this->*slotlist[i].part != iter) { forceupdate = true; @@ -227,12 +229,12 @@ void NpcAnimation::updateParts(bool forceupdate) for(size_t i = 0;i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); - if(this->*slotlist[i].part == mInv->end()) + if(this->*slotlist[i].part == inv.end()) continue; for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index c5d5b7461..aed4868bd 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,7 +3,6 @@ #include "animation.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -11,6 +10,11 @@ namespace ESM struct NPC; } +namespace MWWorld +{ + class InventoryStore; +} + namespace MWRender { @@ -26,7 +30,6 @@ private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; - MWWorld::InventoryStore *mInv; int mStateID; // Bounded Parts @@ -75,11 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - void updateParts(MWWorld::InventoryStore &inventory) - { - mInv = &inventory; - updateParts(true); - } void forceUpdate() { updateParts(true); } }; From d208422ca76da90b9a5a0fa12b47722122948b8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 10:12:36 -0800 Subject: [PATCH 224/239] Add a method to update an Animation's Ptr object --- apps/openmw/mwrender/actors.cpp | 1 + apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d356d922e..485e3a7ad 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -169,6 +169,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Animation *anim = iter->second; mAllActors.erase(iter); + anim->updatePtr(ptr); mAllActors[ptr] = anim; } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 29652ca6a..39323edac 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setLooping(bool loop) mLooping = loop; } +void Animation::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + void Animation::calcAnimVelocity() { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 47bc8c390..b8323cb89 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,7 +49,6 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -78,6 +77,8 @@ public: void setController(MWMechanics::CharacterController *controller); + void updatePtr(const MWWorld::Ptr &ptr); + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just From df8889dcc4eb772a8689252e940ba1275d8fd2fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 13:15:37 -0800 Subject: [PATCH 225/239] Limit maximum frame time to 200ms This effectively slows game time when it drops below 5 fps. Something like this is desirable when dealing with time-based animations, which can jump forward after a lengthy cell transition. --- apps/openmw/engine.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dc18c6e8..6f59349fd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,14 +67,15 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { - mEnvironment.setFrameDuration (evt.timeSinceLastFrame); + float frametime = std::min(evt.timeSinceLastFrame, 0.2f); + mEnvironment.setFrameDuration(frametime); // update input - MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false); + MWBase::Environment::get().getInputManager()->update(frametime, false); // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getSoundManager()->update(frametime); // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); @@ -88,19 +89,19 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // passing of time if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime ( - mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); if (changed) // keep change flag for another frame, if cell changed happend in local script MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update world - MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); + MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); @@ -108,7 +109,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager()->onFrame(frametime); } catch (const std::exception& e) { From d77d035d3a32fe7eefd567068572c805a17a5e97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:15:11 -0800 Subject: [PATCH 226/239] Handle the "sound" events in runAnimation --- apps/openmw/mwmechanics/character.cpp | 14 -------------- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5598e0e56..37477932a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -24,7 +24,6 @@ #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -134,19 +133,6 @@ CharacterController::~CharacterController() void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - return; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - return; - } - if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 39323edac..f453e6a74 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/character.hpp" @@ -406,6 +407,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) /* Do nothing */ continue; } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + continue; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + continue; + } + if(evt == "loop stop") { if(mLooping) From 8e59ea494171740fb7b80d0e8f87ee7a24536f77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:39:01 -0800 Subject: [PATCH 227/239] Use a separate method to handle animation events --- apps/openmw/mwrender/animation.cpp | 92 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f453e6a74..394e25b50 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -346,6 +346,54 @@ void Animation::reset(const std::string &start, const std::string &stop) } +bool Animation::handleEvent(float time, const std::string &evt) +{ + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + return true; + } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return true; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return true; + } + + if(evt == "loop stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + } + return true; + } + if(evt == "stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + return true; + } + // fall-through + } + if(mController) + mController->markerEvent(time, evt); + return true; +} + + void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { @@ -402,48 +450,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed = targetTime - time; - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - continue; - } - - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - continue; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - continue; - } - - if(evt == "loop stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - } - continue; - } - if(evt == "stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - continue; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt); + if(!handleEvent(time, evt)) + break; } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b8323cb89..810ca869f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -59,6 +59,8 @@ protected: */ void reset(const std::string &start, const std::string &stop); + bool handleEvent(float time, const std::string &evt); + /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); From 90cb9ee0ac73dca6388b2f69e1906945d51e4fab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 16:30:11 -0800 Subject: [PATCH 228/239] Don't set a vertical velocity when on the ground --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9b9c9afea..0c1f58048 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); + physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); return newPosition; } From 6a8c532244c901d6de89487e57cf6c611e1f8cc4 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 24 Feb 2013 14:59:21 +0400 Subject: [PATCH 229/239] fix and unify object cell change update in mwrender --- apps/openmw/mwrender/actors.cpp | 12 ++++++------ apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 6 +++--- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 14 +++++--------- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++--- apps/openmw/mwworld/worldimp.cpp | 3 ++- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 485e3a7ad..78521d0ce 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,10 +149,10 @@ Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) return NULL; } -void Actors::updateObjectCell(const MWWorld::Ptr &ptr) +void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); if(celliter != mCellSceneNodes.end()) @@ -162,15 +162,15 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) node = mMwRoot->createChildSceneNode(); mCellSceneNodes[newCell] = node; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); - PtrAnimationMap::iterator iter = mAllActors.find(ptr); + PtrAnimationMap::iterator iter = mAllActors.find(old); if(iter != mAllActors.end()) { Animation *anim = iter->second; mAllActors.erase(iter); - anim->updatePtr(ptr); - mAllActors[ptr] = anim; + anim->updatePtr(cur); + mAllActors[cur] = anim; } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index fc9fa4fbb..c89bfbaf5 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -42,7 +42,7 @@ namespace MWRender void update (float duration); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); Animation* getAnimation(const MWWorld::Ptr &ptr); }; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index fe81eb911..2bbb229a3 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -533,10 +533,10 @@ void Objects::rebuildStaticGeometry() } } -void Objects::updateObjectCell(const MWWorld::Ptr &ptr) +void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { node = mMwRoot->createChildSceneNode(); @@ -544,6 +544,6 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) } else { node = mCellSceneNodes[newCell]; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c05388..b7dd5a3b1 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -95,7 +95,7 @@ public: void rebuildStaticGeometry(); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 0b9730dea..5dd2b3773 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -302,23 +302,19 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot } void -RenderingManager::moveObjectToCell( - const MWWorld::Ptr& ptr, - const Ogre::Vector3& pos, - MWWorld::CellStore *store) +RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *child = - mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle()); + mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); Ogre::SceneNode *parent = child->getParentSceneNode(); parent->removeChild(child); - if (MWWorld::Class::get(ptr).isActor()) { - mActors.updateObjectCell(ptr); + if (MWWorld::Class::get(old).isActor()) { + mActors.updateObjectCell(old, cur); } else { - mObjects.updateObjectCell(ptr); + mObjects.updateObjectCell(old, cur); } - child->setPosition(pos); } void RenderingManager::update (float duration, bool paused) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b6c33f9c0..bdb5447e3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -123,9 +123,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setWaterHeight(const float height); void toggleWater(); - /// Moves object rendering part to proper container - /// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). - void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); + /// Updates object rendering after cell change + /// \param old Object reference in previous cell + /// \param cur Object reference in new cell + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); void update (float duration, bool paused); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 71e956b6e..f723934be 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -770,7 +770,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); - mRendering->moveObjectToCell(copy, vec, currCell); + mRendering->updateObjectCell(ptr, copy); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->updateCell(copy); From 89d4c245e9b2a8b5fff0afa1494ec5417fe67331 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 03:30:33 -0800 Subject: [PATCH 230/239] Better calculate jump velocity The fatigue term isn't currently used correctly --- apps/openmw/mwclass/npc.cpp | 41 +++++++++++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 8 ++++++ apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++---- apps/openmw/mwworld/class.cpp | 5 ++++ apps/openmw/mwworld/class.hpp | 3 ++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 642c7f645..12b40bfdc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -71,6 +71,11 @@ namespace MWClass fMaxFlySpeed = gmst.find("fMaxFlySpeed"); fSwimRunBase = gmst.find("fSwimRunBase"); fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + fJumpEncumbranceBase = gmst.find("fJumpEncumbranceBase"); + fJumpEncumbranceMultiplier = gmst.find("fJumpEncumbranceMultiplier"); + fJumpAcrobaticsBase = gmst.find("fJumpAcrobaticsBase"); + fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier"); + fJumpRunMultiplier = gmst.find("fJumpRunMultiplier"); // Added in Tribunal/Bloodmoon, may not exist fWereWolfRunMult = gmst.search("fWereWolfRunMult"); @@ -371,6 +376,37 @@ namespace MWClass return moveSpeed; } + float Npc::getJump(const MWWorld::Ptr &ptr) const + { + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + + fJumpEncumbranceMultiplier->getFloat() * + (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + + float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float b = 0.0f; + if(a > 50.0f) + { + b = a - 50.0f; + a = 50.0f; + } + + float x = fJumpAcrobaticsBase->getFloat() + + std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); + x += 3 * b * fJumpAcroMultiplier->getFloat(); + x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64; + x *= encumbranceTerm; + + if(Npc::getStance(ptr, Run, false)) + x *= fJumpRunMultiplier->getFloat(); + x *= 1.25f;//fatigueTerm; + x -= -627.2/*gravity constant*/; + x /= 3; + + return x; + } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); @@ -496,5 +532,10 @@ namespace MWClass const ESM::GameSetting *Npc::fMaxFlySpeed; const ESM::GameSetting *Npc::fSwimRunBase; const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fJumpEncumbranceBase; + const ESM::GameSetting *Npc::fJumpEncumbranceMultiplier; + const ESM::GameSetting *Npc::fJumpAcrobaticsBase; + const ESM::GameSetting *Npc::fJumpAcroMultiplier; + const ESM::GameSetting *Npc::fJumpRunMultiplier; const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index a97e4c42e..f41edb0df 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -27,6 +27,11 @@ namespace MWClass static const ESM::GameSetting *fMaxFlySpeed; static const ESM::GameSetting *fSwimRunBase; static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fJumpEncumbranceBase; + static const ESM::GameSetting *fJumpEncumbranceMultiplier; + static const ESM::GameSetting *fJumpAcrobaticsBase; + static const ESM::GameSetting *fJumpAcroMultiplier; + static const ESM::GameSetting *fJumpRunMultiplier; static const ESM::GameSetting *fWereWolfRunMult; public: @@ -81,6 +86,9 @@ namespace MWClass virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 37477932a..8f7929805 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,11 +172,25 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - // This jump is all kinds of wrong. The speed is incorrect, the state should be set to - // Jump, and X/Y movement should be disallowed except for the initial thrust (which would - // be carried by "physics" until landing). - if(onground) - movement.z += vec.z * (500.0f*duration); + /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except + * for the initial thrust (which would be carried by "physics" until landing). */ + if(onground && vec.z > 0.0f) + { + float x = cls.getJump(mPtr); + + if(vec.x == 0 && vec.y == 0) + movement.z += x*duration; + else + { + /* FIXME: this would be more correct if we were going into a jumping state, + * rather than normal walking/idle states. */ + //Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + //movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration; + movement.z += x * 0.707f * duration; + } + + //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; + } if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c76019149..71b24b65d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -122,6 +122,11 @@ namespace MWWorld return 0; } + float Class::getJump (const Ptr& ptr) const + { + return 0; + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 07dcb8fe0..1a6a16ca0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -140,6 +140,9 @@ namespace MWWorld virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. From 7ea1f6a02a06e83a153ff85c7f3b5ab210c37ca7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 00:23:10 -0800 Subject: [PATCH 231/239] fixes for using FFMPEG on windows --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 ++++ cmake/FindFFmpeg.cmake | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 00530a962..54df45ff4 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -153,6 +153,10 @@ void FFmpeg_Decoder::open(const std::string &fname) try { + for(size_t j = 0;j < mFormatCtx->nb_streams;j++) + if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; + if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index c80203a25..4147590d6 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -68,6 +68,7 @@ macro(find_component _component _pkgconfig _library _header) find_path(${_component}_INCLUDE_DIRS ${_header} HINTS + ${FFMPEGSDK_INC} ${PC_LIB${_component}_INCLUDEDIR} ${PC_LIB${_component}_INCLUDE_DIRS} PATH_SUFFIXES @@ -76,6 +77,7 @@ macro(find_component _component _pkgconfig _library _header) find_library(${_component}_LIBRARIES NAMES ${_library} HINTS + ${FFMPEGSDK_LIB} ${PC_LIB${_component}_LIBDIR} ${PC_LIB${_component}_LIBRARY_DIRS} ) @@ -97,6 +99,12 @@ endmacro() # Check for cached results. If there are skip the costly part. if (NOT FFMPEG_LIBRARIES) + set (FFMPEGSDK ENV${FFMPEG_HOME}) + if (FFMPEGSDK) + set (FFMPEGSDK_INC "${FFMPEGSDK}/include") + set (FFMPEGSDK_LIB "${FFMPEGSDK}/lib") + endif () + # Check for all possible component. find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) find_component(AVFORMAT libavformat avformat libavformat/avformat.h) From 1ae2d3c6abd06cb76b151067c88a0b5d3a9090a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:00:06 +0100 Subject: [PATCH 232/239] For light objects without an AttachLight bone, attach the light to the center of the object instead of the origin. --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 17 ++++++++++++++--- apps/openmw/mwrender/objects.hpp | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 9d0fe298b..c23e4b833 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL); + objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index c51cafc0e..06ddcb225 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -49,6 +49,12 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } + + Ogre::Node::ChildNodeIterator it = node->getChildIterator (); + while (it.hasMoreElements ()) + { + clearSceneNode(static_cast(it.getNext ())); + } } void Objects::setMwRoot(Ogre::SceneNode* root) @@ -219,11 +225,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase); + insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } -void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); @@ -291,9 +297,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + { skelBase->attachObjectToBone ("AttachLight", light); + } else - insert->attachObject(light); + { + Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter); + childNode->attachObject(light); + } mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c05388..1a4829d9f 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); void enableLights(); void disableLights(); From f1a33093922a8f16a05e98af5b86c05eed9743f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:03:25 +0100 Subject: [PATCH 233/239] forgot to destroy child scene nodes --- apps/openmw/mwrender/objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 06ddcb225..53957152f 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,6 +55,7 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } + node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From e060713aa350b110c7b9e55f768c558048727d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Feb 2013 20:37:29 +0100 Subject: [PATCH 234/239] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 8b396aad0..535e922ae 100644 --- a/credits.txt +++ b/credits.txt @@ -29,6 +29,7 @@ Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) Karl-Felix Glatzer (k1ll) +Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) From c60e858b0216c5d444db16b7c2eb5003f3886df1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 12:42:32 -0800 Subject: [PATCH 235/239] Create bones for NiTriShape nodes, and attach the entities to them Otherwise some models don't connect properly. NiTriShapes are more guaranteed to have unique names than their parent nodes. --- components/nifogre/ogre_nif_loader.cpp | 26 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 8 ++------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c52a73e1c..8c5d4dc5a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -303,9 +303,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { - if(node->recType == Nif::RC_NiTriShape) - return; - Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -319,7 +316,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setBindingPose(); if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -1073,8 +1071,7 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), - shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), shape->name)); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1108,8 +1105,7 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), - node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), node->name)); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1190,12 +1186,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } else @@ -1248,12 +1239,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen else { if(entity->getMesh()->getName().find(filter) != std::string::npos) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 0064defe2..7a7b0c5a1 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,13 +53,9 @@ struct EntityList { struct MeshInfo { std::string mMeshName; std::string mTargetNode; - Ogre::Vector3 mPos; - Ogre::Matrix3 mRot; - float mScale; - MeshInfo(const std::string &name, const std::string &target, - const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) - : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + MeshInfo(const std::string &name, const std::string &target) + : mMeshName(name), mTargetNode(target) { } }; typedef std::vector MeshInfoList; From 5267d17408017e2f0be488de05aa4b683b7852a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:14:08 -0800 Subject: [PATCH 236/239] Revert "forgot to destroy child scene nodes" This reverts commit f1a33093922a8f16a05e98af5b86c05eed9743f6. Unneeded. The caller already calls this which destroys the children recursively --- apps/openmw/mwrender/objects.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9e79f0256..76f38eefc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,7 +55,6 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } - node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From 74b8095fc70dd66027aebe8da081cc9cf3aae21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:43:20 -0800 Subject: [PATCH 237/239] Use default parameters where appropriate --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c23e4b833..200f6e2d4 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); + objects.insertLight(ptr); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e0b53f906..580101464 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f)); void enableLights(); void disableLights(); From 53eb553c57b69f7ce7bbf36159348724bab184df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 18:12:15 -0800 Subject: [PATCH 238/239] Be a little more aggressive when looking to skip generating a skeleton This is needed to handle the insane number of nodes and trishapes in in_prison_ship.nif, as Ogre has a 256-bone limit for skeletons. This is a bit sketchy, but it works. --- components/nifogre/ogre_nif_loader.cpp | 40 ++++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8c5d4dc5a..1582826b8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -454,23 +454,33 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { - /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do - * not create a skeleton. */ - if(node->recType == Nif::RC_NiTriShape) - return false; - - if(node->recType == Nif::RC_NiNode) + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) { - bool alltrishapes = true; - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length() && alltrishapes;i++) - { - if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) - alltrishapes = false; - } - if(alltrishapes) + if(node->recType == Nif::RC_NiTriShape) return false; + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + if(createSkeleton(name, group, children[i].getPtr())) + return true; + } + } + return false; + } + } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); From dfe29db9cb7cb811c3aef9ceb0b977af2f3d4f35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 06:57:32 +0100 Subject: [PATCH 239/239] Fix bug #591: Don't allow opening new windows (main menu, console) if there's any modal widget active. Also made some windows modal that should be (character creation) --- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 10 ++++++---- apps/openmw/mwgui/class.hpp | 8 ++++---- apps/openmw/mwgui/race.cpp | 4 +++- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/review.cpp | 3 ++- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/text_input.cpp | 3 ++- apps/openmw/mwgui/text_input.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 11 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index c53a68cf4..53e5c022d 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -25,7 +25,7 @@ bool sortBirthSigns(const std::pair& left, c } BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_birth.layout", parWindowManager) + : WindowModal("openmw_chargen_birth.layout", parWindowManager) { // Centre dialog center(); @@ -66,7 +66,7 @@ void BirthDialog::setNextButtonShow(bool shown) void BirthDialog::open() { - WindowBase::open(); + WindowModal::open(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index f16f92325..ad1c0b40f 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -10,7 +10,7 @@ namespace MWGui { - class BirthDialog : public WindowBase + class BirthDialog : public WindowModal { public: BirthDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2eed21a52..f3bac898b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -21,7 +21,7 @@ using namespace MWGui; /* GenerateClassResultDialog */ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager) + : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) { // Centre dialog center(); @@ -68,7 +68,7 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_class.layout", parWindowManager) + : WindowModal("openmw_chargen_class.layout", parWindowManager) { // Centre dialog center(); @@ -122,6 +122,7 @@ void PickClassDialog::setNextButtonShow(bool shown) void PickClassDialog::open() { + WindowModal::open (); updateClasses(); updateStats(); } @@ -276,7 +277,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) } InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_infobox.layout", parWindowManager) + : WindowModal("openmw_infobox.layout", parWindowManager) , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -327,6 +328,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons) void InfoBoxDialog::open() { + WindowModal::open(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); @@ -373,7 +375,7 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_create_class.layout", parWindowManager) + : WindowModal("openmw_chargen_create_class.layout", parWindowManager) , mSpecDialog(nullptr) , mAttribDialog(nullptr) , mSkillDialog(nullptr) diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index c7699b308..2662d94cc 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -12,7 +12,7 @@ namespace MWGui { - class InfoBoxDialog : public WindowBase + class InfoBoxDialog : public WindowModal { public: InfoBoxDialog(MWBase::WindowManager& parWindowManager); @@ -63,7 +63,7 @@ namespace MWGui ClassChoiceDialog(MWBase::WindowManager& parWindowManager); }; - class GenerateClassResultDialog : public WindowBase + class GenerateClassResultDialog : public WindowModal { public: GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); @@ -90,7 +90,7 @@ namespace MWGui std::string mCurrentClassId; }; - class PickClassDialog : public WindowBase + class PickClassDialog : public WindowModal { public: PickClassDialog(MWBase::WindowManager& parWindowManager); @@ -238,7 +238,7 @@ namespace MWGui MyGUI::EditPtr mTextEdit; }; - class CreateClassDialog : public WindowBase + class CreateClassDialog : public WindowModal { public: CreateClassDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 054cce7b8..699c687ff 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -20,7 +20,7 @@ using namespace MWGui; using namespace Widgets; RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_race.layout", parWindowManager) + : WindowModal("openmw_chargen_race.layout", parWindowManager) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -100,6 +100,8 @@ void RaceDialog::setNextButtonShow(bool shown) void RaceDialog::open() { + WindowModal::open(); + updateRaces(); updateSkills(); updateSpellPowers(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index e0dc3306a..619556906 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -23,7 +23,7 @@ namespace MWGui namespace MWGui { - class RaceDialog : public WindowBase + class RaceDialog : public WindowModal { public: RaceDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 45adb5383..50dc26e42 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -23,7 +23,7 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_review.layout", parWindowManager) + : WindowModal("openmw_chargen_review.layout", parWindowManager) , mLastPos(0) { // Centre dialog @@ -97,6 +97,7 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) void ReviewDialog::open() { + WindowModal::open(); updateSkillArea(); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 2b0740234..aac609a64 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -17,7 +17,7 @@ Layout is defined by resources/mygui/openmw_chargen_review.layout. namespace MWGui { - class ReviewDialog : public WindowBase + class ReviewDialog : public WindowModal { public: enum Dialogs { diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 3dbe75165..c19394833 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -5,7 +5,7 @@ using namespace MWGui; TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_text_input.layout", parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) { // Centre dialog center(); @@ -39,6 +39,7 @@ void TextInputDialog::setTextLabel(const std::string &label) void TextInputDialog::open() { + WindowModal::open(); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index 848310369..649990281 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -13,7 +13,7 @@ namespace MWGui namespace MWGui { - class TextInputDialog : public WindowBase + class TextInputDialog : public WindowModal { public: TextInputDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f1f88b9ae..0ce664c9b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,6 +521,9 @@ namespace MWInput void InputManager::toggleMainMenu() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) mWindows.popGuiMode(); else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) @@ -599,6 +602,9 @@ namespace MWInput void InputManager::toggleConsole() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + bool gameMode = !mWindows.isGuiMode(); // Switch to console mode no matter what mode we are currently