1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-31 06:32:39 +00:00
OpenMW/apps/openmw/mwrender/creatureanimation.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

271 lines
8.9 KiB
C++
Raw Normal View History

#include "creatureanimation.hpp"
#include <osg/MatrixTransform>
2018-08-14 23:05:43 +04:00
#include <components/debug/debuglog.hpp>
#include <components/esm3/loadcrea.hpp>
2015-04-19 03:05:47 +02:00
#include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
2015-05-31 01:07:43 +02:00
#include <components/sceneutil/visitor.hpp>
#include <components/settings/settings.hpp>
#include "../mwmechanics/weapontype.hpp"
#include "../mwworld/class.hpp"
namespace MWRender
{
2011-12-11 23:42:39 -05:00
2015-04-19 03:05:47 +02:00
CreatureAnimation::CreatureAnimation(
2023-01-14 04:44:04 +03:00
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem, bool animated)
: ActorAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
{
MWWorld::LiveCellRef<ESM::Creature>* ref = mPtr.get<ESM::Creature>();
if (!model.empty())
2022-09-22 21:26:05 +03:00
{
setObjectRoot(model, false, false, true);
2015-04-19 03:05:47 +02:00
if ((ref->mBase->mFlags & ESM::Creature::Bipedal))
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
2023-01-14 04:44:04 +03:00
if (animated)
addAnimSource(model, model);
2022-09-22 21:26:05 +03:00
}
}
2015-04-19 03:05:47 +02:00
CreatureWeaponAnimation::CreatureWeaponAnimation(
2023-01-14 04:44:04 +03:00
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem, bool animated)
: ActorAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
, mShowWeapons(false)
, mShowCarriedLeft(false)
{
MWWorld::LiveCellRef<ESM::Creature>* ref = mPtr.get<ESM::Creature>();
if (!model.empty())
{
setObjectRoot(model, true, false, true);
if ((ref->mBase->mFlags & ESM::Creature::Bipedal))
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
2023-01-14 04:44:04 +03:00
if (animated)
addAnimSource(model, model);
mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
2014-03-12 11:30:44 +01:00
updateParts();
}
mWeaponAnimationTime = std::make_shared<WeaponAnimationTime>(this);
}
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
{
if (showWeapon != mShowWeapons)
2022-09-22 21:26:05 +03:00
{
mShowWeapons = showWeapon;
updateParts();
2022-09-22 21:26:05 +03:00
}
}
2015-04-19 03:05:47 +02:00
void CreatureWeaponAnimation::showCarriedLeft(bool show)
2022-09-22 21:26:05 +03:00
{
2015-04-19 03:05:47 +02:00
if (show != mShowCarriedLeft)
2022-09-22 21:26:05 +03:00
{
2015-04-19 03:05:47 +02:00
mShowCarriedLeft = show;
updateParts();
2022-09-22 21:26:05 +03:00
}
}
void CreatureWeaponAnimation::updateParts()
{
2015-04-19 03:05:47 +02:00
mAmmunition.reset();
mWeapon.reset();
2015-04-19 03:05:47 +02:00
mShield.reset();
2022-09-22 21:26:05 +03:00
updateHolsteredWeapon(!mShowWeapons);
updateQuiver();
updateHolsteredShield(mShowCarriedLeft);
2022-09-22 21:26:05 +03:00
if (mShowWeapons)
updatePart(mWeapon, MWWorld::InventoryStore::Slot_CarriedRight);
if (mShowCarriedLeft)
updatePart(mShield, MWWorld::InventoryStore::Slot_CarriedLeft);
}
void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
{
if (!mObjectRoot)
2022-09-22 21:26:05 +03:00
return;
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator it = inv.getSlot(slot);
2022-09-22 21:26:05 +03:00
if (it == inv.end())
{
scene.reset();
2022-09-22 21:26:05 +03:00
return;
}
MWWorld::ConstPtr item = *it;
2022-09-22 21:26:05 +03:00
std::string_view bonename;
std::string itemModel = item.getClass().getModel(item);
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
2022-09-22 21:26:05 +03:00
{
if (item.getType() == ESM::Weapon::sRecordId)
2019-08-09 10:00:40 +04:00
{
int type = item.get<ESM::Weapon>()->mBase->mData.mType;
bonename = MWMechanics::getWeaponType(type)->mAttachBone;
2019-08-09 10:00:40 +04:00
if (bonename != "Weapon Bone")
2022-09-22 21:26:05 +03:00
{
2019-08-09 10:00:40 +04:00
const NodeMap& nodeMap = getNodeMap();
NodeMap::const_iterator found = nodeMap.find(bonename);
2019-08-09 10:00:40 +04:00
if (found == nodeMap.end())
bonename = "Weapon Bone";
2022-09-22 21:26:05 +03:00
}
2019-08-09 10:00:40 +04:00
}
2022-09-22 21:26:05 +03:00
else
bonename = "Weapon Bone";
}
else
{
bonename = "Shield Bone";
if (item.getType() == ESM::Armor::sRecordId)
2022-09-22 21:26:05 +03:00
{
itemModel = getShieldMesh(item, false);
2022-09-22 21:26:05 +03:00
}
}
try
2014-03-12 11:30:44 +01:00
{
2021-11-02 18:01:22 +01:00
osg::ref_ptr<osg::Node> attached
= attach(itemModel, bonename, bonename, item.getType() == ESM::Light::sRecordId);
2022-05-29 13:24:48 +02:00
scene = std::make_unique<PartHolder>(attached);
if (!item.getClass().getEnchantment(item).empty())
mGlowUpdater
= SceneUtil::addEnchantedGlow(attached, mResourceSystem, item.getClass().getEnchantmentColor(item));
// Crossbows start out with a bolt attached
// FIXME: code duplicated from NpcAnimation
if (slot == MWWorld::InventoryStore::Slot_CarriedRight && item.getType() == ESM::Weapon::sRecordId
&& item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
const ESM::WeaponType* weaponInfo = MWMechanics::getWeaponType(ESM::Weapon::MarksmanCrossbow);
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == weaponInfo->mAmmoType)
attachArrow();
2022-09-22 21:26:05 +03:00
else
mAmmunition.reset();
2022-09-22 21:26:05 +03:00
}
else
mAmmunition.reset();
2014-03-12 11:30:44 +01:00
std::shared_ptr<SceneUtil::ControllerSource> source;
2015-05-31 01:07:43 +02:00
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
source = mWeaponAnimationTime;
else
2022-05-29 13:24:48 +02:00
source = std::make_shared<NullAnimationTime>();
2015-05-31 01:07:43 +02:00
SceneUtil::AssignControllerSourcesVisitor assignVisitor(source);
attached->accept(assignVisitor);
2022-09-22 21:26:05 +03:00
}
catch (std::exception& e)
2022-09-22 21:26:05 +03:00
{
2018-08-14 23:05:43 +04:00
Log(Debug::Error) << "Can not add creature part: " << e.what();
2022-09-22 21:26:05 +03:00
}
}
2022-09-22 21:26:05 +03:00
bool CreatureWeaponAnimation::isArrowAttached() const
{
2018-08-14 23:05:43 +04:00
return mAmmunition != nullptr;
}
void CreatureWeaponAnimation::detachArrow()
{
WeaponAnimation::detachArrow(mPtr);
updateQuiver();
}
void CreatureWeaponAnimation::attachArrow()
{
WeaponAnimation::attachArrow(mPtr);
2015-05-31 01:07:43 +02:00
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
2019-08-07 09:45:10 +04:00
if (ammo != inv.end() && !ammo->getClass().getEnchantment(*ammo).empty())
2022-09-22 21:26:05 +03:00
{
2015-05-31 01:07:43 +02:00
osg::Group* bone = getArrowBone();
2019-08-07 09:45:10 +04:00
if (bone != nullptr && bone->getNumChildren())
2015-05-31 01:07:43 +02:00
SceneUtil::addEnchantedGlow(
bone->getChild(0), mResourceSystem, ammo->getClass().getEnchantmentColor(*ammo));
2022-09-22 21:26:05 +03:00
}
2019-08-07 09:45:10 +04:00
updateQuiver();
}
void CreatureWeaponAnimation::releaseArrow(float attackStrength)
2022-09-22 21:26:05 +03:00
{
WeaponAnimation::releaseArrow(mPtr, attackStrength);
updateQuiver();
2014-03-12 11:30:44 +01:00
}
osg::Group* CreatureWeaponAnimation::getArrowBone()
2014-03-12 11:30:44 +01:00
{
if (!mWeapon)
return nullptr;
2015-05-31 01:07:43 +02:00
if (!mPtr.getClass().hasInventoryStore(mPtr))
2018-10-09 10:21:12 +04:00
return nullptr;
2015-05-31 01:07:43 +02:00
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weapon == inv.end() || weapon->getType() != ESM::Weapon::sRecordId)
return nullptr;
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
int ammoType = MWMechanics::getWeaponType(type)->mAmmoType;
if (ammoType == ESM::Weapon::None)
return nullptr;
// Try to find and attachment bone in actor's skeleton, otherwise fall back to the ArrowBone in weapon's mesh
osg::Group* bone = getBoneByName(MWMechanics::getWeaponType(ammoType)->mAttachBone);
if (bone == nullptr)
2022-09-22 21:26:05 +03:00
{
SceneUtil::FindByNameVisitor findVisitor("ArrowBone");
mWeapon->getNode()->accept(findVisitor);
bone = findVisitor.mFoundNode;
2022-09-22 21:26:05 +03:00
}
return bone;
2022-09-22 21:26:05 +03:00
}
osg::Node* CreatureWeaponAnimation::getWeaponNode()
{
return mWeapon ? mWeapon->getNode().get() : nullptr;
}
2015-05-31 01:07:43 +02:00
Resource::ResourceSystem* CreatureWeaponAnimation::getResourceSystem()
{
return mResourceSystem;
2014-03-12 11:30:44 +01:00
}
2015-05-31 18:53:16 +02:00
void CreatureWeaponAnimation::addControllers()
{
Animation::addControllers();
2015-05-31 18:53:16 +02:00
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
}
2015-04-19 03:05:47 +02:00
osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)
2014-03-12 11:30:44 +01:00
{
2015-05-22 01:54:06 +02:00
osg::Vec3f ret = Animation::runAnimation(duration);
WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0] + getBodyPitchRadians());
2015-05-22 01:54:06 +02:00
return ret;
2014-03-12 11:30:44 +01:00
}
2012-01-17 15:10:53 +01:00
}