From 6e84d4bcdde03b821c6d880bda2d26b4dfbdf207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 23:19:48 -0800 Subject: [PATCH 001/330] 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 2a3b8cf437..4784771a9d 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 07583db788..ebbfb2a7ac 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 7ee361a6f6..1ca897c15e 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 e6a8006e24..c76c67425b 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/330] 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 4784771a9d..6b8a3283cb 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 ebbfb2a7ac..de4778d876 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/330] 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 31d873489c..61e3a72e91 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/330] 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 6b8a3283cb..d2d253b919 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 36f09e6d96..ae188c11ef 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 61e3a72e91..f579b4b932 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 3e05c58734..9dcd0bea66 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/330] 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 f579b4b932..870b8df0ee 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/330] 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 870b8df0ee..f1aecf720b 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/330] 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 f1aecf720b..04b2822e02 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 9dcd0bea66..47d1573fe7 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/330] 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 cc625b3067..0c9110ed49 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 edf5dd25d6..7b0f9f7289 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 a158fa743e..a96c18a8c5 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 05bb030d70..fc5a46d12b 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 073c5d51f1..71be0bd7b7 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 de4778d876..633a3f9e7a 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 0a11dc2814..b144466c96 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 e1a7bbb8f4..5456f857f7 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 ca76dcc222..ff853de715 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 8cb8e9fa8b..71424aaeda 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 6b9abf508b..6a6ad92d75 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/330] 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 60ecd43034..c8a6ca0eff 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/330] 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 c76c67425b..37c8aee647 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 ff853de715..e6eee54916 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/330] 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 37c8aee647..b7e93cef2b 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 e6eee54916..090366a234 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/330] 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 d2d253b919..d7f3d52d62 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 633a3f9e7a..593538ea68 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 1ca897c15e..caa040d952 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 b7e93cef2b..5682a86cc9 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/330] 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 d7f3d52d62..b8be879e58 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 593538ea68..3bc173d70a 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/330] 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 04b2822e02..3c8b3067a4 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/330] 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 b8be879e58..b73d352644 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 3bc173d70a..d1ae5af4c4 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 b144466c96..7431c2a616 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/330] 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 b73d352644..4cf0db3ed5 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/330] 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 3c8b3067a4..e71c57efa7 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 47d1573fe7..4ed52a84a7 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/330] 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 4cf0db3ed5..4b85804676 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 d1ae5af4c4..73e34befeb 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/330] 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 71424aaeda..51f1150ef7 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/330] 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 4b85804676..aedc131890 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/330] 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 aedc131890..b4bfd06841 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 73e34befeb..44a2eaf3ee 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/330] 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 b4bfd06841..6da3ad5836 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/330] 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 6da3ad5836..4e33873d32 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 e71c57efa7..803496bf9e 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/330] 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 4e33873d32..4448360bd1 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 44a2eaf3ee..e84ebb3585 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 803496bf9e..c4846cdfd9 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/330] 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 c4846cdfd9..1b0d3168c1 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/330] 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 4448360bd1..59dcd451b3 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 e84ebb3585..859d2b9893 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/330] 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 1b0d3168c1..b065e5fd35 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/330] 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 b065e5fd35..b37b989c7f 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/330] 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 b37b989c7f..08a5855ed0 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/330] 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 08a5855ed0..cfc0d8397f 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/330] 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 5682a86cc9..e4eea6c710 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/330] 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 090366a234..1a121be073 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/330] 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 e4eea6c710..4fddb20205 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 1a121be073..1610913176 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/330] 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 59dcd451b3..b8016d0872 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 4fddb20205..ab4c7fa7cc 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 4c3b1166b3..d0087e8dc6 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 c8a6ca0eff..0602fc8bb7 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 cfc0d8397f..f078d90c9f 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 4ed52a84a7..f87d7d3c21 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/330] 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 d0087e8dc6..bd5f95c240 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/330] 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 0602fc8bb7..3592eb46e9 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/330] 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 482007090c..563c9e422a 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 0000000000..319c4fe9bd --- /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 0000000000..cab269112e --- /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/330] 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 fc5a46d12b..ec7c9d0732 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 71be0bd7b7..6ea6a81377 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/330] 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 d541baea99..a7e8f0db16 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 79ae16fc34..f1e5ab437a 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 cab269112e..c7638970db 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/330] 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 a7e8f0db16..aa5119dbaf 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 c7638970db..1b53203754 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/330] 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 aa5119dbaf..4eae6e2137 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 1b53203754..206f6e737f 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/330] 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 e6296ab962..b1554fc750 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 a1023c9866..55eb729a4a 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 4eae6e2137..485d7448ba 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 f1e5ab437a..faf21a12fc 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 dae417d448..3b57c3485f 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 d3a97db361..0efe12f323 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/330] 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 55eb729a4a..401e360d7a 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 0efe12f323..549807285e 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/330] 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 b8557368d0..f846c51ba6 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 c36248aafa..10b654834e 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 53829000ca..92965a059c 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 fdad152e61..d1f0b17aa5 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 68f2d79c37..1a7d213f31 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 f49b4bf9b5..b855bab8f0 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 7e89c1d871..f622144b20 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/330] 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 485d7448ba..bd7a9cef2c 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 206f6e737f..8a09861177 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/330] 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 bd7a9cef2c..d9a3b6878e 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 319c4fe9bd..6d5b928604 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 8a09861177..9bb3a1bfc3 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/330] 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 6d5b928604..21ebd255af 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 b8016d0872..4f32de3647 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 859d2b9893..ed9e4f5855 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/330] 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 4f32de3647..69bd01e2bb 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 ed9e4f5855..43cce0c028 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/330] 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 21ebd255af..6496ba9f27 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/330] 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 563c9e422a..ec7700beee 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 26d286aa14..2926272866 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 d9a3b6878e..23272e6745 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 6496ba9f27..5bf468ffbf 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 0000000000..18ae318651 --- /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 0000000000..f3d8d86c86 --- /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 10b654834e..d62e16fa21 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 92965a059c..4ef78c5779 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 5341ffd7a1..9784198457 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/330] 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 5bf468ffbf..47288b0c1e 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 9784198457..66d64f9d46 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 43cce0c028..0e5c7e66ee 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/330] 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 47288b0c1e..6acd9a7cf9 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/330] 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 23272e6745..7205e7d544 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 6acd9a7cf9..87ed8a9e6a 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 c09cb8e421..3a59ae4bbd 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 d62e16fa21..91395277be 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 0e4c76b0ed..8f3e130395 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/330] 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 401e360d7a..f7bbd6a9f9 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 f846c51ba6..c75e96a6e3 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 7205e7d544..749fb26654 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 faf21a12fc..6fed9eff73 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 87ed8a9e6a..21697f996c 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 3a59ae4bbd..24e129e386 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 3b57c3485f..84145eb082 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 549807285e..c2bbd96cfe 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 91395277be..12ebdab614 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 4ef78c5779..fc9fa4fbba 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 d1f0b17aa5..ea898e1fa1 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 1a7d213f31..b6c33f9c01 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 6f9253e5db..fc52e5e167 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 b855bab8f0..de4cb84ef5 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 f622144b20..67185833f0 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/330] 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 749fb26654..101a0a51d5 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/330] 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 101a0a51d5..35bca441ae 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 21697f996c..8e5ac0a4ac 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 24e129e386..83f42887d6 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/330] 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 66d64f9d46..30532b624e 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/330] 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 8e5ac0a4ac..8786c42e12 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 83f42887d6..9070cbe29c 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/330] 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 8786c42e12..c347312c24 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 9070cbe29c..c29c39acdf 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 30532b624e..1d628aefaa 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 0e5c7e66ee..3afe32a4b2 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/330] 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 c347312c24..547d9e0a50 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 c29c39acdf..202e105784 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 1d628aefaa..c0b6a6e1cc 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 3afe32a4b2..5dbe7b510a 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/330] 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 c0b6a6e1cc..d10accab77 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/330] 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 547d9e0a50..7e5f15a9f1 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/330] 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 7e5f15a9f1..4385d0b9df 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/330] 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 4385d0b9df..9fa2c74bea 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 202e105784..992cb8f1fe 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 d10accab77..4d9ee108c9 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 5dbe7b510a..722eccc30f 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 eb9954df65..cbee9c8659 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/330] 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 4d9ee108c9..18aa982151 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 722eccc30f..726d0cf388 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/330] 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 18aa982151..1a464f5d84 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/330] 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 29a68ca693..e24f44d68a 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 ea898e1fa1..082b561ef5 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/330] 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 9fa2c74bea..a42771e0b2 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/330] 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 a42771e0b2..0b8eff7331 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/330] 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 35bca441ae..00350fcc22 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 0b8eff7331..4e861f35c7 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 992cb8f1fe..cdbe439a43 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/330] 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 4e861f35c7..0767df130d 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/330] 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 00350fcc22..35bca441ae 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 0767df130d..96221cbb8d 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 cdbe439a43..992cb8f1fe 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/330] 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 96221cbb8d..f5b6301a2b 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 1a464f5d84..b6c712522b 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 726d0cf388..32d51775a5 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/330] 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 f5b6301a2b..241033802c 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 992cb8f1fe..902b8cc36b 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 b6c712522b..cfc72de379 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/330] 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 241033802c..97cdf3f492 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/330] 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 97cdf3f492..73a6f2c9c7 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 902b8cc36b..47bb27e837 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/330] 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 35bca441ae..396f34eab6 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 73a6f2c9c7..ff400b9d10 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 47bb27e837..c151b3b9fd 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/330] 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 18ae318651..f951307b68 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 f3d8d86c86..f3ea38f447 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 cfc72de379..f9fa6e14cd 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 32d51775a5..dfa2950f35 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 caa040d952..34b09c0d06 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 5456f857f7..0c277d1985 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 f309ee8990..432a2f5260 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 1610913176..a4e87e7224 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/330] 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 ff400b9d10..226f000692 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 f9fa6e14cd..4d8f9586fb 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 dfa2950f35..349871f0a6 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/330] 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 226f000692..b6adec0681 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/330] 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 396f34eab6..b09bcac4d8 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 b6adec0681..f3a1f2fba7 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 c151b3b9fd..f2651b4cfc 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/330] 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 f3a1f2fba7..ad784d34fb 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 f2651b4cfc..9a82f890d4 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 4d8f9586fb..a86e14c83b 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 349871f0a6..6c8357d59e 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/330] 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 b09bcac4d8..76e02ed36d 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 ad784d34fb..5127b65641 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 9a82f890d4..d773c85b25 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/330] 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 5127b65641..a494008236 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/330] 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 76e02ed36d..8c6da4a318 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 a494008236..7e52ef3d82 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/330] 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 8c6da4a318..6c69c457bb 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 7e52ef3d82..262945c024 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 d773c85b25..6d8b3386c1 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/330] 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 262945c024..ea934a2841 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 6d8b3386c1..43ff21dfb2 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 a86e14c83b..67be0bf0c5 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 6c8357d59e..50ddc34d5c 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/330] 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 67be0bf0c5..4884712c3a 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/330] 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 4884712c3a..75a441a9c9 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 372c38e0fd..357866c7c2 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/330] 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 357866c7c2..890dcf7e98 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/330] 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 ea934a2841..bc065d9d6a 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/330] 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 bc065d9d6a..d0cbf04776 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 43ff21dfb2..ec9102f9f6 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/330] 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 d0cbf04776..83326d25af 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 ec9102f9f6..53349c841e 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 75a441a9c9..45f7ab2e44 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 50ddc34d5c..8398135764 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 cbee9c8659..5a1a93311b 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/330] 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 4ae9c79f35..adc05f7e7f 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/330] 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 45f7ab2e44..5a5761faa3 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 8398135764..ed9c6eb192 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/330] 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 5a5761faa3..a36155dbed 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 adc05f7e7f..ce0fb00fcd 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/330] 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 5d9250ab66..0888a45221 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/330] 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 ce0fb00fcd..e5e949d0ee 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/330] 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 a36155dbed..c4439841fe 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/330] 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 e5e949d0ee..8dbfbff5a4 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/330] 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 ec7700beee..73baa4e72e 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 f7bbd6a9f9..ec616fcaf2 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 2926272866..3a60d9c397 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 7b0f9f7289..90dc707152 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 cfbc64b87d..6069e3b7c7 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 0000000000..799d7ecd55 --- /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 0000000000..3ddb0f8432 --- /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 6c69c457bb..98ae3e7558 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 84145eb082..3e56cbcb12 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 c2bbd96cfe..f70242bb98 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 e116dca579..47751acb39 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 0888a45221..a1d713a8aa 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/330] 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 ec616fcaf2..cb9539ef65 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 799d7ecd55..20b7865f53 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 3ddb0f8432..5c3eba2206 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 98ae3e7558..27b7ad14e9 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 6fed9eff73..8c3df6c281 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 3e56cbcb12..9e76084f5a 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 f70242bb98..99010b7ffd 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 a1d713a8aa..84a6b1b3df 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/330] 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 c4439841fe..b0f21da847 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 ed9c6eb192..091c2f2278 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/330] 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 b0f21da847..9666e62f4a 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/330] 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 9666e62f4a..778efc8132 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 091c2f2278..5fa1bd85c7 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/330] 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 20b7865f53..1a743cad59 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 5c3eba2206..0b9e984aa6 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/330] 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 8dbfbff5a4..d1bf803f13 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/330] 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 83326d25af..6e78adfa4f 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/330] 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 8f3e130395..9ab8a7de33 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/330] 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 778efc8132..03bc92e96d 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 5fa1bd85c7..c281551c7d 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/330] 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 03bc92e96d..73780a7f03 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 c281551c7d..886d967ab7 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/330] 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 73780a7f03..b63de2f166 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 886d967ab7..60e524d280 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 432a2f5260..03fda89820 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 d1bf803f13..5444c803b8 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/330] 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 b63de2f166..b811040676 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 60e524d280..165a6525c3 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/330] 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 5444c803b8..9c9fd3b22f 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 f87d7d3c21..13a76d4721 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/330] 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 b811040676..b63de2f166 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 165a6525c3..60e524d280 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/330] 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 03fda89820..18f44c87ca 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 a4e87e7224..513741d039 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/330] 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 9c9fd3b22f..2da8033e66 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/330] 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 b63de2f166..b811040676 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 60e524d280..165a6525c3 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/330] 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 5a1a93311b..8f0440b116 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/330] 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 2da8033e66..8175279d05 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/330] 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 27b7ad14e9..2466b8a864 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 6e78adfa4f..677ffcf239 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 53349c841e..e5c7a4b8c0 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/330] 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 2466b8a864..df0d6a5e85 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 677ffcf239..4f8525eca2 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 e5c7a4b8c0..c8e92f7a92 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/330] 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 8f0440b116..24df305566 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/330] 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 b811040676..0e906181c5 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 165a6525c3..46a1ed88d2 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/330] 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 df0d6a5e85..c1f552ae49 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 4f8525eca2..f5a4dda51b 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 c8e92f7a92..69d73263bd 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/330] 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 f5a4dda51b..fed6e3e3ef 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 69d73263bd..c5f29beef8 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/330] 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 73baa4e72e..5f425f7a03 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 a426e34543..5f6e27867d 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 fed6e3e3ef..7962e197ee 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 c5f29beef8..efd90ca196 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 0000000000..219f077e4a --- /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 4899a88070..062387e922 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/330] 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 8175279d05..b878c29f40 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 13a76d4721..12be522332 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/330] 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 7962e197ee..29ea723ed8 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/330] 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 29ea723ed8..8eb0caf58a 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 219f077e4a..a758c76f34 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/330] 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 8eb0caf58a..b98a863ae2 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 a758c76f34..4a7a59cb31 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 8bd05fa15e..450bc055ed 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/330] 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 9e76084f5a..085cb66534 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/330] 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 085cb66534..eee72f8805 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/330] 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 c1f552ae49..e829d46799 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/330] 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 e829d46799..e01303c02c 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 8c3df6c281..6968f34015 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/330] 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 b98a863ae2..27c1dc851c 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 4a7a59cb31..f17671a61b 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 450bc055ed..a8b9bf1442 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 b39ba53a22..7f0f6e2f90 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 76bdb491d9..d98625c0ae 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/330] 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 f17671a61b..3fddb28fe0 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 a8b9bf1442..6a965b56ac 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 7f0f6e2f90..1ae916f81c 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 d98625c0ae..daf1c09f2b 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/330] 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 3fddb28fe0..544cb2ab88 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 6a965b56ac..1c56df0364 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/330] 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 1f270df8be..991cf4f518 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/330] 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 9e2e94143f..7d77718a3c 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 81715c31e9..b28f651f67 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 246467fb0e..5f6a2f4a71 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/330] 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 5f6e27867d..b5d8aec9cc 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 6968f34015..fbd787e835 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 7d77718a3c..c95abc5a0f 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 b28f651f67..06b29d2901 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 5f6a2f4a71..d900f555c9 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 062387e922..5977664695 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/330] 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 184a00d509..a491ea5ce0 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 e01303c02c..a8c05f17e3 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 27c1dc851c..3899b05ab7 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 efd90ca196..adb6364a0c 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 544cb2ab88..0000000000 --- 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 1c56df0364..0000000000 --- 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 c95abc5a0f..2d83c9a040 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 06b29d2901..d897c78e9e 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 d900f555c9..fb31c54ab2 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/330] 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 3899b05ab7..42ab78d4f0 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/330] 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 42ab78d4f0..f1f6280e5b 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 2d83c9a040..7020c8fb2e 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/330] 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 7020c8fb2e..9517715b61 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/330] 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 9517715b61..e6e4dd6765 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/330] 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 0e906181c5..ad98efb14e 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 46a1ed88d2..62e93f1100 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/330] 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 ad98efb14e..63bd07beea 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/330] 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 63bd07beea..baca70e37d 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/330] 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 34b09c0d06..094281c46b 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/330] 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 baca70e37d..f0ba8d654c 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 b878c29f40..c7f6ac50da 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 12be522332..0064defe29 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/330] 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 18f44c87ca..74b3945fa1 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/330] 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 f0ba8d654c..019217ca69 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 74b3945fa1..120996a70a 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/330] 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 f1f6280e5b..f119ceb69f 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 adb6364a0c..535680fa15 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/330] 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 e6e4dd6765..b30d9a7b24 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 d897c78e9e..c1f70f2ca9 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 fb31c54ab2..b599076839 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/330] 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 b30d9a7b24..c42214fb20 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/330] 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 b599076839..55270280d1 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/330] 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 6069e3b7c7..3666d9d6ba 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/330] 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 f119ceb69f..b6e96bdf5e 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 535680fa15..d67964b846 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/330] 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 991cf4f518..4868eedae9 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 9deed1f285..6fd6441da5 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 3414ba4489..76d44a5d7b 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 1c1ef76cf0..4ef4d67717 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/330] 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 6fd6441da5..3af39911cb 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/330] 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 c42214fb20..c5c634d79d 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 55270280d1..085add7c9e 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 1ae916f81c..95313cdba4 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 daf1c09f2b..4bc926b8ab 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/330] 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 1548cc1b0f..2061b74d7f 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 d312b6d546..07e5f0a3f4 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 48632dba83..b2bdac683f 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 082b561ef5..1551f73b83 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 c1f70f2ca9..0b4ccd52fd 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 8d98a482e6..9cd76968a1 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 fa303184e5..29a0504712 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 9f53985745..847059530c 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 1bfe0c7178..462d062ebe 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/330] 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 c5c634d79d..9262aa3c5c 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 085add7c9e..6e063e1fed 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/330] 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 9262aa3c5c..6c41d56e65 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 0b4ccd52fd..cbdd9935eb 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 47751acb39..1966603fee 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 ad6ad1559e..2333a95ab0 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/330] 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 6c41d56e65..b6d507da92 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/330] 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 b6d507da92..cb8eb2a025 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 95313cdba4..06f9523050 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 4bc926b8ab..aa832ddcc0 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/330] 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 cb8eb2a025..8bf852f422 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 06f9523050..2b26c3a487 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 aa832ddcc0..1a28023a90 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/330] 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 8bf852f422..a5dd7f3693 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/330] 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 847059530c..138411e11b 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 462d062ebe..94708d403f 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/330] 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 27bdd77ce1..a811cab1c5 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/330] 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 019217ca69..e157afc838 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 62e93f1100..ee73193bf5 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/330] 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 c7f6ac50da..5f7e686a09 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/330] 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 e157afc838..9d9631ecea 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/330] 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 5f7e686a09..e276092c73 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/330] 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 e276092c73..c52a73e1c1 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/330] 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 a5dd7f3693..7a343604c0 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/330] 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 7a343604c0..447c1fa2ab 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/330] 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 447c1fa2ab..4236665631 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 2b42e6f06d..77e29f9bef 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/330] 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 3b71d421c8..278c0d0a95 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 77e29f9bef..f2d2e2c008 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 d7b20ba176..39c87fce75 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/330] 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 d67964b846..eb39070410 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/330] 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 3666d9d6ba..d135d26838 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 20c2da4b14..a97e4c42ee 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/330] 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 b6e96bdf5e..c40fac40aa 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 9d9631ecea..1a606992a2 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 ee73193bf5..fc35c06be6 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/330] 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 c40fac40aa..376092256b 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 eb39070410..996687a3e1 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/330] 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 4236665631..240f1c435b 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 cbdd9935eb..60c8246ae3 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/330] 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 240f1c435b..058160595d 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/330] 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 278c0d0a95..da670cf23e 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 39c87fce75..8b9b39617b 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/330] 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 2b26c3a487..7ffe071895 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/330] 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 376092256b..672ab2e9a8 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/330] 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 672ab2e9a8..27bc62d070 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/330] 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 f2d2e2c008..a80f083b58 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 423924eda8..b20a3ff984 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 7ffe071895..220ba5d515 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 1a28023a90..559bf032ec 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/330] 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 27bc62d070..00a58523d4 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/330] 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 da670cf23e..cc23e035e8 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 d135d26838..998b90e19e 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 a80f083b58..1a6630232d 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 8b9b39617b..d347570fe0 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 220ba5d515..e5045eee60 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 559bf032ec..8ea9657e67 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/330] 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 058160595d..dc290ec28e 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/330] 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 998b90e19e..4a31334adf 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/330] 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 dc290ec28e..63f9cb949e 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/330] 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 00a58523d4..713f1bb3b4 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 1a606992a2..da91af0051 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 fc35c06be6..2f930e9adb 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/330] 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 63f9cb949e..ec867326df 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 e5045eee60..4a1c33fb8e 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 8ea9657e67..bd5d3d50aa 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/330] 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 ec867326df..5552bd7497 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/330] 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 da91af0051..d63e302473 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/330] 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 d63e302473..3300454231 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/330] 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 cfd1c7dd39..fac7bb41ed 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 4a1c33fb8e..5d5749d5d8 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 9cd76968a1..0000000000 --- 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 29a0504712..0000000000 --- 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 138411e11b..618f6ee652 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 94708d403f..7b17da178e 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/330] 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 618f6ee652..2f52d669a4 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 7b17da178e..34ecb7454c 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/330] 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 9c6dafa34a..a619bdda23 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 520878ce1c..0629b208de 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/330] 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 1a6630232d..e75bd16778 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/330] 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 3300454231..f4b618866a 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/330] 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 5552bd7497..0b9e13fb7a 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 2f52d669a4..7664eb418e 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 34ecb7454c..f484497d97 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/330] 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 0b9e13fb7a..a61eebe2fc 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/330] 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 a61eebe2fc..9b9c9afea2 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/330] 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 713f1bb3b4..6c8d558a4d 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/330] 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 e75bd16778..bfc313caa4 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/330] 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 1551f73b83..0b9730dead 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/330] 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 4a31334adf..642c7f6453 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 5e1ec9e128599ee95664799f871122e9db745eff Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 22 Feb 2013 08:27:00 -0800 Subject: [PATCH 214/330] improved book window layout --- files/mygui/openmw_book.layout | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 894c1dbeb7..96d1153f0e 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,41 +2,45 @@ - + - + + - + + - + - + + - + - + + - + - + - - + + From 9dee2a72cd732bc302074f9ecf7e317704da3704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 09:22:06 -0800 Subject: [PATCH 215/330] 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 f4b618866a..707aedcd93 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 2f930e9adb..c6e2306707 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 216/330] 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 120996a70a..4d8119c72a 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 217/330] 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 24df305566..9f8962d7c3 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 218/330] 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 235e57d375..094ae5b168 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 bd5f95c240..c51cafc0e1 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 b2bdac683f..283c053882 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 219/330] 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 094ae5b168..9d0fe298b0 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 220/330] 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 6c8d558a4d..7b166ba91a 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 996687a3e1..2465aea98f 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 c9ca565462b599356e1681bb769218eeda3da411 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:05:09 +0100 Subject: [PATCH 221/330] removed a redundant function call --- apps/opencs/view/doc/view.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6aafef4ed0..286d7a6ed6 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -236,7 +236,6 @@ void CSVDoc::View::addGmstsSubView() void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); - mOperations->quitOperation (type); updateActions(); } From b8f5813609f0c32705d95f83106e2c5005fee19e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 03:34:03 -0800 Subject: [PATCH 222/330] 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 f951307b68..7bc89b9179 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 707aedcd93..160641eb0a 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 c6e2306707..130805a506 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 094281c46b..b85c4dbbda 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 4d8119c72a..3f135b7f67 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 6f5a772d02d886d3777de0b25f45db878f636aad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:35:05 +0100 Subject: [PATCH 223/330] fixed another case handling problem --- apps/opencs/model/world/idcollection.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 5a1d21ae4c..9b69dfb889 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -171,7 +171,7 @@ namespace CSMWorld record2.mModified = record; mRecords.push_back (record2); - mIndex.insert (std::make_pair (id, mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1)); } else { @@ -306,7 +306,7 @@ namespace CSMWorld void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); - mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } template From 868916a9a22d0dd9f8713b6ea57206d6ee689d52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:51:45 +0100 Subject: [PATCH 224/330] added add-on global variables in the same way add-on GMSTs were added --- apps/opencs/model/doc/document.cpp | 32 ++++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d63aaeccb2..b361577bec 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -20,6 +20,7 @@ void CSMDoc::Document::load (const std::vector::const_i getData().loadFile (*end2, false); addOptionalGmsts(); + addOptionalGlobals(); } void CSMDoc::Document::addOptionalGmsts() @@ -139,6 +140,26 @@ void CSMDoc::Document::addOptionalGmsts() } } +void CSMDoc::Document::addOptionalGlobals() +{ + static const char *sGlobals[] = + { + "dayspassed", + "pcwerewolf", + "pcyear", + 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global global; + global.mId = sGlobals[i]; + global.mType = ESM::VT_Int; + global.mValue = 0; + addOptionalGlobal (global); + } +} + void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) { if (getData().getGmsts().searchId (gmst.mId)==-1) @@ -150,6 +171,17 @@ void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) } } +void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global) +{ + if (getData().getGlobals().searchId (global.mId)==-1) + { + CSMWorld::Record record; + record.mBase = global; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGlobals().appendRecord (record); + } +} + void CSMDoc::Document::createBase() { static const char *sGlobals[] = diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 413e840d37..a7b198689e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ class QAbstractItemModel; namespace ESM { struct GameSetting; + struct Global; } namespace CSMDoc @@ -53,8 +54,12 @@ namespace CSMDoc void addOptionalGmsts(); + void addOptionalGlobals(); + void addOptionalGmst (const ESM::GameSetting& gmst); + void addOptionalGlobal (const ESM::Global& global); + public: Document (const std::vector& files, bool new_); From 9659b4a95e1d4bb40560046b288173ec54f07ab2 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 21 Feb 2013 23:56:34 +0400 Subject: [PATCH 225/330] update NpcAnimation inventory reference on cell change --- apps/openmw/mwrender/actors.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 52 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 8 ++++- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 92f5cbe28d..e886f3a093 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -163,7 +163,9 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { /// \note Update key (Ptr's are compared only with refdata so mCell /// on key is outdated), maybe redundant - Animation *anim = iter->second; + NpcAnimation *anim = static_cast(iter->second); + anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); + mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d33bdda91d..6f6c9e740f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -48,21 +48,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), mStateID(-1), - mInv(inv), + mInv(&inv), 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(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()) { mNpc = ptr.get()->mBase; @@ -160,7 +160,7 @@ void NpcAnimation::updateParts() }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { - MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); if(*slotlist[i].iter != iter) { *slotlist[i].iter = iter; @@ -171,7 +171,7 @@ void NpcAnimation::updateParts() if(apparelChanged) { - if(mRobe != mInv.end()) + if(mRobe != mInv->end()) { MWWorld::Ptr ptr = *mRobe; @@ -191,7 +191,7 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(mSkirtIter != mInv.end()) + if(mSkirtIter != mInv->end()) { MWWorld::Ptr ptr = *mSkirtIter; @@ -203,39 +203,39 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(mHelmet != mInv.end()) + 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()) + 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()) + 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()) + 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()) + 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 != mInv->end()) { if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) { @@ -250,7 +250,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } - if(mGloveL != mInv.end()) + if(mGloveL != mInv->end()) { if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) { @@ -265,7 +265,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); } } - if(mGloveR != mInv.end()) + if(mGloveR != mInv->end()) { if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) { @@ -282,13 +282,13 @@ void NpcAnimation::updateParts() } - if(mShirt != mInv.end()) + 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()) + if(mPants != mInv->end()) { const ESM::Clothing *clothes = (mPants->get())->mBase; std::vector parts = clothes->mParts.mParts; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc222..fd1a96aa3e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -17,7 +17,7 @@ namespace MWRender{ class NpcAnimation: public Animation{ private: - MWWorld::InventoryStore& mInv; + MWWorld::InventoryStore *mInv; int mStateID; int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty @@ -78,7 +78,13 @@ public: virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); + void updateParts(); + void updateParts(MWWorld::InventoryStore &inventory) { + mInv = &inventory; + updateParts(); + } + void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From d983ed5c7819046ad4c0166c61f6cc47575196f7 Mon Sep 17 00:00:00 2001 From: greye Date: Fri, 22 Feb 2013 11:14:14 +0400 Subject: [PATCH 226/330] fix invalid SceneNode pointer on cell change --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ca054e776b..12193de408 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -746,7 +746,11 @@ namespace MWWorld copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) { - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr) + .copyToCell(ptr, newCell) + .getRefData() + .setBaseNode(0); + mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); removeContainerScripts (ptr); From ac7095537f9626f62ee9437b241371356b92526e Mon Sep 17 00:00:00 2001 From: greye Date: Sat, 23 Feb 2013 16:50:37 +0400 Subject: [PATCH 227/330] remove insertMesh() call on object cell change --- apps/openmw/mwrender/objects.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ee36126f8d..16ac163ecc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -514,9 +514,5 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) node = mCellSceneNodes[newCell]; } node->addChild(ptr.getRefData().getBaseNode()); - - /// \note Still unaware how to move aabb and static w/o full rebuild, - /// moving static objects may cause problems - insertMesh(ptr, MWWorld::Class::get(ptr).getModel(ptr)); } From a3adcf752d9796279f175d7fbd01080ac53b227f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Fri, 22 Feb 2013 21:33:23 +0400 Subject: [PATCH 228/330] TradeWindow: fixed coding style Mentioned here: https://github.com/zinnschlag/openmw/pull/554 --- apps/openmw/mwgui/tradewindow.cpp | 12 ++++++------ apps/openmw/mwgui/tradewindow.hpp | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2cc8ff4443..290310760e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,11 +19,11 @@ #include "inventorywindow.hpp" -static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds -static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds - namespace MWGui { + const float TradeWindow::sBalanceChangeInitialPause = 0.5; + const float TradeWindow::sBalanceChangeInterval = 0.1; + TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop @@ -157,7 +157,7 @@ namespace MWGui mBalanceChangePause -= frameDuration; if (mBalanceChangePause < 0.0) { - mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + mBalanceChangePause += sBalanceChangeInterval; if (mBalanceButtonsState == BBS_Increase) onIncreaseButtonTriggered(); else if (mBalanceButtonsState == BBS_Decrease) @@ -296,14 +296,14 @@ namespace MWGui void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Increase; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onIncreaseButtonTriggered(); } void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Decrease; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onDecreaseButtonTriggered(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 20d9b60691..c1d31917ba 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -37,6 +37,9 @@ namespace MWGui void onFrame(float frameDuration); protected: + static const float sBalanceChangeInitialPause; // in seconds + static const float sBalanceChangeInterval; // in seconds + MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; MyGUI::Button* mFilterApparel; From e6da9dfae533065a4c258007160b3269c3407a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 05:15:10 -0800 Subject: [PATCH 229/330] 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 7b166ba91a..5598e0e56f 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 160641eb0a..1dd46365bc 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 130805a506..47bc8c3900 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 9f8962d7c3..36cac2155d 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 3472a6f180e81ab510026b4b96760adf4d145181 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 14:40:56 +0100 Subject: [PATCH 230/330] workaround for infinite recursion during local variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 42 +++++++++++++++-------- apps/openmw/mwscript/scriptmanagerimp.hpp | 1 + 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 1f338edbd3..e8489e3cd0 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -140,25 +140,37 @@ namespace MWScript Compiler::Locals& ScriptManager::getLocals (const std::string& name) { - ScriptCollection::iterator iter = mScripts.find (name); - - if (iter==mScripts.end()) { - if (!compile (name)) - { - /// \todo Handle case of cyclic member variable access. Currently this could look up - /// the whole application in an endless recursion. + ScriptCollection::iterator iter = mScripts.find (name); - // failed -> ignore script from now on. - std::vector empty; - mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); - throw std::runtime_error ("failed to compile script " + name); - } - - iter = mScripts.find (name); + if (iter!=mScripts.end()) + return iter->second.second; } - return iter->second.second; + { + std::map::iterator iter = mOtherLocals.find (name); + + if (iter!=mOtherLocals.end()) + return iter->second; + } + + Compiler::Locals locals; + + if (const ESM::Script *script = mStore.get().find (name)) + { + int index = 0; + + for (int i=0; imData.mNumShorts; ++i) + locals.declare ('s', script->mVarNames[index++]); + + for (int i=0; imData.mNumLongs; ++i) + locals.declare ('l', script->mVarNames[index++]); + + for (int i=0; imData.mNumFloats; ++i) + locals.declare ('f', script->mVarNames[index++]); + } + + throw std::logic_error ("script " + name + " does not exist"); } GlobalScripts& ScriptManager::getGlobalScripts() diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index c4a016eb79..1a856e0c58 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -47,6 +47,7 @@ namespace MWScript ScriptCollection mScripts; GlobalScripts mGlobalScripts; + std::map mOtherLocals; public: From 89dace3cc3bea36c7fec02b7b5bba629ab5e8e89 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 23 Feb 2013 09:07:13 -0600 Subject: [PATCH 231/330] Fix for operations widget - hides when no operations are running. --- apps/opencs/view/doc/operations.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 71cacbe17e..ce001afaa9 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -16,7 +16,7 @@ CSVDoc::Operations::Operations() widgetContainer->setLayout (mLayout); setWidget (widgetContainer); - + setVisible (false); setFixedHeight (widgetContainer->height()); setTitleBarWidget (new QWidget (this)); } @@ -42,6 +42,8 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread if ( oldCount > 0) setFixedHeight (height()/oldCount * newCount); + + setVisible (true); } void CSVDoc::Operations::quitOperation (int type) @@ -59,6 +61,8 @@ void CSVDoc::Operations::quitOperation (int type) if (oldCount > 1) setFixedHeight (height() / oldCount * newCount); + else + setVisible (false); break; } From 0d0e75fe0b74c265e6ae31a5dccfa2e240fc196e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 07:36:11 -0800 Subject: [PATCH 232/330] 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 1dd46365bc..29652ca6a9 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 233/330] 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 3f31459005..d356d922e5 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 dcaee55f99..809e3f6d29 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 c5d5b74619..aed4868bdd 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 61fc8ad6e4bed33473c891b3268d91bc2168a56e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 18:56:07 +0100 Subject: [PATCH 234/330] updated credits files --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 5c966d86b2..8b396aad0a 100644 --- a/credits.txt +++ b/credits.txt @@ -40,6 +40,7 @@ Nikolay Kasyanov (corristo) Pieter van der Kloet (pvdk) Roman Melnik (Kromgart) Sebastian Wick (swick) +Sergey Shambir Sylvain T. (Garvek) Tom Mason (wheybags) From d208422ca76da90b9a5a0fa12b47722122948b8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 10:12:36 -0800 Subject: [PATCH 235/330] 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 d356d922e5..485e3a7adc 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 29652ca6a9..39323edac2 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 47bc8c3900..b8323cb895 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 44b1c66c4b1a976024ac1f664793d80737cd27ce Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 14 Feb 2013 21:38:27 -0800 Subject: [PATCH 236/330] fixed various warnings about converting size_t to int --- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/store.hpp | 16 ++++++++-------- components/esm/esmwriter.cpp | 10 +++++----- components/esm/esmwriter.hpp | 8 ++++---- components/to_utf8/to_utf8.cpp | 4 ++-- components/to_utf8/to_utf8.hpp | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b917a89168..254e05e7f6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -25,7 +25,7 @@ namespace const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - int numRefs = cellRefList.mList.size(); + size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc4..c05e372838 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -17,7 +17,7 @@ namespace MWWorld virtual void setUp() {} virtual void listIdentifier(std::vector &list) const {} - virtual int getSize() const = 0; + virtual size_t getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual bool eraseStatic(const std::string &id) {return false;} @@ -158,7 +158,7 @@ namespace MWWorld return mShared.end(); } - int getSize() const { + size_t getSize() const { return mShared.size(); } @@ -269,11 +269,11 @@ namespace MWWorld return ptr; } - int getSize() const { + size_t getSize() const { return mStatic.size(); } - int getSize(size_t plugin) const { + size_t getSize(size_t plugin) const { assert(plugin < mStatic.size()); return mStatic[plugin].size(); } @@ -338,7 +338,7 @@ namespace MWWorld } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -567,7 +567,7 @@ namespace MWWorld return 0; } - int getSize() const { + size_t getSize() const { return mSharedInt.size() + mSharedExt.size(); } @@ -701,7 +701,7 @@ namespace MWWorld mStatic.back().load(esm); } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -930,7 +930,7 @@ namespace MWWorld } } - int getSize() const { + size_t getSize() const { return mStatic.size(); } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index e2f878a257..b9dd5b57b6 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -136,15 +136,15 @@ void ESMWriter::writeHNString(const std::string& name, const std::string& data) endRecord(name); } -void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) +void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size) { - assert(static_cast (data.size()) <= size); + assert(data.size() <= size); startSubRecord(name); writeHString(data); - if (static_cast (data.size()) < size) + if (data.size() < size) { - for (int i = data.size(); i < size; ++i) + for (size_t i = data.size(); i < size; ++i) write("\0",1); } @@ -177,7 +177,7 @@ void ESMWriter::writeName(const std::string& name) write(name.c_str(), name.size()); } -void ESMWriter::write(const char* data, int size) +void ESMWriter::write(const char* data, size_t size) { if (count && !m_records.empty()) { diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index b557a29ad8..94e173b4ce 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -16,7 +16,7 @@ class ESMWriter { std::string name; std::streampos position; - int size; + size_t size; }; public: @@ -35,7 +35,7 @@ public: void close(); void writeHNString(const std::string& name, const std::string& data); - void writeHNString(const std::string& name, const std::string& data, int size); + void writeHNString(const std::string& name, const std::string& data, size_t size); void writeHNCString(const std::string& name, const std::string& data) { startSubRecord(name); @@ -76,7 +76,7 @@ public: } template - void writeT(const T& data, int size) + void writeT(const T& data, size_t size) { write((char*)&data, size); } @@ -87,7 +87,7 @@ public: void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); - void write(const char* data, int size); + void write(const char* data, size_t size); private: std::list m_masters; diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index e2a1b1220f..1de15d79c4 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -70,7 +70,7 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): } } -std::string Utf8Encoder::getUtf8(const char* input, int size) +std::string Utf8Encoder::getUtf8(const char* input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which @@ -111,7 +111,7 @@ std::string Utf8Encoder::getUtf8(const char* input, int size) return std::string(&mOutput[0], outlen); } -std::string Utf8Encoder::getLegacyEnc(const char *input, int size) +std::string Utf8Encoder::getLegacyEnc(const char *input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index d975b3e4d0..839aa36aa3 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -27,13 +27,13 @@ namespace ToUTF8 Utf8Encoder(FromType sourceEncoding); // Convert to UTF8 from the previously given code page. - std::string getUtf8(const char *input, int size); + std::string getUtf8(const char *input, size_t size); inline std::string getUtf8(const std::string &str) { return getUtf8(str.c_str(), str.size()); } - std::string getLegacyEnc(const char *input, int size); + std::string getLegacyEnc(const char *input, size_t size); inline std::string getLegacyEnc(const std::string &str) { return getLegacyEnc(str.c_str(), str.size()); From 1af4e11414c94e4691acefb2fe987790570ae8b4 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 23 Feb 2013 10:24:18 -0800 Subject: [PATCH 237/330] apply MSVC warning settings to shiny projects --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef85e34dd..95d54fed1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,6 +529,8 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS}) + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) if (BUILD_LAUNCHER) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) From a95431c387258d0f3862a9e8a5345336602a4cb2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 20:20:40 +0100 Subject: [PATCH 238/330] fix --- apps/openmw/mwscript/scriptmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index e8489e3cd0..fed5877c4b 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -168,6 +168,11 @@ namespace MWScript for (int i=0; imData.mNumFloats; ++i) locals.declare ('f', script->mVarNames[index++]); + + std::map::iterator iter = + mOtherLocals.insert (std::make_pair (name, locals)).first; + + return iter->second; } throw std::logic_error ("script " + name + " does not exist"); From df8889dcc4eb772a8689252e940ba1275d8fd2fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 13:15:37 -0800 Subject: [PATCH 239/330] 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 7dc18c6e87..6f59349fd5 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 240/330] 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 5598e0e56f..37477932a4 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 39323edac2..f453e6a740 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 241/330] 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 f453e6a740..394e25b504 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 b8323cb895..810ca869f5 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 a5ff8181b737b91f096b1182f03066ac14ef0e06 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sun, 24 Feb 2013 03:35:43 +0400 Subject: [PATCH 242/330] fix for https://bugs.openmw.org/issues/569 --- apps/openmw/mwworld/store.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc4..3eec052347 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,7 +19,7 @@ namespace MWWorld virtual int getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; - + virtual bool eraseStatic(const std::string &id) {return false;} }; @@ -110,7 +110,7 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::const_iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { return &(it->second); } @@ -188,14 +188,14 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); } return true; } - + bool erase(const std::string &id) { std::string key = Misc::StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); @@ -220,9 +220,15 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); - mStatic[idLower] = ESM::Dialogue(); - mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think - mStatic[idLower].load(esm); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed... I think + } + + //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins + it->second.load(esm); } template <> @@ -409,7 +415,7 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - + const ESM::Cell *search(const ESM::Cell &cell) const { if (cell.isExterior()) { return search(cell.getGridX(), cell.getGridY()); @@ -481,7 +487,7 @@ namespace MWWorld newCell->mData.mY = y; mExt[std::make_pair(x, y)] = *newCell; delete newCell; - + return &mExt[std::make_pair(x, y)]; } @@ -528,7 +534,7 @@ namespace MWWorld // There some nasty three-way cyclic header dependency involved, which I could only fix by moving // this method. void load(ESM::ESMReader &esm, const std::string &id); - + iterator intBegin() const { return iterator(mSharedInt.begin()); } From 90cb9ee0ac73dca6388b2f69e1906945d51e4fab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 16:30:11 -0800 Subject: [PATCH 243/330] 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 9b9c9afea2..0c1f580488 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 244/330] 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 485e3a7adc..78521d0ce6 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 fc9fa4fbba..c89bfbaf5e 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 fe81eb9114..2bbb229a39 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 283c053882..b7dd5a3b1a 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 0b9730dead..5dd2b37736 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 b6c33f9c01..bdb5447e32 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 71e956b6ed..f723934be9 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 245/330] 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 642c7f6453..12b40bfdcf 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 a97e4c42ee..f41edb0df6 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 37477932a4..8f7929805f 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 c760191496..71b24b65dc 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 07dcb8fe03..1a6a16ca07 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 62c5568ed9138eb679f0427a2ea655af872303eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Sun, 24 Feb 2013 16:57:07 +0100 Subject: [PATCH 246/330] Fix for the loadingbar to resemble vanilla Morrowind. --- files/mygui/openmw_loading_screen.layout | 4 ++-- files/mygui/openmw_progress.skin.xml | 13 +++++++++++++ files/mygui/smallbars.png | Bin 246 -> 3205 bytes 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 6862702ca1..4b6861151a 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -6,12 +6,12 @@ - + - + diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index c4b94e28e2..4666be2217 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -17,6 +17,11 @@ + + + + + @@ -51,4 +56,12 @@ + + + + + + + + diff --git a/files/mygui/smallbars.png b/files/mygui/smallbars.png index a9ed572ef6dd53092f3e35dd1fc871a60686e91d..f938412c259c540d8e085a339fa0d94c4294a361 100644 GIT binary patch literal 3205 zcmYjTc|6o>7k`GyzGatm$(rnIc4q8r7#UHv7$u?HY>_2fx+Gbr5tV&O)MzYaCo)3T zv1Ch#Zk9%vnRndoeRDpa=X-wNv;Lm*{Bx4dTAQ#k9b*Cju$q|~+EF!>dW0Ehs90ZR z%}7;@0j5qj0AS`iI1rHgh#vqZo6B(c*|R?WLH;*<`~!r|;Beu9>;B%CuX+IxGJ&y2 zA?%lVb%@hjFpI>fhZg>JJPg8iu;eK2Gzn=DMh^2tk%Dm^+m@q7Mo_`-{6yN6l&E_= zwlXYtna1cBM4qI?K25yavo{<5)OVzj__>e#YE*ZrViQx_Pv6YIl4+`Js~W{p3OjN1 zQ*2jz=j?)F_jo_I*hxb=E^%!9MCz)kY@=OGY<*~tlq0OyAy zJdpe}Ak5{JXb60?Kt=z#yG8)10Jyy^+BLwKEKo3W^fm?6b)Xr~!CV6vSb&0UV%#YJ z4F_)BqM{+-P7dHU-f-0Ze!7ZdNt!yToEmMMn1)fbGlOg(y`!Vt2`Ri8-)U|&cN+Ix zeYw`q908?h74}b??*Yh9fz$6cgo3IktG+>S_#DU>r=O!!?Qx9v%b zG*weYySoTs2UDR9o$E9j2`y2 z`dkHVL(;Zq|BGNKXS7i>qZ%|AChUH~z!YhTv>r1p5k4-aa&&@GosssAZL8$T^b(7g z67@%aw)1-^DJCFIWkg3fQ@P|h!V}@`>SCNpa3x9HeHybD&k%#0gT{l`>_nGkO3^B& z$3)ZLOkz-M1kUmgY0oLxhZ9)l`%AdI!eX+b|7KN2hGKP-%@c9rgKmQU`e{?G2 zgmu;j$HCrZlP_6cXt#n{SmSwOyAn}S0%(4Eew08k|MP6iB7vb~fi8rCy5ef~QVx5L zzXMVlD}9S6t%oVYJVPQwP+A^QT2@pxUB>LN>ClTvExl+TQDy9)Y(HPh_%XBGp$v0& z)n3pZRjO5zP=+e;N9a9^bRs3uIkj1~*}$LK=D%>AZ|oFi_7tcMkrDA_Esy^*TD4u` zMc??Xo6-&0B%y|6owCvb4Y;zovSY2?=0k5i`uXg@oku~|j7w6*S(}k}r@6nKnmZ*} zq+*Fv^m6en%go9|mYbH_mYb|Lsa35NV~U!L8l3i`*$leOC0!&A54 zVqPm9&Fw0=GT%bMf(FCjx7Ui-v-93ujLNh0FP;uPywE+vJ!|$(8g4-Q>9Fx%#_ablce>1r&HHuwbv~7# zlMs=xuv)QN&$Y9{6`d;5vedHd>U-b!q;Dig6|JKfFwUoR`6tU|)Ng z)hwJZa$3hWUW+@g;Z%rpIDetmxDrz-KGIOxP<*r)XPs_co;QMOtNxCChb^rWs9qeS zBUEAiuo3Pk4?a{~M^)Q;dQ*BteZ*fR9eUP;akg@y^Fom~US8+cJf}IGi+{AP7tyhm zxh#)D_H*=)DbHiMdQY`q#@M5WOi+9%+>O}H#N;H4m|nRoT{*O1=Tvvof_cz(;Dy<+ z!EFq>7Tvm5LU_Kewtjg%Ve;{NmB**@oRn{TXzPZ5vRxd|V}6{W;5$cvV;jUq(;WQeh zXru95)?8Iuw@mJe_Jn%9O1)mEoVU~aVI&4=cGcpzhMaVj+O?~1X7<-M6Xq~;%=6)V z+49{N0zwP$ty^)$yrpuSGMbtCmWkG99{z2>Azi|IPke(bSUiO(v{k4Tby9vnZ6I+B z?jn7{dc#!OD(u16v_{oXu@2=znMK?k$%JKeYTzP5*OU;WXy$CNeBR?gW6*ur=VM_D1{=cbA)8a3L1p#-LRo+GE@&(T$A zzrKr=_8Yb-Uvtc=ifobyv+|9;*wPcz@(SX+%Iv_j7#FcRIl6Yi1}X0}^U8fU9wVsB zlXSO=o4}XFb9+o`GGtLO!N2Ei&g8?FrRD9oOa0!1-pik-W%HcbGRv|)XR%#l9iMo~ zI&<#j+V&44f_zq=6rmv&3&%ZutNpsstN0zhPfHK+46%jSMX0S0PQ7v;-MKcfE*ReU zL*?r*!MTx0(tY=a-~e&38ulLc+B4g$CF)frl`ZdN?)hD)wDt>J>!KZ`CDDtrVMlQv zhlK`p5O%2}r&mqby8d`W#(WEwWmRK!`0G*UoM?by=)y9QafWz;RdeFzz3_@z`k_B= z3ZaDLufTFQa*fgUxqHqY&h<9$bq7XPro;A42!F6YQqgt_HQz+MyF9TRGn9_n=)Z@_ zz(hpK{hV|oJi&%9dE#fTu={_j=Lnh|G@>LgX*Fu$T{d0^ZPXAJxg1|R=04YS^;-#A z(I%%4*>p8LYRIj^x%lGN!ca&lF-&0wZaIk!On%Y?b5GD>lR4f2LDO9}-z@G{LthfQ7nGFD+{{z0IKN#_sIty(mx2@{Kfu>g|6+9{+|S0+dV|S z9wtMA*M5fq$ib@oOP~-M2n0eyp^&L~V5X1`YETinzq|Es5cPNVcE2AYJBP{c-@iS} z4y(Tj_}zxOqSHeFwKCO2rot|DLICU?AQb%AKa{h%dx-qKcZh5p@}Soa-SpSoNDyiV zGPFpdlA1%EB(*k_g&ok+P$vi>lK^y^2q*^)|7l91u5|wibnE+}Y8zjvFZZt;l%XW^ V+qrc3Ge{oT%#5rJt6*+1{{u-NeNq4b delta 212 zcmV;_04x868TJ8?7Z(}`0ssI2A5Ut+00001b5ch_0Itp)>5(B9e*gz`Nliru*#ZX- z6CpS#nr{FA0EkIMK~xyiZP3990znLg;Xh%(5~&##IK14YFH6+F=H0OkN?-L%E#W(hUno^d&x2M`?)6%mba5mg|}wqAOD zjaaLXgil6Y2Ck=DGTNi*9(IC(f}_*`XaN-7J;m0Vu(X6{noP6(|JxT0PCY1eTX63H O0000 Date: Sun, 24 Feb 2013 16:57:40 +0100 Subject: [PATCH 247/330] Prettier repeated borders. --- files/mygui/openmw_hud_box.skin.xml | 88 +++++++++++++++-------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index ce231e5bb9..464b6343aa 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -2,76 +2,78 @@ - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - From 7ea1f6a02a06e83a153ff85c7f3b5ab210c37ca7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 00:23:10 -0800 Subject: [PATCH 248/330] 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 00530a9628..54df45ff4c 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 c80203a25b..4147590d60 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 249/330] 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 9d0fe298b0..c23e4b833d 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 c51cafc0e1..06ddcb2256 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 283c053882..1a4829d9f4 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 250/330] 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 06ddcb2256..53957152f6 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 251/330] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 8b396aad0a..535e922ae1 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 252/330] 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 c52a73e1c1..8c5d4dc5ac 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 0064defe29..7a7b0c5a1e 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 253/330] 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 9e79f02561..76f38eefc2 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 254/330] 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 c23e4b833d..200f6e2d4a 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 e0b53f9063..5801014642 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 b1381ddd693995d4920a0e683b313ed46869bf6f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Mon, 25 Feb 2013 04:12:41 +0400 Subject: [PATCH 255/330] Nif loader: workaround for missed textures in BB/BH Works for Better Bodies / Better Heads addons. --- components/nifogre/ogre_nif_loader.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index dfbc93ee90..0ee778df30 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -540,7 +540,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); if (st->external) { - /* Bethesda at some at some point converted all their BSA + /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all * texture file name references were kept as .tga. */ @@ -559,6 +559,17 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) texName = path + st->filename; } + else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + { + // workaround for Better Heads addon + size_t lastSlash = st->filename.rfind('\\'); + if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { + texName = path + st->filename.substr(lastSlash + 1); + // workaround for Better Bodies addon + if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + texName = st->filename; + } + } } else warn("Found internal texture, ignoring."); } From 53eb553c57b69f7ce7bbf36159348724bab184df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 18:12:15 -0800 Subject: [PATCH 256/330] 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 8c5d4dc5ac..1582826b81 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 257/330] 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 c53a68cf44..53e5c022d2 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 f16f92325b..ad1c0b40f5 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 2eed21a528..f3bac898b2 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 c7699b3083..2662d94ccf 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 054cce7b85..699c687ff6 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 e0dc3306a8..6195569065 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 45adb53832..50dc26e428 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 2b0740234e..aac609a646 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 3dbe751659..c193948330 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 8483103691..6499902815 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 f1f88b9aec..0ce664c9bf 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 From 151ecaad049411e42fde0de45e36b7dd2bee27aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 10:32:38 +0100 Subject: [PATCH 258/330] workaround for garbage after an end statement --- components/compiler/fileparser.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 9b184f1ffb..98be2d3d1f 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -45,7 +45,10 @@ namespace Compiler reportWarning ("Names for script " + mName + " do not match", loc); mState = EndCompleteState; - return true; + return false; // we are stopping here, because there might be more garbage on the end line, + // that we must ignore. + // + /// \todo allow this workaround to be disabled for newer scripts } return Parser::parseName (name, loc, scanner); From 73d48a95f65ea68e1527ccd056362a855ae73619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 16:31:48 +0100 Subject: [PATCH 259/330] Add message box when the player tries to move when being overencumbered. --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 25 +++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++--- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4f7435fadc..81d7cb9fed 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -198,7 +198,7 @@ namespace MWBase virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()) = 0; virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fff627366e..f574211372 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -188,7 +188,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()); virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5a4c431f58..4a79f77b85 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -21,6 +21,7 @@ #include "../engine.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -51,6 +52,7 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mOverencumberedMessageDelay(0.f) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -268,13 +270,16 @@ namespace MWInput // be done in the physics system. if (mControlSwitch["playercontrols"]) { + bool triedToMove = false; if (actionIsActive(A_MoveLeft)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } @@ -283,11 +288,13 @@ namespace MWInput if (actionIsActive(A_MoveForward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (1); } else if (actionIsActive(A_MoveBackward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (-1); } @@ -295,7 +302,10 @@ namespace MWInput mPlayer.setForwardBackward (0); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) + { mPlayer.setUpDown (1); + triedToMove = true; + } else if (actionIsActive(A_Crouch)) mPlayer.setUpDown (-1); else @@ -306,6 +316,21 @@ namespace MWInput else mPlayer.setRunState(false); + // if player tried to start moving, but can't (due to being overencumbered), display a notification. + if (triedToMove) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + mOverencumberedMessageDelay -= dt; + if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) + { + if (mOverencumberedMessageDelay <= 0) + { + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); + mOverencumberedMessageDelay = 1.0; + } + } + } + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3af39911cb..383fe30359 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -145,6 +145,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + float mOverencumberedMessageDelay; + float mMouseX; float mMouseY; int mMouseWheel; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f8805..3cc3dcde39 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -491,8 +491,10 @@ namespace MWMechanics if(buying) x = buyTerm; else x = std::min(buyTerm, sellTerm); int offerPrice; - if (x < 1) offerPrice = int(x * basePrice); - if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice); + if (x < 1) + offerPrice = int(x * basePrice); + else + offerPrice = basePrice + int((x - 1) * basePrice); offerPrice = std::max(1, offerPrice); return offerPrice; } @@ -555,7 +557,7 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y; + float x,y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From 5d5d28c06ccabbbeae221a8eb4d906aeebc69b79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 07:43:56 -0800 Subject: [PATCH 260/330] Increase the ID cache to 40 Helps improve performance with Tribunal and Bloodmoon's scripts --- apps/openmw/mwworld/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 59c62e37d6..b912f5ccca 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -86,7 +86,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), - mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable + mIdCache (40, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) {} From 88e8659a4959b9dcf0670796f75af6cac8b3b9f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 16:52:31 +0100 Subject: [PATCH 261/330] minor cleanup --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3cc3dcde39..5ed3770fd4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -557,7 +557,8 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y = 0; + float x = 0; + float y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From ff1ecb85c6cc1f02821024e1964abbf81633d545 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 08:22:57 -0800 Subject: [PATCH 262/330] Don't bother storing the shape name for the submesh name The submesh name Ogre has is completely useless to us --- components/nifogre/ogre_nif_loader.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1582826b81..826d247c6f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -763,7 +763,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; std::string mMaterialName; - std::string mShapeName; void warn(const std::string &msg) { @@ -872,8 +871,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::VertexDeclaration *decl; int nextBuf = 0; - Ogre::SubMesh *sub = ((mShapeName.length() > 0) ? mesh->createSubMesh(mShapeName) : - mesh->createSubMesh()); + Ogre::SubMesh *sub = mesh->createSubMesh(); // Add vertices sub->useSharedVertices = false; @@ -1061,12 +1059,11 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); - mShapeName = shape->name; Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(mShapeName.length() > 0) - fullname += "@shape="+mShapeName; + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); From 355390429e68b7df609837f1acfbae631cdab5cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 17:27:50 +0100 Subject: [PATCH 263/330] Fix World::isUnderwater to use dynamic waterlevel --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 10 +++++----- apps/openmw/mwworld/worldimp.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc23e035e8..eef844c761 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -288,7 +288,7 @@ namespace MWBase 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 isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5dd2b37736..559fc01157 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( - *world->getPlayer().getPlayer().getCell()->mCell, + world->getPlayer().getPlayer().getCell(), Ogre::Vector3(cam.x, -cam.z, cam.y)) ); mWater->update(duration); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..eaee8f5a7b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1411,16 +1411,16 @@ namespace MWWorld 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); + return isUnderwater(object.getCell(), pos); } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const + World::isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const { - if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { + if (!(cell->mCell->mData.mFlags & ESM::Cell::HasWater)) { return false; } - return pos.z < cell.mWater; + return pos.z < cell->mWaterLevel; } bool World::isOnGround(const MWWorld::Ptr &ptr) const @@ -1448,7 +1448,7 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d347570fe0..0ae81b33a0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -316,7 +316,7 @@ namespace MWWorld 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 isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From 48271e49eccff7379911ae4abcaf00ba39a87125 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 09:57:34 -0800 Subject: [PATCH 264/330] Properly update the Ptr object in the mechanics manager when moving across cells --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 6 ++++-- apps/openmw/mwmechanics/activators.hpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 10 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index cb9539ef65..b8733259ff 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,7 +43,7 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) = 0; ///< Moves an object to a new cell virtual void drop (const MWWorld::CellStore *cellStore) = 0; diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 1a743cad59..b67fcb2164 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -26,13 +26,15 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } -void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActivators.find(ptr); + PtrControllerMap::iterator iter = mActivators.find(old); if(iter != mActivators.end()) { CharacterController ctrl = iter->second; mActivators.erase(iter); + + ctrl.updatePtr(ptr); mActivators.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 0b9e984aa6..137674a57a 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,8 +28,8 @@ 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 updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an activator with a new Ptr 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 a8c05f17e3..9632bdf769 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,13 +179,15 @@ namespace MWMechanics mActors.erase(iter); } - void Actors::updateActorCell(const MWWorld::Ptr &ptr) + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrControllerMap::iterator iter = mActors.find(old); if(iter != mActors.end()) { CharacterController ctrl = iter->second; mActors.erase(iter); + + ctrl.updatePtr(ptr); mActors.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index fbd787e835..fc4af8dd63 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -58,8 +58,8 @@ 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 updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an actor with a new Ptr void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f7929805f..ae0114a351 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -131,6 +131,12 @@ CharacterController::~CharacterController() } +void CharacterController::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + + void CharacterController::markerEvent(float time, const std::string &evt) { if(evt == "stop") diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2465aea98f..2b3c50864a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,8 @@ public: CharacterController(const CharacterController &rhs); virtual ~CharacterController(); + void updatePtr(const MWWorld::Ptr &ptr); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f8805..a02b64e9d3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -191,12 +191,12 @@ namespace MWMechanics mActivators.removeActivator(ptr); } - void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivatorCell(ptr); + mActivators.updateActivator(old, ptr); else - mActors.updateActorCell(ptr); + mActors.updateActor(old, ptr); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 99010b7ffd..5ad8705719 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,7 +48,7 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr); + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr); ///< Moves an object to a new cell virtual void drop(const MWWorld::CellStore *cellStore); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..c1725c00c8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -773,7 +773,7 @@ namespace MWWorld mRendering->updateObjectCell(ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->updateCell(copy); + mechMgr->updateCell(ptr, copy); std::string script = MWWorld::Class::get(ptr).getScript(ptr); From 661fd73c6e1668a2c929f4ad5dd07afcaf83ec7a Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 25 Feb 2013 22:00:50 +0400 Subject: [PATCH 265/330] fix rotation for objects in inactive cells and forced vanity mode --- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be9..5eaa71b750 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -832,16 +832,16 @@ namespace MWWorld rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - float *objRot = ptr.getRefData().getPosition().rot; - if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust)) + if (mRendering->rotateObject(ptr, rot, adjust)) { - objRot[0] = (adjust ? objRot[0] + rot.x : rot.x), objRot[1] = (adjust ? objRot[1] + rot.y : rot.y), objRot[2] = (adjust ? objRot[2] + rot.z : rot.z); - return; - } + // rotate physically iff renderer confirm so + float *objRot = ptr.getRefData().getPosition().rot; + objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - // do this after rendering rotated the object so it gets changed by Class->adjustRotation - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + mPhysics->rotateObject(ptr); + } + } } void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) From 5f2c8970014a0c0719be67d9e2453f2323ce2731 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 10:29:48 -0800 Subject: [PATCH 266/330] Better handle which collision shapes to load --- components/nifbullet/bullet_nif_loader.cpp | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index a619bdda23..3d9c16ebbf 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -155,6 +155,8 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // the flags we currently use, at least. flags |= node->flags; + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + // Marker objects: no collision /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) @@ -191,25 +193,26 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if(node->hasBounds) + if(!hasCollisionNode || isCollisionNode) { - cShape->boxTranslation = node->boundPos; - cShape->boxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } + if(node->hasBounds) + { + cShape->boxTranslation = node->boundPos; + cShape->boxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } - if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + if(node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + } } // For NiNodes, loop through children const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); - const Nif::NodeList &list = ninode->children; for(size_t i = 0;i < list.length();i++) { From da575b181e4f6929b97d0255ccc8dec1f8362b6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:04:17 -0800 Subject: [PATCH 267/330] Use the correct GMST for the race menu --- apps/openmw/mwgui/race.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 699c687ff6..71a4d1b3e4 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -61,7 +61,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race")); + setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); From 429bc23cf6c2bc763213cb6d1052ee398f374391 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:08:40 -0800 Subject: [PATCH 268/330] Convert the 0-1 glossiness parameter to 0-255 for shininess --- 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 826d247c6f..fd376045f3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -683,7 +683,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); instance->setProperty ("specular", sh::makeProperty ( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); instance->setProperty ("emissive", sh::makeProperty ( new sh::Vector3(emissive.x, emissive.y, emissive.z))); From aefd12dfe046f08ab55160ff4248f8576ca8e406 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 15:44:59 -0800 Subject: [PATCH 269/330] Don't create meshes for collision shapes --- components/nifogre/ogre_nif_loader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index fd376045f3..97b297238f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1031,6 +1031,10 @@ public: void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { + // Do not create meshes for the collision shape (includes all children) + if(node->recType == Nif::RC_RootCollisionNode) + return; + flags |= node->flags; // Marker objects: just skip the entire node From a576e9e430b0feaf5c27bce36a3c3313b831a11a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 16:40:08 -0800 Subject: [PATCH 270/330] Set the race selection character preview in a valid (idle) pose. --- apps/openmw/mwrender/characterpreview.cpp | 6 ++++++ apps/openmw/mwrender/characterpreview.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 36cac2155d..c32e9d1d68 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -161,6 +161,7 @@ namespace MWRender void RaceSelectionPreview::update(float angle) { + mAnimation->runAnimation(0.0f); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); mNode->setVisible (true); @@ -175,4 +176,9 @@ namespace MWRender rebuild(); update(0); } + + void RaceSelectionPreview::onSetup () + { + mAnimation->play("idle", "start", "stop", false); + } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index d07a03be7d..cf1e250692 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -85,6 +85,8 @@ namespace MWRender public: RaceSelectionPreview(); + virtual void onSetup(); + void update(float angle); const ESM::NPC &getPrototype() const { From 955e2713a949e1d65d3c0f1bbf7975048960c8e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 17:29:32 -0800 Subject: [PATCH 271/330] Fix encumbrance term calculation --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 12b40bfdcf..c8c61e118f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -382,7 +382,7 @@ namespace MWClass const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + fJumpEncumbranceMultiplier->getFloat() * - (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); float b = 0.0f; From a5451eb9d92164397a7dd5499976d77bbad436fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 08:30:06 +0100 Subject: [PATCH 272/330] Z-up conversion: terrain, objects --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- apps/openmw/mwrender/terrain.cpp | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 559fc01157..455e84f5ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -147,8 +147,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Morrowind uses, and it automagically makes everything work as it // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt->createChildSceneNode("mwRoot"); - mMwRoot->pitch(Degree(-90)); + mMwRoot = rt; mObjects.setMwRoot(mMwRoot); mActors.setMwRoot(mMwRoot); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 2c2e9e6fcf..47ee6f06f9 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -26,7 +26,7 @@ namespace MWRender //---------------------------------------------------------------------------------------------- TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : - mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) + mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Y, mLandSize, mWorldSize)), mRendering(rend) { mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); @@ -54,8 +54,8 @@ namespace MWRender mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); mTerrainGroup.setOrigin(Vector3(mWorldSize/2, - 0, - -mWorldSize/2)); + mWorldSize/2, + 0)); Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings(); From 3cb3ec91c065cd7ce4c229476b0e95a12cfe41f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 09:12:35 +0100 Subject: [PATCH 273/330] Z-up conversion: camera --- apps/openmw/mwrender/player.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 9ab8a7de33..1ac3b072f5 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -113,11 +113,6 @@ namespace MWRender Ogre::Vector3 dir = mCamera->getRealDirection(); Ogre::Vector3 up = mCamera->getRealUp(); - Ogre::Real xch; - xch = pos.y, pos.y = -pos.z, pos.z = xch; - xch = dir.y, dir.y = -dir.z, dir.z = xch; - xch = up.y, up.y = -up.z, up.z = xch; - MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); } @@ -323,10 +318,8 @@ namespace MWRender bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) { - float xch; mCamera->getParentSceneNode ()->needUpdate(true); camera = mCamera->getRealPosition(); - xch = camera.z, camera.z = camera.y, camera.y = -xch; player = mPlayerNode->getPosition(); return mFirstPersonView && !mVanity.enabled && !mPreviewMode; From 3ef952172d5a05133d94b9f3e6cf65a636eafa26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 10:38:48 +0100 Subject: [PATCH 274/330] Z-up conversion: water, sky --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwrender/water.cpp | 14 +++++------ files/materials/objects.shader | 12 ++++----- files/materials/terrain.shader | 16 ++++++------ files/materials/underwater.h | 6 ++--- files/materials/water.shader | 30 ++++++++++++----------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 455e84f5ef..b2d7fbff08 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -365,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) float *fpos = data.getPosition().pos; // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); + Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( world->getPlayer().getPlayer().getCell(), - Ogre::Vector3(cam.x, -cam.z, cam.y)) + cam) ); mWater->update(duration); } @@ -613,8 +613,7 @@ void RenderingManager::sunDisable() void RenderingManager::setSunDirection(const Ogre::Vector3& direction) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), - // then convert from MW to ogre coordinates (swap y,z and make y negative) - if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y)); + if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); mSkyManager->setSunDirection(direction); } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 767f3c4639..b747b0d9a8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -236,7 +236,6 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) { mSceneMgr = pMwRoot->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e8f099640b..e8ccbb2b46 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -42,9 +42,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mIsUnderwater = false; - mWaterPlane = Plane(Vector3::UNIT_Y, 0); + mWaterPlane = Plane(Vector3::UNIT_Z, 0); - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); + MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Y); mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -168,12 +168,12 @@ void Water::setHeight(const float height) { mTop = height; - mWaterPlane = Plane(Vector3::UNIT_Y, height); + mWaterPlane = Plane(Vector3::UNIT_Z, height); // small error due to reflection texture size & reflection distortion - mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + mErrorPlane = Plane(Vector3::UNIT_Z, height - 5); - mWaterNode->setPosition(0, height, 0); + mWaterNode->setPosition(0, 0, height); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); } @@ -199,7 +199,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); + return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); } void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) @@ -216,7 +216,7 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionRenderActive = true; Vector3 pos = mCamera->getRealPosition(); - pos.y = mTop*2 - pos.y; + pos.z = mTop*2 - pos.z; mSky->setSkyPosition(pos); mReflectionCamera->enableReflection(mWaterPlane); } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 25624351c8..6adf7e3fa0 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -225,9 +225,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel || waterEnabled != 1.f) + if (worldPos.z >= waterLevel || waterEnabled != 1.f) caustics = float3(1,1,1); #endif @@ -269,7 +269,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel || waterEnabled != 1.f) + if (worldPos.z > waterLevel || waterEnabled != 1.f) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -278,7 +278,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -292,14 +292,14 @@ waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dee7332630..e4f1cf091a 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -88,8 +88,8 @@ float toMorph = -min(0, sign(uv1.y - lodMorph.y)); // morph - // this assumes XZ terrain alignment - worldPos.y += uv1.x * toMorph * lodMorph.x; + // this assumes XY terrain alignment + worldPos.z += uv1.x * toMorph * lodMorph.x; shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); @@ -233,9 +233,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel) + if (worldPos.z >= waterLevel) caustics = float3(1,1,1); @@ -341,7 +341,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel) + if (worldPos.z > waterLevel) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -350,7 +350,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -365,14 +365,14 @@ float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 18052a98da..3b25404086 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,9 +79,9 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.y) / 50.0); + float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); - float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,1,0), waterLevel); + float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); ///\ todo clean this up float causticdepth = length(causticPos-worldPos.xyz); @@ -91,7 +91,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xzy * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); diff --git a/files/materials/water.shader b/files/materials/water.shader index 6bd277eab6..b7fb60b6b7 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -219,25 +219,27 @@ float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xyz; - normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); + normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xzy; - lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y, lNormal.z * BUMP)); - + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); + float3 lVec = normalize(sunPosition.xyz); float3 vVec = normalize(position.xyz - cameraPos.xyz); - float isUnderwater = (cameraPos.y > 0) ? 0.0 : 1.0; + float isUnderwater = (cameraPos.z > 0) ? 0.0 : 1.0; // sunlight scattering - float3 pNormal = float3(0,1,0); + float3 pNormal = float3(0,0,1); float3 lR = reflect(lVec, lNormal); float3 llR = reflect(lVec, pNormal); @@ -246,13 +248,13 @@ float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel - float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air float fresnel = fresnel_dielectric(-vVec, normal, ior); fresnel = shSaturate(fresnel); // reflection - float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb); + float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb); // refraction float3 R = reflect(vVec, normal); @@ -260,13 +262,13 @@ // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract // is actually above the water (objectDepth < waterDepth) // this solves silhouettes around objects above the water - float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; + float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xy*REFR_BUMP)).x * far - depthPassthrough; float doRefraction = (refractDepth < 0) ? 0.f : 1.f; - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb); + float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xy*REFR_BUMP * doRefraction))*1.0).rgb); // brighten up the refraction underwater - refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; + refraction = (cameraPos.z < 0) ? shSaturate(refraction * 1.5) : refraction; // specular float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); @@ -290,7 +292,7 @@ watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); float darkness = VISIBILITY*2.0; - darkness = clamp((cameraPos.y+darkness)/darkness,0.2,1.0); + darkness = clamp((cameraPos.z+darkness)/darkness,0.2,1.0); float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); From 5c0c5854e893b0aaa44ab3e936b0af24f9026cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 12:01:10 +0100 Subject: [PATCH 275/330] Unrelated change: we always want the XAutoRepeat workaround, regardless of using exclusive input or not --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b85..f7e1c8a845 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -87,10 +87,12 @@ namespace MWInput std::string("false"))); pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); #endif } +#if defined OIS_LINUX_PLATFORM + pl.insert(std::make_pair(std::string("XAutoRepeatOn"), + std::string("true"))); +#endif #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events From 2e7bc1a368c730d7fc3e3691037c69476c0b5d0e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:39:10 +0100 Subject: [PATCH 276/330] Z-up conversion: local map, fix tcg --- apps/openmw/mwgui/map_window.cpp | 6 +- apps/openmw/mwrender/localmap.cpp | 80 +++++++++++------------ apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 +- files/materials/water.shader | 4 +- libs/openengine/bullet/physic.cpp | 1 - 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 4e2ee517ea..bbb2be648b 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -88,7 +88,7 @@ void LocalMapBase::applyFogOfWar() + boost::lexical_cast(my); std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" @@ -127,7 +127,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { // map std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(y + (-1*(my-1))); std::string name = "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my); @@ -173,7 +173,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) } else { - Ogre::Vector2 position (marker.x, -marker.y); + Ogre::Vector2 position (marker.x, marker.y); MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d878cb86ed..b661c0795b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -28,9 +28,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); - // look down -y - const float sqrt0pt5 = 0.707106781; - mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); mCameraNode->attachObject(mCellCamera); } @@ -82,8 +79,8 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell) } else { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; // divide into segments @@ -107,6 +104,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mInterior = false; mCameraRotNode->setOrientation(Quaternion::IDENTITY); + mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); int x = cell->mCell->getGridX(); int y = cell->mCell->getGridY(); @@ -115,7 +113,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mCameraPosNode->setPosition(Vector3(0,0,0)); - render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name); + render((x+0.5)*sSize, (y+0.5)*sSize, -10000, 10000, sSize, sSize, name); } void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, @@ -124,40 +122,44 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mInterior = true; mBounds = bounds; - Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y); + float zMin = mBounds.getMinimum().z; + float zMax = mBounds.getMaximum().z; const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle(std::atan2(-north.x, -north.y)); + Radian angle = Ogre::Math::ATan2 (north.x, north.y); mAngle = angle.valueRadians(); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0)); + + mCellCamera->setOrientation(Quaternion::IDENTITY); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); // rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().z); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector2 c1(_c1.x, _c1.z); - Vector2 c2(_c2.x, _c2.z); - Vector2 c3(_c3.x, _c3.z); - Vector2 c4(_c4.x, _c4.z); + Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); + Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); + Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); + Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); + Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); + + Vector2 c1(_c1.x, _c1.y); + Vector2 c2(_c2.x, _c2.y); + Vector2 c3(_c3.x, _c3.y); + Vector2 c4(_c4.x, _c4.y); c1 = rotatePoint(c1, _center, mAngle); c2 = rotatePoint(c2, _center, mAngle); c3 = rotatePoint(c3, _center, mAngle); c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, 0, c1.y)); - mBounds.merge(Vector3(c2.x, 0, c2.y)); - mBounds.merge(Vector3(c3.x, 0, c3.y)); - mBounds.merge(Vector3(c4.x, 0, c4.y)); + mBounds.merge(Vector3(c1.x, c1.y, 0)); + mBounds.merge(Vector3(c2.x, c2.y, 0)); + mBounds.merge(Vector3(c3.x, c3.y, 0)); + mBounds.merge(Vector3(c4.x, c4.y, 0)); - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().z); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - mCameraPosNode->setPosition(Vector3(center.x, 0, center.y)); + mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments const int segsX = std::ceil( length.x / sSize ); @@ -172,7 +174,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, Vector2 start = min + Vector2(sSize*x,sSize*y); Vector2 newcenter = start + 4096; - render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize, + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, cell->mCell->mName + "_" + coordStr(x,y)); } } @@ -193,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); + mCameraNode->setPosition(Vector3(x, y, 100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -272,15 +274,15 @@ void LocalMap::render(const float x, const float y, void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); + pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); x = std::ceil((pos.x - min.x)/sSize)-1; y = std::ceil((pos.y - min.y)/sSize)-1; nX = (pos.x - min.x - sSize*x)/sSize; - nY = (pos.y - min.y - sSize*y)/sSize; + nY = 1.0-(pos.y - min.y - sSize*y)/sSize; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) @@ -311,19 +313,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni int x,y; float u,v; - Vector2 pos(position.x, position.z); + Vector2 pos(position.x, position.y); if (mInterior) getInteriorMapPosition(pos, u,v, x,y); - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis(); + Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); if (!mInterior) { x = std::ceil(pos.x / sSize)-1; - y = std::ceil(-pos.y / sSize)-1; + y = std::ceil(pos.y / sSize)-1; mCellX = x; mCellY = y; } @@ -337,7 +339,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1-std::abs((pos.y + (sSize*y))/sSize); + v = 1.0-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -346,15 +348,13 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); + MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) - int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom) - // change the affected fog of war textures (in a 3x3 grid around the player) for (int mx = -1; mx<2; ++mx) { @@ -375,7 +375,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!affected) continue; - std::string texName = texBaseName + coordStr(x+mx,y+my*intExtMult); + std::string texName = texBaseName + coordStr(x+mx,y+my*-1); TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); if (!tex.isNull()) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b2d7fbff08..fe8c5f57fb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -368,8 +368,10 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); + //Ogre::Quaternion orient = + //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = - node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); +node->_getDerivedOrientation(); mLocalMap->updatePlayer(pos, orient); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b747b0d9a8..87790fab5f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -110,7 +110,7 @@ void BillboardObject::setPosition(const Vector3& pPosition) Vector3 BillboardObject::getPosition() const { Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition(); - return Vector3(p.x, -p.z, p.y); + return p; } void BillboardObject::setVisibilityFlags(int flags) @@ -390,7 +390,6 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); - sun = Vector3(sun.x, sun.z, -sun.y); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index eaee8f5a7b..ce39842b31 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1228,8 +1228,8 @@ namespace MWWorld if (!ref) return Vector2(0, 1); Ogre::SceneNode* node = ref->mData.getBaseNode(); - Vector3 dir = node->_getDerivedOrientation().yAxis(); - Vector2 d = Vector2(dir.x, dir.z); + Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0); + Vector2 d = Vector2(dir.x, dir.y); return d; } diff --git a/files/materials/water.shader b/files/materials/water.shader index b7fb60b6b7..a58a9c38b9 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 0.3 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -223,7 +223,7 @@ normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); - + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 5d5749d5d8..f993ce68e2 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -193,7 +193,6 @@ namespace Physic if(!isDebugCreated) { Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); isDebugCreated = true; From 284ba58e1e7372d74c80acd0f3f18d0b728ea901 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:52:01 +0100 Subject: [PATCH 277/330] Z-up conversion: global map, shader fix --- apps/openmw/mwgui/map_window.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 2 +- files/materials/objects.shader | 2 +- files/materials/terrain.shader | 2 +- files/materials/underwater.h | 11 ++++++----- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index bbb2be648b..34f246d8b1 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -397,7 +397,7 @@ void MapWindow::globalMapUpdatePlayer () Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.z, worldX, worldY); + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 072015f9a8..055faaa1f7 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -190,7 +190,7 @@ namespace MWRender { imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1); - imageY = 1.f-float(-z / 8192.f - mMinY) / (mMaxY - mMinY + 1); + imageY = 1.f-float(z / 8192.f - mMinY) / (mMaxY - mMinY + 1); } void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 6adf7e3fa0..0f1b3722fa 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -296,7 +296,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index e4f1cf091a..d8bc00c187 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -369,7 +369,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 3b25404086..a760202fa2 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,7 +79,7 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); + float waterDepth = shSaturate((waterEyePos.z - worldPos.z) / 50.0); float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); @@ -91,20 +91,21 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0); - float causticR = 1.0-perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticR = 1.0-perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; /// \todo sunFade // float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth; float3 caustics = clamp(pow(float3(causticR,causticR,causticR)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth; - float causticG = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - float causticB = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticG = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticB = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; From 341f9b96e2a589a86977d42b1856d147b4bc6f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:53:23 +0100 Subject: [PATCH 278/330] Local map: restore zHigh --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b661c0795b..601ee58e31 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -195,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, y, 100000)); + mCameraNode->setPosition(Vector3(x, y, zhigh+100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite From cc9b72b9b1f75f138bb38e1b095ed84a2b2f71a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:01:10 +0100 Subject: [PATCH 279/330] Removing some leftovers of mwRoot node --- apps/openmw/mwrender/actors.cpp | 8 ++++---- apps/openmw/mwrender/actors.hpp | 4 ++-- apps/openmw/mwrender/debugging.cpp | 8 ++++---- apps/openmw/mwrender/debugging.hpp | 4 ++-- apps/openmw/mwrender/objects.cpp | 20 ++++++++++---------- apps/openmw/mwrender/objects.hpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 19 +++++++------------ apps/openmw/mwrender/renderingmanager.hpp | 5 +---- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- 10 files changed, 35 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 78521d0ce6..83c07737ce 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -28,8 +28,8 @@ Actors::~Actors() } } -void Actors::setMwRoot(Ogre::SceneNode* root) -{ mMwRoot = root; } +void Actors::setRootNode(Ogre::SceneNode* root) +{ mRootNode = root; } void Actors::insertBegin(const MWWorld::Ptr &ptr) { @@ -40,7 +40,7 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) else { //Create the scenenode and put it in the map - cellnode = mMwRoot->createChildSceneNode(); + cellnode = mRootNode->createChildSceneNode(); mCellSceneNodes[ptr.getCell()] = cellnode; } @@ -159,7 +159,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) node = celliter->second; else { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } node->addChild(cur.getRefData().getBaseNode()); diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index c89bfbaf5e..75a18ba915 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -20,7 +20,7 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; @@ -29,7 +29,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); void insertCreature (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 2061b74d7f..54f288bff8 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -150,9 +150,9 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) return result; } -Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) : - mMwRoot(mwRoot), mEngine(engine), - mSceneMgr(mwRoot->getCreator()), +Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : + mRootNode(root), mEngine(engine), + mSceneMgr(root->getCreator()), mPathgridEnabled(false), mInteriorPathgridNode(NULL), mPathGridRoot(NULL), mGridMatsCreated(false) @@ -208,7 +208,7 @@ void Debugging::togglePathgrid() createGridMaterials(); // add path grid meshes to already loaded cells - mPathGridRoot = mMwRoot->createChildSceneNode(); + mPathGridRoot = mRootNode->createChildSceneNode(); for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 07e5f0a3f4..6a4eef58f4 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -54,7 +54,7 @@ namespace MWRender typedef std::vector CellList; CellList mActiveCells; - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; Ogre::SceneNode *mPathGridRoot; @@ -78,7 +78,7 @@ namespace MWRender Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine); + Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine); ~Debugging(); bool toggleRenderMode (int mode); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 76f38eefc2..add781459e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -57,14 +57,14 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) } } -void Objects::setMwRoot(Ogre::SceneNode* root) +void Objects::setRootNode(Ogre::SceneNode* root) { - mMwRoot = root; + mRootNode = root; } void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) { - Ogre::SceneNode* root = mMwRoot; + Ogre::SceneNode* root = mRootNode; Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -390,9 +390,9 @@ void Objects::enableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(true); + mRootNode->getCreator()->getLight(it->name)->setVisible(true); ++it; } else @@ -405,9 +405,9 @@ void Objects::disableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(false); + mRootNode->getCreator()->getLight(it->name)->setVisible(false); ++it; } else @@ -460,9 +460,9 @@ void Objects::update(const float dt) std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); + Ogre::Light* light = mRootNode->getCreator()->getLight(it->name); float brightness; float cycle_time; @@ -550,7 +550,7 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } else { node = mCellSceneNodes[newCell]; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 5801014642..73e95a3c53 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -53,7 +53,7 @@ class Objects{ std::map mStaticGeometrySmall; std::map mBounds; std::vector mLights; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; @@ -90,7 +90,7 @@ public: void removeCell(MWWorld::CellStore* store); void buildStaticGeometry(MWWorld::CellStore &cell); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void rebuildStaticGeometry(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe8c5f57fb..fe3dc776d1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -141,25 +141,20 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const applyCompositors(); - // Turn the entire scene (represented by the 'root' node) -90 - // degrees around the x axis. This makes Z go upwards, and Y go into - // the screen (when x is to the right.) This is the orientation that - // Morrowind uses, and it automagically makes everything work as it - // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt; + mRootNode = rt; - mObjects.setMwRoot(mMwRoot); - mActors.setMwRoot(mMwRoot); + mObjects.setRootNode(mRootNode); + mActors.setRootNode(mRootNode); - Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player"); + Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player"); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mShadows = new Shadows(&mRendering); mTerrainManager = new TerrainManager(mRendering.getScene(), this); - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); + mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); @@ -168,7 +163,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mSun = 0; - mDebugging = new Debugging(mMwRoot, engine); + mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); @@ -321,7 +316,7 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { - orig.z += mPlayer->getHeight() * mMwRoot->getScale().z; + orig.z += mPlayer->getHeight() * mRootNode->getScale().z; btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bdb5447e32..53c63cfedd 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -228,10 +228,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::ColourValue mAmbientColor; Ogre::Light* mSun; - /// Root node for all objects added to the scene. This is rotated so - /// that the OGRE coordinate system matches that used internally in - /// Morrowind. - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; OEngine::Physic::PhysicEngine* mPhysicsEngine; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 87790fab5f..0620796931 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -203,7 +203,7 @@ unsigned int Moon::getPhaseInt() const return 0; } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) +SkyManager::SkyManager (SceneNode* root, Camera* pCamera) : mHour(0.0f) , mDay(0) , mMonth(0) @@ -234,7 +234,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mCloudAnimationTimer(0.f) , mMoonRed(false) { - mSceneMgr = pMwRoot->getCreator(); + mSceneMgr = root->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 52fd7b4aa8..feaba3d969 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -112,7 +112,7 @@ namespace MWRender class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); + SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); ~SkyManager(); void update(float duration); From cd68012498881544eb00b9f902ab3bc9ef1bd1e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:28:35 +0100 Subject: [PATCH 280/330] Z-up conversion: raycasts --- apps/openmw/mwworld/physicssystem.cpp | 14 ++++++-------- apps/openmw/mwworld/worldimp.cpp | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0c1f580488..65cbc1164e 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -264,9 +264,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(queryDistance); btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::vector < std::pair > results; /* auto */ results = mEngine->rayTest2(_from,_to); @@ -287,7 +286,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -295,7 +294,7 @@ namespace MWWorld { //get a ray pointing to the center of the viewport Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -335,9 +334,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::pair result = mEngine->rayTest(_from, _to); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce39842b31..24a1f83022 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1024,7 +1024,6 @@ namespace MWWorld // currently its here because we need to access the physics system float* p = mPlayer->getPlayer().getRefData().getPosition().pos; Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - sun = Vector3(sun.x, -sun.z, sun.y); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } @@ -1122,7 +1121,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; @@ -1150,7 +1149,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.at (1).first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); @@ -1299,7 +1298,7 @@ namespace MWWorld if (isCellExterior()) { int cellX, cellY; - positionToIndex(result.second[0], -result.second[2], cellX, cellY); + positionToIndex(result.second[0], result.second[1], cellX, cellY); cell = mCells.getExterior(cellX, cellY); } else @@ -1307,8 +1306,8 @@ namespace MWWorld ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition(); pos.pos[0] = result.second[0]; - pos.pos[1] = -result.second[2]; - pos.pos[2] = result.second[1]; + pos.pos[1] = result.second[1]; + pos.pos[2] = result.second[2]; Ptr dropped = copyObjectToCell(object, *cell, pos); PCDropped(dropped); From b9912a19e0ed585b041c33ce2861b224dea23369 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:31:30 +0100 Subject: [PATCH 281/330] Z-up conversion: fix player arrow direction on global map --- apps/openmw/mwgui/map_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 34f246d8b1..6f7f0eaabc 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -394,7 +394,7 @@ void MapWindow::globalMapUpdatePlayer () { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); float worldX, worldY; mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); From 1a43d86d9e33cb1a8351347d37eaeaedfebca47b Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 15:58:32 +0100 Subject: [PATCH 282/330] Close messages boxes with the activation key (Bug #589) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f7e1c8a845..5a6998d9ee 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -179,6 +179,11 @@ namespace MWInput case A_Activate: resetIdleTime(); activate(); + if( MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { + // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } break; case A_Journal: toggleJournal (); From b1ca719d61b4df9b5ebcfd58457640febbd7da51 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 16:37:59 +0100 Subject: [PATCH 283/330] Added click sound to OK button for message boxes --- apps/openmw/mwgui/messagebox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 896ab3bb56..0ee042e326 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,6 +1,8 @@ #include #include "messagebox.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" using namespace MWGui; @@ -375,6 +377,7 @@ void InteractiveMessageBox::enterPressed() if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) { buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); break; } } From fb990b5e69d96865f490f5ea4f747ad64d571a51 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 17:08:34 +0100 Subject: [PATCH 284/330] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 535e922ae1..027dc09860 100644 --- a/credits.txt +++ b/credits.txt @@ -34,6 +34,7 @@ lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) From cd99e9d952d9a2b2b3f24425e678a83a1c9dd73c Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 17:28:39 +0100 Subject: [PATCH 285/330] Updated credits.txt and corrected license info in readme.txt --- credits.txt | 58 +++++++++++++++++++++++++++++++++++------------------ readme.txt | 2 +- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/credits.txt b/credits.txt index 027dc09860..6f7e72aa1c 100644 --- a/credits.txt +++ b/credits.txt @@ -12,66 +12,74 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) Aleksandar Jovanov +Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile BrotherBrick -Chris Robinson +Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) +Douglas Mencken (dougmencken) +Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 -Emanuel "potatoesmaster" Guével -gugus / gus +Emanuel Guével (potatoesmaster) +gugus/gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) +Jordan Milne +Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Mark Siewert (mark76) Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) +Nolan Poe (nopoe) +Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) +Radu-Marius Popovici (rpopovici) Roman Melnik (Kromgart) +Sandy Carter (bwrsandman) Sebastian Wick (swick) Sergey Shambir -Sylvain T. (Garvek) +Sylvain Thesnieres (Garvek) Tom Mason (wheybags) + Packagers: Alexander Olofsson (Ace) - Windows BrotherBrick - Ubuntu Linux -Edmondo Tommasina - Gentoo Linux +Edmondo Tommasina (edmondo) - Gentoo Linux +Julian Ospald (hasufell) - Gentoo Linux +Karl-Felix Glatzer (k1ll) - Linux Binaries Kenny Armstrong (artorius) - Fedora Linux Nikolay Kasyanov (corristo) - Mac OS X Sandy Carter (bwrsandman) - Arch Linux -Public Relations: -ElderTroll - Release Manager -sir_herrbatka - News Writer +Public Relations and Translations: +Julien Voisin (jvoisin/ap0) - French News Writer +Artem Kotsynyak (greye) - Russian News Writer +Pithorn - Chinese News Writer +sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster Website: -juanmnzsk8 - Spanish News Writer -Julien Voisin (jvoisin/ap0) - French News Writer -Kingpix - Italian News Writer Lukasz Gromanowski (lgro) - Website Administrator -Nikolay Kasyanov (corristo) - Russian News Writer -Okulo - Dutch News Writer -penguinroad - Indonesian News Writer Ryan Sardonic (Wry) - Wiki Editor -sir_herrbatka - Forum Admin/Polish News Writer -spyboot - German News Writer +sir_herrbatka - Forum Administrator Formula Research: @@ -87,20 +95,32 @@ Sadler Artwork: Necrod - OpenMW Logo -raevol - Wordpress Theme - +Mickey Lyle (raevol) - Wordpress Theme +Okulo - OpenMW Editor Icons Inactive Contributors: Ardekantur Armin Preiml +Carl Maxwell Diggory Hardy -Jan Borsodi +Dmitry Marakasov (AMDmi3) +ElderTroll +guidoj Jan-Peter Nilsson (peppe) +Jan Borsodi Josua Grawitter +juanmnzsk8 +Kingpix Lordrea +Michal Sciubidlo Nicolay Korslund +pchan3 +penguinroad +psi29a sergoz +spyboot Star-Demon +Thoronador Yuri Krupenin diff --git a/readme.txt b/readme.txt index 3124744c30..228278a919 100644 --- a/readme.txt +++ b/readme.txt @@ -9,7 +9,7 @@ Website: http://www.openmw.org Font Licenses: EBGaramond-Regular.ttf: OFL (see OFL.txt for more information) -VeraMono.ttf: custom (see Bitstream Vera License.txt for more information) +DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) From 21f502e3ddf191d67ff5569ac846a01574dcedc5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 26 Feb 2013 09:36:56 -0800 Subject: [PATCH 286/330] properly handle potentially non 16 bit planar audio formats --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4c..7e8751c598 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -134,6 +134,18 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) return dec; } +static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format) +{ + switch (format) + { + case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8; + case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16; + case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32; + case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT; + case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL; + default:return format; + } +} void FFmpeg_Decoder::open(const std::string &fname) { @@ -153,10 +165,6 @@ 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); @@ -164,7 +172,6 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } @@ -172,6 +179,8 @@ void FFmpeg_Decoder::open(const std::string &fname) if(!mStream) fail("No audio streams in "+fname); + (*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt); + AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { From ceafcc2ebbc4a86e4f5cbc6f188658a10fdc58b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 10:19:33 -0800 Subject: [PATCH 287/330] Support float samples with ffmpeg Requires the AL_EXT_FLOAT32 extension in OpenAL --- apps/openmw/mwrender/videoplayer.cpp | 2 ++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 2 ++ apps/openmw/mwsound/openal_output.cpp | 45 +++++++++++++++++++++++++ apps/openmw/mwsound/sound_decoder.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 2 ++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b710225042..a0dedb6bc2 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -404,6 +404,8 @@ public: *type = MWSound::SampleType_UInt8; else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = MWSound::SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4c..8c857f4ea1 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -224,6 +224,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * *type = SampleType_UInt8; else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 67008e2bcd..1dc5f9974f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -88,6 +88,51 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } } + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, + }; + static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + + for(size_t i = 0;i < fltfmtlistsize;i++) + { + if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, + { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, + { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, + }; + static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + + for(size_t i = 0;i < fltmcfmtlistsize;i++) + { + if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltmcfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + } + } fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); return AL_NONE; diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 29d99e8fa4..151b580360 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -9,7 +9,8 @@ namespace MWSound { enum SampleType { SampleType_UInt8, - SampleType_Int16 + SampleType_Int16, + SampleType_Float32 }; const char *getSampleTypeName(SampleType type); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c502906808..1b07dfe627 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -607,6 +607,7 @@ namespace MWSound { case SampleType_UInt8: return "U8"; case SampleType_Int16: return "S16"; + case SampleType_Float32: return "Float32"; } return "(unknown sample type)"; } @@ -638,6 +639,7 @@ namespace MWSound { case SampleType_UInt8: frames *= 1; break; case SampleType_Int16: frames *= 2; break; + case SampleType_Float32: frames *= 4; break; } return frames; } From 13c33c1613adce9e7bf5b81debfe4922f3412734 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:37:47 +0100 Subject: [PATCH 288/330] added missing click sound to main menu --- apps/openmw/mwgui/mainmenu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 14309abc5e..5402d35428 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -5,6 +5,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" namespace MWGui { @@ -65,6 +66,7 @@ namespace MWGui void MainMenu::onButtonClicked(MyGUI::Widget *sender) { + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); if (sender == mButtons["return"]) MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); else if (sender == mButtons["options"]) From 89cba3cf455109e661d7e3db2139a7873628cfa5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:52:51 +0100 Subject: [PATCH 289/330] Replaced ifs/elseifs with switch --- apps/openmw/mwgui/waitdialog.cpp | 65 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2c74dd2fd6..794a9ab55f 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -95,31 +95,46 @@ namespace MWGui // http://www.uesp.net/wiki/Lore:Calendar std::string month; int m = MWBase::Environment::get().getWorld ()->getMonth (); - if (m == 0) - month = "#{sMonthMorningstar}"; - else if (m == 1) - month = "#{sMonthSunsdawn}"; - else if (m == 2) - month = "#{sMonthFirstseed}"; - else if (m == 3) - month = "#{sMonthRainshand}"; - else if (m == 4) - month = "#{sMonthSecondseed}"; - else if (m == 5) - month = "#{sMonthMidyear}"; - else if (m == 6) - month = "#{sMonthSunsheight}"; - else if (m == 7) - month = "#{sMonthLastseed}"; - else if (m == 8) - month = "#{sMonthHeartfire}"; - else if (m == 9) - month = "#{sMonthFrostfall}"; - else if (m == 10) - month = "#{sMonthSunsdusk}"; - else if (m == 11) - month = "#{sMonthEveningstar}"; - + switch (m) { + case 0: + month = "#{sMonthMorningstar}"; + break; + case 1: + month = "#{sMonthSunsdawn}"; + break; + case 2: + month = "#{sMonthFirstseed}"; + break; + case 3: + month = "#{sMonthRainshand}"; + break; + case 4: + month = "#{sMonthSecondseed}"; + break; + case 5: + month = "#{sMonthMidyear}"; + break; + case 6: + month = "#{sMonthSunsheight}"; + break; + case 7: + month = "#{sMonthLastseed}"; + break; + case 8: + month = "#{sMonthHeartfire}"; + break; + case 9: + month = "#{sMonthFrostfall}"; + break; + case 10: + month = "#{sMonthSunsdusk}"; + break; + case 11: + month = "#{sMonthEveningstar}"; + break; + default: + break; + } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); bool pm = hour >= 12; if (hour >= 13) hour -= 12; From 6b86db6b6fa7ff0a5020a4d95baa0da6ee6e9567 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 20:49:20 +0100 Subject: [PATCH 290/330] Forgot the release manager and added the license terms of EB Garamond --- credits.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/credits.txt b/credits.txt index 6f7e72aa1c..d1e85c6904 100644 --- a/credits.txt +++ b/credits.txt @@ -69,8 +69,9 @@ Sandy Carter (bwrsandman) - Arch Linux Public Relations and Translations: -Julien Voisin (jvoisin/ap0) - French News Writer Artem Kotsynyak (greye) - Russian News Writer +Julien Voisin (jvoisin/ap0) - French News Writer +Mickey Lyle (raevol) - Release Manager Pithorn - Chinese News Writer sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster @@ -138,7 +139,7 @@ Thanks to Kevin Ryan, for creating the icon used for the Data Files tab of the OpenMW Launcher. Thanks to Georg Duffner, -for the open-source EB Garamond fontface. +for his EB Garamond fontface, see OFL.txt for his license terms. Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. From 759b2e96bf77a97cc0f2c713c2700ba51024791c Mon Sep 17 00:00:00 2001 From: lazydev Date: Wed, 27 Feb 2013 01:37:40 +0400 Subject: [PATCH 291/330] fix for https://bugs.openmw.org/issues/577 --- components/esm/loadcell.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 7400fd026c..92cb7d5ce8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -112,8 +112,8 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) // instead. if (mData.mFlags & QuasiEx) mRegion = esm.getHNOString("RGNN"); - else - esm.getHNT(mAmbi, "AMBI", 16); + else if (esm.isNextSub("AMBI")) + esm.getHT(mAmbi); } else { @@ -126,7 +126,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) if (esm.isNextSub("NAM0")) { esm.getHT(mNAM0); } - + // preload moved references while (esm.isNextSub("MVRF")) { CellRef ref; @@ -135,7 +135,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) MWWorld::Store &cStore = const_cast&>(store.get()); ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. getNextRef(esm, ref); @@ -143,7 +143,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - + // Add data required to make reference appear in the correct cell. // We should not need to test for duplicates, as this part of the code is pre-cell merge. mMovedRefs.push_back(cMRef); @@ -186,7 +186,7 @@ void Cell::save(ESMWriter &esm) if (mMapColor != 0) esm.writeHNT("NAM5", mMapColor); } - + if (mNAM0 != 0) esm.writeHNT("NAM0", mNAM0); } @@ -226,7 +226,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (ref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; @@ -249,7 +249,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - + // TODO: support loading references from saves, there are tons of keys not recognized yet. // The following is just an incomplete list. if (esm.isNextSub("ACTN")) @@ -266,7 +266,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.skipHSub(); else if (esm.isNextSub("CRED")) // ??? esm.skipHSub(); - + ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -305,7 +305,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); - + // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. @@ -318,7 +318,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } - + if (esm.isNextSub("DELE")) { esm.skipHSub(); ref.mDeleted = 2; // Deleted, will not respawn. @@ -333,7 +333,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefnum); esm.getHNOT(mref.mTarget, "CNDT"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; From b4b20622c670bb15b78ede194f4f57a99b9f36b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 15:24:20 -0800 Subject: [PATCH 292/330] Properly handle NiAlphaProperty values --- components/nifogre/ogre_nif_loader.cpp | 139 ++++++++++--------------- 1 file changed, 57 insertions(+), 82 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5b84807a47..5042f666a5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -492,49 +492,43 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; -// Conversion of blend / test mode from NIF -> OGRE. -// Not in use yet, so let's comment it out. -/* -static SceneBlendFactor getBlendFactor(int mode) +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) { - switch(mode) + switch(mode) { - case 0: return SBF_ONE; - case 1: return SBF_ZERO; - case 2: return SBF_SOURCE_COLOUR; - case 3: return SBF_ONE_MINUS_SOURCE_COLOUR; - case 4: return SBF_DEST_COLOUR; - case 5: return SBF_ONE_MINUS_DEST_COLOUR; - case 6: return SBF_SOURCE_ALPHA; - case 7: return SBF_ONE_MINUS_SOURCE_ALPHA; - case 8: return SBF_DEST_ALPHA; - case 9: return SBF_ONE_MINUS_DEST_ALPHA; - // [Comment from Chris Robinson:] Can't handle this mode? :/ - // case 10: return SBF_SOURCE_ALPHA_SATURATE; - default: - return SBF_SOURCE_ALPHA; + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; } + std::cerr<< "Unexpected blend mode: "<data->colors.size() != 0); @@ -640,7 +634,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if (a) { alphaFlags = a->flags; -// alphaTest = a->data.threshold; + alphaTest = a->data.threshold; } // Material @@ -674,6 +668,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, texName); boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -705,57 +700,37 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + if (result.first) { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/property.h if you need to decode - // other values. 237 basically means normal transparencly. - if (alphaFlags == 237) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); - if (result.first) - { - instance->setProperty("alpha_rejection", - sh::makeProperty(new sh::StringValue("greater_equal " + boost::lexical_cast(result.second)))); - } - else - { - // Enable transparency - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); - } - } - else - warn("Unhandled alpha setting for texture " + texName); + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else - instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - // As of yet UNTESTED code from Chris: - /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); - pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); - pass->setDepthCheckEnabled(true); - - // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + if((alphaFlags>>9)&1) { - std::cout << "Alpha flags set!" << endl; - if ((alphaFlags&1)) - { - pass->setDepthWriteEnabled(false); - pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), - getBlendFactor((alphaFlags>>5)&0xf)); - } - else - pass->setDepthWriteEnabled(true); - - if ((alphaFlags>>9)&1) - pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), - alphaTest); - - pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } -*/ + + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? + "off" : "on"))); return matname; } From f994b7d227bd2639882f5f8a1b525bff6db77c9f Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Feb 2013 07:44:35 +0400 Subject: [PATCH 293/330] Prepare .desktop file for more systems This brings condition for .desktop file preparation in sync with condition for its installation. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6929850b51..dbab836907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,7 +297,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") endif() From 0bc4c3556ae9f9c10e9197fb1ce18aab49a824c1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 15:58:01 +0100 Subject: [PATCH 294/330] Fix dialogue gender filter --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 09bb0ddc4c..6f9d8b42fc 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -289,7 +289,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_PcGender: - return player.get()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; + return player.get()->mBase->isMale() ? 0 : 1; case SelectWrapper::Function_PcClothingModifier: { From be9d49c510ea56aaca83e8c80456a70810ce2bef Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 16:15:59 +0100 Subject: [PATCH 295/330] Do not hide pinned windows during loadings --- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c44..e17190b023 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -424,6 +424,12 @@ void WindowManager::updateVisible() MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Video: From 03ca7f6123e250222bc133f9017f5d8b0aa5e01b Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Wed, 27 Feb 2013 23:45:09 +0400 Subject: [PATCH 296/330] NIF: added NiStencilProperty record handling NiStencilProperty appears in Better Clothes plugin. If it not handled, some parts of NPCs bodies will be not rendered. --- components/nif/nif_file.cpp | 1 + components/nif/nif_file.hpp | 1 + components/nif/property.hpp | 57 ++++++++++++++++++++++++++ components/nif/record.hpp | 1 + components/nifogre/ogre_nif_loader.cpp | 2 + 5 files changed, 62 insertions(+) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 58d1bc9b85..ba3a7513b2 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -256,6 +256,7 @@ void NIFFile::parse() else if(rec == "NiDitherProperty") { r = new NiDitherProperty; r->recType = RC_NiDitherProperty; } else if(rec == "NiWireframeProperty") { r = new NiWireframeProperty; r->recType = RC_NiWireframeProperty; } else if(rec == "NiSpecularProperty") { r = new NiSpecularProperty; r->recType = RC_NiSpecularProperty; } + else if(rec == "NiStencilProperty") { r = new NiStencilProperty; r->recType = RC_NiStencilProperty; } // Controllers else if(rec == "NiVisController") { r = new NiVisController; r->recType = RC_NiVisController; } diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index e8884cd4d4..5e9694f4b4 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -158,6 +158,7 @@ public: short getShort() { return read_le16(); } unsigned short getUShort() { return read_le16(); } int getInt() { return read_le32(); } + unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } Ogre::Vector2 getVector2() { diff --git a/components/nif/property.hpp b/components/nif/property.hpp index b24e49b479..046fb04652 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -257,9 +257,66 @@ struct S_AlphaProperty } }; +/* + Docs taken from: + http://niftools.sourceforge.net/doc/nif/NiStencilProperty.html + */ +struct S_StencilProperty +{ + // Is stencil test enabled? + unsigned char enabled; + + /* + 0 TEST_NEVER + 1 TEST_LESS + 2 TEST_EQUAL + 3 TEST_LESS_EQUAL + 4 TEST_GREATER + 5 TEST_NOT_EQUAL + 6 TEST_GREATER_EQUAL + 7 TEST_ALWAYS + */ + int compareFunc; + unsigned stencilRef; + unsigned stencilMask; + /* + Stencil test fail action, depth test fail action and depth test pass action: + 0 ACTION_KEEP + 1 ACTION_ZERO + 2 ACTION_REPLACE + 3 ACTION_INCREMENT + 4 ACTION_DECREMENT + 5 ACTION_INVERT + */ + int failAction; + int zFailAction; + int zPassAction; + /* + Face draw mode: + 0 DRAW_CCW_OR_BOTH + 1 DRAW_CCW [default] + 2 DRAW_CW + 3 DRAW_BOTH + */ + int drawMode; + + void read(NIFFile *nif) + { + enabled = nif->getChar(); + compareFunc = nif->getInt(); + stencilRef = nif->getUInt(); + stencilMask = nif->getUInt(); + failAction = nif->getInt(); + zFailAction = nif->getInt(); + zPassAction = nif->getInt(); + drawMode = nif->getInt(); + } +}; + typedef StructPropT NiAlphaProperty; typedef StructPropT NiMaterialProperty; typedef StructPropT NiVertexColorProperty; +typedef StructPropT NiStencilProperty; } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index d5f65e83a3..073f4657c0 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -48,6 +48,7 @@ enum RecordType RC_NiDitherProperty, RC_NiWireframeProperty, RC_NiSpecularProperty, + RC_NiStencilProperty, RC_NiVisController, RC_NiGeomMorpherController, RC_NiKeyframeController, diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a5..052334f1da 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -586,6 +586,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String m = static_cast(pr); else if (pr->recType == Nif::RC_NiAlphaProperty) a = static_cast(pr); + else if (pr->recType == Nif::RC_NiStencilProperty) + /* unused */; else warn("Skipped property type: "+pr->recName); } From bfe80bb8dc0fa780ab065bb2086a4a7fc6663016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 12:33:36 -0800 Subject: [PATCH 297/330] Avoid duplicating skeletons due to casing issues Manually created resource names are apparently always case sensitive, causing some skeletons to get loaded multiple times. --- apps/openmw/mwrender/animation.cpp | 15 ++------ components/nifogre/ogre_nif_loader.cpp | 51 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 394e25b504..cc926e685d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -53,8 +53,6 @@ void Animation::setAnimationSources(const std::vector &names) if(!mEntityList.mSkelBase) return; - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -62,19 +60,14 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = NULL; mSkeletonSources.clear(); - std::vector::const_iterator nameiter = names.begin(); + std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); + Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); if(skel.isNull()) { - NifOgre::Loader::createSkeleton(*nameiter); - skel = skelMgr.getByName(*nameiter); - if(skel.isNull()) - { - std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a5..b3d70bb1fe 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -452,7 +452,8 @@ void loadResource(Ogre::Resource *resource) } } -bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) + +static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { /* 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: @@ -463,7 +464,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(!node->boneTrafo) { if(node->recType == Nif::RC_NiTriShape) - return false; + return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) @@ -474,18 +475,18 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif { if(!children[i].empty()) { - if(createSkeleton(name, group, children[i].getPtr())) - return true; + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; } } - return false; + return Ogre::SkeletonPtr(); } } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + return skelMgr.create(name, group, true, &sLoaders[name]); } }; @@ -1140,10 +1141,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); if(!hasSkel) - { - NIFSkeletonLoader skelldr; - hasSkel = skelldr.createSkeleton(name, group, node); - } + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); NIFMeshLoader meshldr(name, group); if(hasSkel) @@ -1253,30 +1251,35 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } -bool Loader::createSkeleton(const std::string &name, const std::string &group) +Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + Ogre::SkeletonPtr skel; + + Misc::StringUtils::toLower(name); + skel = Ogre::SkeletonManager::getSingleton().getByName(name); + if(!skel.isNull()) + return skel; + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRecords() < 1) { - nif.warn("Found no NIF records in "+name+"."); - return false; + nif->warn("Found no NIF records in "+name+"."); + return skel; } // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); + const Nif::Record *r = nif->getRecord(0); assert(r != NULL); - Nif::Node const *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return false; + nif->warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return skel; } - NIFSkeletonLoader skelldr; - return skelldr.createSkeleton(name, group, node); + return NIFSkeletonLoader::createSkeleton(name, group, node); } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 7a7b0c5a1e..eae37dd8a9 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -74,7 +74,7 @@ public: std::string name, const std::string &group="General"); - static bool createSkeleton(const std::string &name, const std::string &group="General"); + static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; } From 3ed0bf97a8a94d98e5d274f7a45a2f72e0b0bb63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 13:16:27 -0800 Subject: [PATCH 298/330] Share the space with the parent entity only when there's real skinned meshes The existence of a base skeleton doesn't mean it shares the same bone structure. If there isn't an actual skinned entity besides the base, simply attach it to the bone like unskinned meshes should be. --- components/nifogre/ogre_nif_loader.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b3d70bb1fe..4d047ae8bb 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,20 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(meshes.size() == 0) return entitylist; + bool isskinned = false; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); 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(!entitylist.mSkelBase && ent->hasSkeleton()) - entitylist.mSkelBase = ent; + if(!entitylist.mSkelBase) + { + if(ent->hasSkeleton()) + entitylist.mSkelBase = ent; + } + else if(!isskinned && ent->hasSkeleton()) + isskinned = true; entitylist.mEntities.push_back(ent); } @@ -1219,7 +1225,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(bonename.find("Left") != std::string::npos) scale.x *= -1.0f; - if(entitylist.mSkelBase) + if(isskinned) { for(size_t i = 0;i < entitylist.mEntities.size();i++) { From b93eb844010f3002bb1acb15534f82f2a5af55c0 Mon Sep 17 00:00:00 2001 From: lazydev Date: Thu, 28 Feb 2013 02:43:03 +0400 Subject: [PATCH 299/330] fix for https://bugs.openmw.org/issues/573 --- components/esm/esmreader.hpp | 16 ++++++++-------- components/esm/loadappa.cpp | 27 +++++++++++++++++++++------ components/esm/loadappa.hpp | 6 ++++-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 45d6d9164c..ae876edf8b 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -37,14 +37,14 @@ public: *************************************************************************/ int getVer() const { return mCtx.header.version; } - float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() { return mSpf; } - int getType() { return mCtx.header.type; } - const std::string getAuthor() { return mCtx.header.author.toString(); } - const std::string getDesc() { return mCtx.header.desc.toString(); } + float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } + int getSpecial() const { return mSpf; } + int getType() const { return mCtx.header.type; } + const std::string getAuthor() const { return mCtx.header.author.toString(); } + const std::string getDesc() const { return mCtx.header.desc.toString(); } const SaveData &getSaveData() const { return mSaveData; } - const MasterList &getMasters() { return mMasters; } - const NAME &retSubName() { return mCtx.subName; } + const MasterList &getMasters() const { return mMasters; } + const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } /************************************************************************* @@ -85,7 +85,7 @@ public: int mIdx; void setIndex(const int index) {mIdx = index; mCtx.index = index;} const int getIndex() {return mIdx;} - + void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} std::vector *getGlobalReaderList() {return mGlobalReaderList;} diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index f5e7e10e1a..80922e2cbe 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -7,13 +7,28 @@ namespace ESM { void Apparatus::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - esm.getHNT(mData, "AADT", 16); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNString("ITEX"); + // we will not treat duplicated subrecords as errors here + while (esm.hasMoreSubs()) + { + esm.getSubName(); + NAME subName = esm.retSubName(); + + if (subName == "MODL") + mModel = esm.getHString(); + else if (subName == "FNAM") + mName = esm.getHString(); + else if (subName == "AADT") + esm.getHT(mData); + else if (subName == "SCRI") + mScript = esm.getHString(); + else if (subName == "ITEX") + mIcon = esm.getHString(); + else + esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + } } -void Apparatus::save(ESMWriter &esm) + +void Apparatus::save(ESMWriter &esm) const { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 486a559f89..a1daeb1237 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H +#include "esmcommon.hpp" #include namespace ESM @@ -13,8 +14,9 @@ class ESMWriter; * Alchemist apparatus */ -struct Apparatus +class Apparatus { +public: enum AppaType { MortarPestle = 0, @@ -35,7 +37,7 @@ struct Apparatus std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm); + void save(ESMWriter &esm) const; }; } #endif From d5aa975675c2bacfe91dd7199143b79fa4ac324d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 27 Feb 2013 23:44:20 +0100 Subject: [PATCH 300/330] Fix some issues that seem to have appeared in the CMake configuration. --- CMakeLists.txt | 6 +++--- cmake/OpenMWMacros.cmake | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab836907..4b092e922d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,7 +378,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/OFL.txt" - "${OpenMW_SOURCE_DIR}/Bitstream Vera License.txt" + "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" @@ -389,7 +389,7 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") + SET(CPACK_PACKAGE_NAME "OpenMW") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) @@ -404,7 +404,7 @@ if(WIN32) SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - SET(CPACK_NSIS_DISPLAY_NAME "OpenMW") + SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index f2382fd8ac..f66dbf2c47 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -2,7 +2,7 @@ macro (add_openmw_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND OPENMW_FILES "${f}") @@ -14,7 +14,7 @@ endmacro (add_openmw_dir) macro (add_component_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") @@ -26,12 +26,12 @@ endmacro (add_component_dir) macro (add_component_qt_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") endforeach (f) -file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp") +file (GLOB MOC_H "${dir}/${u}.hpp") foreach (fi ${MOC_H}) list (APPEND COMPONENT_MOC_FILES "${fi}") endforeach (fi) From 0e8ff22d6fabe839380acdb2cde3fd11706ebbab Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 28 Feb 2013 07:20:01 +0400 Subject: [PATCH 301/330] Only install binaries which are enabled to be built --- CMakeLists.txt | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab836907..e8d5f23c75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,10 +657,18 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install binaries INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + IF(BUILD_LAUNCHER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_LAUNCHER) + IF(BUILD_ESMTOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESMTOOL) + IF(BUILD_MWINIIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_OPENCS) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENCS) # Install icon and .desktop INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") @@ -674,5 +682,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) - INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + IF(BUILD_LAUNCHER) + INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + ENDIF(BUILD_LAUNCHER) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) From f75681d89b3d29cf1561f0a261829f8b8ad6d347 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:12:51 +0100 Subject: [PATCH 302/330] Ignore ESX header version --- components/esm/esmreader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index eca0d78548..41a2f738af 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -77,8 +77,9 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) // Get the header getHNT(mCtx.header, "HEDR", 300); - if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - fail("Unsupported file format version"); + // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. + //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) + //fail("Unsupported file format version"); while (isNextSub("MAST")) { From 6683e43efcfefffc069fa172b2e0cdd15bb04891 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:35:18 +0100 Subject: [PATCH 303/330] Removed commented code --- components/esm/esmreader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 41a2f738af..b4f581d7e8 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -78,8 +78,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getHNT(mCtx.header, "HEDR", 300); // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. - //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - //fail("Unsupported file format version"); while (isNextSub("MAST")) { From ffd96c771593bc85205e53c487adebf4bdcaf41e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 13:19:05 +0100 Subject: [PATCH 304/330] Removed "Unloading Cell..." text from loading screen OpenMW unloads the cell so fast, it's hardly noticable. This commit gets rid of the "flicker" every time a cell loads. --- apps/openmw/mwworld/scene.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fb7653401f..99c1793fe2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,7 @@ namespace MWWorld } } - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +360,7 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From d4aa33b9a7da71682e9afa0cea01b65f9ce57453 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 15:58:03 +0100 Subject: [PATCH 305/330] Removing the unloading cells part instead of just commenting them. --- apps/openmw/mwworld/scene.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 99c1793fe2..c15baf43ba 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,6 @@ namespace MWWorld } } - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +359,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From a6fb58bc59598f77c2ccc415b47ce475b7cf073a Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 16:31:24 +0100 Subject: [PATCH 306/330] Using "Loading Exterior" and "Loading Interior" instead of "Loading Cell" This commit replaces the default "Loading Cell" text with "Loading Interior" and "Loading Exterior" --- apps/openmw/mwworld/scene.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c15baf43ba..1e8f6d339b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -27,13 +27,10 @@ namespace { const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - - size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; if (it->mData.getCount() || it->mData.isEnabled()) @@ -55,10 +52,6 @@ namespace } } } - else - { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, 0, 1); - } } } @@ -216,7 +209,6 @@ namespace MWWorld continue; } } - unloadCell (active++); ++current; } @@ -265,7 +257,9 @@ namespace MWWorld { CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, current, numLoad); + //Loading Exterior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + loadCell (cell); ++current; } @@ -359,7 +353,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - unloadCell (active++); ++current; } @@ -367,7 +360,9 @@ namespace MWWorld // Load cell. std::cout << "cellName: " << cell->mCell->mName << std::endl; - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); + //Loading Interior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + loadCell (cell); mCurrentCell = cell; From f66f67eaa12f0fcddbb615648b478c2215c77d96 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 17:54:42 +0100 Subject: [PATCH 307/330] Loading text uses now the corresponding GMSTs --- apps/openmw/mwworld/scene.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1e8f6d339b..ecf783d6c4 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -169,12 +169,18 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { Nif::NIFFile::CacheLock cachelock; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); mRendering.preCellChange(mCurrentCell); // remove active MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + std::string loadingExteriorText; + + loadingExteriorText = gmst.find ("sLoadingMessage3")->getString(); + CellStoreCollection::iterator active = mActiveCells.begin(); // get the number of cells to unload @@ -258,7 +264,7 @@ namespace MWWorld CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); //Loading Exterior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad); loadCell (cell); ++current; @@ -318,6 +324,13 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string loadingInteriorText; + loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); + CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -361,7 +374,7 @@ namespace MWWorld std::cout << "cellName: " << cell->mCell->mName << std::endl; //Loading Interior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1); loadCell (cell); From bd597f07ab85d667ced3c6ef4afce828db73705e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:22:10 +0100 Subject: [PATCH 308/330] Centered the loading text --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151a..1e4bba5ed8 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From c9a701cfa1cf0c4de63717357673c9044b1ae6f3 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:25:18 +0100 Subject: [PATCH 309/330] Removed the 3 dots after the load text. --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index dd5289edb1..e7c7acb533 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -106,7 +106,7 @@ namespace MWGui float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); assert(progress <= 1 && progress >= 0); - mLoadingText->setCaption(stage + "... "); + mLoadingText->setCaption(stage); mProgressBar->setProgressPosition (static_cast(progress * 1000)); static float loadingScreenFps = 30.f; From 06e077c07ca699fb50f1b3d965394291eb1ccdde Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:36:10 +0100 Subject: [PATCH 310/330] Removing all traces of "Open Morrowind". pvdk said it was ok to remove the header entirely --- components/files/fixedpath.hpp | 22 ---------------------- components/files/linuxpath.cpp | 22 ---------------------- components/files/linuxpath.hpp | 22 ---------------------- components/files/macospath.cpp | 22 ---------------------- components/files/macospath.hpp | 22 ---------------------- components/files/ogreplugin.hpp | 22 ---------------------- components/files/windowspath.hpp | 22 ---------------------- 7 files changed, 154 deletions(-) diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index dce4f96c20..a309dc9fb6 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/fixedpath.hpp */ - #ifndef COMPONENTS_FILES_FIXEDPATH_HPP #define COMPONENTS_FILES_FIXEDPATH_HPP diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 0f08b67feb..c974a91d35 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.cpp */ - #include "linuxpath.hpp" #if defined(__linux__) || defined(__FreeBSD__) diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index 09acd2be7f..6acf2a2d5f 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.hpp */ - #ifndef COMPONENTS_FILES_LINUXPATH_H #define COMPONENTS_FILES_LINUXPATH_H diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 9625612ad4..9edcd6ef2a 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/macospath.cpp */ - #include "macospath.hpp" #if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) diff --git a/components/files/macospath.hpp b/components/files/macospath.hpp index 591c978aa7..576ec16812 100644 --- a/components/files/macospath.hpp +++ b/components/files/macospath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/macospath.hpp */ - #ifndef COMPONENTS_FILES_MACOSPATH_H #define COMPONENTS_FILES_MACOSPATH_H diff --git a/components/files/ogreplugin.hpp b/components/files/ogreplugin.hpp index 2d56bfb47a..6fcf613768 100644 --- a/components/files/ogreplugin.hpp +++ b/components/files/ogreplugin.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/ogreplugin.hpp */ - #ifndef COMPONENTS_FILES_OGREPLUGIN_H #define COMPONENTS_FILES_OGREPLUGIN_H diff --git a/components/files/windowspath.hpp b/components/files/windowspath.hpp index 7fe8bc9559..6044b67c21 100644 --- a/components/files/windowspath.hpp +++ b/components/files/windowspath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 - * along with this program. If not, see . - */ - -/** \file components/files/windowspath.hpp */ - #ifndef COMPONENTS_FILES_WINDOWSPATH_HPP #define COMPONENTS_FILES_WINDOWSPATH_HPP From 3df34fb5ccbb8ec0f1870b7f9072ff6576a22dd9 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Thu, 28 Feb 2013 19:52:32 +0100 Subject: [PATCH 311/330] fix bug 574 --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b85..2b943c50f5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -274,13 +274,11 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } else From f77ace088537a7a999decf39485affe7cb8d0080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Thu, 28 Feb 2013 20:16:46 +0100 Subject: [PATCH 312/330] Removed the "hack" mygui.png and misc fixes for this. --- files/mygui/CMakeLists.txt | 1 - files/mygui/mwgui.png | Bin 13534 -> 0 bytes .../openmw_chargen_class_description.layout | 3 + files/mygui/openmw_chargen_race.layout | 45 +- files/mygui/openmw_dialogue_window.layout | 6 +- files/mygui/openmw_edit.skin.xml | 57 ++- files/mygui/openmw_edit_effect.layout | 8 +- files/mygui/openmw_hud_box.skin.xml | 75 +--- files/mygui/openmw_list.skin.xml | 415 +++++++----------- files/mygui/openmw_loading_screen.layout | 3 +- files/mygui/openmw_map_window_skin.xml | 2 +- files/mygui/openmw_scroll_skin.xml | 6 +- files/mygui/openmw_settings_window.layout | 26 +- 13 files changed, 250 insertions(+), 397 deletions(-) delete mode 100644 files/mygui/mwgui.png diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index e7e5b695e1..beace5b81e 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -9,7 +9,6 @@ set(MYGUI_FILES core.skin core.xml EBGaramond-Regular.ttf - mwgui.png Obliviontt.zip openmw_alchemy_window.layout openmw_book.layout diff --git a/files/mygui/mwgui.png b/files/mygui/mwgui.png deleted file mode 100644 index 318f16e41873af708fd31d302bf0726efbdf916c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13534 zcmcI~3shQnzAi~>Y@3H?&P-zyQ|+`i^dvT>8iR^T)6>M7hccU&Wh ze;|(|x-aTFb%k1H@W@E$uzzS#PhD}(&pw~s`W$k=?Yj@}zH#?X#}}V}5%T{0n|W`# z{qDrwH;#UFb^y#IUB@4tWJ4^RBOw|dOp-1lVZ1-7yC&pFYw=AW<#b0^+2 zUy+?7a9KII_#n_=`m#yetkPiwwTv`A(^f!#d{%A9e-8pdzI!EcGvu24Nh6#zcQ4Vz z%2+g;48FFk&LvjVw8m8@U(#Nc=I53*C}E;;F|TXoLgzxcQ12R6P(`iOCbw#pb8Ovx z##!ZM-NyrqK1S{w&#TJobe-i%#y`__2F{9ZR&863O*G~#E+cI&B6V1Y49>_vQb=S2 zIXk{7Au4uv$<`otT{0nbKw>TNs?z1`LL8#}hq|DUZi8Ev<8lhAoK7LBE74ZE0w)EM z6aw2wg7nm*AKXoEO`dNn&&fB%b8)g*7sv`ptF!TJeq3X?&h&Z59W-J~AoVo)0pS>A z(q&TFxw*=l)!y+Xb86dWi0@{E@tr5$eTI>o)*FS1zk}p%T4K>5`yztX(d{eIfHmJF zY7bnCD5Ex=xqlM%`IaZePXvW7ha$3!e4^r{*H)Kn?$>GNx6hX)jp^e|5C@FLdA+ z$oenC$Fd4T4exBa=6-E$lIikNPT4lWH=8E^vc3@&{zj^?_RXF4jToESMdQ-h)dzr8 z`99KWxNmJonTl-&+JL|&M^Jr<+TZ7yy9$Cj3u>93b<--->DEOY_93atw@_}dTo-tz zDDM?iH<|M+TDI!JXwW#kza@0QiXrG-72#y)Mwf6`MuebK8ZqY-RD4vx5AJ_X=OF3i zX)=9pNnkMAFsjI=%yW%u?etZAr!@VMd z&y+e&tHoHJ5a^7h>mqNYOkH4=y%Y+5Qmbcxz}vR6Oy`=A2b-07%D%rGS@^*HGr&XJ zZ$Vrkxm^>)t+OY&^H`B|Y*5Humha8@h*E!n?+X=4!~^keQCayx{7kGrUMJKJhu8g`o=+RmrhwjnA>%gaTw(IDF^+e&(#L0&|VpR{>L(L#BvN%5=tBYi54xj3&* zB!zNH&g^v4-F;k(dag}Ep`c{Zv1cf#sfc9Zo+z{YOk0`I*v1g12I4-Fm1OD(D$Fl5 zr*mi1xfkAnKzvg+5td&OSAHWI^?ABEMg|&_a%t>z0cTL2U5;!ZAB6{Tt5bp#QHNin zKBY{1S-UIsA}?EpXQ%P#56hYw{j%Dq$J`iEWoOk~ zz*lt_@hq=Uh)UN|J~w?Oofh0_Ra?7xZlNx3Kyq&bUdepKx~<9(9SVZ6SnvRg7oW2{9>n)jwr-Yp$$SA!y>Vb_L)hx>Pxab$Y+~ELW1|V|Ffc=1;^jQ z2BDD%9g%Tti0%e5t@X*mVmgheb}F$8ztz4OLyEyvcAbhW1M z7gIRo$+iRtEIdB$o$X7Po5imi#2Dh^!EkJ;XGmM&vhh_{5ipQwuK`PFtLB|SltxBk zXq%;Qso-Uo;>uz;!uk?QFe1bFQ{g&<6`rR|Et}qkFw}RNfmA*RiPa|^nmOV*J2a6L z!W%u#ovSTXXy3b%fQbm$P{sUIekP}87vujW;V;P2iarZxco zVF@X1hOP;k^+N>KEEH5enW}WdTIPQMqNStFB{O6<3j1q%$YedMm{OeahmcJcBuf}( zJyABj0`pQ#&$-gn?9Lkba@yh#i6_g*WL+4~av*Uf&6A@i&J`^1BRZGmLhSsj?*M<# z{?cBUjSubYzazFJyed`PFFvNwADar29Wb6GDZOO7x{B3qq_Ekgd%T219%kFiD{m2W zemy;KCdo##+_MeicS9zFn7k|P2}wU+?%cLi&+58dmE5(uXOjLU-s%r6rDNxpf+_Jj zZgdB0gl#p5Ns9lVehYyhdNsd)g61YJOl#{|5(#I!nMd;`9u|5m%vTFI6(mbz;_0$e z_xnU5Zxo8$v8b~8a5ch!y9IdbAC(36)?;E%>H7=D#aK&k>X5*dl)qLaeEuzLe)^iK7ptKg9SzNp!D~E@T z4bH8k+$xpITnL0m)nuqw$nOX$soAvZ3Np>|H($c5&n^Sw4FM}};+@H-DqLpSS$c|3 zj9OtkP5exI$qUXO9v+zSx;a1IV8r5^iZanOZ_TrU9(UPMx?@Su|LkVVYH_r}Rk3N#d zA?=vx3rAZ5O^fG#k>%~Fn#Q@#;_Kd!O1IAcZOYPzF!;wn0N1h#H@DR$pyIxo2&@V6=7k0PY`>N922^S{koe_?XSnx+dl985o}At%%(l4LAd(2U9SuQVM=RfhGRL>6r_1U zml~q1XT>IRDq%8W?drF8p1eG^4CA$9ss8|d8jjh4&`D3iy_T_M1j7JbwhQPjbqB6Z zCI4ymcTaTvg_a-5wpW4`v&n;`5h%2gz8>{Q|Bv0J=xH=@=HGnfG{Ds>eF!U09As1b z5<_jTxhpsH#Uyj3{$8S)w|%QM<5qC$ZP_GU;&ZXNv1_VOII>EPsx3AX{jx!8IBu=vvXPVD>HWn%O7O%P=7<~Bw^ ze}>57f9)R2>%MO04PxgTMCG^t1f**##PhwGlrx#{dTv?}Sue_Me- zTn_bJ3_HmjCisV^Hh-%Nak1P>%nm#ZY^^Cr5pNCBT z<&$gr=mRj=@Utx^umOcH8;A?75WqeUU1qf>@z|g`nCDkD<_luP#9%rNKsP!@L}%f@ z_SQpJ%K>0&4Ug(G$`j}h@T?DuW%@{I-trHKEs&1Cx?~1KecO$k+5~K@0KMo=1Z`UDo?Ly~iC_rygsE_Pcl&<|}^PGxBm z1XwE8{KjlPq5LS*lt)~1$X<(Oyy2E!B;eGnR#NW>PtMfwe*z%*!E3|v4~mcJrxJio zO#rj*n<^&A2l@mnw`r`xe|{4(`}r=QPtZ(+A;M=Dv^V7LL<6i-M^daleJtB7)r^kf zmR<166$%LC#{>wIdE|xqh;P=aRrk9;L87S9H8f>x%@)X=tW60~n3jY9udnP^(u9=9 zX)E6J!>*9ep9+|H5 z?Y9%T)Tb?`arYOKM0rQ@c>?Ue@HRodVnLcK zinHOo;)K+lkZb)wSj-Xk4Jg=oCjs92XTZ>=4}gF>AUUyqi9rx*41^&d-q!E7{1zMs zlkwu$mpFqHr#`MBRoIQw#^hEu&UMUPvrpVLbf)J@jhVEWD{sO%cgI*shGbld! z(NMa>a=D?M{AYLaZXZ}(BpVWmexW{0I$*bB+t+kIN&wT7L^@lab@3LM6-djp8>mSPW`?{gh=q7Ac6b^&)p_B?JHN-#>+qYN_+hdQ?!gc%F(O zXw)VPDy#x8E37E0ukSERQ#}!^-t$<0*YF-uZP);x+I^Qx?a_tyT@2}aslBjVA1NhF z5fAz{&ri_`1C;KuqKWZ7ll-)22(dz&Syf;}@?#T8a5|c<`)i6H8$?e z&?H|QsgoNEUtUVpP4uar1~v%l zQcw?XOE{7a?xWB?$rm z?2@;SQ}=4$OKEB2!!ew4fo-f2;J4(7piVMON~~oxMzp#uVuAWUv=Gsnm>)Ep?5pcE z2TF3X+VI~e7gU&KODScRZNeuy+XDI)GS9>cI3yU-4r%r*O_X*36AbIPTW{?w>*Bkn zpI5$bEztshv6L2uR8|U^>60&~P^u8-*05GqKPpWBv)kwsdGyX!#MfJTTuSk>;jk_#J~i zm3eaMOU<4(+vwE9V64}J>xP^ow-P(gZJ}^3>|6}{dJ7vKZ~7H_3nP4DWqK*ILb&I) za19jMpx5$uzoBhl%J9G(u=sgzu@QKZnv=CKvFB^L(Da>vG>_X6 zlDpuoqar2E*8v3}-Bd`En$GX2?Wi%8B1*-% z8G)$@A^ai!OKke2AI-Wx}r{~iux-Nf@;TQsk zld~)@Bnc9q`DyA6ldyAXE_+csZAq(Wh>{M(kiNHaIJL+y-iT_rWAU}5HiXs7mm)h2 ziu#18N)Z?PJ;3viRJe;e%vsIP8as^Ah~re`&P6wDD5p1Gmj9uLN0H@KLn6NjUnhUX zzo6wB0+m9>jHecrj)mG5Xoa7UUiIiwvX%EvRZ>HUM#;j9{vqiZMfG$EhN%8mu0ZA# z;Z{~I94A9X9P^(PO-DVs1!bcbtLr)SciDp;vgMc*Mjr7uJ#7$PTBqPs>qCO`D)2O9 zN*kw~-GkTPvnf4HeX+3l7mdEC5lR0P+1OHb3JVk(?T=Ip(duEkExd(Yp7Dbh6a_Z9afCy@6faWbNc8dctuLkilFHPZg zOt1=S)pPTS`8$9LcMN9)GNT~;hDbKCbbiOF(LCL>1i0CsJxGyt*e3Sm*3`qpnLwUp zBE(*2x8VKH;ee@MCEQf9+G`bj{-Gk?g;sN)JgNFo z@a~-WAZ}e!>*af5K&y;v5T?pgTKY4`1S8qi#l;ajTW_fFV%36KDcUtBP3J_sJ1wH3p1$Pg~t5SmH|8p3BAp(e75#<@EFAF?EHPcVxE&y_Pm#KSL)!)u-QK z^D~ya_I%wePQ?QOa>JFfdwag^Mfx3~POf@7%?kMI_Txp$(a)d~!?L;gI>i*+E$a$+ zuFdw#NAJkEV(=?K@0d6hyE}}z^%m~i)vwVeBlm_3vjf<{gymYm!>^ePk$G`XRnssA zYQ2Dn@5b$8Br6(?+#VP?u6f@8p#Svc-o%LQQ2X1_SEh;Ilha z`NitF->fnvLlojpmfsNeUZmzUQXj$daAEvA625fweKij5;lX(nQw;Q_3v{yK;_YE| zUOor?tu^NUa74aj)RikNkc4om?s5{8{H~PcZe)I(BC8#cVpi2ZMq}LB)O*5nz`bW1 zWA+v2EEf?YeW7vuiXf@DcYojcdfJ(Sa(&-^4jO8GpkGL=V{ z^0YszT6wRiB>RTUYPN_*yaz^%$Pbk;eL~`CYzOQFd*lQ@uop+77WerzVQgUtc1=?2 zm#xg@>eJBF$DKx-%nQB4Z(>h!!R$*Lo!e2J5)##}Np6=RKb%tSw-OOkPxqsgQ!`f< z{9ogTUmIIOGf=_tDWgEYs4HR2S@wK=(7z7B-MUNlD2u&yS8+~^py@i1U2bgxdf8=q z*izxj%ATrwLUo}GC>j^bMzQI4XvqhO&-Z-I^s6R4+`4NxS*ryG7!9KN0Ey3NOdSPA zh-@(Ypqo;S_>d_gpbFTgVmp6`wxS7}b8{b3d?(iIKT*bPAnN9~(=iFx~C_#2Z)R&Yb zNh~Lr_JI}`Be!y#e9fa9Iqni_-`p5dz(@$-{%R*if!yGzh*G;NZUO9a|JZ=teznXS zfY?W>T4QdS&12&Jv~yoUwym2UHXJdUx`JFIYU3`mul=l%dI#a1Gn_u+$^i`&cW_vp zLy208ZYJc`R*BEsd_X){vzAtePHxTUtagyphg@=W*LRLcc@V2A-@DGa(VIdFaTO&* z{XRPdpLo~Mf(`(qwWx@C(;cMAv@mvW*3hb$vQ9}~P7Oa$=)o1m!{My9x&Q}_3jvO; zD5-ikz1`sjnxo?qr}^}%59-g*LB?uW3ic>MgY2H73Y5fvTTdRX=GR~p_DtRx?$Ouo zWcE~zX8YSXN1(%wTOYx}6^qq*6^%LiO@CR}3=Gph{pethbb)UR5{3}mTaV5q12bw^ z9l&)E`=wdJ?MSAn#M4e~E0OJF)q_>NWPPYoE}=>U9F#axH<*%iF0^B3hYyH+KA&7zVN{IsBZZ}ML5mMpeQ9@qS~B9-3#L)ymP_RD!0Ug|K@sN-dExdo*{43tEsqU=ib|=pSth z>vx2~*t^L;p9L9tNMP{bQ^NyrBCV9T&jm~qY7R_7Yykh5?KhzKaaA*150W%O`57*l zZ<&6y`;XC}Ow)#D`cnhA!wx;+=bx)_jnjLdw5*pC{vvLx1P2Di%RA(lqmHaf3HpS+ zu0u#R2f`7j`%PTvF#agF%&DbF>TXSnN~NvEv-)7A4dYpSRHq_DI*xWTdoQ4zri8rB`!|2OAoV zE|d)rHc$b}&CISUR;R8nG0pu+clW7XYkJ~ZNx+Rtvdui5Lyd`S&}VEf081zx)7-K_ z0NX2orY1X^lq4^!~JV0Vk&8d;8>~fc78mde7ivx9@4(vm!sl%>W zu^`BEiT6g%f|aMEqpkO$(83_tou$exD>=$^1n7CFI(tLC2rn9R8r;(}1J#)Uc0z!; z1C<8!)skXgH`>`4V=H5KFN}jWbX#QlCBjH$&J;@V!#I66?K5EdcgGqgr^v$(DxH|2 zQSJxWRN&~1%vK;RoI{0lV5^ELabWOink0jY#(hEob;GgOI6&TW=HFuu71;%M$a&Nz-U8d{S}Xd1`Wr_AjAYcx z+w;op4JXn!l5y7AHu`ewfDA;L?71`06pnr*C5qb{ zYZ$0L22xG|x-7Vtnbxuxwi6zWK6{^$tk+xYvxK|C;~qG>1R8V2+a=afW9jr}|Cs=U zz^<3(VzJbt%*l7F?6_sYm7XI zcA^m@&gdV1#O9N@o-T(5aLYw#{adS{_u(-riHiB*^U;Uaphj(b4QmbLT+%4fl#)=HO=UQj0C6RPB!viqy>P>n`L?? z+(oebP6EPJL~DQLrsUlR08sO@HpLBsQs$%3a>cPjq);-5v~8g zo_87e;OapN2o}O}m8mhnsktL=8w3X#$N+HYjK^ib4!{iOOCz5RD=>1q*6&t&E9Bpwql%9?k>Gx2az^7e)Z!o(zh&|ZJ3E@3wj5S}ZDnNkb1~A2|+Ta*4RxB^&Swcow&g3|7zI8l4?>9|3I`8BM1nufq9m!uuqcw=pj^2`6m{Y!?zfEQx5&S3v zPe{xXTuiDHaIrbJQ@cP^TVF)=*>=!i=iWP)IoW5O3|SB+FsHkUDx?^UZpi z0lcA;QK@QiW=?izZ?@FQmBenelu)M~L%3~`qfP+Kmf+4dDZqmwt(WI?RtT78xtY0D z8xOPYz)my{JNaBzYyah6LGP~fIXm1Ocgf5mBO9Eny2$Cz7zH!yJn2wxn#j3GJ|7Jb zIxyQ|;YHbRhYi^4$jqZ%al0lQ03=~z^)S+5@jzDFmwiQ!Q@-pGUe<_RnE)Nd@t=h0Tm&!ZJyaTC_uN{rX79Rsv<6z5yuX0*W={-X2 z&CLw|`=kTZlw@bpAseWX8;%`Ss<@b;lzgGbu4rqJ)>8S>1WBgAwl>EHg8#NTBXYKvr zE5tikI~^&3k{9xw*xYy?p+BZ)X4$n4TD~EW9N{#3qrne=?ivS=V=x#C!62jR5dtDn zHYgG`yBBX?cEkjxfw62Js1_9es8lDI@-UtDDPR?QISobpAPjEsmGk3CsVLgpz|T z2LcyFaJfe!8m2)g)lz;cg$Kjh{Tg0>=Bzpzj2DfDx;@`%BiOf`N89opY7wUn6_?rI zXqm(uWOjo?pdwtYj_yJ_*j9&sf7Xbl+X3(6F#Z6?cl7_gQBW}9fHp#D99VGb0jnyGxv+Nx0(n=M~Afz`oN8r1)EWP^mFCGIPBatuul zltXMVIdoJ&LwWZ9NJG)`ao=tb7>;tuWy)MTrSRDoS7C>QObGuV|4%Qb?EPj+eKn>L z+<5Uy%&tZSNTyJl3!~~7FsbLJ_eJQ9juIMM=?=)>h&~51#O&LcajlFK4a5KP?pGCS zwQgds!9N~&yTrlD+PGv>3)nifnv4{VQ!5IjM*6>U27gB&xA#XO+L0PCYsK75?ffN;JWv={xJ zQlDt~Zk^@)I&_vURC}9vq$OF>sJP!MTW*?=sFE)o?lsB1*#!l8>X#9bzCF9qXoXh7 zHa+vur95owFD-n1&yvU`meI@yNFUl}(%lLJHbIE6cb-IbW>txJhiUCha(9tt`?BVd za3CQvR+SUH`w>}BNxiSnIbKi9r$$E#F!Qq_Z;kZhMAFoIiKijgWT#zL-=`}&N!SGW z1MoiNKl%ZlhWr;kpKW>rc=!7s`+NlfG^zi>=O5kD>iz$PEv-KDk8a6v|Hf@CoqKI_ Zfjvhb*ux%p4FUc|9E<#-`SbJN{0~$*&Ncu5 diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 11031eb4e6..8823e1e760 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,6 +4,9 @@ + + + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index a9ec9905da..4ef8da0f3f 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -8,33 +8,52 @@ - + - + - - + + + + + + + + + - - - + + + + + + + + + - - - + + + + + + + + + - + @@ -42,11 +61,11 @@ - + - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 1271a287b6..9a9da72d4c 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -3,13 +3,15 @@ + + - + - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index 02fee4b179..da21385e2a 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -1,55 +1,52 @@ + + + + + + - - - - + - - - - - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - + + + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 45ecb63edf..cad22c064a 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -31,7 +31,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 464b6343aa..23480e8d35 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -1,80 +1,31 @@ + - - - - - - - - + - - - - - - - + + + - - - - - - - - - - - - - - - - + + - - - - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - + + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 64435451ad..6631424ccf 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -1,228 +1,107 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + @@ -234,81 +113,85 @@ - - - - + + + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + - + - - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 1e4bba5ed8..4b6861151a 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,8 +8,7 @@ - - + diff --git a/files/mygui/openmw_map_window_skin.xml b/files/mygui/openmw_map_window_skin.xml index 0c6050969d..13f18c6d3c 100644 --- a/files/mygui/openmw_map_window_skin.xml +++ b/files/mygui/openmw_map_window_skin.xml @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 70fad3f4b4..1b94f0c291 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -2,12 +2,12 @@ - + - + - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2f9b5a67f1..8d435bfd53 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -15,7 +15,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -64,35 +64,35 @@ - + - + - + - + - + @@ -117,7 +117,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -208,7 +208,7 @@ - + @@ -233,7 +233,7 @@ - + @@ -241,7 +241,7 @@ - + From 3efbb5e728b5708ee738279ccbe15ed765efadf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 20:27:35 +0100 Subject: [PATCH 313/330] Don't try to render a map in empty cells --- apps/openmw/mwrender/localmap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 601ee58e31..1a14b86bfb 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -119,6 +119,10 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, AxisAlignedBox bounds) { + // if we're in an empty cell, don't bother rendering anything + if (bounds.isNull ()) + return; + mInterior = true; mBounds = bounds; From 0b629791a82cc2abcaa7b1c2b106a81763c56a57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 20:40:32 +0100 Subject: [PATCH 314/330] reverting loading bar layout --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151a..1e4bba5ed8 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From b7ab12e7cf4e919cdd664254163bf8c204be2771 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 21:12:13 +0100 Subject: [PATCH 315/330] Workaround to prevent the map drawing on top of the world button --- apps/openmw/mwgui/map_window.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/map_window.hpp | 3 +++ 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 6f7f0eaabc..52b108f850 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +15,8 @@ #include "../mwrender/globalmap.hpp" +#include "widgets.hpp" + using namespace MWGui; LocalMapBase::LocalMapBase() @@ -96,6 +100,7 @@ void LocalMapBase::applyFogOfWar() : ""); } } + notifyMapChanged (); } void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) @@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); } + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 4e2dd67567..39770a7a26 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -50,6 +50,7 @@ namespace MWGui void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} OEngine::GUI::Layout* mLayout; @@ -99,6 +100,8 @@ namespace MWGui virtual void onPinToggled(); virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + }; } #endif From 1168f153611cb7e017c092496f3b31c978cd090e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 12:17:58 -0800 Subject: [PATCH 316/330] Don't disable depth writes when blending is enabled --- apps/openmw/mwrender/activatoranimation.cpp | 3 +-- apps/openmw/mwrender/creatureanimation.cpp | 3 +-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 3 +-- components/nifogre/ogre_nif_loader.cpp | 2 -- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 7bc89b9179..a3332d4b5c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -42,8 +42,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b85c4dbbda..3adb0c4489 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -43,8 +43,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 809e3f6d29..ce15841fc6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -118,7 +118,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459e..9aa65ac995 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -148,8 +148,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1af..4d4a0d9c51 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -716,8 +716,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String blend_mode += getBlendFactor((alphaFlags>>1)&0xf); blend_mode += " "; blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else From 60f22194507c45f235c13928f3d7ca64e1629536 Mon Sep 17 00:00:00 2001 From: lazydev Date: Fri, 1 Mar 2013 00:46:05 +0400 Subject: [PATCH 317/330] fixed zini's norices --- components/esm/loadappa.cpp | 2 +- components/esm/loadappa.hpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 80922e2cbe..643fefda51 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -28,7 +28,7 @@ void Apparatus::load(ESMReader &esm) } } -void Apparatus::save(ESMWriter &esm) const +void Apparatus::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index a1daeb1237..820c44c592 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,7 +1,6 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H -#include "esmcommon.hpp" #include namespace ESM @@ -14,7 +13,7 @@ class ESMWriter; * Alchemist apparatus */ -class Apparatus +struct Apparatus { public: enum AppaType @@ -37,7 +36,7 @@ public: std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void save(ESMWriter &esm); }; } #endif From 230136438b096d017ac490cc65347d73bc2b8854 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 22:17:07 +0100 Subject: [PATCH 318/330] minor cleanup --- components/esm/loadappa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 820c44c592..486a559f89 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -15,7 +15,6 @@ class ESMWriter; struct Apparatus { -public: enum AppaType { MortarPestle = 0, From 2786cc67f61e9e4aa6338222491ec96c501c4f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:38:48 -0800 Subject: [PATCH 319/330] Fix loading empty NiTriShapeData records --- components/nif/data.hpp | 16 +++++++--------- components/nif/nif_file.cpp | 5 ++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 63df23b273..46b58da8f9 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -142,20 +142,18 @@ public: { ShapeData::read(nif); - int tris = nif->getUShort(); - if(tris) - { - // We have three times as many vertices as triangles, so this - // is always equal to tris*3. - int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); - } + /*int tris =*/ nif->getUShort(); + + // We have three times as many vertices as triangles, so this + // is always equal to tris*3. + int cnt = nif->getInt(); + nif->getShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so // just skip it. int verts = nif->getUShort(); - for(int i=0;igetUShort(); diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index ba3a7513b2..6e806e7ecc 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -220,11 +220,10 @@ void NIFFile::parse() for(size_t i = 0;i < recNum;i++) { - std::string rec = getString(); - //cout << i << ": " << rec.toString() << endl; - Record *r = NULL; + std::string rec = getString(); + /* These are all the record types we know how to read. This can be heavily optimized later if needed. For example, a From eaa6813917498b84eb3ea02adb3d2ab3b26e08ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:54:53 -0800 Subject: [PATCH 320/330] Workaround for meshes without any vertices --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1af..a86487854f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -844,9 +844,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Set the bounding box first BoundsFinder bounds; bounds.add(&srcVerts[0][0], srcVerts.size()); - // No idea why this offset is needed. It works fine without it if the - // vertices weren't transformed first, but otherwise it fails later on - // when the object is being inserted into the scene. + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); mesh->_setBoundingSphereRadius(bounds.getRadius()); From 1d988676febb8b0e6629f6ca9b2eff0bdec6512e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 22:56:29 +0100 Subject: [PATCH 321/330] Local map: the obtained bounding box wasn't exactly accurate, getWorldBoundingBox seems to solve this. --- apps/openmw/mwrender/localmap.cpp | 5 ++++- apps/openmw/mwrender/objects.cpp | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1a14b86bfb..918ec4580d 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -134,7 +134,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mAngle = angle.valueRadians(); mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); // rotate the cell and merge the rotated corners to the bounding box Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); @@ -156,6 +156,9 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mBounds.merge(Vector3(c3.x, c3.y, 0)); mBounds.merge(Vector3(c4.x, c4.y, 0)); + // apply a little padding + mBounds.scale ((mBounds.getSize ()+Ogre::Vector3(1000,1000,0)) / mBounds.getSize ()); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459e..e8ee3f95f5 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -113,12 +113,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; 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(); - bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), - insert->_getDerivedPosition() + tmp.getMaximum()) - ); - } + bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); From 2c05a7477cfc37faab23217c87fe7527aa2a9dbf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 17:16:28 -0800 Subject: [PATCH 322/330] Improve checks for texture resource names that include the "textures\" prefix --- components/nifogre/ogre_nif_loader.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index a86487854f..85fbfea264 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -605,7 +605,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String */ static const char path[] = "textures\\"; - texName = path + st->filename; + texName = st->filename; + Misc::StringUtils::toLower(texName); + + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + Ogre::String::size_type pos = texName.rfind('.'); if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) { @@ -616,18 +621,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + st->filename; - } - else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - // workaround for Better Heads addon - size_t lastSlash = st->filename.rfind('\\'); - if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { - texName = path + st->filename.substr(lastSlash + 1); - // workaround for Better Bodies addon - if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = st->filename; - } + texName = path + Misc::StringUtils::lowerCase(texName); } } else warn("Found internal texture, ignoring."); From d8f2d0195af6b9ac35560057412e0afb1544ec58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 18:45:52 +0100 Subject: [PATCH 323/330] Got rid of the texture rotation hack by rendering the cursor manually. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 4 - apps/openmw/mwgui/cursor.cpp | 130 +++++++++++++++++++++++++ apps/openmw/mwgui/cursor.hpp | 62 ++++++++++++ apps/openmw/mwgui/cursorreplace.cpp | 16 --- apps/openmw/mwgui/cursorreplace.hpp | 16 --- apps/openmw/mwgui/windowmanagerimp.cpp | 19 +++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 + files/mygui/openmw_pointer.xml | 11 ++- files/mygui/openmw_resources.xml | 21 ---- libs/openengine/gui/manager.cpp | 2 +- 11 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 apps/openmw/mwgui/cursor.cpp create mode 100644 apps/openmw/mwgui/cursor.hpp delete mode 100644 apps/openmw/mwgui/cursorreplace.cpp delete mode 100644 apps/openmw/mwgui/cursorreplace.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b3f4cd57b9..7cfeb84c5e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,11 +26,11 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui text_input widgets race class birth review windowmanagerimp console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list + map_window window_pinnable_base tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton exposedwindow + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6f59349fd5..d14696cdd6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -18,7 +18,6 @@ #include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" -#include "mwgui/cursorreplace.hpp" #include "mwscript/scriptmanagerimp.hpp" #include "mwscript/extensions.hpp" @@ -333,9 +332,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) - MWGui::CursorReplace replacer; - // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp new file mode 100644 index 0000000000..852eea29a4 --- /dev/null +++ b/apps/openmw/mwgui/cursor.cpp @@ -0,0 +1,130 @@ +#include "cursor.hpp" + +#include +#include +#include +#include +#include + +#include + + +namespace MWGui +{ + + + ResourceImageSetPointerFix::ResourceImageSetPointerFix() : + mImageSet(nullptr) + { + } + + ResourceImageSetPointerFix::~ResourceImageSetPointerFix() + { + } + + void ResourceImageSetPointerFix::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + Base::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next("Property")) + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Point") + mPoint = MyGUI::IntPoint::parse(value); + else if (key == "Size") + mSize = MyGUI::IntSize::parse(value); + else if (key == "Rotation") + mRotation = MyGUI::utility::parseInt(value); + else if (key == "Resource") + mImageSet = MyGUI::ResourceManager::getInstance().getByName(value)->castType(); + } + } + + int ResourceImageSetPointerFix::getRotation() + { + return mRotation; + } + + void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) + { + if (mImageSet != nullptr) + _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); + } + + void ResourceImageSetPointerFix::setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) + { + _image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height); + } + + MyGUI::ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet() + { + return mImageSet; + } + + MyGUI::IntPoint ResourceImageSetPointerFix::getHotSpot() + { + return mPoint; + } + + MyGUI::IntSize ResourceImageSetPointerFix::getSize() + { + return mSize; + } + + // ---------------------------------------------------------------------------------------- + + Cursor::Cursor() + { + // hide mygui's pointer since we're rendering it ourselves (because mygui's pointer doesn't support rotation) + MyGUI::PointerManager::getInstance().setVisible(false); + + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &Cursor::onCursorChange); + + mWidget = MyGUI::Gui::getInstance().createWidget("RotatingSkin",0,0,0,0,MyGUI::Align::Default,"Pointer",""); + + onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); + } + + Cursor::~Cursor() + { + } + + void Cursor::onCursorChange(const std::string &name) + { + ResourceImageSetPointerFix* imgSetPtr = dynamic_cast( + MyGUI::PointerManager::getInstance().getByName(name)); + assert(imgSetPtr != NULL); + + MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); + + std::string texture = imgSet->getIndexInfo(0,0).texture; + + mSize = imgSetPtr->getSize(); + mHotSpot = imgSetPtr->getHotSpot(); + + int rotation = imgSetPtr->getRotation(); + + mWidget->setImageTexture(texture); + MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); + } + + void Cursor::update() + { + MyGUI::IntPoint position = MyGUI::InputManager::getInstance().getMousePosition(); + + mWidget->setPosition(position - mHotSpot); + mWidget->setSize(mSize); + } + + void Cursor::setVisible(bool visible) + { + mWidget->setVisible(visible); + } + +} diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp new file mode 100644 index 0000000000..3a4a05f4ca --- /dev/null +++ b/apps/openmw/mwgui/cursor.hpp @@ -0,0 +1,62 @@ +#ifndef MWGUI_CURSOR_H +#define MWGUI_CURSOR_H + +#include +#include +#include + +namespace MWGui +{ + + /// \brief Allows us to get the members of + /// ResourceImageSetPointer that we need. + /// \example MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + /// MyGUI::ResourceManager::getInstance().load("core.xml"); + class ResourceImageSetPointerFix : + public MyGUI::IPointer + { + MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) + + public: + ResourceImageSetPointerFix(); + virtual ~ResourceImageSetPointerFix(); + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual void setImage(MyGUI::ImageBox* _image); + virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point); + + //and now for the whole point of this class, allow us to get + //the hot spot, the image and the size of the cursor. + virtual MyGUI::ResourceImageSetPtr getImageSet(); + virtual MyGUI::IntPoint getHotSpot(); + virtual MyGUI::IntSize getSize(); + virtual int getRotation(); + + private: + MyGUI::IntPoint mPoint; + MyGUI::IntSize mSize; + MyGUI::ResourceImageSetPtr mImageSet; + int mRotation; // rotation in degrees + }; + + class Cursor + { + public: + Cursor(); + ~Cursor(); + void update (); + + void setVisible (bool visible); + + void onCursorChange (const std::string& name); + + private: + MyGUI::ImageBox* mWidget; + + MyGUI::IntSize mSize; + MyGUI::IntPoint mHotSpot; + }; +} + +#endif diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp deleted file mode 100644 index 2079538fc2..0000000000 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "cursorreplace.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; - -CursorReplace::CursorReplace() -{ - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); -} diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp deleted file mode 100644 index 06fe28e39a..0000000000 --- a/apps/openmw/mwgui/cursorreplace.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GAME_CURSORREPLACE_H -#define GAME_CURSORREPLACE_H - -#include - -namespace MWGui -{ - /// \brief MyGUI does not support rotating cursors, so we have to do it manually - class CursorReplace - { - public: - CursorReplace(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e17190b023..1138f62faa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,7 @@ #include "trainingwindow.hpp" #include "imagebutton.hpp" #include "exposedwindow.hpp" +#include "cursor.hpp" using namespace MWGui; @@ -130,6 +131,9 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Get size info from the Gui object @@ -178,6 +182,8 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + mCursor = new Cursor(); + // The HUD is always on mHud->setVisible(true); @@ -236,6 +242,7 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mCursor; cleanupGarbage(); @@ -262,6 +269,8 @@ void WindowManager::update() mHud->setFPS(mFPS); mHud->setTriangleCount(mTriangleCount); mHud->setBatchCount(mBatchCount); + + mCursor->update(); } void WindowManager::updateVisible() @@ -293,7 +302,7 @@ void WindowManager::updateVisible() mHud->setVisible(true); // Mouse is visible whenever we're not in game mode - MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + mCursor->setVisible(isGuiMode()); bool gameMode = !isGuiMode(); @@ -421,7 +430,7 @@ void WindowManager::updateVisible() break; case GM_LoadingWallpaper: mHud->setVisible(false); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Loading: // Show the pinned windows @@ -430,10 +439,10 @@ void WindowManager::updateVisible() mInventoryWindow->setVisible(mInventoryWindow->pinned()); mSpellWindow->setVisible(mSpellWindow->pinned()); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Video: - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); mHud->setVisible(false); break; default: @@ -755,7 +764,7 @@ void WindowManager::setSpellVisibility(bool visible) void WindowManager::setMouseVisible(bool visible) { - MyGUI::PointerManager::getInstance().setVisible(visible); + mCursor->setVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f574211372..e2d64a855d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -72,6 +72,7 @@ namespace MWGui class SpellCreationDialog; class EnchantingDialog; class TrainingWindow; + class Cursor; class WindowManager : public MWBase::WindowManager { @@ -260,6 +261,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; Translation::Storage& mTranslationDataStorage; + Cursor* mCursor; CharacterCreation* mCharGen; diff --git a/files/mygui/openmw_pointer.xml b/files/mygui/openmw_pointer.xml index 42ee5d4351..cf21037f8e 100644 --- a/files/mygui/openmw_pointer.xml +++ b/files/mygui/openmw_pointer.xml @@ -5,26 +5,31 @@ + + - + + - + + - + + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 5a695515d4..e47ff6386d 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -17,27 +17,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 925891e1b3..e5a164b818 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -53,7 +53,7 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Create GUI mGui = new Gui(); - mGui->initialise("core.xml"); + mGui->initialise(""); } void MyGUIManager::shutdown() From 166d529c5071bd88e59374cfa7ba9078e47eee86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:26:31 -0800 Subject: [PATCH 324/330] Ensure the material is properly built after creating it --- components/nifogre/ogre_nif_loader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4d4a0d9c51..c856c4ab33 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -733,6 +733,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? "off" : "on"))); + sh::Factory::getInstance()._ensureMaterial(matname, "Default"); return matname; } From 238a8feb1819d1b1b430a0fd5211b13b71998e79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:27:25 -0800 Subject: [PATCH 325/330] Fix transparency checks --- apps/openmw/mwrender/activatoranimation.cpp | 9 +++---- apps/openmw/mwrender/creatureanimation.cpp | 9 +++---- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----- apps/openmw/mwrender/objects.cpp | 11 ++++---- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index a3332d4b5c..0dc16ecb6f 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -31,19 +31,18 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) Ogre::Entity *ent = mEntityList.mEntities[i]; bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 3adb0c4489..73bb80547d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -32,19 +32,18 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Actors); bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ce15841fc6..1f1cd0530b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -107,19 +107,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; - for(unsigned int j=0;j < base->getNumSubEntities();++j) + for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j) { Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } @@ -322,8 +321,26 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { - parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + parts[i]->setVisibilityFlags(mVisibilityFlags); + + bool transparent = false; + for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j) + { + Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while(!transparent && techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while(!transparent && passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + transparent = pass->isTransparent(); + } + } + } + parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } if(entities.mSkelBase) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9aa65ac995..fb2b0e50a6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -134,22 +134,21 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;!transparent && i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i) { Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } From 9810eafe230104ba4356bc5f53d6ee74bdaa3079 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:27:53 +0100 Subject: [PATCH 326/330] Removing now unused oengine/imagerotate --- CMakeLists.txt | 1 - libs/openengine/ogre/imagerotate.cpp | 88 ---------------------------- libs/openengine/ogre/imagerotate.hpp | 27 --------- 3 files changed, 116 deletions(-) delete mode 100644 libs/openengine/ogre/imagerotate.cpp delete mode 100644 libs/openengine/ogre/imagerotate.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b976df57a..e583f23d44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp - ${LIBDIR}/openengine/ogre/imagerotate.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp deleted file mode 100644 index 3dd5840785..0000000000 --- a/libs/openengine/ogre/imagerotate.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "imagerotate.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) -{ - Root* root = Ogre::Root::getSingletonPtr(); - - std::string destImageRot = std::string(destImage) + std::string("_rot"); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); - - MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); - Degree deg(angle); - tus->setTextureRotate(Radian(deg.valueRadians())); - tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setCorners(-1.0, 1.0, 1.0, -1.0); - rect->setMaterial("ImageRotateMaterial"); - // Render the background before everything else - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - // retrieve image width and height - TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); - unsigned int width = sourceTexture->getWidth(); - unsigned int height = sourceTexture->getHeight(); - - TexturePtr destTextureRot = TextureManager::getSingleton().createManual( - destImageRot, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - TU_RENDERTARGET); - - RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - //copy the rotated image to a static texture - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - Ogre::TU_STATIC); - - destTexture->getBuffer()->blit(destTextureRot->getBuffer()); - - // remove all the junk we've created - TextureManager::getSingleton().remove(destImageRot); - MaterialManager::getSingleton().remove("ImageRotateMaterial"); - root->destroySceneManager(sceneMgr); - delete rect; -} diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp deleted file mode 100644 index a3f6d662f3..0000000000 --- a/libs/openengine/ogre/imagerotate.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef OENGINE_OGRE_IMAGEROTATE_HPP -#define OENGINE_OGRE_IMAGEROTATE_HPP - -#include - -namespace OEngine -{ -namespace Render -{ - - /// Rotate an image by certain degrees and save as file, uses the GPU - /// Make sure Ogre Root is initialised before calling - class ImageRotate - { - public: - /** - * @param source image (file name - has to exist in an resource group) - * @param name of the destination texture to save to (in memory) - * @param angle in degrees to turn - */ - static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); - }; - -} -} - -#endif From ef1678e47eaf1974fd8322b8c1b70c6653965b15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:32:02 +0100 Subject: [PATCH 327/330] Oops, rotation center should be dynamic --- apps/openmw/mwgui/cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 852eea29a4..15f61d5b66 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -110,7 +110,7 @@ namespace MWGui mWidget->setImageTexture(texture); MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setCenter(MyGUI::IntPoint(mSize.width/2,mSize.height/2)); rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); } From ccb7ed93b3d231c112b7ab7541178e19cb2adcf3 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 2 Mar 2013 03:54:25 +0400 Subject: [PATCH 328/330] fix for https://bugs.openmw.org/issues/593 --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +++- apps/openmw/mwdialogue/filter.cpp | 34 ++++++++++++++----- apps/openmw/mwdialogue/filter.hpp | 3 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f548c46f75..43d201fbf3 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -251,8 +251,12 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - if (const ESM::DialInfo *info = filter.search (dialogue, true)) + std::vector infos; + filter.search (infos, dialogue, true, true); + if (!infos.empty()) { + const ESM::DialInfo* info = infos[rand() % infos.size()]; + parseText (info->mResponse); if (dialogue.mType==ESM::Dialogue::Persuasion) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 6f9d8b42fc..4391716fd6 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -559,8 +559,22 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const +const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { + std::vector suitableInfos; + search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + + if (suitableInfos.empty()) + return NULL; + else + return suitableInfos[0]; +} + +void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, + const bool fallbackToInfoRefusal, bool searchAll) const +{ + suitableInfos.clear(); + bool infoRefusal = false; // Iterate over topic responses to find a matching one @@ -569,14 +583,17 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) - return &*iter; + if (testDisposition (*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } else infoRefusal = true; } } - if (infoRefusal && fallbackToInfoRefusal) + if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -588,11 +605,12 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) - return &*iter; + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } } - - return 0; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 707c0154b6..e1e22a51ca 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -51,7 +51,8 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; + void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. From e3fd4b842954e31e15e81cd71eb4ad2b5acca69f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 17:57:34 -0800 Subject: [PATCH 329/330] Fix restoring the original texture name when the DDS check fails --- components/nifogre/ogre_nif_loader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 0b53177e13..d33243dd47 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -621,7 +621,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + Misc::StringUtils::lowerCase(texName); + { + texName = st->filename; + Misc::StringUtils::toLower(texName); + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + } } } else warn("Found internal texture, ignoring."); From 0f4f91605a402f636e45ac81cd45708eab6fa121 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Mar 2013 11:19:48 +0100 Subject: [PATCH 330/330] some cleanup --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 7 ++++--- apps/openmw/mwdialogue/filter.cpp | 21 ++++++++++--------- apps/openmw/mwdialogue/filter.hpp | 6 +++++- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 43d201fbf3..35f0c94937 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -2,6 +2,7 @@ #include "dialoguemanagerimp.hpp" #include +#include #include #include @@ -251,11 +252,11 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - std::vector infos; - filter.search (infos, dialogue, true, true); + std::vector infos = filter.list (dialogue, true, true); + if (!infos.empty()) { - const ESM::DialInfo* info = infos[rand() % infos.size()]; + const ESM::DialInfo* info = infos[std::rand() % infos.size()]; parseText (info->mResponse); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 4391716fd6..10740794ea 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -561,8 +561,7 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { - std::vector suitableInfos; - search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + std::vector suitableInfos = list (dialogue, fallbackToInfoRefusal, false); if (suitableInfos.empty()) return NULL; @@ -570,10 +569,10 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, return suitableInfos[0]; } -void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, - const bool fallbackToInfoRefusal, bool searchAll) const +std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const { - suitableInfos.clear(); + std::vector infos; bool infoRefusal = false; @@ -584,16 +583,16 @@ void MWDialogue::Filter::search (std::vector& suitableInfo if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { if (testDisposition (*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } else infoRefusal = true; } } - if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) + if (infos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -606,11 +605,13 @@ void MWDialogue::Filter::search (std::vector& suitableInfo for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } } + + return infos; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index e1e22a51ca..069bf6353d 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWDIALOGUE_FILTER_H #define GAME_MWDIALOGUE_FILTER_H +#include + #include "../mwworld/ptr.hpp" namespace ESM @@ -51,7 +53,9 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + std::vector list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.