diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 36a0f4085..a90de2589 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,5 +1,9 @@ #include "creatureanimation.hpp" +#include + +#include + #include #include @@ -9,6 +13,8 @@ #include #include +#include + #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -107,39 +113,51 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) else bonename = "Shield Bone"; - osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); - osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename); - mResourceSystem->getSceneManager()->notifyAttached(attached); - - scene.reset(new PartHolder(attached)); - - if (!item.getClass().getEnchantment(item).empty()) - addGlow(attached, getEnchantmentColor(item)); - - // Crossbows start out with a bolt attached - // FIXME: code duplicated from NpcAnimation - if (slot == MWWorld::InventoryStore::Slot_CarriedRight && - item.getTypeName() == typeid(ESM::Weapon).name() && - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + try { - MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); - if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) - attachArrow(); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); + + const NodeMap& nodeMap = getNodeMap(); + NodeMap::const_iterator found = getNodeMap().find(Misc::StringUtils::lowerCase(bonename)); + if (found == nodeMap.end()) + throw std::runtime_error("Can't find attachment node " + bonename); + osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, found->second.get()); + mResourceSystem->getSceneManager()->notifyAttached(attached); + + scene.reset(new PartHolder(attached)); + + if (!item.getClass().getEnchantment(item).empty()) + addGlow(attached, getEnchantmentColor(item)); + + // Crossbows start out with a bolt attached + // FIXME: code duplicated from NpcAnimation + if (slot == MWWorld::InventoryStore::Slot_CarriedRight && + item.getTypeName() == typeid(ESM::Weapon).name() && + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); + if (ammo != inv.end() && ammo->get()->mBase->mData.mType == ESM::Weapon::Bolt) + attachArrow(); + else + mAmmunition.reset(); + } else mAmmunition.reset(); - } - else - mAmmunition.reset(); - boost::shared_ptr source; + boost::shared_ptr source; - if (slot == MWWorld::InventoryStore::Slot_CarriedRight) - source = mWeaponAnimationTime; - else - source.reset(new NullAnimationTime); + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + source = mWeaponAnimationTime; + else + source.reset(new NullAnimationTime); - SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); - attached->accept(assignVisitor); + SceneUtil::AssignControllerSourcesVisitor assignVisitor(source); + attached->accept(assignVisitor); + } + catch (std::exception& e) + { + std::cerr << "Error adding creature part: " << e.what() << std::endl; + } } void CreatureWeaponAnimation::attachArrow() diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e85008679..8f87c46fb 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -667,10 +667,18 @@ void NpcAnimation::updateParts() attachArrow(); } + + PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model); - osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); + + const NodeMap& nodeMap = getNodeMap(); + NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); + if (found == nodeMap.end()) + throw std::runtime_error("Can't find attachment node " + bonename); + + osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, found->second); mResourceSystem->getSceneManager()->notifyAttached(attached); if (enchantedGlow) addGlow(attached, *glowColor); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index c80b9be36..f80ae9520 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -63,7 +63,7 @@ namespace SceneUtil std::string mFilter2; }; - osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, const std::string &attachNode) + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, osg::Group* attachNode) { if (dynamic_cast(toAttach.get())) { @@ -88,11 +88,6 @@ namespace SceneUtil } else { - FindByNameVisitor find(attachNode); - master->accept(find); - if (!find.mFoundNode) - throw std::runtime_error(std::string("Can't find attachment node ") + attachNode); - FindByNameVisitor findBoneOffset("BoneOffset"); toAttach->accept(findBoneOffset); @@ -110,7 +105,7 @@ namespace SceneUtil trans->setAttitude(osg::Quat(osg::DegreesToRadians(-90.f), osg::Vec3f(1,0,0))); } - if (attachNode.find("Left") != std::string::npos) + if (attachNode->getName().find("Left") != std::string::npos) { if (!trans) trans = new osg::PositionAttitudeTransform; @@ -132,13 +127,13 @@ namespace SceneUtil if (trans) { - find.mFoundNode->addChild(trans); + attachNode->addChild(trans); trans->addChild(toAttach); return trans; } else { - find.mFoundNode->addChild(toAttach); + attachNode->addChild(toAttach); return toAttach; } } diff --git a/components/sceneutil/attach.hpp b/components/sceneutil/attach.hpp index 72f7809e9..a8a2239a8 100644 --- a/components/sceneutil/attach.hpp +++ b/components/sceneutil/attach.hpp @@ -8,6 +8,7 @@ namespace osg { class Node; + class Group; } namespace SceneUtil @@ -18,7 +19,7 @@ namespace SceneUtil /// Otherwise, just attach all of the toAttach scenegraph to the attachment node on the master scenegraph, with no filtering. /// @note The master scene graph is expected to include a skeleton. /// @return A newly created node that is directly attached to the master scene graph - osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, const std::string& attachNode); + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, osg::Group* attachNode); }