From 106ef4c9369e303aaf79654c597961e1516f3522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 22:53:03 +0200 Subject: [PATCH 001/134] Rotate script --- apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7e9827062..7810c2874 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -318,5 +318,7 @@ op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference +op 0x20001ff: Rotate +op 0x2000200: Rotate, explicit reference -opcodes 0x20001ff-0x3ffffff unused +opcodes 0x2000201-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 49688efb5..6c4fb0f4b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -542,6 +542,42 @@ namespace MWScript } }; + template + class OpRotate : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + runtime.pop(); + + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + + //Axis in morrowind are inverted + if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -568,6 +604,8 @@ namespace MWScript const int opcodePlaceAtMeExplicit = 0x200019e; const int opcodeModScale = 0x20001e3; const int opcodeModScaleExplicit = 0x20001e4; + const int opcodeRotate = 0x20001ff; + const int opcodeRotateExplicit = 0x2000200; void registerExtensions (Compiler::Extensions& extensions) { @@ -585,6 +623,7 @@ namespace MWScript extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); + extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -614,6 +653,8 @@ namespace MWScript interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); interpreter.installSegment5(opcodeModScale,new OpModScale); interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); + interpreter.installSegment5(opcodeRotate,new OpRotate); + interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); } } } From acb1b5f0025a01e827a18159aeef9a95cbbebdf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 22:54:32 -0700 Subject: [PATCH 002/134] Try to handle NiBSAnimationNode This is still incomplete guess work. Currently it seems as though flag 0x20 specifies whether the controllers auto-play (if on), rather than follow the object's animation time. --- components/nifogre/ogrenifloader.cpp | 26 ++++++++++++++++---------- components/nifogre/skeleton.cpp | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f43131..ec53b79aa 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -492,7 +492,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags) + ObjectList &objectlist, int flags, int animflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -503,7 +503,10 @@ class NIFObjectLoader if (node->name.find("marker") != std::string::npos) return; - flags |= node->flags; + if(node->recType == Nif::RC_NiBSAnimationNode) + animflags |= node->flags; + else + flags |= node->flags; Nif::ExtraPtr e = node->extra; while(!e.empty()) @@ -539,9 +542,10 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -552,9 +556,10 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -599,9 +604,10 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -627,7 +633,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); } } } @@ -674,7 +680,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef0..28df4894d 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -164,6 +164,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From f4695ec4ac487812b2b9120e1ebd90726ba9fd58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 00:06:40 -0700 Subject: [PATCH 003/134] Cleanup NIFObjectLoader some --- components/nifogre/ogrenifloader.cpp | 213 +++++++++++++-------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ec53b79aa..631d39728 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -331,9 +331,9 @@ public: -/** Manual resource loader for NIF objects (meshes, particle systems, etc). - * This is the main class responsible for translating the internal NIF - * structures into something Ogre can use. +/** Object creator for NIFs. This is the main class responsible for creating + * "live" Ogre objects (entities, particle systems, controllers, etc) from + * their NIF equivalents. */ class NIFObjectLoader { @@ -349,6 +349,57 @@ class NIFObjectLoader } + static void createEntity(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *node, int flags, int animflags) + { + const Nif::NiTriShape *shape = static_cast(node); + + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); + + Ogre::Entity *entity = sceneMgr->createEntity(fullname); + entity->setVisible(!(flags&0x01)); + + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) + { + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); + else + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } + } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + } + + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); @@ -416,9 +467,9 @@ class NIFObjectLoader } } - static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static void createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *partnode, int flags, int animflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -426,67 +477,63 @@ class NIFObjectLoader else if(partnode->recType == Nif::RC_NiRotatingParticles) particledata = static_cast(partnode)->data.getPtr(); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); - try { - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents)); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleRadius*2.0f, - particledata->particleRadius*2.0f); - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - // TODO: There is probably a field or flag to specify this, as some - // particle effects have it and some don't. - partsys->setKeepParticlesInLocalSpace(true); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) { - if(ctrl->recType == Nif::RC_NiParticleSystemController) + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - createParticleEmitterAffectors(partsys, partctrl); - if(!partctrl->emitter.empty() && !partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); - } + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - ctrl = ctrl->next; - } - - if(!partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); } + ctrl = ctrl->next; } - catch(std::exception &e) { - std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); - partsys = NULL; - }; - return partsys; + + if(!partsys->isAttached()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); + } + + partsys->setVisible(!(flags&0x01)); + objectlist.mParticles.push_back(partsys); } @@ -569,61 +616,13 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); - - objectlist.mEntities.push_back(entity); - if(objectlist.mSkelBase) - { - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(objectlist.mSkelBase); - else - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - ctrl = ctrl->next; - } + createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); } if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); - if(partsys != NULL) - { - partsys->setVisible(!(flags&0x01)); - objectlist.mParticles.push_back(partsys); - } + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); } const Nif::NiNode *ninode = dynamic_cast(node); From 4e0233cf06384472ef49f47de87fcccc1068066c Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 14 Apr 2013 21:42:37 +0200 Subject: [PATCH 004/134] Base local rotations implementation --- .../mwscript/transformationextensions.cpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6c4fb0f4b..922353974 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -553,26 +553,30 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float *objRot = ptr.getRefData().getPosition().rot; - //Axis in morrowind are inverted - if (axis == "y") + if (axis == "x") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + objRot[0]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; } - else if (axis == "x") + else if (axis == "y") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + objRot[1]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + objRot[2]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); } + else throw std::runtime_error ("invalid rotation axis: " + axis); } From bf8bc989fc0184f59aa40f9d3a028d4fad6f749b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 12:52:20 -0700 Subject: [PATCH 005/134] Recognize and partly handle NiBSParticleNode --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 12 +++++++----- components/nifogre/skeleton.cpp | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 3b41e96a7..2c4f3506e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -208,7 +208,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, - { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiBSParticleNode }, { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 361af3f64..97b10503e 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -39,6 +39,7 @@ enum RecordType RC_NiTriShape, RC_NiRotatingParticles, RC_NiAutoNormalParticles, + RC_NiBSParticleNode, RC_NiCamera, RC_NiTexturingProperty, RC_NiMaterialProperty, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 631d39728..1ed5e24a3 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -469,7 +469,7 @@ class NIFObjectLoader static void createParticleSystem(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, ObjectList &objectlist, - const Nif::Node *partnode, int flags, int animflags) + const Nif::Node *partnode, int flags, int partflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -539,7 +539,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags, int animflags) + ObjectList &objectlist, int flags, int animflags, int partflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -552,6 +552,8 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; + else if(node->recType == Nif::RC_NiBSParticleNode) + partflags |= node->flags; else flags |= node->flags; @@ -622,7 +624,7 @@ class NIFObjectLoader if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, partflags); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -632,7 +634,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags, partflags); } } } @@ -679,7 +681,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags, 0); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 28df4894d..75bc90715 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -165,6 +165,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ + node->recType == Nif::RC_NiBSParticleNode || node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From 7000a1aa3eba373f33741e7f208e1af8bd6c45e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 13:50:55 -0700 Subject: [PATCH 006/134] Add a ParticleSystemController --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1ed5e24a3..69f14b663 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -329,6 +329,35 @@ public: typedef DefaultFunction Function; }; +class ParticleSystemController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::ParticleSystem *mParticleSys; + float mEmitStart; + float mEmitStop; + + public: + Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) + : mParticleSys(psys) + , mEmitStart(pctrl->startTime) + , mEmitStop(pctrl->stopTime) + { + } + + Ogre::Real getValue() const + { return 0.0f; } + + void setValue(Ogre::Real value) + { + mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); + } + }; + + typedef DefaultFunction Function; +}; /** Object creator for NIFs. This is the main class responsible for creating @@ -521,6 +550,13 @@ class NIFObjectLoader Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } + + Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } From f9dee25fd1c0218fd40ac11e2b3406bbb70283b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 16:56:35 -0700 Subject: [PATCH 007/134] Store the base skeleton entity in MWRender::Animation --- apps/openmw/mwrender/animation.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/animation.hpp | 3 ++- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a849b20ef..d6f762ab7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -33,6 +33,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) , mInsert(NULL) + , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) @@ -65,7 +66,7 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { - if(!mObjectList.mSkelBase) + if(!mSkelBase) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); @@ -81,7 +82,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.clear(); Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -127,7 +128,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } for(int i = 0;i < skel->getNumAnimations();i++) @@ -152,7 +153,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model mObjectList = NifOgre::Loader::createObjects(mInsert, model); if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); + mSkelBase = mObjectList.mSkelBase; + + Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -164,7 +167,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // 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 = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); @@ -182,9 +185,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model Ogre::Node *Animation::getNode(const std::string &name) { - if(mObjectList.mSkelBase) + if(mSkelBase) { - Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); if(skel->hasBone(name)) return skel->getBone(name); } @@ -508,11 +511,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); - if(mObjectList.mSkelBase) + if(mSkelBase) { // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mSkelBase->getAllAnimationStates()->_notifyDirty(); } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 029c56523..32344a2c0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -42,7 +42,8 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; - Ogre::SceneNode* mInsert; + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d..a2446b867 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -359,8 +359,7 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, - mInsert, model); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); for(size_t i = 0;i < objects.mEntities.size();i++) { objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -408,7 +407,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; From 69084139aaf2c4711061dd62a84666d6f34c6d10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 17:58:21 -0700 Subject: [PATCH 008/134] Use an array of objectlists, instead of one base objectlist and an array of 'animation sources' --- apps/openmw/mwrender/activatoranimation.cpp | 10 +- apps/openmw/mwrender/animation.cpp | 136 +++++++------------- apps/openmw/mwrender/animation.hpp | 14 +- apps/openmw/mwrender/creatureanimation.cpp | 21 ++- apps/openmw/mwrender/npcanimation.cpp | 27 ++-- 5 files changed, 75 insertions(+), 133 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4630208b4..27ddce339 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -27,9 +27,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) std::string mesh = "meshes\\" + ref->mBase->mModel; createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,14 +38,12 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); } - setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d6f762ab7..30bcd3c4c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -55,68 +55,45 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - destroyObjectList(sceneMgr, mObjectList); - - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + for(size_t i = 0;i < mObjectLists.size();i++) + destroyObjectList(sceneMgr, mObjectLists[i]); + mObjectLists.clear(); } } -void Animation::setAnimationSources(const std::vector &names) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { - if(!mSkelBase) - return; - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + assert(!mInsert); + mInsert = node->createChildSceneNode(); + assert(mInsert); - mCurrentControllers = &mObjectList.mControllers; - mCurrentAnim = NULL; - mCurrentKeys = NULL; - mAnimVelocity = 0.0f; - mAccumRoot = NULL; - mNonAccumRoot = NULL; - mTextKeys.clear(); - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + mObjectLists.resize(1); - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - std::vector::const_iterator nameiter; - for(nameiter = names.begin();nameiter != names.end();nameiter++) + mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectLists[0].mSkelBase) { - mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); - if(!mAnimationSources.back().mSkelBase) + mSkelBase = mObjectLists[0].mSkelBase; + + Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - std::cerr<< "Failed to get skeleton source "<<*nameiter < *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); - if(!dstval) continue; - - const Ogre::String &trgtname = dstval->getNode()->getName(); - if(!skelinst->hasBone(trgtname)) continue; - - Ogre::Bone *bone = skelinst->getBone(trgtname); - dstval->setNode(bone); + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); } - for(size_t i = 0;i < objects.mControllers.size();i++) - { - if(objects.mControllers[i].getSource().isNull()) - objects.mControllers[i].setSource(ctrlval); - } + // 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 = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); - Ogre::Entity *ent = objects.mSkelBase; - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); + boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { Ogre::Bone *bone = boneiter.getNext(); @@ -143,43 +120,14 @@ void Animation::setAnimationSources(const std::vector &names) break; } } -} - -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) -{ - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectList = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectList.mSkelBase) - { - mSkelBase = mObjectList.mSkelBase; - - Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - 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 = mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectList.mControllers.size();i++) + for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) { - if(mObjectList.mControllers[i].getSource().isNull()) - mObjectList.mControllers[i].setSource(ctrlval); + if(mObjectLists[0].mControllers[i].getSource().isNull()) + mObjectLists[0].mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectList.mControllers; + mCurrentControllers = &mObjectLists[0].mControllers; } @@ -197,9 +145,9 @@ Ogre::Node *Animation::getNode(const std::string &name) bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) + for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase->hasAnimationState(anim)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -449,7 +397,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { @@ -513,9 +461,19 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mSkelBase) { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + for(size_t i = 0;i < mObjectLists.size();i++) + { + Ogre::Entity *ent = mObjectLists[i].mSkelBase; + if(!ent) continue; + + Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); + if(skelsrc != skeldst) + updateSkeletonInstance(skelsrc, skeldst); + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + ent->getAllAnimationStates()->_notifyDirty(); + } } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32344a2c0..3c7433db9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,15 +44,13 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - NifOgre::ObjectList mObjectList; + std::vector mObjectLists; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mAnimationSources; - std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -83,16 +81,6 @@ protected: 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); - - /* 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 createObjectList(Ogre::SceneNode *node, const std::string &model); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c714a2372..7084974b8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,10 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + + createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,19 +43,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Actors); part->setRenderQueueGroup(RQG_Alpha); } - - 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 a2446b867..a713ae79e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,10 +96,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createObjectList(node, smodel); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + + createObjectList(node, smodel/*skelnames*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *base = mObjectList.mEntities[i]; + Ogre::Entity *base = mObjectLists[0].mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -111,9 +119,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if(mVisibilityFlags != 0) @@ -121,15 +129,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor part->setRenderQueueGroup(RQG_Alpha); } - std::vector skelnames(1, smodel); - if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); - else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); - if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - setAnimationSources(skelnames); - forceUpdate(); } From 972481f63f7ef724364b6cf9672aac50fc558788 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 16:45:53 +0200 Subject: [PATCH 009/134] Working rotate, rotateworld --- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 + apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 56 +++++++++++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ++ apps/openmw/mwworld/worldimp.hpp | 2 + 8 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 976d7d84c..b34117df2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,6 +251,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890..94a30d759 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -230,6 +230,8 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + virtual void localRotateObject (const MWWorld::Ptr& ptr, float rotation, Ogre::Vector3 axis) = 0; + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a6..b3a080bf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,3 +1200,8 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } + +int WindowManager::getFPS() const +{ + return mFPS; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a..3a7296b5b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,6 +248,8 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); + virtual int getFPS() const; + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7810c2874..b7ee2d31c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -320,5 +320,7 @@ op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference op 0x20001ff: Rotate op 0x2000200: Rotate, explicit reference +op 0x2000201: RotateWorld +op 0x2000202: RotateWorld, explicit reference -opcodes 0x2000201-0x3ffffff unused +opcodes 0x2000203-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 922353974..41bacf110 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,6 +13,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -549,11 +550,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + const MWWorld::Ptr& ptr = R()(runtime); std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -562,19 +563,22 @@ namespace MWScript { objRot[0]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { objRot[1]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { objRot[2]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } else @@ -582,6 +586,43 @@ namespace MWScript } }; + template + class OpRotateWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + runtime.pop(); + + float *objRot = ptr.getRefData().getPosition().rot; + + float ax = Ogre::Radian(objRot[0]).valueDegrees(); + float ay = Ogre::Radian(objRot[1]).valueDegrees(); + float az = Ogre::Radian(objRot[2]).valueDegrees(); + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -610,6 +651,8 @@ namespace MWScript const int opcodeModScaleExplicit = 0x20001e4; const int opcodeRotate = 0x20001ff; const int opcodeRotateExplicit = 0x2000200; + const int opcodeRotateWorld = 0x2000201; + const int opcodeRotateWorldExplicit = 0x2000202; void registerExtensions (Compiler::Extensions& extensions) { @@ -628,6 +671,7 @@ namespace MWScript extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); + extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -659,6 +703,8 @@ namespace MWScript interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); interpreter.installSegment5(opcodeRotate,new OpRotate); interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); + interpreter.installSegment5(opcodeRotateWorld,new OpRotateWorld); + interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2f..c5ebbb306 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,6 +826,12 @@ namespace MWWorld } } + void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) + { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } + void World::adjustPosition(const Ptr &ptr) { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee..59a359b6b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -254,6 +254,8 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis); + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. From 763308868d501bc7bd7102d6a442855f8c155f1b Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 17:45:18 +0200 Subject: [PATCH 010/134] Fixed rotation speed --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwscript/transformationextensions.cpp | 5 ++--- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b34117df2..976d7d84c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,8 +251,6 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b3a080bf2..f994683a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,8 +1200,3 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } - -int WindowManager::getFPS() const -{ - return mFPS; -} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a7296b5b..3c9fc586a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,8 +248,6 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); - virtual int getFPS() const; - private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 41bacf110..8ac5a7802 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,7 +13,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -554,7 +553,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -597,7 +596,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; From 1b1f9f7921d91bc2c2c853cfc0b0f5c71fba0574 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 18:55:28 -0700 Subject: [PATCH 011/134] Allow multiple ObjectLists to be created for Animations. addObjectList may not currently be called outside of the related constructor. --- apps/openmw/mwrender/activatoranimation.cpp | 13 ++-- apps/openmw/mwrender/animation.cpp | 80 +++++++++++++-------- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 17 +++-- apps/openmw/mwrender/npcanimation.cpp | 39 +++------- components/nifogre/ogrenifloader.cpp | 7 +- components/nifogre/ogrenifloader.hpp | 2 +- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 27ddce339..1f9a2e23c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -24,12 +24,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + const std::string name = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), name, false); + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,9 +39,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Misc); part->setRenderQueueGroup(RQG_Alpha); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30bcd3c4c..979046ea0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -36,7 +36,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) - , mAccumulate(Ogre::Vector3::ZERO) + , mAccumulate(0.0f) , mLastPosition(0.0f) , mCurrentControllers(NULL) , mCurrentKeys(NULL) @@ -62,20 +62,24 @@ Animation::~Animation() } -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) +void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly) { - assert(!mInsert); - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectLists.resize(1); - - mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectLists[0].mSkelBase) + if(!mInsert) { - mSkelBase = mObjectLists[0].mSkelBase; + mInsert = node->createChildSceneNode(); + assert(mInsert); + } + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + NifOgre::ObjectList &objlist = mObjectLists.back(); + if(objlist.mSkelBase) + { + if(!mSkelBase) + mSkelBase = objlist.mSkelBase; + + Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -87,11 +91,28 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // 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 = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objlist.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + if(mSkelBase != objlist.mSkelBase) + { + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!baseinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = baseinst->getBone(trgtname); + dstval->setNode(bone); + } + } + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -120,14 +141,14 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model break; } } - - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { - if(mObjectLists[0].mControllers[i].getSource().isNull()) - mObjectLists[0].mControllers[i].setSource(ctrlval); + if(objlist.mControllers[i].getSource().isNull()) + objlist.mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectLists[0].mControllers; + + if(!mCurrentControllers || (*mCurrentControllers).size() == 0) + mCurrentControllers = &objlist.mControllers; } @@ -399,9 +420,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); + Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); + mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; @@ -456,20 +478,22 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mCurrentControllers->size();i++) + + for(size_t i = 0;i < (*mCurrentControllers).size();i++) (*mCurrentControllers)[i].update(); if(mSkelBase) { - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); - for(size_t i = 0;i < mObjectLists.size();i++) + const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - Ogre::Entity *ent = mObjectLists[i].mSkelBase; + Ogre::Entity *ent = iter->mSkelBase; if(!ent) continue; - Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); - if(skelsrc != skeldst) - updateSkeletonInstance(skelsrc, skeldst); + Ogre::SkeletonInstance *inst = ent->getSkeleton(); + if(baseinst != inst) + updateSkeletonInstance(baseinst, inst); + // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. ent->getAllAnimationStates()->_notifyDirty(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3c7433db9..79262f3c5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -81,7 +81,7 @@ protected: bool handleEvent(float time, const std::string &evt); - void createObjectList(Ogre::SceneNode *node, const std::string &model); + void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7084974b8..a48b8da9f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,15 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); + addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); - createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), model, false); + + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -43,11 +43,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a713ae79e..3ef357440 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,38 +96,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); + addObjectList(node, smodel, true); if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); + addObjectList(node, "meshes\\base_anim_female.nif", true); else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + addObjectList(node, "meshes\\argonian_swimkna.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - - createObjectList(node, smodel/*skelnames*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) - { - Ogre::Entity *base = mObjectLists[0].mEntities[i]; - - base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if (mVisibilityFlags != 0) - base->setVisibilityFlags(mVisibilityFlags); - - for(unsigned int j=0; j < base->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = base->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) - { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; - - part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if(mVisibilityFlags != 0) - part->setVisibilityFlags(mVisibilityFlags); - part->setRenderQueueGroup(RQG_Alpha); - } + addObjectList(node, "meshes\\"+mNpc->mModel, true); forceUpdate(); } @@ -406,14 +381,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; - updateSkeletonInstance(skelsrc, ent->getSkeleton()); + updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); } + return ret; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 69f14b663..04cdb142f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -800,12 +800,15 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group, 0xC0000000); + + if(objectlist.mSkelBase) + parentNode->attachObject(objectlist.mSkelBase); return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fa5182aea..e3bb55064 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,7 @@ public: std::string name, const std::string &group="General"); - static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + static ObjectList createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); }; From 4ce98e9bd65ff2035e2f36e89a90cb6f892472fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 20:37:10 -0700 Subject: [PATCH 012/134] Store iterators for start and stop keys --- apps/openmw/mwrender/animation.cpp | 51 ++++++++++++------------------ apps/openmw/mwrender/animation.hpp | 7 ++-- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 979046ea0..11876a247 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,11 +38,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) + , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) - , mCurrentAnim(NULL) , mCurrentTime(0.0f) - , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -313,35 +312,26 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { - mNextKey = mCurrentKeys->begin(); + mStartKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + mStartKey++; + if(mStartKey != mCurrentKeys->end()) + mCurrentTime = mStartKey->first; else { - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; - else - { - mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; - } + mStartKey = mCurrentKeys->begin(); + mCurrentTime = mStartKey->first; } + mNextKey = mStartKey; 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(); + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; } if(mNonAccumRoot) @@ -390,7 +380,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; } @@ -400,7 +390,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; return true; @@ -455,13 +445,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; - if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) + if(mNextKey->first > targetTime) { - mCurrentTime = std::min(mStopTime, targetTime); + mCurrentTime = targetTime; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); - timepassed = targetTime - mCurrentTime; break; } @@ -472,7 +460,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mCurrentTime = time; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); + + mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 79262f3c5..f8ddceeaa 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,13 +50,14 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; + Ogre::Animation *mCurrentAnim; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::Animation *mCurrentAnim; float mCurrentTime; - float mStopTime; bool mPlaying; bool mLooping; @@ -77,7 +78,7 @@ protected: * 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); + void reset(const std::string &start, const std::string &stop=std::string()); bool handleEvent(float time, const std::string &evt); From 36170c5374402f06b49bcf63d7c856572072ebda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 01:20:32 -0700 Subject: [PATCH 013/134] Use flag enums instead of hard-coded hex values --- components/nif/node.hpp | 18 +++++++------ components/nifbullet/bulletnifloader.cpp | 6 ++--- components/nifogre/ogrenifloader.cpp | 32 +++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 9c345baab..917bc8add 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -128,13 +128,17 @@ struct NiNode : Node NodeList children; NodeList effects; - /* Known NiNode flags: - 0x01 hidden - 0x02 use mesh for collision - 0x04 use bounding box for collision (?) - 0x08 unknown, but common - 0x20, 0x40, 0x80 unknown - */ + enum Flags { + Flag_Hidden = 0x0001, + Flag_MeshCollision = 0x0002, + Flag_BBoxCollision = 0x0004 + }; + enum BSAnimFlags { + AnimFlag_AutoPlay = 0x0020 + }; + enum BSParticleFlags { + ParticleFlag_AutoPlay = 0x0020 + }; void read(NIFStream *nif) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6bd43f6e3..a3eff95c3 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -255,9 +255,9 @@ void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif:: assert(shape != NULL); // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision + bool hidden = (flags&Nif::NiNode::Flag_Hidden) != 0; + bool collide = (flags&Nif::NiNode::Flag_MeshCollision) != 0; + bool bbcollide = (flags&Nif::NiNode::Flag_BBoxCollision) != 0; // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 04cdb142f..2e77adb08 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -394,7 +394,7 @@ class NIFObjectLoader NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); + entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mEntities.push_back(entity); if(objectlist.mSkelBase) @@ -417,10 +417,11 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -551,10 +552,11 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -568,7 +570,7 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - partsys->setVisible(!(flags&0x01)); + partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mParticles.push_back(partsys); } @@ -627,10 +629,11 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -641,10 +644,11 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 1e92ffc3147229b9d1b08e972b4372f7b8ca9f49 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:17:19 +0200 Subject: [PATCH 014/134] Added rotation layer --- .../mwscript/transformationextensions.cpp | 27 +++++++++---------- apps/openmw/mwworld/refdata.cpp | 12 ++++++++- apps/openmw/mwworld/refdata.hpp | 10 +++++++ apps/openmw/mwworld/scene.cpp | 7 +++++ apps/openmw/mwworld/worldimp.cpp | 6 +++-- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8ac5a7802..e2d701268 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -102,6 +102,11 @@ namespace MWScript } else throw std::runtime_error ("invalid ration axis: " + axis); + + //Local rotations clear + ptr.getRefData().getLocalRotation().rot[0]=0; + ptr.getRefData().getLocalRotation().rot[1]=0; + ptr.getRefData().getLocalRotation().rot[2]=0; } }; @@ -148,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -556,27 +561,19 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objRot = ptr.getRefData().getPosition().rot; - if (axis == "x") { - objRot[0]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - objRot[1]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - objRot[2]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 4be287810..db565c451 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -19,6 +19,7 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; + mLocalRotation = refData.mLocalRotation; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -34,7 +35,11 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0) - {} + { + mLocalRotation.rot[0]=0; + mLocalRotation.rot[1]=0; + mLocalRotation.rot[2]=0; + } RefData::RefData (const RefData& refData) : mBaseNode(0), mCustomData (0) @@ -141,6 +146,11 @@ namespace MWWorld return mPosition; } + LocalRotation& RefData::getLocalRotation() + { + return mLocalRotation; + } + void RefData::setCustomData (CustomData *data) { delete mCustomData; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 3a6e0fc9f..c3aa647ec 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; @@ -18,6 +20,10 @@ namespace ESM namespace MWWorld { + struct LocalRotation{ + float rot[3]; + }; + class CustomData; class RefData @@ -34,6 +40,8 @@ namespace MWWorld ESM::Position mPosition; + LocalRotation mLocalRotation; + CustomData *mCustomData; void copy (const RefData& refData); @@ -78,6 +86,8 @@ namespace MWWorld ESM::Position& getPosition(); + LocalRotation& getLocalRotation(); + void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \æ data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f76131..b11b59ac6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -50,6 +50,13 @@ namespace rendering.addObject(ptr); class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + + //To keep local-rotations + const float *local = ptr.getRefData().getLocalRotation().rot; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[0], Ogre::Vector3::UNIT_X); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[1], Ogre::Vector3::UNIT_Y); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[2], Ogre::Vector3::UNIT_Z); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); class_.adjustPosition(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 52d0d953a..69bcad619 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,8 +826,10 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } } void World::adjustPosition(const Ptr &ptr) From 1fd59d0ce0c63e893f6203a723579d25dc3ec7c9 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:21:54 +0200 Subject: [PATCH 015/134] Removed useless include --- apps/openmw/mwworld/refdata.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index c3aa647ec..77ceb3721 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,8 +5,6 @@ #include "../mwscript/locals.hpp" -#include - namespace Ogre { class SceneNode; From e3a9f73eb6008159b3ba1fa1fa15451050360407 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:40:34 +0200 Subject: [PATCH 016/134] Improved getangle script behaviour --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e2d701268..beb6c3d8c 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); From 3def2a0f453932c8fed8e83bc2654082e6ab0c46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 19:16:45 -0700 Subject: [PATCH 017/134] Treat the particle random values as the max differential --- components/nifogre/ogrenifloader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 2e77adb08..c5cc45ae9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -433,11 +433,11 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, - partctrl->velocity+partctrl->velocityRandom); + emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f); emitter->setEmissionRate(partctrl->emitRate); - emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, - partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setTimeToLive(partctrl->lifetime - partctrl->lifetimeRandom*0.5f, + partctrl->lifetime + partctrl->lifetimeRandom*0.5f); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); From 50bb92beb349f340801923565db15c1c78832c38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 02:01:50 -0700 Subject: [PATCH 018/134] Use a method to set the visibility flags and render queue. --- apps/openmw/mwrender/activatoranimation.cpp | 24 +------------------ apps/openmw/mwrender/animation.cpp | 26 +++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 25 +------------------- apps/openmw/mwrender/npcanimation.cpp | 21 ++++------------- 5 files changed, 35 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 1f9a2e23c..c3a3045c2 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,10 +1,5 @@ #include "activatoranimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -27,24 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Misc); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 11876a247..8e5bd0108 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -150,6 +152,30 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mCurrentControllers = &objlist.mControllers; } +void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) +{ + for(size_t i = 0;i < objlist.mEntities.size();i++) + { + Ogre::Entity *ent = objlist.mEntities[i]; + if(visflags != 0) + ent->setVisibilityFlags(visflags); + + for(unsigned int j = 0;j < ent->getNumSubEntities();++j) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue); + } + } + for(size_t i = 0;i < objlist.mParticles.size();i++) + { + Ogre::ParticleSystem *part = objlist.mParticles[i]; + if(visflags != 0) + part->setVisibilityFlags(visflags); + // TODO: Check particle material for actual transparency + part->setRenderQueueGroup(transqueue); + } +} + Ogre::Node *Animation::getNode(const std::string &name) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f8ddceeaa..db2195c34 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -85,6 +85,8 @@ protected: void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); + static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a48b8da9f..51632b2ee 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,10 +1,5 @@ #include "creatureanimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -30,25 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Actors); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cea0225ef..0b05b4ba6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,25 +361,13 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); - for(size_t i = 0;i < objects.mEntities.size();i++) - { - objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); + setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha); - for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } + for(size_t i = 0;i < objects.mEntities.size();i++) + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); for(size_t i = 0;i < objects.mParticles.size();i++) - { objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); - objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); - } + if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); @@ -395,6 +383,7 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + return objects; } From 1051fa51a71f964fa55a73d054c558862ee95ed0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 15:07:08 -0700 Subject: [PATCH 019/134] Recognize NiFlipController --- components/nif/controller.hpp | 23 +++++++++++++++++++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nif/recordptr.hpp | 1 + 4 files changed, 26 insertions(+) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index aa6a9ef4f..011e0e445 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -303,5 +303,28 @@ public: } }; +class NiFlipController : public Controller +{ +public: + int mTexSlot; + float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources + NiSourceTextureList mSources; + + void read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } +}; + } // Namespace #endif diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 2c4f3506e..a66bd99db 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -235,6 +235,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiFlipController", &construct , RC_NiFlipController }, { "NiAmbientLight", &construct , RC_NiLight }, { "NiDirectionalLight", &construct , RC_NiLight }, { "NiTextureEffect", &construct , RC_NiTextureEffect }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 97b10503e..3f852ed83 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiFlipController, RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea12..2ecde7f60 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -163,6 +163,7 @@ typedef RecordPtrT NiAutoNormalParticlesDataPtr; typedef RecordListT NodeList; typedef RecordListT PropertyList; +typedef RecordListT NiSourceTextureList; } // Namespace #endif From f37a71f02584dddfe50655dea4689aaea4bf89f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 23:56:47 -0700 Subject: [PATCH 020/134] Use a separate method to build node-based controllers --- components/nifogre/ogrenifloader.cpp | 77 +++++++++++++++------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5cc45ae9..21acfca0f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -575,6 +575,44 @@ class NIFObjectLoader } + static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectList &objectlist, int animflags) + { + do { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + } + ctrl = ctrl->next; + } while(!ctrl.empty()); + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -613,6 +651,9 @@ class NIFObjectLoader e = e->extra; } + if(!node->controller.empty()) + createNodeControllers(name, node->controller, objectlist, animflags); + if(node->recType == Nif::RC_NiCamera) { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); @@ -620,42 +661,6 @@ class NIFObjectLoader objectlist.mCameras.push_back(trgtbone); } - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); From ace7d647e5af1182a972505bb6f3aa1a01ee16d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 15:35:19 -0700 Subject: [PATCH 021/134] Add a method to apply a NodeTargetValue-based controller to a specified node. --- components/nifogre/ogrenifloader.cpp | 147 +++++++++++++++------------ components/nifogre/ogrenifloader.hpp | 2 + 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 21acfca0f..90147a43b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -104,7 +104,7 @@ public: private: std::vector mData; - virtual bool calculate(Ogre::Real time) + bool calculate(Ogre::Real time) const { if(mData.size() == 0) return true; @@ -144,16 +144,21 @@ public: , mData(data->mVis) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + bool vis = calculate(time); + setVisible(node, vis); + } + virtual Ogre::Real getValue() const { // Should not be called - return 1.0f; + return 0.0f; } virtual void setValue(Ogre::Real time) { - bool vis = calculate(time); - setVisible(mNode, vis); + Value::applyToNode(mNode, time); } }; @@ -170,6 +175,66 @@ public: Nif::Vector3KeyList mTranslations; Nif::FloatKeyList mScales; + static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); + } + return Ogre::Quaternion(); + } + public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) : NodeTargetValue(target) @@ -178,6 +243,16 @@ public: , mScales(data->mScales) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + if(mRotations.mKeys.size() > 0) + node->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + node->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + } + virtual Ogre::Real getValue() const { // Should not be called @@ -186,69 +261,7 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) - { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } - } + Value::applyToNode(mNode, time); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e3bb55064..b53815fa0 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -85,6 +85,8 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } + virtual void applyToNode(Ogre::Node *node, float time) const = 0; + void setNode(Ogre::Node *target) { mNode = target; } Ogre::Node *getNode() const From 835ff8eb1eb36bc16cffaca85343ee86d1533275 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 17:13:27 -0700 Subject: [PATCH 022/134] Avoid creating an AnimationValue per ObjectList --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8e5bd0108..56b601727 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,7 +32,8 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mPtr(ptr) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + , mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -70,7 +71,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mInsert = node->createChildSceneNode(); assert(mInsert); } - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : NifOgre::Loader::createObjectBase(mInsert, model)); @@ -145,7 +145,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(ctrlval); + objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } if(!mCurrentControllers || (*mCurrentControllers).size() == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index db2195c34..d3cb6bebb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,6 +38,7 @@ protected: mAnimation->mCurrentTime = value; } }; + Ogre::SharedPtr > mAnimationBaseValuePtr; MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; From d7c9df16f81ceebc7ee5da0b5242d33814a7e85e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:32:34 -0700 Subject: [PATCH 023/134] Store the current animation group --- apps/openmw/mwrender/animation.cpp | 3 ++- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 56b601727..ea27cbb5e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -441,9 +441,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; + mAnimVelocity = 0.0f; if(mNonAccumRoot) calcAnimVelocity(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d3cb6bebb..472a6289c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -53,6 +53,7 @@ protected: Ogre::Vector3 mLastPosition; Ogre::Animation *mCurrentAnim; + std::string mCurrentGroup; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; From 6c85d6763aec95b2f3367fea90437f4e818042e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:38:25 -0700 Subject: [PATCH 024/134] Pass "loop stop" to the character controller --- apps/openmw/mwmechanics/character.cpp | 9 +++++++++ apps/openmw/mwrender/animation.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02a5aa100..16d811528 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,6 +150,15 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { + if(evt == "loop stop") + { + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); + } + 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 ea27cbb5e..68fae99dd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -409,10 +409,10 @@ bool Animation::handleEvent(float time, const std::string &evt) reset("loop start"); if(mCurrentTime >= time) return false; + return true; } - return true; } - if(evt == "stop") + else if(evt == "stop") { if(mLooping) { From 7d59340ed6c27b4b895e9e9b7200c35bc612714c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:13:49 -0700 Subject: [PATCH 025/134] Don't clip out the group name from the textkeys --- apps/openmw/mwrender/animation.cpp | 39 +++++++++++++++++++----------- components/nifogre/skeleton.cpp | 12 +-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 68fae99dd..2f2ffccb5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -243,14 +243,16 @@ void Animation::calcAnimVelocity() if(track && track->getNumKeyFrames() > 1) { + const std::string loopstart = mCurrentGroup+": loop start"; + const std::string loopstop = mCurrentGroup+": loop stop"; float loopstarttime = 0.0f; float loopstoptime = mCurrentAnim->getLength(); NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); while(keyiter != mCurrentKeys->end()) { - if(keyiter->second == "loop start") + if(keyiter->second == loopstart) loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") + else if(keyiter->second == loopstop) { loopstoptime = keyiter->first; break; @@ -383,12 +385,6 @@ 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(); @@ -402,21 +398,36 @@ bool Animation::handleEvent(float time, const std::string &evt) return true; } - if(evt == "loop stop") + if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + { + // Not ours + return true; + } + size_t off = mCurrentGroup.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) + { + /* Do nothing */ + return true; + } + + if(evt.compare(off, len, "loop stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; } } - else if(evt == "stop") + else if(evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; @@ -424,7 +435,7 @@ bool Animation::handleEvent(float time, const std::string &evt) // fall-through } if(mController) - mController->markerEvent(time, evt); + mController->markerEvent(time, evt.substr(off)); return true; } @@ -455,7 +466,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start, stop); + reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); setLooping(loop); mPlaying = true; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 75bc90715..5eb043614 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -282,17 +282,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->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, insiter->second)); - } while(insiter++ != lastkeyiter); - + TextKeyMap groupkeys(keyiter, ++lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 2345b5e8b3d7ebe69ef901098ac9d4603973ad09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:56:40 -0700 Subject: [PATCH 026/134] Avoid storing text keys for each animation --- apps/openmw/mwrender/animation.cpp | 15 +++------------ apps/openmw/mwrender/animation.hpp | 1 - components/nifogre/ogrenifloader.hpp | 2 ++ components/nifogre/skeleton.cpp | 7 +------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2f2ffccb5..d51a30a77 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -121,24 +121,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b 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(data.isEmpty()) continue; + objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } - 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; } } @@ -451,7 +442,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mCurrentKeys = &iter->mTextKeys.begin()->second; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 472a6289c..b60bd21a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -46,7 +46,6 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjectLists; - std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b53815fa0..8e220ea38 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -50,6 +50,8 @@ struct ObjectList { // bones in the mSkelBase which are NiCamera nodes. std::vector mCameras; + std::map mTextKeys; + std::vector > mControllers; ObjectList() : mSkelBase(0) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 5eb043614..3660be81b 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,6 +193,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -255,9 +256,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) return; } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) @@ -281,9 +279,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap groupkeys(keyiter, ++lastkeyiter); - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From a3511c62cf2c120636b4960f34f0a4973292d1c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:01:30 -0700 Subject: [PATCH 027/134] Don't store textkeys in user object bindings It's a bit unwieldy to have them stored in the 'skeleton master' instead of the skeleton instance. And although the text keys are extracted for each created instance now, this shouldn't be much worse than the multimap copying going on before. Plus, proper serialization can help for future optimizations. --- apps/openmw/mwrender/animation.cpp | 16 +++------------- components/nifogre/ogrenifloader.cpp | 10 +++++++++- components/nifogre/skeleton.cpp | 11 +++++------ components/nifogre/skeleton.hpp | 3 +-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d51a30a77..31f54107e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -97,9 +97,9 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); if(mSkelBase != objlist.mSkelBase) { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; @@ -114,23 +114,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b } } - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); - boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) + if(objlist.mTextKeys.size() > 0) { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) continue; - - objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); } - - break; } } for(size_t i = 0;i < objlist.mControllers.size();i++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90147a43b..97dfc59ef 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -649,7 +649,14 @@ class NIFObjectLoader Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiStringExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); + objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + } + else if(e->recType == Nif::RC_NiStringExtraData) { const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information @@ -661,6 +668,7 @@ class NIFObjectLoader flags |= 0x80000000; } } + e = e->extra; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 3660be81b..1809212a7 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,7 +193,6 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -287,16 +286,16 @@ Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, con { /* 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. + * There are no bones used for skinning, there are no controllers, there + * are no nodes named "AttachLight", and the tree consists of NiNode, + * NiTriShape, and RootCollisionNode types only. */ if(!node->boneTrafo) { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) { const Nif::NiNode *ninode = static_cast(node); diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index c69c2a12f..e71dcfb15 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -37,8 +37,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader } static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - - 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); // Lookup to retrieve an Ogre bone handle for a given Nif record index @@ -48,6 +46,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From a7776e124cda07bc69bae504eebe6ccdb14bb07f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:22:31 -0700 Subject: [PATCH 028/134] Only set mNonAccumRoot from mSkelBase --- apps/openmw/mwrender/animation.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 31f54107e..54416c45a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,7 +98,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b boneiter.getNext()->setManuallyControlled(true); Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mSkelBase != objlist.mSkelBase) + if(mSkelBase == objlist.mSkelBase) + { + if(objlist.mTextKeys.size() > 0) + { + mAccumRoot = mInsert; + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); + } + } + else { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -113,15 +121,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b dstval->setNode(bone); } } - - if(objlist.mTextKeys.size() > 0) - { - if(!mNonAccumRoot) - { - mAccumRoot = mInsert; - mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); - } - } } for(size_t i = 0;i < objlist.mControllers.size();i++) { From 9485a4aa6df48e9370b87a9bee5aec812cdca003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 01:40:41 -0700 Subject: [PATCH 029/134] Look through the whole animation stack to find the "velocity" --- apps/openmw/mwrender/animation.cpp | 55 +++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 54416c45a..d71b33cdd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,26 +209,26 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -void Animation::calcAnimVelocity() +float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) { const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); while(!track && trackiter.hasMoreElements()) { const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + if(cur->getAssociatedNode()->getName() == bonename) track = cur; } if(track && track->getNumKeyFrames() > 1) { - const std::string loopstart = mCurrentGroup+": loop start"; - const std::string loopstop = mCurrentGroup+": loop stop"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) + float loopstoptime = anim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -245,13 +245,15 @@ void Animation::calcAnimVelocity() Ogre::TransformKeyFrame startkf(0, loopstarttime); Ogre::TransformKeyFrame endkf(0, loopstoptime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); + return startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); } } + + return 0.0f; } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -423,27 +425,34 @@ bool Animation::handleEvent(float time, const std::string &evt) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { - bool found = false; + bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &iter->mTextKeys.begin()->second; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; + Ogre::Animation *anim = skel->getAnimation(groupname); + const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + if(!foundanim) + { + mCurrentAnim = anim; + mCurrentKeys = keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; - if(mNonAccumRoot) - calcAnimVelocity(); + mAnimVelocity = 0.0f; + foundanim = true; + } - found = true; - break; + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + if(mAnimVelocity > 0.0f) break; } } - if(!found) + if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b60bd21a8..cd2523b63 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,7 +54,7 @@ protected: std::string mCurrentGroup; std::vector > *mCurrentControllers; - NifOgre::TextKeyMap *mCurrentKeys; + const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -65,7 +65,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; - void calcAnimVelocity(); + static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ From d936291dbf2b7c9e5240aad64b1d338aed2207df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 02:53:32 -0700 Subject: [PATCH 030/134] Remove an unused ostream operator<< --- components/nifogre/ogrenifloader.cpp | 9 --------- components/nifogre/ogrenifloader.hpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 97dfc59ef..dc6bb8d24 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -44,15 +44,6 @@ #include "material.hpp" #include "mesh.hpp" -namespace std -{ - -// TODO: Do something useful -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) -{ return o; } - -} - namespace NifOgre { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 8e220ea38..d0ff94217 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -98,14 +98,4 @@ typedef Ogre::SharedPtr > NodeTargetValueRealPtr; } -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 59137d93c99bdd9795a0dd0be7d3e9d4e63a2bb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:24:02 -0700 Subject: [PATCH 031/134] Partially handle NiGeomMorpherController The morphs aren't actually applied yet, but the Ogre controller is set up so all that has to be done is to implement the setValue method. --- components/nifogre/mesh.cpp | 14 +++++++++ components/nifogre/ogrenifloader.cpp | 45 +++++++++++++++++++++++++++- components/nifogre/skeleton.cpp | 3 +- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c3..851160de2 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -116,6 +116,20 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape std::vector srcNorms = data->normals; Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; + + if(!shape->controller.empty()) + { + Nif::ControllerPtr ctrl = shape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + if(skin != NULL) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dc6bb8d24..942b3858a 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -293,7 +293,7 @@ public: } public: - Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data) : mMaterial(material) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -363,6 +363,36 @@ public: typedef DefaultFunction Function; }; +class GeomMorpherController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::SubEntity *mSubEntity; + std::vector mMorphs; + + public: + Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) + : mSubEntity(subent) + , mMorphs(data->mMorphs) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real value) + { + // TODO: Implement + } + }; + + typedef DefaultFunction Function; +}; + /** Object creator for NIFs. This is the main class responsible for creating * "live" Ogre objects (entities, particle systems, controllers, etc) from @@ -429,6 +459,19 @@ class NIFObjectLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); + + Ogre::SubEntity *subent = entity->getSubEntity(0); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1809212a7..1306d037c 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -179,7 +179,8 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiGeomMorpherController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; From adc6a948c7ed308c57c5996c57c8227c91d4af99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:41:38 -0700 Subject: [PATCH 032/134] Add methods to get the rotation, translation, and scale from a NodeTargetValue --- components/nifogre/ogrenifloader.cpp | 41 ++++++++++++++++++++-------- components/nifogre/ogrenifloader.hpp | 4 ++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 942b3858a..451993cf4 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -135,11 +135,14 @@ public: , mData(data->mVis) { } - virtual void applyToNode(Ogre::Node *node, float time) const - { - bool vis = calculate(time); - setVisible(node, vis); - } + virtual Ogre::Quaternion getRotation(float time) const + { return Ogre::Quaternion(); } + + virtual Ogre::Vector3 getTranslation(float time) const + { return Ogre::Vector3(0.0f); } + + virtual Ogre::Vector3 getScale(float time) const + { return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const { @@ -149,7 +152,8 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + bool vis = calculate(time); + setVisible(mNode, vis); } }; @@ -223,7 +227,7 @@ public: float a = (time-last->mTime) / (iter->mTime-last->mTime); return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); } - return Ogre::Quaternion(); + return keys.back().mValue; } public: @@ -234,14 +238,25 @@ public: , mScales(data->mScales) { } - virtual void applyToNode(Ogre::Node *node, float time) const + virtual Ogre::Quaternion getRotation(float time) const { if(mRotations.mKeys.size() > 0) - node->setOrientation(interpKey(mRotations.mKeys, time)); + return interpKey(mRotations.mKeys, time); + return Ogre::Quaternion(); + } + + virtual Ogre::Vector3 getTranslation(float time) const + { if(mTranslations.mKeys.size() > 0) - node->setPosition(interpKey(mTranslations.mKeys, time)); + return interpKey(mTranslations.mKeys, time); + return Ogre::Vector3(0.0f); + } + + virtual Ogre::Vector3 getScale(float time) const + { if(mScales.mKeys.size() > 0) - node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + return Ogre::Vector3(interpKey(mScales.mKeys, time)); + return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const @@ -252,7 +267,9 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + mNode->setOrientation(Value::getRotation(time)); + mNode->setPosition(Value::getTranslation(time)); + mNode->setScale(Value::getScale(time)); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index d0ff94217..40577e451 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -87,7 +87,9 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } - virtual void applyToNode(Ogre::Node *node, float time) const = 0; + virtual Ogre::Quaternion getRotation(T value) const = 0; + virtual Ogre::Vector3 getTranslation(T value) const = 0; + virtual Ogre::Vector3 getScale(T value) const = 0; void setNode(Ogre::Node *target) { mNode = target; } From cc70c6263bf377f600d8af023985ec8a092c3f5a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 04:10:46 -0700 Subject: [PATCH 033/134] Use the NodeTargetValue for the NonAccum root --- apps/openmw/mwrender/animation.cpp | 114 ++++++++++------------------- apps/openmw/mwrender/animation.hpp | 4 +- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d71b33cdd..5700af3d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,12 +41,12 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -209,48 +209,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + float loopstarttime = 0.0f; + float loopstoptime = std::numeric_limits::max(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == bonename) - track = cur; + if(keyiter->second == loopstart) + loopstarttime = keyiter->first; + else if(keyiter->second == loopstop) + { + loopstoptime = keyiter->first; + break; + } + keyiter++; } - if(track && track->getNumKeyFrames() > 1) + if(loopstoptime > loopstarttime) { - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = anim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) - { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - - return startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } + return startpos.distance(endpos) / (loopstoptime-loopstarttime); } return 0.0f; @@ -298,20 +281,8 @@ Ogre::Vector3 Animation::updatePosition() { Ogre::Vector3 posdiff; - Ogre::TransformKeyFrame kf(0, mCurrentTime); - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *track = trackiter.getNext(); - if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - { - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - break; - } - } - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -344,24 +315,9 @@ void Animation::reset(const std::string &start, const std::string &stop) mStopKey--; } - 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) - { - Ogre::TransformKeyFrame kf(0, mCurrentTime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - mLastPosition = kf.getTranslate() * mAccumulate; - } - } + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * + mAccumulate; } @@ -431,24 +387,34 @@ void Animation::play(const std::string &groupname, const std::string &start, con { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - Ogre::Animation *anim = skel->getAnimation(groupname); const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + if(!foundanim) { - mCurrentAnim = anim; mCurrentKeys = keys; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; + foundanim = true; } if(!mNonAccumRoot) break; - mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); if(mAnimVelocity > 0.0f) break; } } @@ -469,7 +435,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying) + while(!mCurrentGroup.empty() && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cd2523b63..92f636d0a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,7 +50,6 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - Ogre::Animation *mCurrentAnim; std::string mCurrentGroup; std::vector > *mCurrentControllers; @@ -62,10 +61,11 @@ protected: bool mPlaying; bool mLooping; + NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; - static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + static float calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on From bb64efc18e9252292b82f3540e487bb14b22901e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 05:08:52 -0700 Subject: [PATCH 034/134] Improve looping behavior --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 78 ++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d811528..4684ca6ea 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5700af3d6..d065195ad 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -293,36 +293,51 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { + std::string tag = mCurrentGroup+": "+start; mStartKey = mCurrentKeys->begin(); - - while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) mStartKey++; - if(mStartKey != mCurrentKeys->end()) - mCurrentTime = mStartKey->first; - else + if(mStartKey == mCurrentKeys->end() && tag == "loop start") { + tag = mCurrentGroup+": start"; mStartKey = mCurrentKeys->begin(); - mCurrentTime = mStartKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) + mStartKey++; } - mNextKey = mStartKey; + if(mStartKey == mCurrentKeys->end()) + mStartKey = mCurrentKeys->begin(); - if(stop.length() > 0) - { - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; - } + tag = mCurrentGroup+": "+stop; + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; + + mCurrentTime = mStartKey->first; + mLoopStartKey = mStartKey; + mNextKey = mStartKey; + ++mNextKey; if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * - mAccumulate; + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; +} + +void Animation::doLoop() +{ + mCurrentTime = mLoopStartKey->first; + mNextKey = mLoopStartKey; + ++mNextKey; + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; } -bool Animation::handleEvent(float time, const std::string &evt) +bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) { + float time = key->first; + const std::string &evt = key->second; + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -347,25 +362,15 @@ bool Animation::handleEvent(float time, const std::string &evt) if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - /* Do nothing */ + mLoopStartKey = key; return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset(mCurrentGroup+": loop start"); - if(mCurrentTime >= time) - return false; - return true; - } - } - else if(evt.compare(off, len, "stop") == 0) - { - if(mLooping) - { - reset(mCurrentGroup+": loop start"); + doLoop(); if(mCurrentTime >= time) return false; return true; @@ -421,7 +426,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); + reset(start, stop); setLooping(loop); mPlaying = true; } @@ -446,18 +451,15 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) break; } - float time = mNextKey->first; - const std::string &evt = mNextKey->second; - mNextKey++; - - mCurrentTime = time; + NifOgre::TextKeyMap::const_iterator key(mNextKey++); + mCurrentTime = key->first; if(mNonAccumRoot) movement += updatePosition(); mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; - if(!handleEvent(time, evt)) + if(!handleTextKey(key)) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 92f636d0a..0d81cf3b4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,6 +55,7 @@ protected: std::vector > *mCurrentControllers; const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; float mCurrentTime; @@ -82,7 +83,9 @@ protected: */ void reset(const std::string &start, const std::string &stop=std::string()); - bool handleEvent(float time, const std::string &evt); + void doLoop(); + + bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); From a2fc43c7df22786b4d022be550928c2478a16c24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:41:54 -0700 Subject: [PATCH 035/134] Use reset to check that the animation exists and has the right markers --- apps/openmw/mwrender/animation.cpp | 123 ++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 10 ++- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d065195ad..a17d225e9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,14 +209,14 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = std::numeric_limits::max(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) + float loopstoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + while(keyiter != keys.end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -291,36 +291,44 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -void Animation::reset(const std::string &start, const std::string &stop) +bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { - std::string tag = mCurrentGroup+": "+start; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; - if(mStartKey == mCurrentKeys->end() && tag == "loop start") + std::string tag = groupname+": "+start; + NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); + while(startkey != keys.end() && startkey->second != tag) + startkey++; + if(startkey == keys.end() && tag == "loop start") { - tag = mCurrentGroup+": start"; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; + tag = groupname+": start"; + startkey = keys.begin(); + while(startkey != keys.end() && startkey->second != tag) + startkey++; } - if(mStartKey == mCurrentKeys->end()) - mStartKey = mCurrentKeys->begin(); + if(startkey == keys.end()) + return false; - tag = mCurrentGroup+": "+stop; - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; + tag = groupname+": "+stop; + NifOgre::TextKeyMap::const_iterator stopkey(startkey); + while(stopkey != keys.end() && stopkey->second != tag) + stopkey++; + if(stopkey == keys.end()) + return false; - mCurrentTime = mStartKey->first; + if(startkey == stopkey) + return false; + + mStartKey = startkey; mLoopStartKey = mStartKey; + mStopKey = stopkey; mNextKey = mStartKey; ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mCurrentTime = mStartKey->first; + + if(nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + + return true; } void Animation::doLoop() @@ -390,45 +398,46 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) { - const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - - if(!foundanim) - { - mCurrentKeys = keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - - foundanim = true; - } - - if(!mNonAccumRoot) + nonaccumctrl = dstval; break; - - mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); - if(mAnimVelocity > 0.0f) break; + } } + + if(!foundanim) + { + if(!reset(keys, nonaccumctrl, groupname, start, stop)) + continue; + mCurrentKeys = &keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + + setLooping(loop); + mPlaying = true; + + foundanim = true; + } + + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); + if(mAnimVelocity > 0.0f) break; } if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - - reset(start, stop); - setLooping(loop); - mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < *nonaccumctrl, - const std::string &groupname, const NifOgre::TextKeyMap *keys); + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ @@ -79,9 +80,10 @@ protected: /* 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. + * the marker is not found, or if the markers are the same, it returns + * false. */ - void reset(const std::string &start, const std::string &stop=std::string()); + bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); void doLoop(); From 7279e015e9e76a0dec940f2f10fd2948c39500f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:59:55 -0700 Subject: [PATCH 036/134] Search the textkeys to check if an animation group exists --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a17d225e9..b5f23b2c4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,11 +169,28 @@ Ogre::Node *Animation::getNode(const std::string &name) } +NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) +{ + NifOgre::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();iter++) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + if(findGroupStart(keys, anim) != keys.end()) return true; } return false; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 06c2b485b..6393ee7c9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -78,6 +78,8 @@ protected: * returns the wanted movement vector from the previous update. */ Ogre::Vector3 updatePosition(); + static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + /* 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, or if the markers are the same, it returns From c3ce49798a315c9fd8065b356f7fae87557c69cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 21:34:39 -0700 Subject: [PATCH 037/134] Fix animation velocity calculation --- apps/openmw/mwrender/animation.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f23b2c4..45f2a6fcb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,29 +228,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { + const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = 0.0f; - NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter(keys.begin()); while(keyiter != keys.end()) { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) + if(keyiter->second == start || keyiter->second == loopstart) + starttime = keyiter->first; + else if(keyiter->second == loopstop || keyiter->second == stop) { - loopstoptime = keyiter->first; + stoptime = keyiter->first; break; } keyiter++; } - if(loopstoptime > loopstarttime) + if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); - return startpos.distance(endpos) / (loopstoptime-loopstarttime); + return startpos.distance(endpos) / (stoptime-starttime); } return 0.0f; From 8782ae6976aa316a5394dd4e33c6cf0cd290779a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 23:35:50 -0700 Subject: [PATCH 038/134] Separate some Animation fields into a separate AnimLayer class --- apps/openmw/mwmechanics/character.cpp | 4 - apps/openmw/mwrender/animation.cpp | 179 +++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 52 ++++---- 3 files changed, 130 insertions(+), 105 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4684ca6ea..07f7b6940 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -304,11 +304,7 @@ 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 45f2a6fcb..4c5a86985 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,32 @@ namespace MWRender { +Animation::AnimLayer::AnimLayer() + : mControllers(NULL) + , mTextKeys(NULL) + , mTime(0.0f) + , mPlaying(false) + , mLooping(false) +{ +} + + +Ogre::Real Animation::AnimationValue::getValue() const +{ + size_t idx = mIndex; + while(idx > 0 && mAnimation->mLayer[idx].mGroupName.empty()) + idx--; + if(!mAnimation->mLayer[idx].mGroupName.empty()) + return mAnimation->mLayer[idx].mTime; + return 0.0f; +} + +void Animation::AnimationValue::setValue(Ogre::Real value) +{ + mAnimation->mLayer[mIndex].mTime = value; +} + + void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mParticles.size();i++) @@ -32,7 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) , mPtr(ptr) , mController(NULL) , mInsert(NULL) @@ -41,11 +67,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentControllers(NULL) - , mCurrentKeys(NULL) - , mCurrentTime(0.0f) - , mPlaying(false) - , mLooping(false) , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) @@ -127,9 +148,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } - - if(!mCurrentControllers || (*mCurrentControllers).size() == 0) - mCurrentControllers = &objlist.mControllers; } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -215,10 +233,6 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } -void Animation::setLooping(bool loop) -{ - mLooping = loop; -} void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -301,7 +315,7 @@ Ogre::Vector3 Animation::updatePosition() Ogre::Vector3 posdiff; /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -310,7 +324,7 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -336,31 +350,31 @@ bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue< if(startkey == stopkey) return false; - mStartKey = startkey; - mLoopStartKey = mStartKey; - mStopKey = stopkey; - mNextKey = mStartKey; - ++mNextKey; + mLayer[layeridx].mStartKey = startkey; + mLayer[layeridx].mLoopStartKey = startkey; + mLayer[layeridx].mStopKey = stopkey; + mLayer[layeridx].mNextKey = startkey; + mLayer[layeridx].mNextKey++; - mCurrentTime = mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + if(layeridx == 0 && nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; return true; } -void Animation::doLoop() +void Animation::doLoop(size_t layeridx) { - mCurrentTime = mLoopStartKey->first; - mNextKey = mLoopStartKey; - ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; + mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; + mLayer[layeridx].mNextKey++; + if(layeridx == 0 && mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } -bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) +bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key) { float time = key->first; const std::string &evt = key->second; @@ -378,27 +392,27 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) return true; } - if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + if(evt.compare(0, mLayer[layeridx].mGroupName.size(), mLayer[layeridx].mGroupName) != 0 || + evt.compare(mLayer[layeridx].mGroupName.size(), 2, ": ") != 0) { - // Not ours + // Not ours, skip it return true; } - size_t off = mCurrentGroup.size()+2; + size_t off = mLayer[layeridx].mGroupName.size()+2; size_t len = evt.size() - off; if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - mLoopStartKey = key; + mLayer[layeridx].mLoopStartKey = key; return true; } if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLooping) + if(mLayer[layeridx].mLooping) { - doLoop(); - if(mCurrentTime >= time) + doLoop(layeridx); + if(mLayer[layeridx].mTime >= time) return false; return true; } @@ -412,6 +426,9 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { + // TODO: parameterize this + size_t layeridx = 0; + try { bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ @@ -422,34 +439,40 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + if(layeridx == 0) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) + for(size_t i = 0;i < iter->mControllers.size();i++) { - nonaccumctrl = dstval; - break; + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } } } if(!foundanim) { - if(!reset(keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) continue; - mCurrentKeys = &keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; - setLooping(loop); - mPlaying = true; + if(layeridx == 0) + { + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + } foundanim = true; } - if(!mNonAccumRoot) + if(!nonaccumctrl) break; mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); @@ -463,37 +486,43 @@ void Animation::play(const std::string &groupname, const std::string &start, con } } -Ogre::Vector3 Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - timepassed *= mAnimSpeedMult; - while(!mCurrentGroup.empty() && mPlaying) + duration *= mAnimSpeedMult; + for(size_t layeridx = 0;layeridx < sMaxLayers;layeridx++) { - float targetTime = mCurrentTime + timepassed; - if(mNextKey->first > targetTime) + if(mLayer[layeridx].mGroupName.empty()) + continue; + + float timepassed = duration; + while(mLayer[layeridx].mPlaying) { - mCurrentTime = targetTime; - if(mNonAccumRoot) + float targetTime = mLayer[layeridx].mTime + timepassed; + if(mLayer[layeridx].mNextKey->first > targetTime) + { + mLayer[layeridx].mTime = targetTime; + if(layeridx == 0 && mNonAccumRoot) + movement += updatePosition(); + break; + } + + NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); + mLayer[layeridx].mTime = key->first; + if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - break; + + mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + timepassed = targetTime - mLayer[layeridx].mTime; + + if(!handleTextKey(layeridx, key)) + break; } - - NifOgre::TextKeyMap::const_iterator key(mNextKey++); - mCurrentTime = key->first; - if(mNonAccumRoot) - movement += updatePosition(); - - mPlaying = (mLooping || mStopKey->first > mCurrentTime); - timepassed = targetTime - mCurrentTime; - - if(!handleTextKey(key)) - break; + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); } - for(size_t i = 0;i < (*mCurrentControllers).size();i++) - (*mCurrentControllers)[i].update(); - if(mSkelBase) { const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6393ee7c9..96138cf74 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,20 +23,15 @@ protected: { private: Animation *mAnimation; + size_t mIndex; public: - AnimationValue(Animation *anim) : mAnimation(anim) + AnimationValue(Animation *anim, size_t layeridx) + : mAnimation(anim), mIndex(layeridx) { } - virtual Ogre::Real getValue() const - { - return mAnimation->mCurrentTime; - } - - virtual void setValue(Ogre::Real value) - { - mAnimation->mCurrentTime = value; - } + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); }; Ogre::SharedPtr > mAnimationBaseValuePtr; @@ -51,21 +46,28 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::string mCurrentGroup; - std::vector > *mCurrentControllers; - const NifOgre::TextKeyMap *mCurrentKeys; - NifOgre::TextKeyMap::const_iterator mStartKey; - NifOgre::TextKeyMap::const_iterator mLoopStartKey; - NifOgre::TextKeyMap::const_iterator mStopKey; - NifOgre::TextKeyMap::const_iterator mNextKey; - float mCurrentTime; - bool mPlaying; - bool mLooping; - NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + static const size_t sMaxLayers = 1; + struct AnimLayer { + std::string mGroupName; + std::vector > *mControllers; + const NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; + NifOgre::TextKeyMap::const_iterator mNextKey; + + float mTime; + + bool mPlaying; + bool mLooping; + + AnimLayer(); + } mLayer[sMaxLayers]; + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname); @@ -85,11 +87,11 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(); + void doLoop(size_t layeridx); - bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); + bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); @@ -113,8 +115,6 @@ public: void setSpeed(float speed); - void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e3781769371e8c736bcf2643537c60cf6fe106f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 00:15:31 -0700 Subject: [PATCH 039/134] Don't update controllers that have already been updated --- apps/openmw/mwrender/animation.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4c5a86985..0166eb843 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -519,8 +519,23 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!handleTextKey(layeridx, key)) break; } - for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) - (*(mLayer[layeridx].mControllers))[i].update(); + + bool updatectrls = true; + for(size_t i = layeridx-1;i < layeridx;i--) + { + if(mLayer[i].mGroupName.empty()) + continue; + if(mLayer[i].mControllers == mLayer[layeridx].mControllers) + { + updatectrls = false; + break; + } + } + if(updatectrls) + { + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); + } } if(mSkelBase) From e4c5aac9664db105fde2b31b0973d5c7b483d80a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 02:48:11 -0700 Subject: [PATCH 040/134] Keep track of the animation layers a given object list is animating on This only tracks layers they explicitly animate on. They may animate on other layers as well, if nothing else is animating on them. --- apps/openmw/mwrender/activatoranimation.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 63 +++++++++++++++------ apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index c3a3045c2..4eb844607 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -22,7 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0166eb843..98e2f9104 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,9 +78,9 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectLists.size();i++) - destroyObjectList(sceneMgr, mObjectLists[i]); - mObjectLists.clear(); + for(size_t i = 0;i < mObjects.size();i++) + destroyObjectList(sceneMgr, mObjects[i].mObjectList); + mObjects.clear(); } } @@ -93,9 +93,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b assert(mInsert); } - mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - NifOgre::ObjectList &objlist = mObjectLists.back(); + mObjects.push_back(ObjectInfo()); + ObjectInfo &obj = mObjects.back(); + obj.mActiveLayers = 0; + obj.mObjectList = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + + NifOgre::ObjectList &objlist = obj.mObjectList; if(objlist.mSkelBase) { if(!mSkelBase) @@ -202,12 +206,12 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::const_iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - if(iter->mTextKeys.size() == 0) + if(iter->mObjectList.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = iter->mObjectList.mTextKeys.begin()->second; if(findGroupStart(keys, anim) != keys.end()) return true; } @@ -430,21 +434,45 @@ void Animation::play(const std::string &groupname, const std::string &start, con size_t layeridx = 0; try { + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) + for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) { - if(iter->mTextKeys.size() == 0) + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; if(layeridx == 0) { - for(size_t i = 0;i < iter->mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); if(dstval && dstval->getNode() == mNonAccumRoot) { nonaccumctrl = dstval; @@ -459,7 +487,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mControllers = &objlist.mControllers; mLayer[layeridx].mLooping = loop; mLayer[layeridx].mPlaying = true; @@ -469,6 +497,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mAnimVelocity = 0.0f; } + iter->mActiveLayers |= (1<getSkeleton(); - for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - Ogre::Entity *ent = iter->mSkelBase; + Ogre::Entity *ent = iter->mObjectList.mSkelBase; if(!ent) continue; Ogre::SkeletonInstance *inst = ent->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 96138cf74..840c22ae4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,9 +38,18 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; + struct ObjectInfo { + NifOgre::ObjectList mObjectList; + /* Bit-field specifying which animation layers this object list is + * explicitly animating on (1 = layer 0, 2 = layer 1, 4 = layer 2. + * etc). + */ + int mActiveLayers; + }; + Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - std::vector mObjectLists; + std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 51632b2ee..97c28c0ae 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Actors, RQG_Main, RQG_Alpha); } } From cfccf0981dee740e725eb819d1dbb2cf00c66b2d Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 23 Apr 2013 13:24:06 +0400 Subject: [PATCH 041/134] update IndexedStore::setUp() for multiple datafile support --- apps/openmw/mwworld/store.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c482..959b944e1 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -872,7 +872,28 @@ namespace MWWorld } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); + /// \note This method sorts indexed values for further + /// searches. Every loaded item is present in storage, but + /// latest loaded shadows any previous while searching. + /// If memory cost will be too high, it is possible to remove + /// unused values. + + Compare cmp; + + std::stable_sort(mStatic.begin(), mStatic.end(), cmp); + + typename std::vector::iterator first, next; + next = first = mStatic.begin(); + + while (first != mStatic.end() && ++next != mStatic.end()) { + while (next != mStatic.end() && !cmp(*first, *next)) { + ++next; + } + if (first != --next) { + std::swap(*first, *next); + } + first = ++next; + } } const T *search(int index) const { From c4806f01f850bbf18052659e45b222553b9f747c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 03:42:00 -0700 Subject: [PATCH 042/134] Use a separate list of controllers to update This should make it easier to figure out what controllers need to be updated for various animation sources and layers. --- apps/openmw/mwrender/animation.cpp | 220 ++++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 3 + 2 files changed, 139 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98e2f9104..fbf5725c4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -71,6 +71,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + /* As long as we remain under 128 active controllers, we can avoid + * reallocations. */ + mActiveCtrls.reserve(128); } Animation::~Animation() @@ -179,6 +182,79 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::updateActiveControllers() +{ + mActiveCtrls.clear(); + + /* First, get all controllers that don't target a node, or that target + * nodes that don't belong to any particular layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + std::vector >::const_iterator ctrl(obj->mObjectList.mControllers.begin()); + for(;ctrl != obj->mObjectList.mControllers.end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*if(getLayerByName(dstval->getNode()->getName()) >= 0)*/ + continue; + } + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + std::vector > *ctrls = NULL; + size_t layer = 0; + while(layer < sMaxLayers) + { + /* Now get controllers that target nodes that belong to this layer from + * whatever objectlist is active on this layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1<mObjectList.mControllers; + break; + } + } + + /* Check if any objectlists are active on subsequent layers. Include + * those layers if not. + */ + size_t nextlayer = layer+1; + for(;nextlayer < sMaxLayers;nextlayer++) + { + for(obj = mObjects.begin();obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1< >::const_iterator ctrl(ctrls->begin()); + for(;ctrl != ctrls->end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*ssize_t idx = getLayerByName(dstval->getNode()->getName()); + if(idx >= (ssize_t)layer && idx < (ssize_t)nextlayer)*/ + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + layer = nextlayer; + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) @@ -433,86 +509,76 @@ void Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; - try { - for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) - iter->mActiveLayers &= ~(1<::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + { + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + if(layeridx == 0) { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + } - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; - mLayer[layeridx].mPlaying = false; + if(!foundanim) + { + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + continue; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &objlist.mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; if(layeridx == 0) { - mNonAccumCtrl = NULL; + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; } - return; + iter->mActiveLayers |= (1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) - { - NifOgre::ObjectList &objlist = iter->mObjectList; - if(objlist.mTextKeys.size() == 0) - continue; + if(!nonaccumctrl) + break; - const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) - { - for(size_t i = 0;i < objlist.mControllers.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) - continue; - mLayer[layeridx].mGroupName = groupname; - mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; - mLayer[layeridx].mPlaying = true; - - if(layeridx == 0) - { - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - } - - iter->mActiveLayers |= (1< 0.0f) break; - } - if(!foundanim) - throw std::runtime_error("Failed to find animation "+groupname); - } - catch(std::exception &e) { - std::cerr<< e.what() < 0.0f) break; } + if(!foundanim) + std::cerr<< "Failed to find animation "<getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 840c22ae4..4860f44f5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -58,6 +58,7 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; struct AnimLayer { @@ -107,6 +108,8 @@ protected: static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + void updateActiveControllers(); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); From 8c9e2e0ee9e24b444efa67f811ed8be1cd87fbcb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 05:34:08 -0700 Subject: [PATCH 043/134] Improve handling of reaching the stop animation text key --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fbf5725c4..d98a32828 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -449,6 +449,7 @@ void Animation::doLoop(size_t layeridx) mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; + mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } @@ -608,7 +609,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; if(!handleTextKey(layeridx, key)) From 634b0fd067a7c4ac65123be69dd29c0c4739be2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 17:57:40 -0700 Subject: [PATCH 044/134] Fix for controller delta time going below start time --- components/nifogre/ogrenifloader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 451993cf4..95ba439d1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -65,11 +65,7 @@ public: , mStopTime(ctrl->timeStop) { if(mDeltaInput) - { mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } } virtual Ogre::Real calculate(Ogre::Real value) @@ -77,6 +73,9 @@ public: if(mDeltaInput) { mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); mDeltaCount = std::fmod(mDeltaCount - mStartTime, mStopTime - mStartTime) + mStartTime; return mDeltaCount; From 7e2995bc2f7b21f2335424e0d49e7d5231a673d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 19:43:26 -0700 Subject: [PATCH 045/134] Fix setting up active controllers --- apps/openmw/mwrender/animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d98a32828..cb54a0366 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -155,6 +155,8 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } + + mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -231,7 +233,7 @@ void Animation::updateActiveControllers() { for(obj = mObjects.begin();obj != mObjects.end();obj++) { - if((obj->mActiveLayers&(1<mActiveLayers&(1< Date: Tue, 23 Apr 2013 20:42:54 -0700 Subject: [PATCH 046/134] Don't create Ogre animations for skeletons --- components/nifogre/ogrenifloader.cpp | 28 +++- components/nifogre/skeleton.cpp | 220 ++------------------------- components/nifogre/skeleton.hpp | 4 +- 3 files changed, 37 insertions(+), 215 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 95ba439d1..e451326fe 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,6 +676,32 @@ class NIFObjectLoader } + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + { + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -704,7 +730,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + objectlist.mTextKeys[trgtid] = extractTextKeys(tk); } else if(e->recType == Nif::RC_NiStringExtraData) { diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1306d037c..3aec920fc 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -11,142 +11,7 @@ namespace NifOgre { -void NIFSkeletonLoader::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); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const 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]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - 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 = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - 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, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // 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 = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - 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(); -} - - -TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -175,29 +40,16 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) + if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiKeyframeController || + ctrl->recType == Nif::RC_NiGeomMorpherController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -205,7 +57,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), bone); } } } @@ -218,68 +70,14 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); const Nif::Node *node = static_cast(nif->getRoot(0)); - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; try { - buildBones(skel, node, animroot, textkeys, ctrls); + buildBones(skel, node); } 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 - if(ctrls.size() == 0) // No animations? Then we're done. - return; - - float maxtime = 0.0f; - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *ctrl = ctrls[i]; - maxtime = std::max(maxtime, ctrl->timeStop); - Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(target != NULL) - targets.push_back(target->name); - } - - if(targets.size() != ctrls.size()) - { - warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ - Ogre::StringConverter::toString(ctrls.size())+" controllers)"); - return; - } - - 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) || - (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_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - } } diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index e71dcfb15..38cfe14e3 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -36,8 +36,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader abort(); } - static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index std::map mNifToOgreHandleMap; @@ -46,7 +45,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From 6f0b9a5f2cb98747715dbfa6c88b86f178c6f94c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 21:42:59 -0700 Subject: [PATCH 047/134] Avoid unnecessary multimap copies --- components/nifogre/ogrenifloader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e451326fe..57aa79403 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,9 +676,8 @@ class NIFObjectLoader } - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) { - TextKeyMap textkeys; for(size_t i = 0;i < tk->list.size();i++) { const std::string &str = tk->list[i].text; @@ -698,7 +697,6 @@ class NIFObjectLoader pos = nextpos; } } - return textkeys; } @@ -730,7 +728,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = extractTextKeys(tk); + extractTextKeys(tk, objectlist.mTextKeys[trgtid]); } else if(e->recType == Nif::RC_NiStringExtraData) { From 544011e0962b28b9cb978d90b9f1fe32455fb1ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:40:58 -0700 Subject: [PATCH 048/134] Fix 'start' text key fallback lookup --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cb54a0366..dc1312837 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -412,7 +412,7 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); while(startkey != keys.end() && startkey->second != tag) startkey++; - if(startkey == keys.end() && tag == "loop start") + if(startkey == keys.end() && start == "loop start") { tag = groupname+": start"; startkey = keys.begin(); From 26cc86ffdcd152b9acb6b953fff7de7acf2c48a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:42:45 -0700 Subject: [PATCH 049/134] Use the Nif node's transform for skinned fixups --- components/nifogre/mesh.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 5637cd828..ca92f62d4 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -109,7 +109,6 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { - Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; @@ -139,10 +138,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // explicitly attached later. 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(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 // be a reliable way to do that. @@ -153,11 +148,10 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Bone *bone = skel->getBone(bones[b]->name); Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; + mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -310,6 +304,8 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Assign bone weights for this TriShape if(skin != NULL) { + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); + const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) From 9e05ee53da793846d0ddebd0b960aba621a621a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:18:08 -0700 Subject: [PATCH 050/134] Avoid looking for the controller if there is no NonAccum node Also, make sure there is a controller before updating the position. --- apps/openmw/mwrender/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dc1312837..a2b429840 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -538,7 +538,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) + if(layeridx == 0 && mNonAccumRoot) { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -601,14 +601,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(mLayer[layeridx].mNextKey->first > targetTime) { mLayer[layeridx].mTime = targetTime; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); From 102b3bdef99d0d7ea1ee601565d3463a7cb5212d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:57:51 -0700 Subject: [PATCH 051/134] Update position by reference --- apps/openmw/mwrender/animation.cpp | 13 +++++++------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a2b429840..a8b2a1897 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -392,18 +392,19 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition() +void Animation::updatePosition(Ogre::Vector3 &position) { Ogre::Vector3 posdiff; - /* Get the non-accumulation root's difference from the last update. */ + /* Get the non-accumulation root's difference from the last update, and move the position + * accordingly. + */ posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; + position += posdiff; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; mAccumRoot->setPosition(-mLastPosition); - - return posdiff; } bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) @@ -602,14 +603,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) { mLayer[layeridx].mTime = targetTime; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4860f44f5..a874cb1a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -88,7 +88,7 @@ protected: /* Updates the position of the accum root node for the current time, and * returns the wanted movement vector from the previous update. */ - Ogre::Vector3 updatePosition(); + void updatePosition(Ogre::Vector3 &position); static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); From 68a9a4de5f77153f16e41fea47654b722fa6119d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:12:27 -0700 Subject: [PATCH 052/134] Fix setting and getting KeyframeController transforms --- components/nifogre/ogrenifloader.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 57aa79403..d36199f86 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -173,8 +173,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -193,8 +191,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -213,8 +209,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -241,21 +235,21 @@ public: { if(mRotations.mKeys.size() > 0) return interpKey(mRotations.mKeys, time); - return Ogre::Quaternion(); + return mNode->getOrientation(); } virtual Ogre::Vector3 getTranslation(float time) const { if(mTranslations.mKeys.size() > 0) return interpKey(mTranslations.mKeys, time); - return Ogre::Vector3(0.0f); + return mNode->getPosition(); } virtual Ogre::Vector3 getScale(float time) const { if(mScales.mKeys.size() > 0) return Ogre::Vector3(interpKey(mScales.mKeys, time)); - return Ogre::Vector3(1.0f); + return mNode->getScale(); } virtual Ogre::Real getValue() const @@ -266,9 +260,12 @@ public: virtual void setValue(Ogre::Real time) { - mNode->setOrientation(Value::getRotation(time)); - mNode->setPosition(Value::getTranslation(time)); - mNode->setScale(Value::getScale(time)); + if(mRotations.mKeys.size() > 0) + mNode->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + mNode->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); } }; From 7241267d5c036f8c052598c18f04bdb8fef0b70e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:41:52 -0700 Subject: [PATCH 053/134] Make an AnimationValue for each animation layer --- apps/openmw/mwrender/animation.cpp | 8 +++--- apps/openmw/mwrender/animation.hpp | 40 ++++++++++++++++-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8b2a1897..3d938cc25 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -58,8 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) - , mPtr(ptr) + : mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -71,6 +70,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + for(size_t i = 0;i < sMaxLayers;i++) + mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this, i)); + /* As long as we remain under 128 active controllers, we can avoid * reallocations. */ mActiveCtrls.reserve(128); @@ -153,7 +155,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(mAnimationBaseValuePtr); + objlist.mControllers[i].setSource(mAnimationValuePtr[0]); } mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a874cb1a8..282cd3eca 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,10 +33,6 @@ protected: virtual Ogre::Real getValue() const; virtual void setValue(Ogre::Real value); }; - Ogre::SharedPtr > mAnimationBaseValuePtr; - - MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; struct ObjectInfo { NifOgre::ObjectList mObjectList; @@ -47,20 +43,6 @@ protected: int mActiveLayers; }; - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - std::vector mObjects; - Ogre::Node *mAccumRoot; - Ogre::Bone *mNonAccumRoot; - Ogre::Vector3 mAccumulate; - Ogre::Vector3 mLastPosition; - - NifOgre::NodeTargetValue *mNonAccumCtrl; - float mAnimVelocity; - float mAnimSpeedMult; - std::vector > mActiveCtrls; - - static const size_t sMaxLayers = 1; struct AnimLayer { std::string mGroupName; std::vector > *mControllers; @@ -76,7 +58,27 @@ protected: bool mLooping; AnimLayer(); - } mLayer[sMaxLayers]; + }; + + MWWorld::Ptr mPtr; + MWMechanics::CharacterController *mController; + + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; + std::vector mObjects; + Ogre::Node *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; + Ogre::Vector3 mLastPosition; + + NifOgre::NodeTargetValue *mNonAccumCtrl; + float mAnimVelocity; + float mAnimSpeedMult; + std::vector > mActiveCtrls; + + static const size_t sMaxLayers = 1; + AnimLayer mLayer[sMaxLayers]; + Ogre::SharedPtr > mAnimationValuePtr[sMaxLayers]; static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, From c58dfbe921cda569f950648f3307145a9c2cfe37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:56:39 -0700 Subject: [PATCH 054/134] Specify the loop count to Animation::play --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ apps/openmw/mwrender/animation.cpp | 19 ++++++++++++------- apps/openmw/mwrender/animation.hpp | 6 +++--- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07f7b6940..664ed7c03 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } CharacterController::CharacterController(const CharacterController &rhs) @@ -155,7 +155,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", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } return; } @@ -164,7 +164,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", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } else if(mAnimQueue.size() > 0) { @@ -172,7 +172,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", false); + mAnimation->play(mCurrentGroup, "start", "stop", 0); } } return; @@ -284,7 +284,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"), "stop", false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); } else if(mode == 0) { @@ -316,7 +316,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3d938cc25..4e82f0b8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,7 @@ Animation::AnimLayer::AnimLayer() , mTextKeys(NULL) , mTime(0.0f) , mPlaying(false) - , mLooping(false) + , mLoopCount(0) { } @@ -449,14 +449,20 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: return true; } -void Animation::doLoop(size_t layeridx) +bool Animation::doLoop(size_t layeridx) { + if(mLayer[layeridx].mLoopCount == 0) + return false; + mLayer[layeridx].mLoopCount--; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; + + return true; } @@ -495,9 +501,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLayer[layeridx].mLooping) + if(doLoop(layeridx)) { - doLoop(layeridx); if(mLayer[layeridx].mTime >= time) return false; return true; @@ -510,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -527,7 +532,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; + mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; foundanim = true; @@ -562,7 +567,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mLoopCount = loops; mLayer[layeridx].mPlaying = true; if(layeridx == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 282cd3eca..1b300887f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,7 +55,7 @@ protected: float mTime; bool mPlaying; - bool mLooping; + size_t mLoopCount; AnimLayer(); }; @@ -101,7 +101,7 @@ protected: */ bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(size_t layeridx); + bool doLoop(size_t layeridx); bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); @@ -129,7 +129,7 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); Ogre::Node *getNode(const std::string &name); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 41770d489..c22d8a4da 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", false); + mAnimation->play("inventoryhandtohand", "start", "stop", 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", false); + mAnimation->play("idle", "start", "stop", 0); updateCamera(); } From b482d5be097b16a8df8ecc04c8b25252e81e746c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 05:23:45 -0700 Subject: [PATCH 055/134] Add a method to check if a given layer is playing --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1b300887f..87c57ebf7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -132,6 +132,9 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); + bool isPlaying(size_t layeridx) const + { return mLayer[layeridx].mPlaying; } + Ogre::Node *getNode(const std::string &name); }; From e8cabc94349d95bbb9e23a3604e8d1afe85ed8b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:32:11 -0700 Subject: [PATCH 056/134] Pass the loop count from loopgroup to the play method Instead of queueing each iteration separately. --- apps/openmw/mwmechanics/character.cpp | 34 +++++++-------------------- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 11 ++++++++- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 664ed7c03..086a2fc25 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,29 +150,16 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt == "loop stop") - { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - return; - } if(evt == "stop") { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - else if(mAnimQueue.size() > 0) + if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) { - mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0); + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimation->play(mCurrentGroup, "start", "stop", count); } } return; @@ -223,7 +210,6 @@ void CharacterController::update(float duration, Movement &movement) if(vec.x > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); - else if(vec.x < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); @@ -236,10 +222,10 @@ void CharacterController::update(float duration, Movement &movement) if(vec.y > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); - else if(vec.y < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); + // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } @@ -250,7 +236,7 @@ void CharacterController::update(float duration, Movement &movement) else if(rot.z < 0.0f) setState(CharState_TurnLeft, true); } - else if(mAnimQueue.size() == 0) + else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); movement.mRotation[0] += rot.x * duration; @@ -280,17 +266,15 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || mAnimQueue.size() == 0) { mAnimQueue.clear(); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { mAnimQueue.resize(1); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5b5a65f79..4453b078d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -72,7 +72,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - typedef std::deque AnimationQueue; + typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; std::string mCurrentGroup; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e82f0b8c..b205d9519 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,16 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) + if(evt.compare(off, len, "loop stop") == 0) + { + if(doLoop(layeridx)) + { + if(mLayer[layeridx].mTime >= time) + return false; + } + return true; + } + if(evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { From b80891099e0171af7a58dd9733b4abfd901fc3aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:48:34 -0700 Subject: [PATCH 057/134] Don't use the character controller to handle text keys The Animation class has the Ptr and can call to whatever subsystem is needed. --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwmechanics/character.hpp | 6 ----- apps/openmw/mwrender/animation.cpp | 16 +++-------- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 086a2fc25..bbf679cda 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -148,27 +148,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) } -void CharacterController::markerEvent(float time, const std::string &evt) -{ - if(evt == "stop") - { - if(mAnimQueue.size() > 0) - { - mAnimQueue.pop_front(); - if(mAnimQueue.size() > 0) - { - mCurrentGroup = mAnimQueue.front().first; - size_t count = mAnimQueue.front().second; - mAnimation->play(mCurrentGroup, "start", "stop", count); - } - } - return; - } - - std::cerr<< "Unhandled animation event: "<isPlaying(0)) - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + { + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "start", "stop", count); + } + else + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + } movement.mRotation[0] += rot.x * duration; movement.mRotation[1] += rot.y * duration; @@ -263,17 +252,16 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int else { count = std::max(count, 1); - if(mode != 0 || mAnimQueue.size() == 0) + if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { - mAnimQueue.resize(1); + mAnimQueue.clear(); mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4453b078d..4bbea1551 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,12 +79,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; -protected: - /* Called by the animation whenever a new text key is reached. */ - void markerEvent(float time, const std::string &evt); - - friend class MWRender::Animation; - public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b205d9519..c0fee0d3b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { @@ -508,18 +508,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } return true; } - if(evt.compare(off, len, "stop") == 0) - { - if(doLoop(layeridx)) - { - if(mLayer[layeridx].mTime >= time) - return false; - return true; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt.substr(off)); + + std::cerr<< "Unhandled animation textkey: "< Date: Wed, 24 Apr 2013 07:10:41 -0700 Subject: [PATCH 058/134] Remove the character controller from the Animation class --- apps/openmw/mwmechanics/character.cpp | 13 ------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 9 +-------- apps/openmw/mwrender/animation.hpp | 12 +++--------- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bbf679cda..2a7ab8b09 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -108,8 +108,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; - mAnimation->setController(this); - getStateInfo(mState, &mCurrentGroup); if(MWWorld::Class::get(mPtr).isActor()) { @@ -126,17 +124,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } -CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) - , mSkipAnim(rhs.mSkipAnim) -{ - if(!mAnimation) - return; - /* We've been copied. Update the animation with the new controller. */ - mAnimation->setController(this); -} - CharacterController::~CharacterController() { } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4bbea1551..ffd220ff2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -81,7 +81,6 @@ class CharacterController public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); - CharacterController(const CharacterController &rhs); virtual ~CharacterController(); void updatePtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0fee0d3b..c2f453516 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -59,14 +59,13 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) - , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mNonAccumCtrl(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -299,12 +298,6 @@ bool Animation::hasAnimation(const std::string &anim) } -void Animation::setController(MWMechanics::CharacterController *controller) -{ - mController = controller; -} - - void Animation::setAccumulation(const Ogre::Vector3 &accum) { mAccumulate = accum; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 87c57ebf7..526bca69a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -8,10 +8,6 @@ #include "../mwworld/ptr.hpp" -namespace MWMechanics -{ - class CharacterController; -} namespace MWRender { @@ -61,20 +57,20 @@ protected: }; MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; + NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - NifOgre::NodeTargetValue *mNonAccumCtrl; + std::vector > mActiveCtrls; + float mAnimVelocity; float mAnimSpeedMult; - std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; AnimLayer mLayer[sMaxLayers]; @@ -116,8 +112,6 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); - void setController(MWMechanics::CharacterController *controller); - void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); From 53fb17da10436022178562d5d573659f769e0102 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 24 Apr 2013 21:42:04 +0200 Subject: [PATCH 059/134] Rotation system fixes --- apps/openmw/mwscript/transformationextensions.cpp | 9 +++------ apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index beb6c3d8c..f2179897d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -563,17 +563,14 @@ namespace MWScript if (axis == "x") { - ptr.getRefData().getLocalRotation().rot[0]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 69bcad619..aa9107c6e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -827,6 +827,14 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { if (ptr.getRefData().getBaseNode() != 0) { + + if(axis==Ogre::Vector3::UNIT_X) + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Y) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Z) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); mPhysics->rotateObject(ptr); } From c0102954f1d435b21aa2e6a7f1b6d61207ac925b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 30 Mar 2013 13:28:17 +0100 Subject: [PATCH 060/134] Add non-breaking space to font code range --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index b1446fae1..f1be51e16 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -9,6 +9,7 @@ + From cd57e3f896260e480db9fab1aa0d0b9e03f2aa09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 061/134] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb1..ea49ae4a4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 2c8b0a154175f3320fe4e082a5208d538f707875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 062/134] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f3845776..d5a5dcc18 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 21bdcc9f20d14e7d5aabf906860cee573e0e31a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 063/134] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586f..a0a4ab0ae 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8..9535f2a24 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 87ce2110dcc912394a6d49599a7bb7558bac68a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 064/134] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea..41770d489 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From 51580ead4f9c20f8b683384c618c5f1b25c2afd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 065/134] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76c..220adf566 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 2dc01fe56b923c382ebfe7da5c1829d8580bb450 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 066/134] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 959b944e1..7949cbe00 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From a7092ef2d709a575848451ade18e45e360f80f09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 067/134] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d92..86a85be18 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - if (mPtr.isEmpty()) - return; - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || mPtr.getRefData().getCount() == 0) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From baa7a9160c35b4ce13dde8666a2039eb998354e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 068/134] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0..52c7bd4f3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From 8d0e5fc0c4b7272508309e4325ab6c5590b2aa8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 069/134] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc18..c033f9547 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From ad05f238deaec2679336e7d0c35366b53cdfa4c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 070/134] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c3..6d940deed 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 933f89414842eaa566803bb6ed506e85380fd2e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 02:31:51 +0200 Subject: [PATCH 071/134] Added Blind and Night Eye effects --- apps/openmw/mwrender/renderingmanager.cpp | 27 ++++++++++++++++------- libs/openengine/ogre/fader.cpp | 12 +++++----- libs/openengine/ogre/fader.hpp | 4 ++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 029cf394b..da51f10c1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,6 +30,8 @@ #include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME +#include "../mwmechanics/creaturestats.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/player.hpp" @@ -315,13 +317,15 @@ void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + mRendering.getFader()->setFactor(1.f-(blind / 100.f)); + + setAmbientMode(); + // player position - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); + MWWorld::RefData &data = player.getRefData(); float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); @@ -597,8 +601,15 @@ void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) { - mRendering.getScene()->setAmbientLight(colour); - mTerrainManager->setAmbient(colour); + mAmbientColor = colour; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::NightEye)).mMagnitude; + Ogre::ColourValue final = colour; + final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + + mRendering.getScene()->setAmbientLight(final); + mTerrainManager->setAmbient(final); } void RenderingManager::sunEnable(bool real) diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 9390d0664..923b0b7e3 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -19,6 +19,7 @@ Fader::Fader(Ogre::SceneManager* sceneMgr) , mTargetAlpha(0.f) , mCurrentAlpha(0.f) , mStartAlpha(0.f) + , mFactor(1.f) { // Create the fading material MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); @@ -62,19 +63,20 @@ void Fader::update(float dt) mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; } - - applyAlpha(); - + mRemainingTime -= dt; } - if (mCurrentAlpha == 0.f) mRectangle->setVisible(false); + if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) + mRectangle->setVisible(false); + else + applyAlpha(); } void Fader::applyAlpha() { mRectangle->setVisible(true); - mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, mCurrentAlpha); + mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor)); } void Fader::fadeIn(float time) diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index bddf5dc91..53124e2f6 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -29,6 +29,8 @@ namespace Render void fadeOut(const float time); void fadeTo(const int percent, const float time); + void setFactor (float factor) { mFactor = factor; } + private: enum FadingMode { @@ -49,6 +51,8 @@ namespace Render float mCurrentAlpha; float mStartAlpha; + float mFactor; + Ogre::SceneManager* mSceneMgr; }; }} From 0817d59f23d4b2f36711109696c87cf6c22ad672 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 19:09:36 -0700 Subject: [PATCH 072/134] Allow specifying where to start in an animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++------- apps/openmw/mwrender/animation.cpp | 18 +++++++++++++----- apps/openmw/mwrender/animation.hpp | 18 ++++++++++++++++-- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2a7ab8b09..9397b2e35 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -204,15 +204,15 @@ void CharacterController::update(float duration, Movement &movement) } else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) { - if(mAnimQueue.size() > 0) + if(mAnimQueue.size() == 0) + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + else { mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", count); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } - else - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } movement.mRotation[0] += rot.x * duration; @@ -244,7 +244,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -275,7 +275,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2f453516..0f509d276 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ void Animation::updatePosition(Ogre::Vector3 &position) mAccumRoot->setPosition(-mLastPosition); } -bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -432,9 +432,17 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: mLayer[layeridx].mLoopStartKey = startkey; mLayer[layeridx].mStopKey = stopkey; mLayer[layeridx].mNextKey = startkey; - mLayer[layeridx].mNextKey++; - mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first + ((mLayer[layeridx].mStopKey->first- + mLayer[layeridx].mStartKey->first) * startpoint); + + tag = groupname+": loop start"; + while(mLayer[layeridx].mNextKey->first <= mLayer[layeridx].mTime && mLayer[layeridx].mNextKey != mLayer[layeridx].mStopKey) + { + if(mLayer[layeridx].mNextKey->second == tag) + mLayer[layeridx].mLoopStartKey = mLayer[layeridx].mNextKey; + mLayer[layeridx].mNextKey++; + } if(layeridx == 0 && nonaccumctrl) mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; @@ -507,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -554,7 +562,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop, startpoint)) continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 526bca69a..d7f38545f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,7 +95,10 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint); bool doLoop(size_t layeridx); @@ -123,7 +126,18 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); + /** Plays an animation. + * \param groupname Name of the animation group to play. + * \param start Key marker from which to start. + * \param stop Key marker to stop at. + * \param startpoint How far in between the two markers to start. 0 starts + * at the start marker, 1 starts at the stop marker. + * \param loops How many times to loop the animation. This will use the + * "loop start" and "loop stop" markers if they exist, + * otherwise it will use "start" and "stop". + */ + void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + virtual Ogre::Vector3 runAnimation(float timepassed); bool isPlaying(size_t layeridx) const diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c22d8a4da..24b089db3 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", 0); + mAnimation->play("inventoryhandtohand", "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", 0); + mAnimation->play("idle", "start", "stop", 0.0f, 0); updateCamera(); } From 9e3917881d5d4f0b1c23c31d879369a06a9bc4bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 04:44:30 +0200 Subject: [PATCH 073/134] Don't fail on nonexistent items in a levelled list --- apps/openmw/mwworld/containerstore.cpp | 85 ++++++++++++++------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05026a98b..5cf534239 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -193,59 +193,68 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + try { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - const std::vector& items = levItem->mList; + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); - - failChance += levItem->mChanceNone; - - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i()->mBase; + const std::vector& items = levItem->mList; - float random = static_cast (std::rand()) / RAND_MAX; - if (random >= failChance/100.f) - { - std::vector candidates; - int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - if (it->mLevel > highestLevel) - highestLevel = it->mLevel; + for (int i=0; i highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + float random = static_cast (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) { - if (playerLevel >= it->mLevel - && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { - candidates.push_back(it->mId); - if (it->mLevel >= highest.first) - highest = std::make_pair(it->mLevel, it->mId); + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; } + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, owner, count, failChance, false); } - if (!candidates.size()) - return; - std::string item = candidates[std::rand()%candidates.size()]; - addInitialItem(item, owner, count, failChance, false); + } + else + { + ref.getPtr().getRefData().setCount (count); + ref.getPtr().getCellRef().mOwner = owner; + addImp (ref.getPtr()); } } - else + catch (std::logic_error& e) { - ref.getPtr().getRefData().setCount (count); - ref.getPtr().getCellRef().mOwner = owner; - addImp (ref.getPtr()); + // Vanilla doesn't fail on nonexistent items in levelled lists + std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; + return; } } From 24f1eba9025f3e7dca4ff20fcd9fb9fba57eb74a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 22:45:43 -0700 Subject: [PATCH 074/134] Keep track of whether an animation supplies movement Also handle it when it doesn't. --- apps/openmw/mwmechanics/character.cpp | 18 ++++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 22 ++++++++++++++++------ apps/openmw/mwrender/animation.hpp | 5 ++++- apps/openmw/mwrender/npcanimation.cpp | 6 +++--- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9397b2e35..0085f8de6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,7 +103,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) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false), mMovingAnim(false) { if(!mAnimation) return; @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -180,6 +180,9 @@ void CharacterController::update(float duration, Movement &movement) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); + // If this animation isn't moving us sideways, do it manually + if(!mMovingAnim) + movement.mPosition[0] += vec.x * (speed*duration); // Apply any forward/backward movement manually movement.mPosition[1] += vec.y * (speed*duration); } @@ -194,6 +197,9 @@ void CharacterController::update(float duration, Movement &movement) // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); + // If this animation isn't moving us forward/backward, do it manually + if(!mMovingAnim) + movement.mPosition[1] += vec.y * (speed*duration); } else if(rot.z != 0.0f && !inwater && !sneak) { @@ -211,7 +217,7 @@ void CharacterController::update(float duration, Movement &movement) mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } } @@ -244,7 +250,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); + mMovingAnim = mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -272,10 +278,10 @@ void CharacterController::setState(CharacterState state, bool loop) std::string anim; getStateInfo(mState, &anim); - if(mAnimation->hasAnimation(anim)) + if((mMovingAnim=mAnimation->hasAnimation(anim)) != false) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index ffd220ff2..8e4bd2f09 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,8 @@ class CharacterController CharacterState mState; bool mSkipAnim; + bool mMovingAnim; + public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); virtual ~CharacterController(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0f509d276..5838b1ff3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -317,7 +317,7 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname) { const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; @@ -340,8 +340,8 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum; + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum; return startpos.distance(endpos) / (stoptime-starttime); } @@ -515,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) +bool Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -523,6 +523,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) iter->mActiveLayers &= ~(1<mActiveLayers |= (1< 0.0f) break; + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, mAccumulate, groupname); + if(mAnimVelocity > 1.0f) + { + movinganim = (nonaccumctrl==mNonAccumCtrl); + break; + } } if(!foundanim) std::cerr<< "Failed to find animation "< *nonaccumctrl, + const Ogre::Vector3 &accum, const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on @@ -135,8 +136,10 @@ public: * \param loops How many times to loop the animation. This will use the * "loop start" and "loop stop" markers if they exist, * otherwise it will use "start" and "stop". + * \return Boolean specifying whether the animation will return movement + * for the character at all. */ - void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + bool play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b05b4ba6..c0f2e7e29 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -97,10 +97,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); addObjectList(node, smodel, true); - if(!mNpc->isMale() && !isBeast) - addObjectList(node, "meshes\\base_anim_female.nif", true); - else if(mBodyPrefix.find("argonian") != std::string::npos) + if(mBodyPrefix.find("argonian") != std::string::npos) addObjectList(node, "meshes\\argonian_swimkna.nif", true); + else if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.nif", true); if(mNpc->mModel.length() > 0) addObjectList(node, "meshes\\"+mNpc->mModel, true); From 09fc50948bff04e319dedc646c17e92be0f16ae5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 00:03:27 -0700 Subject: [PATCH 075/134] Add methods to disable and get info for a layer --- apps/openmw/mwrender/animation.cpp | 54 ++++++++++++++++++++++-------- apps/openmw/mwrender/animation.hpp | 16 ++++++++- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5838b1ff3..36fa1197d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -225,6 +225,8 @@ void Animation::updateActiveControllers() break; } } + if(ctrls == NULL) + continue; /* Check if any objectlists are active on subsequent layers. Include * those layers if not. @@ -239,7 +241,6 @@ void Animation::updateActiveControllers() } } - assert(ctrls != NULL); std::vector >::const_iterator ctrl(ctrls->begin()); for(;ctrl != ctrls->end();ctrl++) { @@ -525,21 +526,9 @@ bool Animation::play(const std::string &groupname, const std::string &start, con bool movinganim = false; bool foundanim = false; - if(groupname.empty()) - { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLoopCount = 0; - mLayer[layeridx].mPlaying = false; - - foundanim = true; - } /* Look in reverse; last-inserted source has priority. */ - else for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) { NifOgre::ObjectList &objlist = iter->mObjectList; if(objlist.mTextKeys.size() == 0) @@ -602,6 +591,43 @@ bool Animation::play(const std::string &groupname, const std::string &start, con return movinganim; } +void Animation::disable(size_t layeridx) +{ + if(mLayer[layeridx].mGroupName.empty()) + return; + + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<first) / + (mLayer[layeridx].mStopKey->first - mLayer[layeridx].mStartKey->first); + if(groupname) *groupname = mLayer[layeridx].mGroupName; + if(start) *start = mLayer[layeridx].mStartKey->second.substr(mLayer[layeridx].mGroupName.size()+2); + if(stop) *stop = mLayer[layeridx].mStopKey->second.substr(mLayer[layeridx].mGroupName.size()+2); + return true; +} + + Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f349dd71f..4d342e0b1 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -141,8 +141,22 @@ public: */ bool play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); - virtual Ogre::Vector3 runAnimation(float timepassed); + /** Stops and removes the animation from the given layer. */ + void disable(size_t layeridx); + /** Gets info about the given animation layer. + * \param layeridx Layer index to get info about. + * \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc. + * \param groupname Stores animation group being played. + * \param start Stores the start key + * \param stop Stores the stop key + * \return True if an animation is active on the layer, false otherwise. + */ + bool getInfo(size_t layeridx, float *complete=NULL, std::string *groupname=NULL, std::string *start=NULL, std::string *stop=NULL) const; + + virtual Ogre::Vector3 runAnimation(float duration); + + /* Returns if there's an animation playing on the given layer. */ bool isPlaying(size_t layeridx) const { return mLayer[layeridx].mPlaying; } From 7eac37be231eb7ef883ca65b448383b81f7e7c6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 00:18:02 -0700 Subject: [PATCH 076/134] Make sure the old layer is cleared before starting the next --- apps/openmw/mwrender/animation.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 36fa1197d..8d6508aee 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -524,6 +524,12 @@ bool Animation::play(const std::string &groupname, const std::string &start, con for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) iter->mActiveLayers &= ~(1< Date: Thu, 25 Apr 2013 00:52:26 -0700 Subject: [PATCH 077/134] Only set mSkelBase from the first objectlist --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8d6508aee..7383734ee 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -106,7 +106,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b NifOgre::ObjectList &objlist = obj.mObjectList; if(objlist.mSkelBase) { - if(!mSkelBase) + if(mObjects.size() == 1) mSkelBase = objlist.mSkelBase; Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); @@ -125,7 +125,9 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); - + } + if(objlist.mSkelBase && mSkelBase) + { Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); if(mSkelBase == objlist.mSkelBase) { @@ -286,6 +288,9 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { + if(!mSkelBase) + return false; + for(std::vector::const_iterator iter(mObjects.begin());iter != mObjects.end();iter++) { if(iter->mObjectList.mTextKeys.size() == 0) @@ -521,6 +526,9 @@ bool Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; + if(!mSkelBase) + return false; + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) iter->mActiveLayers &= ~(1< Date: Thu, 25 Apr 2013 10:27:43 +0200 Subject: [PATCH 078/134] fixed a typo in a doxygen comment --- apps/openmw/mwdialogue/journalentry.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 19a9f42b5..9d009b48b 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -3,7 +3,7 @@ #include -namespace MWWorld +namespace MWWorld { struct ESMStore; } @@ -27,7 +27,7 @@ namespace MWDialogue static std::string idFromIndex (const std::string& topic, int index); }; - /// \biref A quest entry with a timestamp. + /// \brief A quest entry with a timestamp. struct StampedJournalEntry : public JournalEntry { int mDay; From d5d14c514758b9137850b521a12f58f0cc48edbf Mon Sep 17 00:00:00 2001 From: pvdk Date: Thu, 25 Apr 2013 11:04:12 +0200 Subject: [PATCH 079/134] Fixes issue with multiple spaces in plugin filename not being read correctly --- apps/launcher/settings/gamesettings.cpp | 6 +++--- apps/launcher/settings/settingsbase.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 56c08582f..9a9b8df41 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -96,15 +96,15 @@ bool GameSettings::readFile(QTextStream &stream) QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); while (!stream.atEnd()) { - QString line = stream.readLine().simplified(); + QString line = stream.readLine(); if (line.isEmpty() || line.startsWith("#")) continue; if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1).simplified(); - QString value = keyRe.cap(2).simplified(); + QString key = keyRe.cap(1); + QString value = keyRe.cap(2); // Don't remove existing data entries if (key != QLatin1String("data")) diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index bbfad1fbb..155f5f9a9 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -52,7 +52,7 @@ public: QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); while (!stream.atEnd()) { - QString line = stream.readLine().simplified(); + QString line = stream.readLine(); if (line.isEmpty() || line.startsWith("#")) continue; @@ -65,8 +65,8 @@ public: if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1).simplified(); - QString value = keyRe.cap(2).simplified(); + QString key = keyRe.cap(1); + QString value = keyRe.cap(2); if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); From 9be20b90f1bfa0fea800f12db2f176371a4bd33d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 03:35:40 -0700 Subject: [PATCH 080/134] Fix potential infinite loop when layer 0 is empty --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7383734ee..81701c65e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,7 +228,10 @@ void Animation::updateActiveControllers() } } if(ctrls == NULL) + { + layer++; continue; + } /* Check if any objectlists are active on subsequent layers. Include * those layers if not. From 9a2a32f2a5c5a826cbac4f441927fc1610c0730d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 03:44:15 -0700 Subject: [PATCH 081/134] Add a method to clear all Animation sources except the first The first needs to remain, since that's where any mSkelBase entity comes from, and where any retrieved nodes are from. --- apps/openmw/mwrender/animation.cpp | 33 ++++++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++++ 2 files changed, 38 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 81701c65e..b4a219e38 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -187,6 +187,36 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::clearExtraSources() +{ + for(size_t layer = 0;layer < sMaxLayers;layer++) + { + mLayer[layer].mGroupName.clear(); + mLayer[layer].mTextKeys = NULL; + mLayer[layer].mControllers = NULL; + mLayer[layer].mTime = 0.0f; + mLayer[layer].mLoopCount = 0; + mLayer[layer].mPlaying = false; + } + mNonAccumCtrl = NULL; + mAnimVelocity = 0.0f; + + mLastPosition = Ogre::Vector3(0.0f); + if(mAccumRoot) + mAccumRoot->setPosition(mLastPosition); + + if(mObjects.size() > 1) + { + mObjects.resize(1); + mObjects[0].mActiveLayers = 0; + + NifOgre::ObjectList &objlist = mObjects[0].mObjectList; + mActiveCtrls.clear(); + mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); + } +} + + void Animation::updateActiveControllers() { mActiveCtrls.clear(); @@ -538,6 +568,7 @@ bool Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; + mLayer[layeridx].mTime = 0.0f; mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; @@ -571,6 +602,7 @@ bool Animation::play(const std::string &groupname, const std::string &start, con { if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop, startpoint)) continue; + mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; mLayer[layeridx].mControllers = &objlist.mControllers; @@ -619,6 +651,7 @@ void Animation::disable(size_t layeridx) mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; + mLayer[layeridx].mTime = 0.0f; mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4d342e0b1..3b6cc4abf 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -116,6 +116,11 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); + /** Clears all ObjectLists except the first one. As a consequence, any + * playing animations are stopped. + */ + void clearExtraSources(); + void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); From 2769adcee09fd51ede8063c4705436b485c1a167 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 05:23:05 -0700 Subject: [PATCH 082/134] Implement switching to and from first-person animations Note that the current animation gets interrupted, so switching to first person may break movement until you stop and try to move again. This can be fixed by alerting the character controller in the mechanics manager to force a state update when switching POV. --- apps/openmw/mwrender/npcanimation.cpp | 42 +++++++++++++-------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c0f2e7e29..563bca4c7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -97,14 +97,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); addObjectList(node, smodel, true); - if(mBodyPrefix.find("argonian") != std::string::npos) - addObjectList(node, "meshes\\argonian_swimkna.nif", true); - else if(!mNpc->isMale() && !isBeast) - addObjectList(node, "meshes\\base_anim_female.nif", true); - if(mNpc->mModel.length() > 0) - addObjectList(node, "meshes\\"+mNpc->mModel, true); - - forceUpdate(); + if(viewMode != VM_HeadOnly) + setViewMode(viewMode); + else + forceUpdate(); } void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) @@ -112,28 +108,30 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) assert(viewMode != VM_HeadOnly); mViewMode = viewMode; - /* FIXME: Enable this once first-person animations work. */ -#if 0 + Ogre::SceneNode *node = mInsert->getParentSceneNode(); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; - std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); - if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); - else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + clearExtraSources(); + if(mBodyPrefix.find("argonian") != std::string::npos) + addObjectList(node, "meshes\\argonian_swimkna.nif", true); + else if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + addObjectList(node, "meshes\\"+mNpc->mModel, true); if(mViewMode == VM_FirstPerson) { - smodel = (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif"); - skelnames.push_back(smodel); + /* A bit counter-intuitive, but unlike third-person anims, it seems + * beast races get both base_anim.1st.nif and base_animkna.1st.nif. + */ + addObjectList(node, "meshes\\base_anim.1st.nif", true); + if(isBeast) + addObjectList(node, "meshes\\base_animkna.1st.nif", true); + if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.1st.nif", true); } - setAnimationSources(skelnames); -#endif for(size_t i = 0;i < sPartListSize;i++) removeIndividualPart(i); From 9da2c9153e7b035cb3bb46cc4437586c6fcd21c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 06:12:37 -0700 Subject: [PATCH 083/134] Don't store the animation group string in the character controller --- apps/openmw/mwmechanics/character.cpp | 21 +++++++++------------ apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0085f8de6..cf323b0f2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -108,7 +108,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; - getStateInfo(mState, &mCurrentGroup); + std::string group; + getStateInfo(mState, &group); if(MWWorld::Class::get(mPtr).isActor()) { /* Accumulate along X/Y only for now, until we can figure out how we should @@ -120,8 +121,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim /* Don't accumulate with non-actors. */ mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } - if(mAnimation->hasAnimation(mCurrentGroup)) - mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); + if(mAnimation->hasAnimation(group)) + mMovingAnim = mAnimation->play(group, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -214,10 +215,10 @@ void CharacterController::update(float duration, Movement &movement) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); else { - mCurrentGroup = mAnimQueue.front().first; - size_t count = mAnimQueue.front().second; + mMovingAnim = mAnimation->play(mAnimQueue.front().first, + "start", "stop", 0.0f, + mAnimQueue.front().second); mAnimQueue.pop_front(); - mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } } @@ -248,9 +249,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mMovingAnim = mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); + mMovingAnim = mAnimation->play(groupname, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -279,10 +279,7 @@ void CharacterController::setState(CharacterState state, bool loop) std::string anim; getStateInfo(mState, &anim); if((mMovingAnim=mAnimation->hasAnimation(anim)) != false) - { - mCurrentGroup = anim; - mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); - } + mMovingAnim = mAnimation->play(anim, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8e4bd2f09..d102e6961 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -75,7 +75,6 @@ class CharacterController typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; - std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; From e4eb4b7e307d47451d310b2f17f7ac56b369bcdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 06:29:17 -0700 Subject: [PATCH 084/134] Keep track of the character looping state --- apps/openmw/mwmechanics/character.cpp | 16 +++++++++------- apps/openmw/mwmechanics/character.hpp | 5 +++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cf323b0f2..682ad834c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,13 +103,13 @@ 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), mMovingAnim(false) + : mPtr(ptr), mAnimation(anim), mCharState(state), mSkipAnim(false), mMovingAnim(false) { if(!mAnimation) return; std::string group; - getStateInfo(mState, &group); + getStateInfo(mCharState, &group); if(MWWorld::Class::get(mPtr).isActor()) { /* Accumulate along X/Y only for now, until we can figure out how we should @@ -249,7 +249,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mState = CharState_SpecialIdle; + mCharState = CharState_SpecialIdle; + mLooping = false; mMovingAnim = mAnimation->play(groupname, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) @@ -268,18 +269,19 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { - if(mState == state) + if(mCharState == state) return; - mState = state; + mCharState = state; + mLooping = loop; if(!mAnimation) return; mAnimQueue.clear(); std::string anim; - getStateInfo(mState, &anim); + getStateInfo(mCharState, &anim); if((mMovingAnim=mAnimation->hasAnimation(anim)) != false) - mMovingAnim = mAnimation->play(anim, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(anim, "start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d102e6961..bfaf33be5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -75,7 +75,8 @@ class CharacterController typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; - CharacterState mState; + CharacterState mCharState; + bool mLooping; bool mSkipAnim; bool mMovingAnim; @@ -93,7 +94,7 @@ public: void setState(CharacterState state, bool loop); CharacterState getState() const - { return mState; } + { return mCharState; } }; } From 274f3c7b778be536b81e2bfd67ded22c8508e339 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 07:08:11 -0700 Subject: [PATCH 085/134] Force character state to update after switching view modes --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwmechanics/actors.cpp | 7 ++++++ apps/openmw/mwmechanics/actors.hpp | 2 ++ apps/openmw/mwmechanics/character.cpp | 5 ++++ apps/openmw/mwmechanics/character.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 6 +++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwrender/npcanimation.cpp | 25 ++++++++++++++++--- 8 files changed, 48 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 020647744..38794269b 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -99,6 +99,9 @@ namespace MWBase float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC + virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; + ///< Forces an object to refresh its animation state. + 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. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 82e46ea46..a20bf6d1f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -290,6 +290,13 @@ namespace MWMechanics return 0; } + void Actors::forceStateUpdate(const MWWorld::Ptr & ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.forceStateUpdate(); + } + void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrControllerMap::iterator iter = mActors.find(ptr); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index aabd86dc7..c01d63093 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -78,6 +78,8 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + void forceStateUpdate(const MWWorld::Ptr &ptr); + 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 682ad834c..86a266033 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -274,6 +274,11 @@ void CharacterController::setState(CharacterState state, bool loop) mCharState = state; mLooping = loop; + forceStateUpdate(); +} + +void CharacterController::forceStateUpdate() +{ if(!mAnimation) return; mAnimQueue.clear(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index bfaf33be5..7b26d6b34 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -95,6 +95,8 @@ public: void setState(CharacterState state, bool loop); CharacterState getState() const { return mCharState; } + + void forceStateUpdate(); }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 66d20e662..969a233bc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -654,6 +654,12 @@ namespace MWMechanics } } + void MechanicsManager::forceStateUpdate(const MWWorld::Ptr &ptr) + { + if(MWWorld::Class::get(ptr).isActor()) + mActors.forceStateUpdate(ptr); + } + void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { if(MWWorld::Class::get(ptr).isActor()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 4b8d42cd3..f3a38bf36 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -96,6 +96,8 @@ namespace MWMechanics void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC + virtual void forceStateUpdate(const MWWorld::Ptr &ptr); + 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/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 563bca4c7..9403c7dd3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "renderconst.hpp" @@ -97,10 +98,25 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); addObjectList(node, smodel, true); - if(viewMode != VM_HeadOnly) - setViewMode(viewMode); - else - forceUpdate(); + if(mBodyPrefix.find("argonian") != std::string::npos) + addObjectList(node, "meshes\\argonian_swimkna.nif", true); + else if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.nif", true); + if(mNpc->mModel.length() > 0) + addObjectList(node, "meshes\\"+mNpc->mModel, true); + if(mViewMode == VM_FirstPerson) + { + /* A bit counter-intuitive, but unlike third-person anims, it seems + * beast races get both base_anim.1st.nif and base_animkna.1st.nif. + */ + addObjectList(node, "meshes\\base_anim.1st.nif", true); + if(isBeast) + addObjectList(node, "meshes\\base_animkna.1st.nif", true); + if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.1st.nif", true); + } + + forceUpdate(); } void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) @@ -132,6 +148,7 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) if(!mNpc->isMale() && !isBeast) addObjectList(node, "meshes\\base_anim_female.1st.nif", true); } + MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); for(size_t i = 0;i < sPartListSize;i++) removeIndividualPart(i); From 7cd4dd0c910b014d4d3b35e35ea71bf07021c2f6 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 25 Apr 2013 19:14:10 +0200 Subject: [PATCH 086/134] Improved local rotations --- apps/openmw/mwbase/world.hpp | 2 +- .../mwscript/transformationextensions.cpp | 42 ++++++++++--------- apps/openmw/mwworld/scene.cpp | 10 ++--- apps/openmw/mwworld/worldimp.cpp | 23 ++++++---- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index e1fb57b77..a00ae9c3c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -230,7 +230,7 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual void localRotateObject (const MWWorld::Ptr& ptr, float rotation, Ogre::Vector3 axis) = 0; + virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index f2179897d..617d496ff 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -84,29 +84,30 @@ namespace MWScript Interpreter::Type_Float angle = runtime[0].mFloat; runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); + + float *objRot = ptr.getRefData().getPosition().rot; + + float lx = Ogre::Radian(objRot[0]).valueDegrees(); + float ly = Ogre::Radian(objRot[1]).valueDegrees(); + float lz = Ogre::Radian(objRot[2]).valueDegrees(); if (axis == "x") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,angle-lx,ay,az); } else if (axis == "y") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,angle-ly,az); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,angle-lz); } else throw std::runtime_error ("invalid ration axis: " + axis); - - //Local rotations clear - ptr.getRefData().getLocalRotation().rot[0]=0; - ptr.getRefData().getLocalRotation().rot[1]=0; - ptr.getRefData().getLocalRotation().rot[2]=0; } }; @@ -153,15 +154,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -561,21 +562,24 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); + float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); + if (axis == "x") { - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax+rotation,ay,az); } else if (axis == "y") { - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay+rotation,az); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); + MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,az+rotation); } - else - throw std::runtime_error ("invalid rotation axis: " + axis); + throw std::runtime_error ("invalid ration axis: " + axis); } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b11b59ac6..df35a6f5b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -49,13 +49,11 @@ namespace { rendering.addObject(ptr); class_.insertObject(ptr, physics); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - //To keep local-rotations - const float *local = ptr.getRefData().getLocalRotation().rot; - MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[0], Ogre::Vector3::UNIT_X); - MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[1], Ogre::Vector3::UNIT_Y); - MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[2], Ogre::Vector3::UNIT_Z); + float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, ax, ay, az); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); class_.adjustPosition(ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index aa9107c6e..2f488a230 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -824,18 +824,25 @@ namespace MWWorld } } - void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) + void World::localRotateObject (const Ptr& ptr, float x, float y, float z) { if (ptr.getRefData().getBaseNode() != 0) { - if(axis==Ogre::Vector3::UNIT_X) - ptr.getRefData().getLocalRotation().rot[0]+=rotation; - else if(axis==Ogre::Vector3::UNIT_Y) - ptr.getRefData().getLocalRotation().rot[1]+=rotation; - else if(axis==Ogre::Vector3::UNIT_Z) - ptr.getRefData().getLocalRotation().rot[2]+=rotation; + ptr.getRefData().getLocalRotation().rot[0]=Ogre::Degree(x).valueRadians(); + ptr.getRefData().getLocalRotation().rot[1]=Ogre::Degree(y).valueRadians(); + ptr.getRefData().getLocalRotation().rot[2]=Ogre::Degree(z).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + float *worldRot = ptr.getRefData().getPosition().rot; + + Ogre::Quaternion worldRotQuat(Ogre::Quaternion(Ogre::Radian(-worldRot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-worldRot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-worldRot[2]), Ogre::Vector3::UNIT_Z)); + + Ogre::Quaternion rot(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-x).valueRadians()), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-y).valueRadians()), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-z).valueRadians()), Ogre::Vector3::UNIT_Z)); + + ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); mPhysics->rotateObject(ptr); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index b0eb65679..a51bdc2e6 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -254,7 +254,7 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - virtual void localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis); + virtual void localRotateObject (const Ptr& ptr, float x, float y, float z); virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. From 240217ae421c1455b08459533e471482600195b9 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 25 Apr 2013 20:52:38 +0200 Subject: [PATCH 087/134] Fixed rotations more than 360 degrees --- apps/openmw/mwworld/worldimp.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2f488a230..d3190e0b5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -818,6 +818,22 @@ namespace MWWorld objRot[1] = rot.y; objRot[2] = rot.z; + float fullRotateRad=Ogre::Degree(360).valueRadians(); + + while(objRot[0]>=fullRotateRad) + objRot[0] -= fullRotateRad; + while(objRot[1]>=fullRotateRad) + objRot[1] -= fullRotateRad; + while(objRot[2]>=fullRotateRad) + objRot[2] -= fullRotateRad; + + while(objRot[0]<=-fullRotateRad) + objRot[0] += fullRotateRad; + while(objRot[1]<=-fullRotateRad) + objRot[1] += fullRotateRad; + while(objRot[2]<=-fullRotateRad) + objRot[2] += fullRotateRad; + if (ptr.getRefData().getBaseNode() != 0) { mPhysics->rotateObject(ptr); } @@ -832,6 +848,22 @@ namespace MWWorld ptr.getRefData().getLocalRotation().rot[1]=Ogre::Degree(y).valueRadians(); ptr.getRefData().getLocalRotation().rot[2]=Ogre::Degree(z).valueRadians(); + float fullRotateRad=Ogre::Degree(360).valueRadians(); + + while(ptr.getRefData().getLocalRotation().rot[0]>=fullRotateRad) + ptr.getRefData().getLocalRotation().rot[0]-=fullRotateRad; + while(ptr.getRefData().getLocalRotation().rot[1]>=fullRotateRad) + ptr.getRefData().getLocalRotation().rot[1]-=fullRotateRad; + while(ptr.getRefData().getLocalRotation().rot[2]>=fullRotateRad) + ptr.getRefData().getLocalRotation().rot[2]-=fullRotateRad; + + while(ptr.getRefData().getLocalRotation().rot[0]<=-fullRotateRad) + ptr.getRefData().getLocalRotation().rot[0]+=fullRotateRad; + while(ptr.getRefData().getLocalRotation().rot[1]<=-fullRotateRad) + ptr.getRefData().getLocalRotation().rot[1]+=fullRotateRad; + while(ptr.getRefData().getLocalRotation().rot[2]<=-fullRotateRad) + ptr.getRefData().getLocalRotation().rot[2]+=fullRotateRad; + float *worldRot = ptr.getRefData().getPosition().rot; Ogre::Quaternion worldRotQuat(Ogre::Quaternion(Ogre::Radian(-worldRot[0]), Ogre::Vector3::UNIT_X)* From a373f539886e1d1752f9b354f465badbd2289da9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Apr 2013 02:02:51 +0200 Subject: [PATCH 088/134] Added SetAtStart --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- .../mwscript/transformationextensions.cpp | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index b7ee2d31c..e201d13f7 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -322,5 +322,7 @@ op 0x20001ff: Rotate op 0x2000200: Rotate, explicit reference op 0x2000201: RotateWorld op 0x2000202: RotateWorld, explicit reference +op 0x2000203: SetAtStart +op 0x2000204: SetAtStart, explicit -opcodes 0x2000203-0x3ffffff unused +opcodes 0x2000205-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 617d496ff..cb06faea7 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -620,6 +620,24 @@ namespace MWScript } }; + template + class OpSetAtStart : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + ptr.getRefData().getLocalRotation().rot[0] = 0; + ptr.getRefData().getLocalRotation().rot[1] = 0; + ptr.getRefData().getLocalRotation().rot[2] = 0; + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().mPos.pos[0], + ptr.getCellRef().mPos.pos[1], ptr.getCellRef().mPos.pos[2]); + + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -650,6 +668,8 @@ namespace MWScript const int opcodeRotateExplicit = 0x2000200; const int opcodeRotateWorld = 0x2000201; const int opcodeRotateWorldExplicit = 0x2000202; + const int opcodeSetAtStart = 0x2000203; + const int opcodeSetAtStartExplicit = 0x2000204; void registerExtensions (Compiler::Extensions& extensions) { @@ -669,6 +689,7 @@ namespace MWScript extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); + extensions.registerInstruction("setatstart","",opcodeSetAtStart,opcodeSetAtStartExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -702,6 +723,8 @@ namespace MWScript interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); interpreter.installSegment5(opcodeRotateWorld,new OpRotateWorld); interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); + interpreter.installSegment5(opcodeSetAtStart,new OpSetAtStart); + interpreter.installSegment5(opcodeSetAtStartExplicit,new OpSetAtStart); } } } From 7821610ec60df01710d5762d8b3708634e88204a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 26 Apr 2013 02:08:53 +0200 Subject: [PATCH 089/134] Make OnDeath work with explicit reference --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/statsextensions.cpp | 14 ++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index e201d13f7..3abd14c78 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -324,5 +324,6 @@ op 0x2000201: RotateWorld op 0x2000202: RotateWorld, explicit reference op 0x2000203: SetAtStart op 0x2000204: SetAtStart, explicit +op 0x2000205: OnDeath, explicit -opcodes 0x2000205-0x3ffffff unused +opcodes 0x2000206-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 1d321fbbb..04e89edc6 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1025,16 +1025,14 @@ namespace MWScript } }; + template class OpOnDeath : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - MWWorld::Ptr ptr = context.getReference(); + MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = MWWorld::Class::get (ptr).getCreatureStats (ptr).hasDied(); @@ -1146,9 +1144,8 @@ namespace MWScript const int opcodeRaiseRankExplicit = 0x20001e9; const int opcodeLowerRank = 0x20001ea; const int opcodeLowerRankExplicit = 0x20001eb; - const int opcodeOnDeath = 0x20001fc; - + const int opcodeOnDeathExplicit = 0x2000205; const int opcodeIsWerewolf = 0x20001fd; const int opcodeIsWerewolfExplicit = 0x20001fe; @@ -1266,7 +1263,7 @@ namespace MWScript extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); - extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); + extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath, opcodeOnDeathExplicit); extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit); } @@ -1384,7 +1381,8 @@ namespace MWScript interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); - interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); + interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); + interpreter.installSegment5 (opcodeOnDeathExplicit, new OpOnDeath); interpreter.installSegment5 (opcodeIsWerewolf, new OpIsWerewolf); interpreter.installSegment5 (opcodeIsWerewolfExplicit, new OpIsWerewolf); From 55ee4e65a9ed647a96a6c48e086e14efdc511550 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Apr 2013 23:42:20 -0700 Subject: [PATCH 090/134] Clean up the slotlist struct --- apps/openmw/mwrender/npcanimation.cpp | 132 +++++++++----------------- 1 file changed, 47 insertions(+), 85 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9403c7dd3..1b1f01f9d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -158,84 +158,31 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) void NpcAnimation::updateParts(bool forceupdate) { static const struct { - int numRemoveParts; // Max: 1 - ESM::PartReferenceType removeParts[1]; - - MWWorld::ContainerStoreIterator NpcAnimation::*part; - int slot; - - int numReserveParts; // Max: 12 - ESM::PartReferenceType reserveParts[12]; + MWWorld::ContainerStoreIterator NpcAnimation::*mPart; + int mSlot; + int mBasePriority; } slotlist[] = { - { 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, { } - }, + // FIXME: Priority is based on the number of reserved slots. There should be a better way. + { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe, 12 }, + { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt, 3 }, + { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet, 0 }, + { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass, 0 }, + { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves, 0 }, + { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron, 0 }, + { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron, 0 }, + { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots, 0 }, + { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet, 0 }, + { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, + { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, + { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 0 }, }; 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 = inv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].part != iter) + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot); + if(this->*slotlist[i].mPart != iter) { forceupdate = true; break; @@ -248,40 +195,55 @@ void NpcAnimation::updateParts(bool forceupdate) if(mViewMode == VM_FirstPerson) { for(size_t i = 0;i < slotlistsize;i++) - this->*slotlist[i].part = inv.getSlot(slotlist[i].slot); + this->*slotlist[i].mPart = inv.getSlot(slotlist[i].mSlot); return; } for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { - MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot); - this->*slotlist[i].part = iter; - removePartGroup(slotlist[i].slot); + this->*slotlist[i].mPart = iter; + removePartGroup(slotlist[i].mSlot); - if(this->*slotlist[i].part == inv.end()) + if(this->*slotlist[i].mPart == inv.end()) continue; - for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) - removeIndividualPart(slotlist[i].removeParts[rem]); + if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Helmet) + removeIndividualPart(ESM::PRT_Hair); int prio = 1; - MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part; + MWWorld::ContainerStoreIterator &store = this->*slotlist[i].mPart; if(store->getTypeName() == typeid(ESM::Clothing).name()) { - prio = ((slotlist[i].numReserveParts+1)<<1) + 0; + prio = ((slotlist[i].mBasePriority+1)<<1) + 0; const ESM::Clothing *clothes = store->get()->mBase; - addPartGroup(slotlist[i].slot, prio, clothes->mParts.mParts); + addPartGroup(slotlist[i].mSlot, prio, clothes->mParts.mParts); } else if(store->getTypeName() == typeid(ESM::Armor).name()) { - prio = ((slotlist[i].numReserveParts+1)<<1) + 1; + prio = ((slotlist[i].mBasePriority+1)<<1) + 1; const ESM::Armor *armor = store->get()->mBase; - addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts); + addPartGroup(slotlist[i].mSlot, prio, armor->mParts.mParts); } - for(int res = 0;res < slotlist[i].numReserveParts;res++) - reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); + if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Robe) + { + ESM::PartReferenceType parts[] = { + 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 + }; + size_t parts_size = sizeof(parts)/sizeof(parts[0]); + for(int p = 0;p < parts_size;p++) + reserveIndividualPart(parts[p], slotlist[i].mSlot, prio); + } + else if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Skirt) + { + reserveIndividualPart(ESM::PRT_Groin, slotlist[i].mSlot, prio); + reserveIndividualPart(ESM::PRT_RLeg, slotlist[i].mSlot, prio); + reserveIndividualPart(ESM::PRT_LLeg, slotlist[i].mSlot, prio); + } } if(mViewMode != VM_FirstPerson) From b666f1d551f7ae2c980f4547c2a9f9ef87a4c631 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Apr 2013 01:30:36 -0700 Subject: [PATCH 091/134] Work around a problem with MWRender::Player::renderPlayer NpcAnimation::setViewMode makes a call to the character controller, in the mechanics manager, to forcefully update the character's state. This in turn makes a call to the player's old NpcAniamtion object that was just deleted. The mechanics manager will eventually remove and reinsert the player, so the old character controller will be removed and a new one will get the right Animation object again, but not in time for the setViewMode call. There's many factors that all contribute to this run-around, which needs discussion on how to best fix. --- apps/openmw/mwrender/player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 439264f3a..fb0602bda 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -307,11 +307,11 @@ namespace MWRender void Player::setAnimation(NpcAnimation *anim) { + anim->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + delete mAnimation; mAnimation = anim; - - mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); } void Player::setHeight(float height) From 32138dbb0f7f444ff31f3a270885e2770ed6184c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 26 Apr 2013 13:33:47 +0200 Subject: [PATCH 092/134] silenced a warning --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1b1f01f9d..27f1508f7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -235,7 +235,7 @@ void NpcAnimation::updateParts(bool forceupdate) ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron }; size_t parts_size = sizeof(parts)/sizeof(parts[0]); - for(int p = 0;p < parts_size;p++) + for(int p = 0;p < static_cast (parts_size);++p) reserveIndividualPart(parts[p], slotlist[i].mSlot, prio); } else if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Skirt) From 89f7ef247261e67582e56d0763ed421f6977006c Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 26 Apr 2013 17:28:19 +0200 Subject: [PATCH 093/134] Move, moveworld script instructions --- apps/openmw/mwscript/docs/vmformat.txt | 4 + .../mwscript/transformationextensions.cpp | 81 ++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 3abd14c78..a0c9757d2 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -325,5 +325,9 @@ op 0x2000202: RotateWorld, explicit reference op 0x2000203: SetAtStart op 0x2000204: SetAtStart, explicit op 0x2000205: OnDeath, explicit +op 0x2000206: Move +op 0x2000207: Move, explicit +op 0x2000208: MoveWorld +op 0x2000209: MoveWorld, explicit opcodes 0x2000206-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index cb06faea7..327047cdc 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -579,7 +579,7 @@ namespace MWScript MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,az+rotation); } else - throw std::runtime_error ("invalid ration axis: " + axis); + throw std::runtime_error ("invalid rotation axis: " + axis); } }; @@ -638,6 +638,75 @@ namespace MWScript } }; + template + class OpMove : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + const MWWorld::Ptr& ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + runtime.pop(); + + Ogre::Vector3 posChange; + if (axis == "x") + { + posChange=Ogre::Vector3(movement, 0, 0); + } + else if (axis == "y") + { + posChange=Ogre::Vector3(0, movement, 0); + } + else if (axis == "z") + { + posChange=Ogre::Vector3(0, 0, movement); + } + else + throw std::runtime_error ("invalid movement axis: " + axis); + + Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); + } + }; + + template + class OpMoveWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); + runtime.pop(); + + float *objPos = ptr.getRefData().getPosition().pos; + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); + } + else + throw std::runtime_error ("invalid movement axis: " + axis); + } + }; + + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -670,6 +739,10 @@ namespace MWScript const int opcodeRotateWorldExplicit = 0x2000202; const int opcodeSetAtStart = 0x2000203; const int opcodeSetAtStartExplicit = 0x2000204; + const int opcodeMove = 0x2000206; + const int opcodeMoveExplicit = 0x2000207; + const int opcodeMoveWorld = 0x2000208; + const int opcodeMoveWorldExplicit = 0x2000209; void registerExtensions (Compiler::Extensions& extensions) { @@ -690,6 +763,8 @@ namespace MWScript extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); extensions.registerInstruction("setatstart","",opcodeSetAtStart,opcodeSetAtStartExplicit); + extensions.registerInstruction("move","cf",opcodeMove,opcodeMoveExplicit); + extensions.registerInstruction("moveworld","cf",opcodeMoveWorld,opcodeMoveWorldExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -725,6 +800,10 @@ namespace MWScript interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); interpreter.installSegment5(opcodeSetAtStart,new OpSetAtStart); interpreter.installSegment5(opcodeSetAtStartExplicit,new OpSetAtStart); + interpreter.installSegment5(opcodeMove,new OpMove); + interpreter.installSegment5(opcodeMoveExplicit,new OpMove); + interpreter.installSegment5(opcodeMoveWorld,new OpMoveWorld); + interpreter.installSegment5(opcodeMoveWorldExplicit,new OpMoveWorld); } } } From ade871ce128015ad99f9139dd0148d33543c4e78 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 26 Apr 2013 17:31:58 +0200 Subject: [PATCH 094/134] Corrected unused opcodes --- apps/openmw/mwscript/docs/vmformat.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index a0c9757d2..be253b59b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -330,4 +330,4 @@ op 0x2000207: Move, explicit op 0x2000208: MoveWorld op 0x2000209: MoveWorld, explicit -opcodes 0x2000206-0x3ffffff unused +opcodes 0x200020a-0x3ffffff unused From 137017b3259bb0eb9c593d39aad868fef3c8adc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2013 01:24:36 -0700 Subject: [PATCH 095/134] Don't allow forcing vanity mode --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 10 ++- apps/openmw/mwrender/player.cpp | 81 ++++++++--------------- apps/openmw/mwrender/player.hpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 6 +- apps/openmw/mwworld/worldimp.hpp | 4 +- 7 files changed, 40 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a00ae9c3c..fa092203f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -317,7 +317,7 @@ namespace MWBase virtual void togglePOV() = 0; virtual void togglePreviewMode(bool enable) = 0; - virtual bool toggleVanityMode(bool enable, bool force) = 0; + virtual bool toggleVanityMode(bool enable) = 0; virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; virtual void changeVanityModeScale(float factor) = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6a34161e0..b494c4597 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -719,19 +719,17 @@ namespace MWInput void InputManager::resetIdleTime() { - if (mTimeIdle < 0) { - MWBase::Environment::get().getWorld()->toggleVanityMode(false, false); - } + if (mTimeIdle < 0) + MWBase::Environment::get().getWorld()->toggleVanityMode(false); mTimeIdle = 0.f; } void InputManager::updateIdleTime(float dt) { - if (mTimeIdle >= 0.f) { + if (mTimeIdle >= 0.f) mTimeIdle += dt; - } if (mTimeIdle > 30.f) { - MWBase::Environment::get().getWorld()->toggleVanityMode(true, false); + MWBase::Environment::get().getWorld()->toggleVanityMode(true); mTimeIdle = -1.f; } } diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index fb0602bda..0566cbd5e 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -28,7 +28,6 @@ namespace MWRender { mVanity.enabled = false; mVanity.allowed = true; - mVanity.forced = false; mCameraNode->attachObject(mCamera); mCameraNode->setPosition(0.f, 0.f, mHeight); @@ -44,32 +43,13 @@ namespace MWRender bool Player::rotate(const Ogre::Vector3 &rot, bool adjust) { - if (mVanity.enabled) { + if (mVanity.enabled) toggleVanityMode(false); - } - Ogre::Vector3 trueRot = rot; + if (mFreeLook || mVanity.enabled || mPreviewMode) + rotateCamera(rot, adjust); - /// \note rotate player on forced vanity - if (mVanity.forced) { - if (mFreeLook) { - float diff = (adjust) ? rot.z : mMainCam.yaw - rot.z; - - mVanity.enabled = false; - rotateCamera(rot, adjust); - mVanity.enabled = true; - - compensateYaw(diff); - } - trueRot.z = 0.f; - } - - if (mFreeLook || mVanity.enabled || mPreviewMode) { - rotateCamera(trueRot, adjust); - } - - /// \note if vanity mode is forced by TVM then rotate player - return (!mVanity.enabled && !mPreviewMode) || mVanity.forced; + return (!mVanity.enabled && !mPreviewMode); } void Player::rotateCamera(const Ogre::Vector3 &rot, bool adjust) @@ -81,14 +61,9 @@ namespace MWRender setYaw(rot.z); setPitch(rot.x); } - Ogre::Quaternion xr( - Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), - Ogre::Vector3::UNIT_X - ); - Ogre::Quaternion zr( - Ogre::Radian(getYaw()), - Ogre::Vector3::NEGATIVE_UNIT_Z - ); + + Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); + Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z); if (!mVanity.enabled && !mPreviewMode) { mPlayerNode->setOrientation(zr); mCameraNode->setOrientation(xr); @@ -150,23 +125,19 @@ namespace MWRender void Player::allowVanityMode(bool allow) { - if (!allow && mVanity.enabled && !mVanity.forced) { + if (!allow && mVanity.enabled) toggleVanityMode(false); - } mVanity.allowed = allow; } - bool Player::toggleVanityMode(bool enable, bool force) + bool Player::toggleVanityMode(bool enable) { - if ((mVanity.forced && !force) || - (!mVanity.allowed && (force || enable))) - { + if(!mVanity.allowed && enable) return false; - } else if (mVanity.enabled == enable) { + + if(mVanity.enabled == enable) return true; - } mVanity.enabled = enable; - mVanity.forced = force && enable; mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); @@ -185,6 +156,7 @@ namespace MWRender setLowHeight(!mFirstPersonView); } rot.z = getYaw(); + mCamera->setPosition(0.f, 0.f, offset); rotateCamera(rot, false); @@ -193,12 +165,13 @@ namespace MWRender void Player::togglePreviewMode(bool enable) { - if (mPreviewMode == enable) { + if(mPreviewMode == enable) return; - } + mPreviewMode = enable; mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + float offset = mCamera->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; @@ -211,15 +184,15 @@ namespace MWRender setLowHeight(!mFirstPersonView); } + mCamera->setPosition(0.f, 0.f, offset); rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); } float Player::getYaw() { - if (mVanity.enabled || mPreviewMode) { + if(mVanity.enabled || mPreviewMode) return mPreviewCam.yaw; - } return mMainCam.yaw; } @@ -247,16 +220,16 @@ namespace MWRender void Player::setPitch(float angle) { - const float epsilon = 0.000001; + const float epsilon = 0.000001f; float limit = Ogre::Math::HALF_PI - epsilon; - if (mVanity.forced || mPreviewMode) { - limit /= 2; - } - if (angle > limit) { + if(mPreviewMode) + limit /= 2; + + if(angle > limit) angle = limit; - } else if (angle < -limit) { + else if(angle < -limit) angle = -limit; - } + if (mVanity.enabled || mPreviewMode) { mPreviewCam.pitch = angle; } else { @@ -266,9 +239,9 @@ namespace MWRender void Player::setCameraDistance(float dist, bool adjust, bool override) { - if (mFirstPersonView && !mPreviewMode && !mVanity.enabled) { + if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) return; - } + Ogre::Vector3 v(0.f, 0.f, dist); if (adjust) { v += mCamera->getPosition(); diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 9de41823d..d9e65d9a6 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -37,7 +37,7 @@ namespace MWRender bool mFreeLook; struct { - bool enabled, allowed, forced; + bool enabled, allowed; } mVanity; float mHeight, mCameraDistance; @@ -79,7 +79,7 @@ namespace MWRender void toggleViewMode(); - bool toggleVanityMode(bool enable, bool force = false); + bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); void togglePreviewMode(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index cece7a95f..0284a6837 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -71,8 +71,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->togglePreviewMode(enable); } - bool toggleVanityMode(bool enable, bool force) { - return mPlayer->toggleVanityMode(enable, force); + bool toggleVanityMode(bool enable) { + return mPlayer->toggleVanityMode(enable); } void allowVanityMode(bool allow) { diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 489f6bd3d..1f172a2da 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -282,10 +282,8 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); - if (world->toggleVanityMode(sActivate, true)) { - context.report( - (sActivate) ? "Vanity Mode -> On" : "Vanity Mode -> Off" - ); + if (world->toggleVanityMode(sActivate)) { + context.report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); sActivate = !sActivate; } else { context.report("Vanity Mode -> No"); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a51bdc2e6..250ad9ef1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -347,8 +347,8 @@ namespace MWWorld mRendering->togglePreviewMode(enable); } - virtual bool toggleVanityMode(bool enable, bool force) { - return mRendering->toggleVanityMode(enable, force); + virtual bool toggleVanityMode(bool enable) { + return mRendering->toggleVanityMode(enable); } virtual void allowVanityMode(bool allow) { From 90b38cbfbebc2bcb5a5f4b36305f783749da3191 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 27 Apr 2013 14:06:23 +0200 Subject: [PATCH 096/134] fixed parsing of end statements in scripts with IDs matching keywords --- components/compiler/fileparser.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 98be2d3d1..185af4a51 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -71,6 +71,19 @@ namespace Compiler return true; } + if (mState==EndNameState) + { + // optional repeated name after end statement + if (mName!=loc.mLiteral) + reportWarning ("Names for script " + mName + " do not match", loc); + + mState = EndCompleteState; + 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::parseKeyword (keyword, loc, scanner); } From 3669d0a99887d8663fbb14d64d5f318c717aff62 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sat, 27 Apr 2013 20:57:44 +0200 Subject: [PATCH 097/134] Bugfix #742 --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d3190e0b5..7ceb3e2f7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1453,7 +1453,7 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos)) + if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; From 07891fa21385362be585479bc24a9e6d25957c99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 07:53:04 +0200 Subject: [PATCH 098/134] Athletics skill increase --- apps/openmw/mwmechanics/character.cpp | 26 +++++++++++++++++++++++++- apps/openmw/mwmechanics/character.hpp | 4 ++++ apps/openmw/mwmechanics/npcstats.cpp | 3 +-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 86a266033..b82fc4dc5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -28,6 +28,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -103,7 +104,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), mCharState(state), mSkipAnim(false), mMovingAnim(false) + : mPtr(ptr), mAnimation(anim), mCharState(state), mSkipAnim(false), mMovingAnim(false), mSecondsOfRunning(0), mSecondsOfSwimming(0) { if(!mAnimation) return; @@ -152,6 +153,29 @@ void CharacterController::update(float duration, Movement &movement) const Ogre::Vector3 &rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); + // advance athletics + if (vec.squaredLength() > 0 && mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) + { + if (inwater) + { + mSecondsOfSwimming += duration; + while (mSecondsOfSwimming > 1) + { + MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 1); + mSecondsOfSwimming -= 1; + } + } + else if (isrunning) + { + mSecondsOfRunning += duration; + while (mSecondsOfRunning > 1) + { + MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 0); + mSecondsOfRunning -= 1; + } + } + } + /* 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) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7b26d6b34..4ee217d11 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,10 @@ class CharacterController bool mLooping; bool mSkipAnim; + // counted for skill increase + float mSecondsOfSwimming; + float mSecondsOfRunning; + bool mMovingAnim; public: diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7216e8fe0..def91a6c5 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -169,8 +169,7 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - - return 1.0 / (level +1) * (1.0 / (skillFactor)) * typeFactor * specialisationFactor; + return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType) From ce7bc20fa199b41c00c5e30a9ed0ff301dd81872 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2013 01:14:58 -0700 Subject: [PATCH 099/134] Avoid special-casing player rotation --- apps/openmw/mwrender/player.cpp | 29 +----------- apps/openmw/mwrender/player.hpp | 7 +-- apps/openmw/mwrender/renderingmanager.cpp | 36 ++++----------- apps/openmw/mwrender/renderingmanager.hpp | 7 +-- apps/openmw/mwworld/physicssystem.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 55 +++++++++++++++-------- 6 files changed, 52 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 0566cbd5e..6835fd64c 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -40,17 +40,6 @@ namespace MWRender { delete mAnimation; } - - bool Player::rotate(const Ogre::Vector3 &rot, bool adjust) - { - if (mVanity.enabled) - toggleVanityMode(false); - - if (mFreeLook || mVanity.enabled || mPreviewMode) - rotateCamera(rot, adjust); - - return (!mVanity.enabled && !mPreviewMode); - } void Player::rotateCamera(const Ogre::Vector3 &rot, bool adjust) { @@ -63,16 +52,15 @@ namespace MWRender } Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); - Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z); if (!mVanity.enabled && !mPreviewMode) { - mPlayerNode->setOrientation(zr); mCameraNode->setOrientation(xr); } else { + Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z); mCameraNode->setOrientation(zr * xr); } } - std::string Player::getHandle() const + const std::string &Player::getHandle() const { return mPlayerNode->getName(); } @@ -318,19 +306,6 @@ namespace MWRender yaw = mMainCam.yaw; } - void Player::compensateYaw(float diff) - { - mPreviewCam.yaw -= diff; - Ogre::Quaternion zr( - Ogre::Radian(mPreviewCam.yaw), - Ogre::Vector3::NEGATIVE_UNIT_Z - ); - Ogre::Quaternion xr( - Ogre::Radian(mPreviewCam.pitch), - Ogre::Vector3::UNIT_X); - mCameraNode->setOrientation(zr * xr); - } - void Player::togglePlayerLooking(bool enable) { mFreeLook = enable; diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index d9e65d9a6..332db457c 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -57,9 +57,6 @@ namespace MWRender /// Set where the player is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians - /// \return true if player object needs to bo rotated physically - bool rotate(const Ogre::Vector3 &rot, bool adjust); - void rotateCamera(const Ogre::Vector3 &rot, bool adjust); float getYaw(); @@ -68,9 +65,7 @@ namespace MWRender float getPitch(); void setPitch(float angle); - void compensateYaw(float diff); - - std::string getHandle() const; + const std::string &getHandle() const; /// Attach camera to object /// \note there is no protection from attaching the same camera to diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index da51f10c1..1ce1baa39 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -264,37 +264,19 @@ void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3 ptr.getRefData().getBaseNode()->setScale(scale); } -bool RenderingManager::rotateObject(const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) +void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) { - bool isActive = ptr.getRefData().getBaseNode() != 0; - bool isPlayer = isActive && ptr.getRefData().getHandle() == "player"; - bool force = true; + Ogre::Vector3 rot(ptr.getRefData().getPosition().rot); - if (isPlayer) - force = mPlayer->rotate(rot, adjust); + if(ptr.getRefData().getHandle() == mPlayer->getHandle()) + mPlayer->rotateCamera(rot, false); - MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); - if (!isPlayer && isActive) - { - if(adjust) - { - const float *objRot = ptr.getRefData().getPosition().rot; - rot.x += objRot[0]; - rot.y += objRot[1]; - rot.z += objRot[2]; - } + Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); + if(!MWWorld::Class::get(ptr).isActor()) + newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * newo; - Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) * - Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * - Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); - ptr.getRefData().getBaseNode()->setOrientation(newo); - } - else if(isPlayer) - { - rot.x = -mPlayer->getPitch(); - rot.z = mPlayer->getYaw(); - } - return force; + ptr.getRefData().getBaseNode()->setOrientation(newo); } void diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0284a6837..6420a5b7e 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -121,11 +121,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale); - /// Rotates object accordingly to its type - /// \param rot euler angles in radians - /// \param adjust indicates should rotation be set or adjusted - /// \return true if object needs to be rotated physically - bool rotateObject (const MWWorld::Ptr& ptr, Ogre::Vector3 &rot, bool adjust = false); + /// Updates an object's rotation + void rotateObject (const MWWorld::Ptr& ptr); void setWaterHeight(const float height); void toggleWater(); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 19ee2e517..6a0ff6cae 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -145,7 +145,7 @@ namespace MWWorld // 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)) * + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; } @@ -161,7 +161,7 @@ namespace MWWorld { 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)) * + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement / time; } else diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d3190e0b5..d1e19bf8b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -810,33 +810,50 @@ namespace MWWorld void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) { - if (mRendering->rotateObject(ptr, rot, adjust)) + const float two_pi = Ogre::Math::TWO_PI; + const float pi = Ogre::Math::PI; + + float *objRot = ptr.getRefData().getPosition().rot; + if(adjust) + { + objRot[0] += rot.x; + objRot[1] += rot.y; + objRot[2] += rot.z; + } + else { - // rotate physically iff renderer confirm so - float *objRot = ptr.getRefData().getPosition().rot; objRot[0] = rot.x; objRot[1] = rot.y; objRot[2] = rot.z; + } - float fullRotateRad=Ogre::Degree(360).valueRadians(); + if(Class::get(ptr).isActor()) + { + /* HACK? Actors shouldn't really be rotating around X (or Y), but + * currently it's done so for rotating the camera, which needs + * clamping. + */ + const float half_pi = Ogre::Math::HALF_PI; - while(objRot[0]>=fullRotateRad) - objRot[0] -= fullRotateRad; - while(objRot[1]>=fullRotateRad) - objRot[1] -= fullRotateRad; - while(objRot[2]>=fullRotateRad) - objRot[2] -= fullRotateRad; + if(objRot[0] < -half_pi) objRot[0] = -half_pi; + else if(objRot[0] > half_pi) objRot[0] = half_pi; + } + else + { + while(objRot[0] < -pi) objRot[0] += two_pi; + while(objRot[0] > pi) objRot[0] -= two_pi; + } - while(objRot[0]<=-fullRotateRad) - objRot[0] += fullRotateRad; - while(objRot[1]<=-fullRotateRad) - objRot[1] += fullRotateRad; - while(objRot[2]<=-fullRotateRad) - objRot[2] += fullRotateRad; + while(objRot[1] < -pi) objRot[1] += two_pi; + while(objRot[1] > pi) objRot[1] -= two_pi; - if (ptr.getRefData().getBaseNode() != 0) { - mPhysics->rotateObject(ptr); - } + while(objRot[2] < -pi) objRot[2] += two_pi; + while(objRot[2] > pi) objRot[2] -= two_pi; + + if(ptr.getRefData().getBaseNode() != 0) + { + mRendering->rotateObject(ptr); + mPhysics->rotateObject(ptr); } } From db78d15fc4d7329bc2531d00da24d53085bdec60 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 05:29:34 +0200 Subject: [PATCH 100/134] Fix changeWeather --- apps/openmw/mwworld/weather.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3e8525312..d0ed835dc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -289,7 +289,7 @@ void WeatherManager::update(float duration) if (exterior) { - std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; + std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); Misc::StringUtils::toLower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) @@ -621,6 +621,10 @@ unsigned int WeatherManager::getWeatherID() const void WeatherManager::changeWeather(const std::string& region, const unsigned int id) { + // make sure this region exists + const ESM::Region *reg = + MWBase::Environment::get().getWorld()->getStore().get().find(region); + std::string weather; if (id==0) weather = "clear"; @@ -645,5 +649,9 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int else weather = "clear"; - mRegionOverrides[region] = weather; + mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; + + std::string playerRegion = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; + if (Misc::StringUtils::ciEqual(region, playerRegion)) + setWeather(weather); } From fdf80c1c4f0e0e0456eedec99356cb067852bfae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 11:05:01 +0200 Subject: [PATCH 101/134] Fix unused variable --- apps/openmw/mwworld/weather.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d0ed835dc..10d065cbc 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -622,8 +622,7 @@ unsigned int WeatherManager::getWeatherID() const void WeatherManager::changeWeather(const std::string& region, const unsigned int id) { // make sure this region exists - const ESM::Region *reg = - MWBase::Environment::get().getWorld()->getStore().get().find(region); + MWBase::Environment::get().getWorld()->getStore().get().find(region); std::string weather; if (id==0) From 7d61459ccdb4b454cf8866e241f05169d56c7ef4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 11:13:21 +0200 Subject: [PATCH 102/134] Added stub implementation for 'Fall'. There is no use for this function because our physics controller applies gravity constantly anyway. --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/miscextensions.cpp | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index be253b59b..d02fc9289 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -329,5 +329,7 @@ op 0x2000206: Move op 0x2000207: Move, explicit op 0x2000208: MoveWorld op 0x2000209: MoveWorld, explicit +op 0x200020a: Fall +op 0x200020b: Fall, explicit -opcodes 0x200020a-0x3ffffff unused +opcodes 0x200020c-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 489f6bd3d..daf64c0d5 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -557,6 +557,16 @@ namespace MWScript } }; + template + class OpFall : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -598,6 +608,8 @@ namespace MWScript const int opcodeSetDelete = 0x20001e5; const int opcodeSetDeleteExplicit = 0x20001e6; const int opcodeGetSquareRoot = 0x20001e7; + const int opcodeFall = 0x200020a; + const int opcodeFallExplicit = 0x200020b; const int opcodePlayBink = 0x20001f7; @@ -639,6 +651,7 @@ namespace MWScript extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot); + extensions.registerInstruction ("fall", "", opcodeFall, opcodeFallExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -685,6 +698,9 @@ namespace MWScript interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete); interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete); interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot); + interpreter.installSegment5 (opcodeFall, new OpFall); + interpreter.installSegment5 (opcodeFallExplicit, new OpFall); + } } } From 766d1efa845d23640e0680f8d7ccd1a41744466f Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 11:41:01 +0100 Subject: [PATCH 103/134] Render weapon and shield. Only shield can be seen right now as weapons need to be drawed out. --- apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++++++++++--- apps/openmw/mwrender/npcanimation.hpp | 5 +++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b4a219e38..39bffbded 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -737,4 +737,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) return movement; } +void Animation::showWeapons(bool showWeapon){} + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3b6cc4abf..b2d4bc6e7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -161,6 +161,8 @@ public: virtual Ogre::Vector3 runAnimation(float duration); + virtual void showWeapons(bool showWeapon); + /* Returns if there's an animation playing on the given layer. */ bool isPlaying(size_t layeridx) const { return mLayer[layeridx].mPlaying; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 27f1508f7..09d4546bc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -30,7 +30,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize { ESM::PRT_LHand, "Left Hand" }, { ESM::PRT_RWrist, "Right Wrist" }, { ESM::PRT_LWrist, "Left Wrist" }, - { ESM::PRT_Shield, "Shield" }, + { ESM::PRT_Shield, "Shield Bone" }, { ESM::PRT_RForearm, "Right Forearm" }, { ESM::PRT_LForearm, "Left Forearm" }, { ESM::PRT_RUpperarm, "Right Upper Arm" }, @@ -45,7 +45,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize { ESM::PRT_LLeg, "Left Upper Leg" }, { ESM::PRT_RPauldron, "Right Clavicle" }, { ESM::PRT_LPauldron, "Left Clavicle" }, - { ESM::PRT_Weapon, "Weapon" }, + { ESM::PRT_Weapon, "Weapon Bone" }, { ESM::PRT_Tail, "Tail" } }; @@ -74,7 +74,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveL(inv.end()), mGloveR(inv.end()), mSkirtIter(inv.end()), - mViewMode(viewMode) + mWeapon(inv.end()), + mShield(inv.end()), + mViewMode(viewMode), + mShowWeapons(false) { mNpc = mPtr.get()->mBase; @@ -175,6 +178,7 @@ void NpcAnimation::updateParts(bool forceupdate) { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 0 }, + { &NpcAnimation::mShield, MWWorld::InventoryStore::Slot_CarriedLeft, 0 } }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); @@ -333,6 +337,7 @@ void NpcAnimation::updateParts(bool forceupdate) if (mPartPriorities[part] < 1 && bodypart) addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); } + } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) @@ -464,4 +469,23 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorget())->mBase; + addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,"meshes\\"+weapon->mModel); + } + } + else + { + removeIndividualPart(ESM::PRT_Weapon); + } +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index f2f4c6669..e72fa56ed 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -46,6 +46,7 @@ private: std::string mHairModel; std::string mBodyPrefix; ViewMode mViewMode; + bool mShowWeapons; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -60,6 +61,8 @@ private: MWWorld::ContainerStoreIterator mGloveL; MWWorld::ContainerStoreIterator mGloveR; MWWorld::ContainerStoreIterator mSkirtIter; + MWWorld::ContainerStoreIterator mWeapon; + MWWorld::ContainerStoreIterator mShield; int mVisibilityFlags; @@ -85,6 +88,8 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); + virtual void showWeapons(bool showWeapon); + void setViewMode(ViewMode viewMode); void forceUpdate() From 5388c25e648cb3af79b785637c86bb9cd8d0ae7e Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 11:55:50 +0100 Subject: [PATCH 104/134] Fix or lockpicks. --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 09d4546bc..d6bc22cc0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -478,8 +478,8 @@ void NpcAnimation::showWeapons(bool showWeapon) mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(mWeapon != inv.end()) // special case for weapons { - const ESM::Weapon* weapon = (mWeapon->get())->mBase; - addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,"meshes\\"+weapon->mModel); + std::string mesh = MWWorld::Class::get(*mWeapon).getModel(*mWeapon); + addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,mesh); } } else From 3d9ceede77b5e3e08f6be7d265f4d4b49e8c6271 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 12:33:41 +0100 Subject: [PATCH 105/134] little fix (weapons disapeared when tab was pressed) --- apps/openmw/mwrender/npcanimation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d6bc22cc0..1d1ebf6b6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -338,6 +338,7 @@ void NpcAnimation::updateParts(bool forceupdate) addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); } + showWeapons(mShowWeapons); } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) From 738a54337d724971d48ea34ccb75d0016fa657c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 28 Apr 2013 14:07:53 +0200 Subject: [PATCH 106/134] removed redundant case smashing --- apps/openmw/mwworld/weather.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 10d065cbc..c940398fa 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -290,7 +290,6 @@ void WeatherManager::update(float duration) if (exterior) { std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); - Misc::StringUtils::toLower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { From 9343b4459e42f25c9ab657153c0ee431e985c520 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 14:59:15 +0200 Subject: [PATCH 107/134] Opening doors --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/door.cpp | 14 +++---- apps/openmw/mwworld/actiondoor.cpp | 16 ++++++++ apps/openmw/mwworld/actiondoor.hpp | 18 +++++++++ apps/openmw/mwworld/physicssystem.cpp | 6 ++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 56 ++++++++++++++++++++++++++- apps/openmw/mwworld/worldimp.hpp | 6 +++ libs/openengine/bullet/physic.cpp | 23 +++++++++++ libs/openengine/bullet/physic.hpp | 2 + 11 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 apps/openmw/mwworld/actiondoor.cpp create mode 100644 apps/openmw/mwworld/actiondoor.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390..08033f822 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a00ae9c3c..42821e361 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -326,6 +326,9 @@ namespace MWBase virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; + virtual void activateDoor(const MWWorld::Ptr& door) = 0; + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 163cf0277..5b061e090 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -12,6 +12,7 @@ #include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/actionteleport.hpp" +#include "../mwworld/actiondoor.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" @@ -71,7 +72,7 @@ namespace MWClass ptr.get(); const std::string &openSound = ref->mBase->mOpenSound; - //const std::string &closeSound = ref->mBase->closeSound; + const std::string &closeSound = ref->mBase->mCloseSound; const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; @@ -139,12 +140,11 @@ namespace MWClass else { // animated door - // TODO return action for rotating the door - - // This is a little pointless, but helps with testing - boost::shared_ptr action(new MWWorld::NullAction); - - action->setSound(openSound); + boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); + if (ptr.getRefData().getLocalRotation().rot[2] == 0) + action->setSound(openSound); + else + action->setSound(closeSound); return action; } diff --git a/apps/openmw/mwworld/actiondoor.cpp b/apps/openmw/mwworld/actiondoor.cpp new file mode 100644 index 000000000..6e3441e22 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.cpp @@ -0,0 +1,16 @@ +#include "actiondoor.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWWorld +{ + ActionDoor::ActionDoor (const MWWorld::Ptr& object) : Action (false, object) + { + } + + void ActionDoor::executeImp (const MWWorld::Ptr& actor) + { + MWBase::Environment::get().getWorld()->activateDoor(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actiondoor.hpp b/apps/openmw/mwworld/actiondoor.hpp new file mode 100644 index 000000000..2dc5ad8c1 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.hpp @@ -0,0 +1,18 @@ +#ifndef GAME_MWWORLD_ACTIONDOOR_H +#define GAME_MWWORLD_ACTIONDOOR_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionDoor : public Action + { + virtual void executeImp (const MWWorld::Ptr& actor); + + public: + ActionDoor (const Ptr& object); + }; +} + +#endif diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 19ee2e517..34e6036e6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -131,7 +131,6 @@ namespace MWWorld return position; } - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -390,6 +389,11 @@ namespace MWWorld } } + std::vector PhysicsSystem::getCollisions(const Ptr &ptr) + { + return mEngine->getCollisions(ptr.getRefData().getBaseNode()->getName()); + } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { return MovementSolver::move(ptr, movement, time, gravity, mEngine); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 4eec9367c..48214029e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + std::vector getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7ceb3e2f7..e4f28ecc5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -978,7 +978,45 @@ namespace MWWorld !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 + + // doors + for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) + { + if (!it->first.getRefData().getCount()) + mDoorStates.erase(it); + else + { + if (mPlayer->getPlayer().getCell() != it->first.getCell()) + continue; + float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); + float diff = duration * 90 * (it->second ? 1 : -1); + float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); + localRotateObject(it->first, 0, 0, targetRot); + + std::vector collisions = mPhysics->getCollisions(it->first); + for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + { + MWWorld::Ptr ptr = getPtrViaHandle(*cit); + if (MWWorld::Class::get(ptr).isActor()) + { + // figure out which side of the door the object we collided with is + Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> + convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); + if(relativePos.y >= 0) + targetRot = std::min(std::max(0.f, oldRot + diff*0.1f), 90.f); + else + targetRot = std::min(std::max(0.f, oldRot - diff*0.1f), 90.f); + + localRotateObject(it->first, 0, 0, targetRot); + break; + } + } + + if ((targetRot == 90.f && it->second) || targetRot == 0.f) + mDoorStates.erase(it); + } + } + mPhysEngine->stepSimulation (duration); } @@ -1480,4 +1518,20 @@ namespace MWWorld { mRendering->frameStarted(dt); } + + void World::activateDoor(const MWWorld::Ptr& door) + { + if (mDoorStates.find(door) != mDoorStates.end()) + { + // if currently opening, then close, if closing, then open + mDoorStates[door] = !mDoorStates[door]; + } + else + { + if (door.getRefData().getLocalRotation().rot[2] == 0) + mDoorStates[door] = 1; // open + else + mDoorStates[door] = 0; // close + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a51bdc2e6..35c53e29e 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,9 @@ namespace MWWorld float mFaced2Distance; int mNumFacing; + std::map mDoorStates; + ///< only holds doors that are currently moving. 0 means closing, 1 opening + unsigned long lastTick; Ogre::Timer mTimer; @@ -368,6 +371,9 @@ namespace MWWorld virtual void setupPlayer(bool newGame); virtual void renderPlayer(); + virtual void activateDoor(const MWWorld::Ptr& door); + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); virtual int canRest(); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index eaeae7dc3..d522ebaf8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -509,6 +509,29 @@ namespace Physic } } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + public: + std::vector mResult; + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) + { + const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); + if (body) + mResult.push_back(body->mName); + return 0.f; + } + }; + + std::vector PhysicEngine::getCollisions(const std::string& name) + { + RigidBody* body = getRigidBody(name); + ContactTestResultCallback callback; + dynamicsWorld->contactTest(body, callback); + return callback.mResult; + } + void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6ce4edba3..6d88fcb55 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -298,6 +298,8 @@ namespace Physic */ std::vector< std::pair > rayTest2(btVector3& from, btVector3& to); + std::vector getCollisions(const std::string& name); + //event list of non player object std::list NPEventList; From 4ee1a6ee02eb604d53062d34c92801bf9e1c2204 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:36:37 +0200 Subject: [PATCH 108/134] Put door physics in a separate method, some fixes --- apps/openmw/mwworld/worldimp.cpp | 16 +++++++++++----- apps/openmw/mwworld/worldimp.hpp | 3 +++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e4f28ecc5..ffa87f58c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -979,15 +979,23 @@ namespace MWWorld moveObjectImp(player->first, vec.x, vec.y, vec.z); } + processDoors(duration); + + mPhysEngine->stepSimulation (duration); + } + + void World::processDoors(float duration) + { // doors for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) { - if (!it->first.getRefData().getCount()) - mDoorStates.erase(it); + if (it->first.isEmpty() || !it->first.getRefData().getCount()) + mDoorStates.erase(it++); else { - if (mPlayer->getPlayer().getCell() != it->first.getCell()) + if (!mWorldScene->isCellActive(*it->first.getCell())) continue; + float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); float diff = duration * 90 * (it->second ? 1 : -1); float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); @@ -1016,8 +1024,6 @@ namespace MWWorld mDoorStates.erase(it); } } - - mPhysEngine->stepSimulation (duration); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 35c53e29e..172ae406c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -272,6 +272,9 @@ namespace MWWorld virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. + virtual void processDoors(float duration); + ///< Run physics simulation and modify \a world accordingly. + virtual bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. From 208f9ca8c550da17baa23e9ae1f8aff8b4d017f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:56:09 +0200 Subject: [PATCH 109/134] Fix problem with newer (or older?) bullet version (thanks travis) --- libs/openengine/bullet/physic.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d522ebaf8..b41da093d 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -522,6 +522,15 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } + + virtual btScalar addSingleResult(btManifoldPoint&, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const RigidBody* body = dynamic_cast(col0); + if (body) + mResult.push_back(body->mName); + return 0.f; + } }; std::vector PhysicEngine::getCollisions(const std::string& name) From 6ecd88af1426cf406f0fcb92261ad15a785f74be Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:59:59 +0200 Subject: [PATCH 110/134] More fixes --- apps/openmw/mwworld/worldimp.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ffa87f58c..6fc7324e5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -986,19 +986,16 @@ namespace MWWorld void World::processDoors(float duration) { - // doors - for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) + std::map::iterator it = mDoorStates.begin(); + while (it != mDoorStates.end()) { - if (it->first.isEmpty() || !it->first.getRefData().getCount()) + if (!mWorldScene->isCellActive(*it->first.getCell())) mDoorStates.erase(it++); else { - if (!mWorldScene->isCellActive(*it->first.getCell())) - continue; - float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); - float diff = duration * 90 * (it->second ? 1 : -1); - float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); + float diff = duration * 90; + float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); std::vector collisions = mPhysics->getCollisions(it->first); @@ -1021,7 +1018,9 @@ namespace MWWorld } if ((targetRot == 90.f && it->second) || targetRot == 0.f) - mDoorStates.erase(it); + mDoorStates.erase(it++); + else + ++it; } } } From 2e1dda9010f8434a8ab91913eeea218338be58d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 16:19:40 +0200 Subject: [PATCH 111/134] Fix old bullet versions --- libs/openengine/bullet/physic.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b41da093d..dbb42a645 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -513,7 +513,11 @@ namespace Physic { public: std::vector mResult; - virtual btScalar addSingleResult(btManifoldPoint& cp, + + // added in bullet 2.81 + // this is just a quick hack, as there does not seem to be a BULLET_VERSION macro? +#if defined(BT_COLLISION_OBJECT_WRAPPER_H) + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) { @@ -522,8 +526,8 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } - - virtual btScalar addSingleResult(btManifoldPoint&, const btCollisionObject* col0, int partId0, int index0, +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { const RigidBody* body = dynamic_cast(col0); @@ -531,6 +535,7 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } +#endif }; std::vector PhysicEngine::getCollisions(const std::string& name) From 98baf9fac190d2793b50ee499ff5d03c575a19ce Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 28 Apr 2013 16:36:12 +0200 Subject: [PATCH 112/134] Bugfix #718 --- apps/openmw/mwworld/store.cpp | 38 ++++++++++++++++++++++++++++++++--- components/esm/loadcell.cpp | 33 ++++-------------------------- components/esm/loadcell.hpp | 3 ++- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 005601cd1..ebc7ef03f 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,4 +1,5 @@ #include "store.hpp" +#include "esmstore.hpp" namespace MWWorld { @@ -15,8 +16,39 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) ESM::Cell *cell = new ESM::Cell; cell->mName = id; - // The cell itself takes care of some of the hairy details - cell->load(esm, *mEsmStore); + //First part of cell loading + cell->preLoad(esm); + + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + MWWorld::Store &cStore = const_cast&>(mEsmStore->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. + cell->getNextRef(esm, ref); + std::string lowerCase; + + 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. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; + } + + //Second part of cell loading + cell->postLoad(esm); if(cell->mData.mFlags & ESM::Cell::Interior) { @@ -62,4 +94,4 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) delete cell; } -} \ No newline at end of file +} diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 77e4d3691..27d320887 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -132,38 +132,13 @@ void Cell::load(ESMReader &esm, bool saveContext) } } -void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +void Cell::preLoad(ESMReader &esm) //Can't be "load" because it conflicts with function in esmtool { this->load(esm, false); +} - // preload moved references - while (esm.isNextSub("MVRF")) { - CellRef ref; - MovedCellRef cMRef; - getNextMVRF(esm, cMRef); - - 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); - std::string lowerCase; - - 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); - // But there may be duplicates here! - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; - } - +void Cell::postLoad(ESMReader &esm) +{ // Save position of the cell references and move on mContextList.push_back(esm.getContext()); esm.skipRecord(); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index d7f64817f..eda8a5418 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -96,7 +96,8 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - void load(ESMReader &esm, MWWorld::ESMStore &store); + void preLoad(ESMReader &esm); + void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. From 6ea82333d4b269af59724408d41533b3ac5b0a42 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 28 Apr 2013 16:38:33 +0200 Subject: [PATCH 113/134] Headers cleanup --- components/esm/loadcell.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 27d320887..779f303f3 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -8,9 +8,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include -#include - namespace ESM { From 67e5e939a113c17589351f83140d177f76c558aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 17:57:36 +0200 Subject: [PATCH 114/134] Fix some doors --- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6fc7324e5..f1fd020df 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -998,19 +998,28 @@ namespace MWWorld float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); + // AABB of the door + Ogre::Vector3 min,max; + mPhysics->getObjectAABB(it->first, min, max); + Ogre::Vector3 dimensions = max-min; + std::vector collisions = mPhysics->getCollisions(it->first); for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { MWWorld::Ptr ptr = getPtrViaHandle(*cit); if (MWWorld::Class::get(ptr).isActor()) { - // figure out which side of the door the object we collided with is + // we collided with an actor, we need to undo the rotation and push the door away from the actor + + // figure out on which side of the door the actor we collided with is Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); - if(relativePos.y >= 0) - targetRot = std::min(std::max(0.f, oldRot + diff*0.1f), 90.f); + + float axisToCheck = (dimensions.x > dimensions.y) ? relativePos.y : -relativePos.x; + if (axisToCheck >= 0) + targetRot = std::min(std::max(0.f, oldRot + diff*0.5f), 90.f); else - targetRot = std::min(std::max(0.f, oldRot - diff*0.1f), 90.f); + targetRot = std::min(std::max(0.f, oldRot - diff*0.5f), 90.f); localRotateObject(it->first, 0, 0, targetRot); break; From 4cedf0fbab922fa81da75a689853100a9a5fbc6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2013 11:12:55 -0700 Subject: [PATCH 115/134] Avoid colliding with AvoidNodes These are placed under the RootCollisionNode hierarchy, but the shapes they hold aren't collided with. Their exact function is unknown, but seems to be related to lava? Maybe damage avoidance info for the AI. --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifbullet/bulletnifloader.cpp | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index a66bd99db..cb7c2feb0 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -207,7 +207,7 @@ struct RecordFactoryEntry { static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, - { "AvoidNode", &construct , RC_NiNode }, + { "AvoidNode", &construct , RC_AvoidNode }, { "NiBSParticleNode", &construct , RC_NiBSParticleNode }, { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3f852ed83..87e342dca 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -36,6 +36,7 @@ enum RecordType { RC_MISSING = 0, RC_NiNode, + RC_AvoidNode, RC_NiTriShape, RC_NiRotatingParticles, RC_NiAutoNormalParticles, diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index a3eff95c3..a1e2cd8d1 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -185,6 +185,10 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * else isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); + // Don't collide with AvoidNode shapes + if(node->recType == Nif::RC_AvoidNode) + flags |= 0x800; + // Marker objects /// \todo don't do this in the editor std::string nodename = node->name; From ba3a67f84b4594b2d2b23662e4e710478bce4327 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2013 23:44:44 -0700 Subject: [PATCH 116/134] Don't store the player base node in MWRender::Player --- apps/openmw/mwrender/player.cpp | 37 +++++++++++++---------- apps/openmw/mwrender/player.hpp | 12 +++----- apps/openmw/mwrender/renderingmanager.cpp | 3 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwworld/refdata.cpp | 9 ++++-- apps/openmw/mwworld/refdata.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 14 +++++---- 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 6835fd64c..153d4af49 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -16,8 +17,7 @@ namespace MWRender { Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node) : mCamera(camera), - mPlayerNode(node), - mCameraNode(mPlayerNode->createChildSceneNode()), + mCameraNode(NULL), mFirstPersonView(true), mPreviewMode(false), mFreeLook(true), @@ -29,9 +29,6 @@ namespace MWRender mVanity.enabled = false; mVanity.allowed = true; - mCameraNode->attachObject(mCamera); - mCameraNode->setPosition(0.f, 0.f, mHeight); - mPreviewCam.yaw = 0.f; mPreviewCam.offset = 400.f; } @@ -62,12 +59,22 @@ namespace MWRender const std::string &Player::getHandle() const { - return mPlayerNode->getName(); + return mTrackingPtr.getRefData().getHandle(); } void Player::attachTo(const MWWorld::Ptr &ptr) { - ptr.getRefData().setBaseNode(mPlayerNode); + mTrackingPtr = ptr; + Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); + if(mCameraNode) + { + node->setOrientation(mCameraNode->getOrientation()); + node->setPosition(mCameraNode->getPosition()); + node->setScale(mCameraNode->getScale()); + mCameraNode->getCreator()->destroySceneNode(mCameraNode); + } + mCameraNode = node; + mCameraNode->attachObject(mCamera); } void Player::updateListener() @@ -84,13 +91,11 @@ namespace MWRender updateListener(); // only show the crosshair in game mode and in first person mode. - MWBase::Environment::get().getWindowManager ()->showCrosshair - (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); + MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); + wm->showCrosshair(!wm->isGuiMode() && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - if (mFirstPersonView && !mVanity.enabled) { - return; - } - if (mVanity.enabled) { + if(mVanity.enabled) + { Ogre::Vector3 rot(0.f, 0.f, 0.f); rot.z = Ogre::Degree(3.f * duration).valueRadians(); rotateCamera(rot, true); @@ -283,21 +288,21 @@ namespace MWRender float Player::getHeight() { - return mHeight * mPlayerNode->getScale().z; + return mHeight * mTrackingPtr.getRefData().getBaseNode()->getScale().z; } bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) { mCamera->getParentSceneNode ()->needUpdate(true); camera = mCamera->getRealPosition(); - player = mPlayerNode->getPosition(); + player = mTrackingPtr.getRefData().getBaseNode()->getPosition(); return mFirstPersonView && !mVanity.enabled && !mPreviewMode; } Ogre::Vector3 Player::getPosition() { - return mPlayerNode->getPosition(); + return mTrackingPtr.getRefData().getBaseNode()->getPosition(); } void Player::getSightAngles(float &pitch, float &yaw) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 332db457c..3c645230b 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -3,6 +3,8 @@ #include +#include "../mwworld/ptr.hpp" + namespace Ogre { class Vector3; @@ -10,14 +12,10 @@ namespace Ogre class SceneNode; } -namespace MWWorld -{ - class Ptr; -} - namespace MWRender { class NpcAnimation; + /// \brief Player character rendering and camera control class Player { @@ -25,9 +23,9 @@ namespace MWRender float pitch, yaw, offset; }; - Ogre::Camera *mCamera; + MWWorld::Ptr mTrackingPtr; - Ogre::SceneNode *mPlayerNode; + Ogre::Camera *mCamera; Ogre::SceneNode *mCameraNode; NpcAnimation *mAnimation; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1ce1baa39..252e29666 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -858,8 +858,9 @@ void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned i } } -void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) +void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) { + ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); mPlayer->attachTo(ptr); } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 6420a5b7e..20ec0d9ae 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -92,7 +92,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); - void attachCameraTo(const MWWorld::Ptr &ptr); + void setupPlayer(const MWWorld::Ptr &ptr); void renderPlayer(const MWWorld::Ptr &ptr); SkyManager* getSkyManager(); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index db565c451..c1a3ae785 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -81,10 +81,13 @@ namespace MWWorld {} } - std::string RefData::getHandle() + const std::string &RefData::getHandle() { - if (!mBaseNode) - return ""; + if(!mBaseNode) + { + static const std::string empty; + return empty; + } return mBaseNode->getName(); } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 77ceb3721..642f5412c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -60,7 +60,7 @@ namespace MWWorld RefData& operator= (const RefData& refData); /// Return OGRE handle (may be empty). - std::string getHandle(); + const std::string &getHandle(); /// Return OGRE base node (can be a null pointer). Ogre::SceneNode* getBaseNode(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a3fda913d..f3909a1da 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1493,13 +1493,15 @@ namespace MWWorld void World::setupPlayer(bool newGame) { - const ESM::NPC* player = mStore.get().find ("player"); - mPlayer = new MWWorld::Player (player, *this); - mRendering->attachCameraTo(mPlayer->getPlayer()); - if (newGame) + const ESM::NPC *player = mStore.get().find("player"); + mPlayer = new MWWorld::Player(player, *this); + + Ptr ptr = mPlayer->getPlayer(); + mRendering->setupPlayer(ptr); + if(newGame) { - MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore); - MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer()); + MWWorld::Class::get(ptr).getContainerStore(ptr).fill(player->mInventory, "", mStore); + MWWorld::Class::get(ptr).getInventoryStore(ptr).autoEquip(ptr); } } From 78596cad83b00a1fb9db33c87c84fae0a225707d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 10:19:09 +0200 Subject: [PATCH 117/134] Fix enchantment points value --- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++-- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- apps/openmw/mwmechanics/enchanting.hpp | 4 ++-- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- components/esm/loadweap.hpp | 2 +- 14 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 8a8f72c88..fa0d47107 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -375,12 +375,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell); } - short Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + float Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mEnchant; + return ref->mBase->mData.mEnchant/10.f; } bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 9b8e9dd14..964ba7146 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -77,7 +77,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index b658295f8..472d17da9 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -176,12 +176,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell); } - short Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + float Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mEnchant; + return ref->mBase->mData.mEnchant/10.f; } bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 3f083f552..3d728e506 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -58,7 +58,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 3072f852d..599efa51a 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -295,12 +295,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell); } - short Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + float Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mEnchant; + return ref->mBase->mData.mEnchant/10.f; } bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index a6de0cb4f..db4b7a2e9 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -71,7 +71,7 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 6c6b3daa6..306a2d671 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -428,12 +428,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell); } - short Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + float Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mEnchant; + return ref->mBase->mData.mEnchant/10.f; } bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 05b1aee22..ba444ba05 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -79,7 +79,7 @@ namespace MWClass virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; - virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 2ae98f358..6f7cfbf40 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -57,8 +57,9 @@ namespace MWGui void EnchantingDialog::updateLabels() { - mEnchantmentPoints->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost()) - + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); + std::stringstream enchantCost; + enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost(); + mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a38cb0037..ded75f03a 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -134,7 +134,7 @@ namespace MWMechanics } } - int Enchanting::getEnchantCost() const + float Enchanting::getEnchantCost() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); float cost = 0; @@ -193,7 +193,7 @@ namespace MWMechanics return soul->mData.mSoul; } - int Enchanting::getMaxEnchantValue() const + float Enchanting::getMaxEnchantValue() const { if (itemEmpty()) return 0; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index d8a6342ac..2831f9ddb 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -35,9 +35,9 @@ namespace MWMechanics bool create(); //Return true if created, false if failed. void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) int getEnchantType() const; - int getEnchantCost() const; + float getEnchantCost() const; int getEnchantPrice() const; - int getMaxEnchantValue() const; + float getMaxEnchantValue() const; int getGemCharge() const; float getEnchantChance() const; bool soulEmpty() const; //Return true if empty diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 451f0c5c1..03a55c7f0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -132,7 +132,7 @@ namespace MWWorld return 0; } - short Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + float Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const { throw std::runtime_error ("class does not support enchanting"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index b901950e3..e203fedc3 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,7 +231,7 @@ namespace MWWorld ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) - virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index e482d3b10..384af125d 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -48,7 +48,7 @@ struct Weapon short mType; short mHealth; float mSpeed, mReach; - short mEnchant; // Enchantment points + short mEnchant; // Enchantment points. The real value is mEnchant/10.f unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max int mFlags; }; // 32 bytes From 9648804af5d27da19f77c3880fe82a9c2ba69e4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 10:20:38 +0200 Subject: [PATCH 118/134] Fix terrain material leak, this should in theory allow the terrain to free its temporary resources --- apps/openmw/mwrender/terrainmaterial.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index dd74254be..b9c055acd 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -54,9 +54,10 @@ namespace MWRender TerrainMaterial::Profile::~Profile() { + if (mMaterial) + sh::Factory::getInstance().destroyMaterialInstance(mMaterial->getName()); } - Ogre::MaterialPtr TerrainMaterial::Profile::generate(const Ogre::Terrain* terrain) { const Ogre::String& matName = terrain->getMaterialName(); From 867c7db01401e3f987689b61479af2ffb45864cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 11:00:15 +0200 Subject: [PATCH 119/134] Fix wrong door sounds --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 7 +++++++ apps/openmw/mwworld/worldimp.hpp | 8 +++++--- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 42821e361..1b8d813fd 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -326,6 +326,8 @@ namespace MWBase virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; + virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0; + ///< if activated, should this door be opened or closed? virtual void activateDoor(const MWWorld::Ptr& door) = 0; ///< activate (open or close) an non-teleport door diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 5b061e090..91d38b8ef 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -141,7 +141,7 @@ namespace MWClass { // animated door boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); - if (ptr.getRefData().getLocalRotation().rot[2] == 0) + if (MWBase::Environment::get().getWorld()->getOpenOrCloseDoor(ptr)) action->setSound(openSound); else action->setSound(closeSound); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f1fd020df..736c52a38 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1548,4 +1548,11 @@ namespace MWWorld mDoorStates[door] = 0; // close } } + + bool World::getOpenOrCloseDoor(const Ptr &door) + { + if (mDoorStates.find(door) != mDoorStates.end()) + return !mDoorStates[door]; // if currently opening or closing, then do the opposite + return door.getRefData().getLocalRotation().rot[2] == 0; + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 172ae406c..8ea43cb25 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -113,6 +113,9 @@ namespace MWWorld void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); void PCDropped (const Ptr& item); + virtual void processDoors(float duration); + ///< Run physics simulation and modify \a world accordingly. + public: World (OEngine::Render::OgreRenderer& renderer, @@ -272,9 +275,6 @@ namespace MWWorld virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. - virtual void processDoors(float duration); - ///< Run physics simulation and modify \a world accordingly. - virtual bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. @@ -374,6 +374,8 @@ namespace MWWorld virtual void setupPlayer(bool newGame); virtual void renderPlayer(); + virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door); + ///< if activated, should this door be opened or closed? virtual void activateDoor(const MWWorld::Ptr& door); ///< activate (open or close) an non-teleport door From 5ff098b8fb9ff8865851d9b693c7e693a4f05c4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 11:55:30 +0200 Subject: [PATCH 120/134] Fix quick keys being triggered when in UI mode --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6a34161e0..882edadce 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -679,7 +679,8 @@ namespace MWInput void InputManager::quickKey (int index) { - mWindows.activateQuickKey (index); + if (!mWindows.isGuiMode()) + mWindows.activateQuickKey (index); } void InputManager::showQuickKeysMenu() From 6c5ea1ea7ae3a53f2cfb3335e206d547326f5da4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 12:05:10 +0200 Subject: [PATCH 121/134] Fix incorrect weapon health meter for fully repaired weapons, fix exception when equipping lockpicks or probes --- apps/openmw/mwclass/lockpick.cpp | 8 ++++++++ apps/openmw/mwclass/lockpick.hpp | 3 +++ apps/openmw/mwclass/probe.cpp | 8 ++++++++ apps/openmw/mwclass/probe.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++-- 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index bfbf10756..52a22d28e 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -181,4 +181,12 @@ namespace MWClass { return npcServices & ESM::NPC::Picks; } + + int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mUses; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index edd884a3e..df794debd 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -59,6 +59,9 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + ///< Return item max health or throw an exception, if class does not have item health }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 4ec6a8340..1c14c894d 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -180,4 +180,12 @@ namespace MWClass { return npcServices & ESM::NPC::Probes; } + + int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mUses; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 75ebaa01c..70390c85c 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -59,6 +59,9 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + ///< Return item max health or throw an exception, if class does not have item health }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2171beaff..36e53ca09 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -918,14 +918,16 @@ namespace MWGui const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() .find(MWWorld::Class::get(item).getEnchantment(item)); - int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; + int chargePercent = (item.getCellRef().mEnchantmentCharge == -1) ? 100 + : (item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100); mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { - int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; + int durabilityPercent = (item.getCellRef().mCharge == -1) ? 100 + : (item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } From bb8277920b8c5c5c2f5264e3372e183a846cab7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 03:31:46 -0700 Subject: [PATCH 122/134] Manage the player's NpcAnimation object in the RenderingManager It may be more appropriate to manage it in MWRender::Actors with the other Animation-based objects, but that will need some (minor) interface changes. --- apps/openmw/mwrender/player.cpp | 13 ++++---- apps/openmw/mwrender/player.hpp | 5 +-- apps/openmw/mwrender/renderingmanager.cpp | 38 ++++++++++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 153d4af49..7eb7156ab 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -15,7 +15,7 @@ namespace MWRender { - Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node) + Player::Player (Ogre::Camera *camera) : mCamera(camera), mCameraNode(NULL), mFirstPersonView(true), @@ -35,7 +35,6 @@ namespace MWRender Player::~Player() { - delete mAnimation; } void Player::rotateCamera(const Ogre::Vector3 &rot, bool adjust) @@ -273,11 +272,13 @@ namespace MWRender void Player::setAnimation(NpcAnimation *anim) { - anim->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); - - delete mAnimation; + // If we're switching to a new NpcAnimation, ensure the old one is + // using a normal view mode + if(mAnimation && mAnimation != anim) + mAnimation->setViewMode(NpcAnimation::VM_Normal); mAnimation = anim; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); } void Player::setHeight(float height) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 3c645230b..8675e0760 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -49,8 +49,7 @@ namespace MWRender void setLowHeight(bool low = true); public: - - Player (Ogre::Camera *camera, Ogre::SceneNode* mNode); + Player(Ogre::Camera *camera); ~Player(); /// Set where the player is looking at. Uses Morrowind (euler) angles @@ -89,8 +88,6 @@ namespace MWRender void setCameraDistance(); 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 252e29666..2e168caed 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -53,8 +53,9 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback) : mRendering(_rend) , mFallback(fallback) - , mObjects(mRendering,mFallback) + , mObjects(mRendering, mFallback) , mActors(mRendering, this) + , mPlayerAnimation(NULL) , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) @@ -148,14 +149,13 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const applyCompositors(); - SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mRootNode = rt; + mRootNode = mRendering.getScene()->getRootSceneNode(); + mRootNode->createChildSceneNode("player"); mObjects.setRootNode(mRootNode); mActors.setRootNode(mRootNode); - Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player"); - mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); + mPlayer = new MWRender::Player(mRendering.getCamera()); mShadows = new Shadows(&mRendering); @@ -183,6 +183,7 @@ RenderingManager::~RenderingManager () mRendering.getWindow()->removeListener(this); mRendering.removeWindowEventListener(this); + delete mPlayerAnimation; delete mPlayer; delete mSkyManager; delete mDebugging; @@ -866,14 +867,23 @@ void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) { - MWRender::NpcAnimation *anim = - new MWRender::NpcAnimation( - ptr, ptr.getRefData ().getBaseNode (), - MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors - ); - mPlayer->setAnimation(anim); - mWater->removeEmitter (ptr); - mWater->addEmitter (ptr); + if(!mPlayerAnimation) + { + mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), + MWWorld::Class::get(ptr).getInventoryStore(ptr), + RV_Actors); + } + else + { + // Reconstruct the NpcAnimation in-place + mPlayerAnimation->~NpcAnimation(); + new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), + MWWorld::Class::get(ptr).getInventoryStore(ptr), + RV_Actors); + } + mPlayer->setAnimation(mPlayerAnimation); + mWater->removeEmitter(ptr); + mWater->addEmitter(ptr); // apply race height MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); } @@ -914,7 +924,7 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); if(!anim && ptr.getRefData().getHandle() == "player") - anim = mPlayer->getAnimation(); + anim = mPlayerAnimation; return anim; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 20ec0d9ae..c7e27a405 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -238,6 +238,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Objects mObjects; MWRender::Actors mActors; + MWRender::NpcAnimation *mPlayerAnimation; + // 0 normal, 1 more bright, 2 max int mAmbientMode; From d5c7a26041d825e1cbd675831a8bfe32fd25bcdb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Apr 2013 12:32:24 +0200 Subject: [PATCH 123/134] Fix broken loose file resources when using Ogre 1.9 --- components/bsa/bsa_archive.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index c97ca4562..7d3df1590 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -313,21 +313,26 @@ public: void destroyInstance( Archive* arch) { delete arch; } }; -class DirArchiveFactory : public FileSystemArchiveFactory +class DirArchiveFactory : public ArchiveFactory { public: - const String& getType() const - { - static String name = "Dir"; - return name; - } + const String& getType() const + { + static String name = "Dir"; + return name; + } - Archive *createInstance( const String& name ) - { - return new DirArchive(name); - } + Archive *createInstance( const String& name ) + { + return new DirArchive(name); + } - void destroyInstance( Archive* arch) { delete arch; } + virtual Archive* createInstance(const String& name, bool readOnly) + { + return new DirArchive(name); + } + + void destroyInstance( Archive* arch) { delete arch; } }; From dbba126344b1483514e1585202405aab4e0c5fa3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 04:40:28 -0700 Subject: [PATCH 124/134] Use a method to check if the view should be first person --- apps/openmw/mwrender/player.cpp | 16 ++++++++-------- apps/openmw/mwrender/player.hpp | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 7eb7156ab..640f8bd66 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -104,8 +104,8 @@ namespace MWRender void Player::toggleViewMode() { mFirstPersonView = !mFirstPersonView; - mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson : + NpcAnimation::VM_Normal); if (mFirstPersonView) { mCamera->setPosition(0.f, 0.f, 0.f); setLowHeight(false); @@ -131,8 +131,8 @@ namespace MWRender return true; mVanity.enabled = enable; - mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson : + NpcAnimation::VM_Normal); float offset = mPreviewCam.offset; Ogre::Vector3 rot(0.f, 0.f, 0.f); @@ -161,8 +161,8 @@ namespace MWRender return; mPreviewMode = enable; - mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson : + NpcAnimation::VM_Normal); float offset = mCamera->getPosition().z; if (mPreviewMode) { @@ -277,8 +277,8 @@ namespace MWRender if(mAnimation && mAnimation != anim) mAnimation->setViewMode(NpcAnimation::VM_Normal); mAnimation = anim; - mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? - NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson : + NpcAnimation::VM_Normal); } void Player::setHeight(float height) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 8675e0760..5ded521d4 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -76,6 +76,9 @@ namespace MWRender void togglePreviewMode(bool enable); + bool isFirstPerson() const + { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } + void update(float duration); /// Set camera distance for current mode. Don't work on 1st person view. From d17e1e83d585548d6ff75f0b8aa362bf289273c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 05:50:40 -0700 Subject: [PATCH 125/134] Rename MWRender's Player to Camera --- apps/openmw/CMakeLists.txt | 2 +- .../mwrender/{player.cpp => camera.cpp} | 54 +++++++------- .../mwrender/{player.hpp => camera.hpp} | 16 ++--- apps/openmw/mwrender/debugging.cpp | 1 - apps/openmw/mwrender/debugging.hpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 62 +++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 70 +++++++++---------- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 30 ++++---- apps/openmw/mwworld/physicssystem.hpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 5 +- 11 files changed, 113 insertions(+), 135 deletions(-) rename apps/openmw/mwrender/{player.cpp => camera.cpp} (87%) rename apps/openmw/mwrender/{player.hpp => camera.hpp} (87%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 08033f822..b5d4badf2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -14,7 +14,7 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation + renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction ) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/camera.cpp similarity index 87% rename from apps/openmw/mwrender/player.cpp rename to apps/openmw/mwrender/camera.cpp index 640f8bd66..b4fd6a543 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -1,4 +1,4 @@ -#include "player.hpp" +#include "camera.hpp" #include #include @@ -15,7 +15,7 @@ namespace MWRender { - Player::Player (Ogre::Camera *camera) + Camera::Camera (Ogre::Camera *camera) : mCamera(camera), mCameraNode(NULL), mFirstPersonView(true), @@ -33,11 +33,11 @@ namespace MWRender mPreviewCam.offset = 400.f; } - Player::~Player() + Camera::~Camera() { } - void Player::rotateCamera(const Ogre::Vector3 &rot, bool adjust) + void Camera::rotateCamera(const Ogre::Vector3 &rot, bool adjust) { if (adjust) { setYaw(getYaw() + rot.z); @@ -56,12 +56,12 @@ namespace MWRender } } - const std::string &Player::getHandle() const + const std::string &Camera::getHandle() const { return mTrackingPtr.getRefData().getHandle(); } - void Player::attachTo(const MWWorld::Ptr &ptr) + void Camera::attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); @@ -76,7 +76,7 @@ namespace MWRender mCameraNode->attachObject(mCamera); } - void Player::updateListener() + void Camera::updateListener() { Ogre::Vector3 pos = mCamera->getRealPosition(); Ogre::Vector3 dir = mCamera->getRealDirection(); @@ -85,7 +85,7 @@ namespace MWRender MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); } - void Player::update(float duration) + void Camera::update(float duration) { updateListener(); @@ -101,7 +101,7 @@ namespace MWRender } } - void Player::toggleViewMode() + void Camera::toggleViewMode() { mFirstPersonView = !mFirstPersonView; mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson : @@ -115,14 +115,14 @@ namespace MWRender } } - void Player::allowVanityMode(bool allow) + void Camera::allowVanityMode(bool allow) { if (!allow && mVanity.enabled) toggleVanityMode(false); mVanity.allowed = allow; } - bool Player::toggleVanityMode(bool enable) + bool Camera::toggleVanityMode(bool enable) { if(!mVanity.allowed && enable) return false; @@ -155,7 +155,7 @@ namespace MWRender return true; } - void Player::togglePreviewMode(bool enable) + void Camera::togglePreviewMode(bool enable) { if(mPreviewMode == enable) return; @@ -181,14 +181,14 @@ namespace MWRender rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); } - float Player::getYaw() + float Camera::getYaw() { if(mVanity.enabled || mPreviewMode) return mPreviewCam.yaw; return mMainCam.yaw; } - void Player::setYaw(float angle) + void Camera::setYaw(float angle) { if (angle > Ogre::Math::PI) { angle -= Ogre::Math::TWO_PI; @@ -202,7 +202,7 @@ namespace MWRender } } - float Player::getPitch() + float Camera::getPitch() { if (mVanity.enabled || mPreviewMode) { return mPreviewCam.pitch; @@ -210,7 +210,7 @@ namespace MWRender return mMainCam.pitch; } - void Player::setPitch(float angle) + void Camera::setPitch(float angle) { const float epsilon = 0.000001f; float limit = Ogre::Math::HALF_PI - epsilon; @@ -229,7 +229,7 @@ namespace MWRender } } - void Player::setCameraDistance(float dist, bool adjust, bool override) + void Camera::setCameraDistance(float dist, bool adjust, bool override) { if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) return; @@ -258,7 +258,7 @@ namespace MWRender } } - void Player::setCameraDistance() + void Camera::setCameraDistance() { if (mDistanceAdjusted) { if (mVanity.enabled || mPreviewMode) { @@ -270,7 +270,7 @@ namespace MWRender mDistanceAdjusted = false; } - void Player::setAnimation(NpcAnimation *anim) + void Camera::setAnimation(NpcAnimation *anim) { // If we're switching to a new NpcAnimation, ensure the old one is // using a normal view mode @@ -281,18 +281,18 @@ namespace MWRender NpcAnimation::VM_Normal); } - void Player::setHeight(float height) + void Camera::setHeight(float height) { mHeight = height; mCameraNode->setPosition(0.f, 0.f, mHeight); } - float Player::getHeight() + float Camera::getHeight() { return mHeight * mTrackingPtr.getRefData().getBaseNode()->getScale().z; } - bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) + bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) { mCamera->getParentSceneNode ()->needUpdate(true); camera = mCamera->getRealPosition(); @@ -301,23 +301,23 @@ namespace MWRender return mFirstPersonView && !mVanity.enabled && !mPreviewMode; } - Ogre::Vector3 Player::getPosition() + Ogre::Vector3 Camera::getPosition() { return mTrackingPtr.getRefData().getBaseNode()->getPosition(); } - void Player::getSightAngles(float &pitch, float &yaw) + void Camera::getSightAngles(float &pitch, float &yaw) { pitch = mMainCam.pitch; yaw = mMainCam.yaw; } - void Player::togglePlayerLooking(bool enable) + void Camera::togglePlayerLooking(bool enable) { mFreeLook = enable; } - void Player::setLowHeight(bool low) + void Camera::setLowHeight(bool low) { if (low) { mCameraNode->setPosition(0.f, 0.f, mHeight * 0.85); @@ -326,7 +326,7 @@ namespace MWRender } } - bool Player::isVanityOrPreviewModeEnabled() + bool Camera::isVanityOrPreviewModeEnabled() { return mPreviewMode || mVanity.enabled; } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/camera.hpp similarity index 87% rename from apps/openmw/mwrender/player.hpp rename to apps/openmw/mwrender/camera.hpp index 5ded521d4..7bbdd303d 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWRENDER_PLAYER_H -#define GAME_MWRENDER_PLAYER_H +#ifndef GAME_MWRENDER_CAMERA_H +#define GAME_MWRENDER_CAMERA_H #include @@ -16,8 +16,8 @@ namespace MWRender { class NpcAnimation; - /// \brief Player character rendering and camera control - class Player + /// \brief Camera control + class Camera { struct CamData { float pitch, yaw, offset; @@ -49,10 +49,10 @@ namespace MWRender void setLowHeight(bool low = true); public: - Player(Ogre::Camera *camera); - ~Player(); + Camera(Ogre::Camera *camera); + ~Camera(); - /// Set where the player is looking at. Uses Morrowind (euler) angles + /// Set where the camera is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians void rotateCamera(const Ogre::Vector3 &rot, bool adjust); @@ -65,8 +65,6 @@ namespace MWRender const std::string &getHandle() const; /// Attach camera to object - /// \note there is no protection from attaching the same camera to - /// several different objects void attachTo(const MWWorld::Ptr &); void toggleViewMode(); diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 54f288bff..b318c2d56 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -20,7 +20,6 @@ #include "../mwworld/ptr.hpp" -#include "player.hpp" #include "renderconst.hpp" using namespace Ogre; diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 6a4eef58f..4a574017c 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -39,8 +39,6 @@ namespace MWWorld namespace MWRender { - class Player; - class Debugging { OEngine::Physic::PhysicEngine* mEngine; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2e168caed..7180f6efd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -49,8 +49,9 @@ using namespace Ogre; namespace MWRender { -RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback) +RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, + MWWorld::Fallback* fallback) : mRendering(_rend) , mFallback(fallback) , mObjects(mRendering, mFallback) @@ -155,7 +156,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mObjects.setRootNode(mRootNode); mActors.setRootNode(mRootNode); - mPlayer = new MWRender::Player(mRendering.getCamera()); + mCamera = new MWRender::Camera(mRendering.getCamera()); mShadows = new Shadows(&mRendering); @@ -184,7 +185,7 @@ RenderingManager::~RenderingManager () mRendering.removeWindowEventListener(this); delete mPlayerAnimation; - delete mPlayer; + delete mCamera; delete mSkyManager; delete mDebugging; delete mShadows; @@ -269,8 +270,8 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) { Ogre::Vector3 rot(ptr.getRefData().getPosition().rot); - if(ptr.getRefData().getHandle() == mPlayer->getHandle()) - mPlayer->rotateCamera(rot, false); + if(ptr.getRefData().getHandle() == mCamera->getHandle()) + mCamera->rotateCamera(rot, false); Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); if(!MWWorld::Class::get(ptr).isActor()) @@ -300,7 +301,7 @@ void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; mRendering.getFader()->setFactor(1.f-(blind / 100.f)); @@ -313,16 +314,16 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); Ogre::Vector3 orig, dest; - mPlayer->setCameraDistance(); - if (!mPlayer->getPosition(orig, dest)) { - orig.z += mPlayer->getHeight() * mRootNode->getScale().z; + mCamera->setCameraDistance(); + if(!mCamera->getPosition(orig, dest)) + { + orig.z += mCamera->getHeight() * mRootNode->getScale().z; btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = - mPhysicsEngine->rayTest(btOrig, btDest); + std::pair test = mPhysicsEngine->rayTest(btOrig, btDest); if (!test.first.empty()) { - mPlayer->setCameraDistance(test.second * orig.distance(dest), false, false); + mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } } @@ -336,14 +337,12 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - applyFog(world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)); + applyFog(world->isUnderwater(player.getCell(), cam)); if(paused) - { return; - } - mPlayer->update(duration); + mCamera->update(duration); mActors.update (duration); mObjects.update (duration); @@ -354,18 +353,11 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); Ogre::SceneNode *node = data.getBaseNode(); - //Ogre::Quaternion orient = - //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); - Ogre::Quaternion orient = -node->_getDerivedOrientation(); + Ogre::Quaternion orient = node->_getDerivedOrientation(); mLocalMap->updatePlayer(playerPos, orient); - mWater->updateUnderwater( - world->isUnderwater( - world->getPlayer().getPlayer().getCell(), - cam) - ); + mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); mWater->update(duration, playerPos); } @@ -862,7 +854,7 @@ void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned i void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) { ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); - mPlayer->attachTo(ptr); + mCamera->attachTo(ptr); } void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) @@ -881,27 +873,27 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors); } - mPlayer->setAnimation(mPlayerAnimation); + mCamera->setAnimation(mPlayerAnimation); mWater->removeEmitter(ptr); mWater->addEmitter(ptr); // apply race height MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); } -void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) +void RenderingManager::getCameraData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) { - eyepos = mPlayer->getPosition(); - eyepos.z += mPlayer->getHeight(); - mPlayer->getSightAngles(pitch, yaw); + eyepos = mCamera->getPosition(); + eyepos.z += mCamera->getHeight(); + mCamera->getSightAngles(pitch, yaw); } -bool RenderingManager::vanityRotateCamera(float* rot) +bool RenderingManager::vanityRotateCamera(const float *rot) { - if(!mPlayer->isVanityOrPreviewModeEnabled()) + if(!mCamera->isVanityOrPreviewModeEnabled()) return false; Ogre::Vector3 vRot(rot); - mPlayer->rotateCamera(vRot, true); + mCamera->rotateCamera(vRot, true); return true; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c7e27a405..6a35bfb6d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -17,7 +17,7 @@ #include "objects.hpp" #include "actors.hpp" -#include "player.hpp" +#include "camera.hpp" #include "occlusionquery.hpp" namespace Ogre @@ -50,47 +50,42 @@ namespace MWRender class VideoPlayer; class Animation; -class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener, public Ogre::RenderTargetListener { - - private: - - +class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener, public Ogre::RenderTargetListener +{ +private: virtual MWRender::Objects& getObjects(); virtual MWRender::Actors& getActors(); - public: +public: RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback); + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine, + MWWorld::Fallback* fallback); virtual ~RenderingManager(); - void togglePOV() { - mPlayer->toggleViewMode(); + void togglePOV() + { mCamera->toggleViewMode(); } + + void togglePreviewMode(bool enable) + { mCamera->togglePreviewMode(enable); } + + bool toggleVanityMode(bool enable) + { return mCamera->toggleVanityMode(enable); } + + void allowVanityMode(bool allow) + { mCamera->allowVanityMode(allow); } + + void togglePlayerLooking(bool enable) + { mCamera->togglePlayerLooking(enable); } + + void changeVanityModeScale(float factor) + { + if(mCamera->isVanityOrPreviewModeEnabled()) + mCamera->setCameraDistance(-factor/120.f*10, true, true); } - void togglePreviewMode(bool enable) { - mPlayer->togglePreviewMode(enable); - } + bool vanityRotateCamera(const float *rot); - bool toggleVanityMode(bool enable) { - return mPlayer->toggleVanityMode(enable); - } - - void allowVanityMode(bool allow) { - mPlayer->allowVanityMode(allow); - } - - void togglePlayerLooking(bool enable) { - mPlayer->togglePlayerLooking(enable); - } - - void changeVanityModeScale(float factor) { - if (mPlayer->isVanityOrPreviewModeEnabled()) - mPlayer->setCameraDistance(-factor/120.f*10, true, true); - } - - bool vanityRotateCamera(float* rot); - - void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); + void getCameraData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void setupPlayer(const MWWorld::Ptr &ptr); void renderPlayer(const MWWorld::Ptr &ptr); @@ -204,12 +199,11 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void stopVideo(); void frameStarted(float dt); - protected: - virtual void windowResized(Ogre::RenderWindow* rw); +protected: + virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); - private: - +private: sh::Factory* mFactory; void setAmbientMode(); @@ -254,7 +248,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList OEngine::Physic::PhysicEngine* mPhysicsEngine; - MWRender::Player *mPlayer; + MWRender::Camera *mCamera; MWRender::Debugging *mDebugging; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7f3abce70..516b48dde 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -205,7 +205,7 @@ unsigned int Moon::getPhaseInt() const return 0; } -SkyManager::SkyManager (SceneNode* root, Camera* pCamera) +SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) : mHour(0.0f) , mDay(0) , mMonth(0) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 18db2dca8..ce32b79e5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -260,14 +260,13 @@ namespace MWWorld std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world, float queryDistance) { btVector3 dir(0, 1, 0); - dir = dir.rotate(btVector3(1, 0, 0), mPlayerData.pitch); - dir = dir.rotate(btVector3(0, 0, 1), mPlayerData.yaw); + dir = dir.rotate(btVector3(1, 0, 0), mCameraData.pitch); + dir = dir.rotate(btVector3(0, 0, 1), mCameraData.yaw); dir.setX(-dir.x()); - btVector3 origin( - mPlayerData.eyepos.x, - mPlayerData.eyepos.y, - mPlayerData.eyepos.z); + btVector3 origin(mCameraData.eyepos.x, + mCameraData.eyepos.y, + mCameraData.eyepos.z); origin += dir * 5; btVector3 dest = origin + dir * queryDistance; @@ -280,14 +279,13 @@ namespace MWWorld std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) { btVector3 dir(0, 1, 0); - dir = dir.rotate(btVector3(1, 0, 0), mPlayerData.pitch); - dir = dir.rotate(btVector3(0, 0, 1), mPlayerData.yaw); + dir = dir.rotate(btVector3(1, 0, 0), mCameraData.pitch); + dir = dir.rotate(btVector3(0, 0, 1), mCameraData.yaw); dir.setX(-dir.x()); - btVector3 origin( - mPlayerData.eyepos.x, - mPlayerData.eyepos.y, - mPlayerData.eyepos.z); + btVector3 origin(mCameraData.eyepos.x, + mCameraData.eyepos.y, + mCameraData.eyepos.z); origin += dir * 5; btVector3 dest = origin + dir * queryDistance; @@ -552,10 +550,10 @@ namespace MWWorld return true; } - void PhysicsSystem::updatePlayerData(Ogre::Vector3 &eyepos, float pitch, float yaw) + void PhysicsSystem::updateCameraData(const Ogre::Vector3 &eyepos, float pitch, float yaw) { - mPlayerData.eyepos = eyepos; - mPlayerData.pitch = pitch; - mPlayerData.yaw = yaw; + mCameraData.eyepos = eyepos; + mCameraData.pitch = pitch; + mCameraData.yaw = yaw; } } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 48214029e..3322c38a6 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -77,13 +77,13 @@ namespace MWWorld bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max); - void updatePlayerData(Ogre::Vector3 &eyepos, float pitch, float yaw); + void updateCameraData(const Ogre::Vector3 &eyepos, float pitch, float yaw); private: struct { Ogre::Vector3 eyepos; float pitch, yaw; - } mPlayerData; + } mCameraData; OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f3909a1da..855fdfe09 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,7 +16,6 @@ #include "../mwmechanics/movement.hpp" #include "../mwrender/sky.hpp" -#include "../mwrender/player.hpp" #include "../mwclass/door.hpp" @@ -1146,8 +1145,8 @@ namespace MWWorld float pitch, yaw; Ogre::Vector3 eyepos; - mRendering->getPlayerData(eyepos, pitch, yaw); - mPhysics->updatePlayerData(eyepos, pitch, yaw); + mRendering->getCameraData(eyepos, pitch, yaw); + mPhysics->updateCameraData(eyepos, pitch, yaw); performUpdateSceneQueries (); From 6222b3f52a5aaea6802ccd0de7e436db4d919a15 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 29 Apr 2013 17:19:20 +0200 Subject: [PATCH 126/134] Bugfix #744 --- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2171beaff..fcd784dec 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1110,6 +1110,13 @@ namespace MWGui { mLoadingScreen->loadingDone (); } + bool WindowManager::getRestEnabled() + { + //Enable rest dialogue if character creation finished + if(mRestAllowed==false && MWBase::Environment::get().getWorld()->getGlobalVariable ("chargenstate").mFloat==-1) + mRestAllowed=true; + return mRestAllowed; + } bool WindowManager::getPlayerSleeping () { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 652ad870f..acac77bf3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -220,7 +220,7 @@ namespace MWGui virtual void loadingDone(); virtual void enableRest() { mRestAllowed = true; } - virtual bool getRestEnabled() { return mRestAllowed; } + virtual bool getRestEnabled(); virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); From a15758ac85e24dec9b872ad20a6d52d4eb7d9aa9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 08:48:45 -0700 Subject: [PATCH 127/134] Fix preview and vanity cameras --- 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 7180f6efd..60a9b22a3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -270,7 +270,8 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr) { Ogre::Vector3 rot(ptr.getRefData().getPosition().rot); - if(ptr.getRefData().getHandle() == mCamera->getHandle()) + if(ptr.getRefData().getHandle() == mCamera->getHandle() && + !mCamera->isVanityOrPreviewModeEnabled()) mCamera->rotateCamera(rot, false); Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); From 74de8b83b60de56d39b300b383ec3b090571abcd Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 29 Apr 2013 17:56:16 +0200 Subject: [PATCH 128/134] Enabled collision when new game --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 11 +++++++---- apps/openmw/mwworld/worldimp.hpp | 4 +++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4472b205f..39e1137ca 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,7 +368,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); - MWBase::Environment::get().getWorld()->setupPlayer(mNewGame); + MWBase::Environment::get().getWorld()->setupPlayer(); //Load translation data mTranslationDataStorage.setEncoder(mEncoder); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 42821e361..072dc7514 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -323,7 +323,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; - virtual void setupPlayer(bool newGame) = 0; + virtual void setupPlayer() = 0; virtual void renderPlayer() = 0; virtual void activateDoor(const MWWorld::Ptr& door) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6fc7324e5..990223322 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -163,7 +163,8 @@ namespace MWWorld ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride),mFallback(fallbackMap) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), + mFallback(fallbackMap), mNewGame(newGame) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -214,7 +215,7 @@ namespace MWWorld // global variables mGlobalVariables = new Globals (mStore); - if (newGame) + if (mNewGame) { // set new game mark mGlobalVariables->setInt ("chargenstate", 1); @@ -1465,12 +1466,12 @@ namespace MWWorld return mRendering->vanityRotateCamera(rot); } - void World::setupPlayer(bool newGame) + void World::setupPlayer() { const ESM::NPC* player = mStore.get().find ("player"); mPlayer = new MWWorld::Player (player, *this); mRendering->attachCameraTo(mPlayer->getPlayer()); - if (newGame) + if (mNewGame) { MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore); MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer()); @@ -1481,6 +1482,8 @@ namespace MWWorld { mRendering->renderPlayer(mPlayer->getPlayer()); mPhysics->addActor(mPlayer->getPlayer()); + if (mNewGame) + toggleCollisionMode(); } void World::setupExternalRendering (MWRender::ExternalRendering& rendering) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 172ae406c..19106c901 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,8 @@ namespace MWWorld float mFaced2Distance; int mNumFacing; + bool mNewGame; + std::map mDoorStates; ///< only holds doors that are currently moving. 0 means closing, 1 opening @@ -371,7 +373,7 @@ namespace MWWorld virtual bool vanityRotateCamera(float * rot); - virtual void setupPlayer(bool newGame); + virtual void setupPlayer(); virtual void renderPlayer(); virtual void activateDoor(const MWWorld::Ptr& door); From 0cf531ba12979bc649d813212a0ea0f926054b3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 09:53:36 -0700 Subject: [PATCH 129/134] Make sure to update parts when the weapon changes --- apps/openmw/mwrender/npcanimation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1d1ebf6b6..88f45daff 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -178,7 +178,8 @@ void NpcAnimation::updateParts(bool forceupdate) { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 0 }, - { &NpcAnimation::mShield, MWWorld::InventoryStore::Slot_CarriedLeft, 0 } + { &NpcAnimation::mShield, MWWorld::InventoryStore::Slot_CarriedLeft, 0 }, + { &NpcAnimation::mWeapon, MWWorld::InventoryStore::Slot_CarriedRight, 0 } }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); @@ -239,7 +240,7 @@ void NpcAnimation::updateParts(bool forceupdate) ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron }; size_t parts_size = sizeof(parts)/sizeof(parts[0]); - for(int p = 0;p < static_cast (parts_size);++p) + for(size_t p = 0;p < parts_size;++p) reserveIndividualPart(parts[p], slotlist[i].mSlot, prio); } else if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Skirt) @@ -260,6 +261,8 @@ void NpcAnimation::updateParts(bool forceupdate) if(mViewMode == VM_HeadOnly) return; + showWeapons(mShowWeapons); + std::map bodypartMap; bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; From 063322b081855969957a738a079574bd187b94e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 10:12:50 -0700 Subject: [PATCH 130/134] Declare some variables closer to where they're used --- apps/openmw/mwrender/npcanimation.cpp | 60 +++++++++++++-------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 88f45daff..c616a1ff5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -263,30 +263,6 @@ void NpcAnimation::updateParts(bool forceupdate) showWeapons(mShowWeapons); - std::map bodypartMap; - bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; - bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; - bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin; - bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand; - bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand; - bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist; - bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist; - bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm; - bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm; - bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm; - bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm; - bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot; - bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot; - bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle; - bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle; - bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee; - bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee; - bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg; - bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg; - bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail; - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const int Flag_Female = 0x01; const int Flag_FirstPerson = 0x02; @@ -302,21 +278,43 @@ void NpcAnimation::updateParts(bool forceupdate) std::pair thisCombination = std::make_pair(race, flags); if (sRaceMapping.find(thisCombination) == sRaceMapping.end()) { - sRaceMapping[thisCombination].resize(ESM::PRT_Count); - for (int i=0; i bodypartMap; + if(bodypartMap.size() == 0) + { + bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; + bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; + bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin; + bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail; + } + sRaceMapping[thisCombination].resize(ESM::PRT_Count, NULL); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::Store &partStore = store.get(); - - for (MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) + for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) { const ESM::BodyPart& bodypart = *it; if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) continue; if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) - { continue; - } + if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) continue; if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) From 854de1c6c14ebd55b1cf05884ef4b4207cf6d094 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 11:43:37 -0700 Subject: [PATCH 131/134] Make sure the weapon is in the proper group --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c616a1ff5..a92092020 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -481,7 +481,7 @@ void NpcAnimation::showWeapons(bool showWeapon) if(mWeapon != inv.end()) // special case for weapons { std::string mesh = MWWorld::Class::get(*mWeapon).getModel(*mWeapon); - addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,mesh); + addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh); } } else From 020e3e8a8ed6425665e17ef729ac2ca2e7465480 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2013 12:08:43 -0700 Subject: [PATCH 132/134] Show the equipped weapon in the inventory screen And use the proper pose based on what's equipped. --- apps/openmw/mwrender/characterpreview.cpp | 46 ++++++++++++++++++++++- apps/openmw/mwrender/characterpreview.hpp | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 24b089db3..4d9680b2c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -12,6 +12,7 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "renderconst.hpp" #include "npcanimation.hpp" @@ -134,6 +135,46 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { + MWWorld::InventoryStore &inv = MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter); + MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + std::string groupname; + if(iter == inv.end()) + groupname = "inventoryhandtohand"; + else + { + const std::string &type = iter->getTypeName(); + if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name()) + groupname = "inventoryweapononehand"; + else if(type == typeid(ESM::Weapon).name()) + { + MWWorld::LiveCellRef *ref = iter->get(); + + int type = ref->mBase->mData.mType; + if(type == ESM::Weapon::ShortBladeOneHand || + type == ESM::Weapon::LongBladeOneHand || + type == ESM::Weapon::BluntOneHand || + type == ESM::Weapon::AxeOneHand) + groupname = "inventoryweapononehand"; + else if(type == ESM::Weapon::LongBladeTwoHand || + type == ESM::Weapon::BluntTwoClose || + type == ESM::Weapon::AxeTwoHand) + groupname = "inventoryweapontwohand"; + else if(type == ESM::Weapon::BluntTwoWide || + type == ESM::Weapon::SpearTwoWide) + groupname = "inventoryweapontwowide"; + else + groupname = "inventoryhandtohand"; + } + else + groupname = "inventoryhandtohand"; + } + + if(groupname != mCurrentAnimGroup) + { + mCurrentAnimGroup = groupname; + mAnimation->play(mCurrentAnimGroup, "start", "stop", 0.0f, 0); + } + mAnimation->forceUpdate(); mAnimation->runAnimation(0.0f); @@ -155,7 +196,10 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", 0.0f, 0); + mAnimation->showWeapons(true); + + mCurrentAnimGroup = "inventoryhandtohand"; + mAnimation->play(mCurrentAnimGroup, "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 08cbd5108..d8f43f71b 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -53,6 +53,7 @@ namespace MWRender MWWorld::Ptr mCharacter; MWRender::NpcAnimation* mAnimation; + std::string mCurrentAnimGroup; std::string mName; From d283f8d85fa2b70d6d517fd79f8b9f10986d1e75 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 29 Apr 2013 21:19:13 +0200 Subject: [PATCH 133/134] Bugfix #748 --- apps/openmw/mwgui/console.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 463c645dc..cba3412e9 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -397,11 +397,24 @@ namespace MWGui void Console::setSelectedObject(const MWWorld::Ptr& object) { - mPtr = object; - if (!mPtr.isEmpty()) - setTitle("#{sConsoleTitle} (" + mPtr.getCellRef().mRefID + ")"); + if (!object.isEmpty()) + { + if (object == mPtr) + { + setTitle("#{sConsoleTitle}"); + mPtr=MWWorld::Ptr(); + } + else + { + setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")"); + mPtr = object; + } + } else + { setTitle("#{sConsoleTitle}"); + mPtr = MWWorld::Ptr(); + } MyGUI::InputManager::getInstance().setKeyFocusWidget(command); } From c0dd383cd014bbb2919d854fe22a6c5e564f377e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 30 Apr 2013 09:43:32 +0200 Subject: [PATCH 134/134] Fix door collision to work with all possible movement directions --- apps/openmw/mwworld/worldimp.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5f44545e9..c5970a32c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -1016,7 +1018,11 @@ namespace MWWorld Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); - float axisToCheck = (dimensions.x > dimensions.y) ? relativePos.y : -relativePos.x; + float axisToCheck; + if (dimensions.x > dimensions.y) + axisToCheck = relativePos.y * boost::math::sign((min+max).y); + else + axisToCheck = relativePos.x * boost::math::sign((min+max).x); if (axisToCheck >= 0) targetRot = std::min(std::max(0.f, oldRot + diff*0.5f), 90.f); else