mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +00:00
Merge branch 'xanim' into 'master'
X-file handling fixes (bug #5371) Closes #5371 See merge request OpenMW/openmw!2614
This commit is contained in:
commit
32733d23fa
@ -6,6 +6,7 @@
|
||||
Bug #4816: GetWeaponDrawn returns 1 before weapon is attached
|
||||
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
||||
Bug #5129: Stuttering animation on Centurion Archer
|
||||
Bug #5371: Keyframe animation tracks are used for any file that begins with an X
|
||||
Bug #5714: Touch spells cast using ExplodeSpell don't always explode
|
||||
Bug #5849: Paralysis breaks landing
|
||||
Bug #5883: Immobile creatures don't cause water ripples
|
||||
|
@ -45,7 +45,7 @@ namespace MWClass
|
||||
{
|
||||
if (!model.empty())
|
||||
{
|
||||
renderingInterface.getObjects().insertModel(ptr, model, true);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ namespace MWClass
|
||||
{
|
||||
if (!model.empty())
|
||||
{
|
||||
renderingInterface.getObjects().insertModel(ptr, model, true);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace MWClass
|
||||
{
|
||||
if (!model.empty())
|
||||
{
|
||||
renderingInterface.getObjects().insertModel(ptr, model, true);
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,7 @@ namespace MWClass
|
||||
MWWorld::LiveCellRef<ESM::Light>* ref = ptr.get<ESM::Light>();
|
||||
|
||||
// Insert even if model is empty, so that the light is added
|
||||
renderingInterface.getObjects().insertModel(
|
||||
ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
||||
renderingInterface.getObjects().insertModel(ptr, model, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <components/esm3/loadgmst.hpp>
|
||||
#include <components/esm3/loadmgef.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
@ -642,15 +643,15 @@ namespace MWPhysics
|
||||
|
||||
void PhysicsSystem::addActor(const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||
{
|
||||
osg::ref_ptr<const Resource::BulletShape> shape = mShapeManager->getShape(mesh);
|
||||
std::string animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
|
||||
osg::ref_ptr<const Resource::BulletShape> shape = mShapeManager->getShape(animationMesh);
|
||||
|
||||
// Try to get shape from basic model as fallback for creatures
|
||||
if (!ptr.getClass().isNpc() && shape && shape->mCollisionBox.mExtents.length2() == 0)
|
||||
{
|
||||
const std::string fallbackModel = ptr.getClass().getModel(ptr);
|
||||
if (fallbackModel != mesh)
|
||||
if (animationMesh != mesh)
|
||||
{
|
||||
shape = mShapeManager->getShape(fallbackModel);
|
||||
shape = mShapeManager->getShape(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,7 +609,7 @@ namespace MWRender
|
||||
{
|
||||
std::string kfname = Misc::StringUtils::lowerCase(model);
|
||||
|
||||
if (kfname.size() > 4 && kfname.compare(kfname.size() - 4, 4, ".nif") == 0)
|
||||
if (kfname.ends_with(".nif"))
|
||||
kfname.replace(kfname.size() - 4, 4, ".kf");
|
||||
|
||||
addSingleAnimSource(kfname, baseModel);
|
||||
|
@ -17,7 +17,7 @@ namespace MWRender
|
||||
{
|
||||
|
||||
CreatureAnimation::CreatureAnimation(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
||||
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>();
|
||||
@ -28,12 +28,14 @@ namespace MWRender
|
||||
|
||||
if ((ref->mBase->mFlags & ESM::Creature::Bipedal))
|
||||
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||
addAnimSource(model, model);
|
||||
|
||||
if (animated)
|
||||
addAnimSource(model, model);
|
||||
}
|
||||
}
|
||||
|
||||
CreatureWeaponAnimation::CreatureWeaponAnimation(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
||||
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)
|
||||
@ -45,10 +47,10 @@ namespace MWRender
|
||||
setObjectRoot(model, true, false, true);
|
||||
|
||||
if ((ref->mBase->mFlags & ESM::Creature::Bipedal))
|
||||
{
|
||||
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||
}
|
||||
addAnimSource(model, model);
|
||||
|
||||
if (animated)
|
||||
addAnimSource(model, model);
|
||||
|
||||
mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
|
||||
|
||||
|
@ -15,7 +15,8 @@ namespace MWRender
|
||||
class CreatureAnimation : public ActorAnimation
|
||||
{
|
||||
public:
|
||||
CreatureAnimation(const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);
|
||||
CreatureAnimation(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem, bool animated);
|
||||
virtual ~CreatureAnimation() {}
|
||||
};
|
||||
|
||||
@ -28,7 +29,7 @@ namespace MWRender
|
||||
{
|
||||
public:
|
||||
CreatureWeaponAnimation(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);
|
||||
const MWWorld::Ptr& ptr, const std::string& model, Resource::ResourceSystem* resourceSystem, bool animated);
|
||||
virtual ~CreatureWeaponAnimation() {}
|
||||
|
||||
void equipmentChanged() override { updateParts(); }
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <osg/Group>
|
||||
#include <osg/UserDataContainer>
|
||||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/sceneutil/unrefqueue.hpp>
|
||||
|
||||
@ -68,12 +69,21 @@ namespace MWRender
|
||||
ptr.getRefData().setBaseNode(insert);
|
||||
}
|
||||
|
||||
void Objects::insertModel(const MWWorld::Ptr& ptr, const std::string& mesh, bool animated, bool allowLight)
|
||||
void Objects::insertModel(const MWWorld::Ptr& ptr, const std::string& mesh, bool allowLight)
|
||||
{
|
||||
insertBegin(ptr);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Object);
|
||||
bool animated = ptr.getClass().useAnim();
|
||||
std::string animationMesh = mesh;
|
||||
if (animated && !mesh.empty())
|
||||
{
|
||||
animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
|
||||
if (animationMesh == mesh)
|
||||
animated = false;
|
||||
}
|
||||
|
||||
osg::ref_ptr<ObjectAnimation> anim(new ObjectAnimation(ptr, mesh, mResourceSystem, animated, allowLight));
|
||||
osg::ref_ptr<ObjectAnimation> anim(
|
||||
new ObjectAnimation(ptr, animationMesh, mResourceSystem, animated, allowLight));
|
||||
|
||||
mObjects.emplace(ptr.mRef, std::move(anim));
|
||||
}
|
||||
@ -83,13 +93,18 @@ namespace MWRender
|
||||
insertBegin(ptr);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(Mask_Actor);
|
||||
|
||||
bool animated = true;
|
||||
std::string animationMesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mResourceSystem->getVFS());
|
||||
if (animationMesh == mesh)
|
||||
animated = false;
|
||||
|
||||
// CreatureAnimation
|
||||
osg::ref_ptr<Animation> anim;
|
||||
|
||||
if (weaponsShields)
|
||||
anim = new CreatureWeaponAnimation(ptr, mesh, mResourceSystem);
|
||||
anim = new CreatureWeaponAnimation(ptr, animationMesh, mResourceSystem, animated);
|
||||
else
|
||||
anim = new CreatureAnimation(ptr, mesh, mResourceSystem);
|
||||
anim = new CreatureAnimation(ptr, animationMesh, mResourceSystem, animated);
|
||||
|
||||
if (mObjects.emplace(ptr.mRef, anim).second)
|
||||
ptr.getClass().getContainerStore(ptr).setContListener(static_cast<ActorAnimation*>(anim.get()));
|
||||
|
@ -72,10 +72,8 @@ namespace MWRender
|
||||
SceneUtil::UnrefQueue& unrefQueue);
|
||||
~Objects();
|
||||
|
||||
/// @param animated Attempt to load separate keyframes from a .kf file matching the model file?
|
||||
/// @param allowLight If false, no lights will be created, and particles systems will be removed.
|
||||
void insertModel(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, bool animated = false, bool allowLight = true);
|
||||
void insertModel(const MWWorld::Ptr& ptr, const std::string& model, bool allowLight = true);
|
||||
|
||||
void insertNPC(const MWWorld::Ptr& ptr);
|
||||
void insertCreature(const MWWorld::Ptr& ptr, const std::string& model, bool weaponsShields);
|
||||
|
@ -90,15 +90,11 @@ namespace
|
||||
rendering.rotateObject(ptr, rotation);
|
||||
}
|
||||
|
||||
std::string getModel(const MWWorld::Ptr& ptr, const VFS::Manager* vfs)
|
||||
std::string getModel(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (Misc::ResourceHelpers::isHiddenMarker(ptr.getCellRef().getRefId()))
|
||||
return {};
|
||||
bool useAnim = ptr.getClass().useAnim();
|
||||
std::string model = ptr.getClass().getModel(ptr);
|
||||
if (useAnim)
|
||||
model = Misc::ResourceHelpers::correctActorModelPath(model, vfs);
|
||||
return model;
|
||||
return ptr.getClass().getModel(ptr);
|
||||
}
|
||||
|
||||
void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector<ESM::RefNum>& pagedRefs,
|
||||
@ -110,7 +106,7 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
||||
std::string model = getModel(ptr);
|
||||
const auto rotation = makeDirectNodeRotation(ptr);
|
||||
|
||||
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
||||
@ -279,8 +275,7 @@ namespace MWWorld
|
||||
{
|
||||
if (!ptr.getRefData().getBaseNode())
|
||||
return;
|
||||
ptr.getClass().insertObjectRendering(
|
||||
ptr, getModel(ptr, mRendering.getResourceSystem()->getVFS()), mRendering);
|
||||
ptr.getClass().insertObjectRendering(ptr, getModel(ptr), mRendering);
|
||||
setNodeRotation(ptr, mRendering, makeNodeRotation(ptr, RotationOrder::direct));
|
||||
reloadTerrain();
|
||||
}
|
||||
@ -630,7 +625,7 @@ namespace MWWorld
|
||||
ptr.mRef->mData.mPhysicsPostponed = false;
|
||||
if (ptr.mRef->mData.isEnabled() && ptr.mRef->mData.getCount() > 0)
|
||||
{
|
||||
std::string model = getModel(ptr, MWBase::Environment::get().getResourceSystem()->getVFS());
|
||||
std::string model = getModel(ptr);
|
||||
if (!model.empty())
|
||||
{
|
||||
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
||||
|
@ -2430,10 +2430,8 @@ namespace MWWorld
|
||||
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
|
||||
MWBase::Environment::get().getWindowManager()->watchActor(getPlayerPtr());
|
||||
|
||||
std::string model = getPlayerPtr().getClass().getModel(getPlayerPtr());
|
||||
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
|
||||
mPhysics->remove(getPlayerPtr());
|
||||
mPhysics->addActor(getPlayerPtr(), model);
|
||||
mPhysics->addActor(getPlayerPtr(), getPlayerPtr().getClass().getModel(getPlayerPtr()));
|
||||
|
||||
applyLoopingParticles(player);
|
||||
|
||||
|
@ -134,7 +134,11 @@ std::string Misc::ResourceHelpers::correctActorModelPath(const std::string& resP
|
||||
mdlname.insert(mdlname.begin() + p + 1, 'x');
|
||||
else
|
||||
mdlname.insert(mdlname.begin(), 'x');
|
||||
if (!vfs->exists(mdlname))
|
||||
std::string kfname = mdlname;
|
||||
if (kfname.ends_with(".nif"))
|
||||
kfname.replace(kfname.size() - 4, 4, ".kf");
|
||||
|
||||
if (!vfs->exists(kfname))
|
||||
{
|
||||
return resPath;
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ namespace Misc
|
||||
std::string correctIconPath(std::string_view resPath, const VFS::Manager* vfs);
|
||||
std::string correctBookartPath(std::string_view resPath, const VFS::Manager* vfs);
|
||||
std::string correctBookartPath(std::string_view resPath, int width, int height, const VFS::Manager* vfs);
|
||||
/// Use "xfoo.nif" instead of "foo.nif" if available
|
||||
/// Use "xfoo.nif" instead of "foo.nif" if "xfoo.kf" is available
|
||||
/// Note that if "xfoo.nif" is actually unavailable, we can't fall back to "foo.nif". :(
|
||||
std::string correctActorModelPath(const std::string& resPath, const VFS::Manager* vfs);
|
||||
std::string correctMeshPath(const std::string& resPath, const VFS::Manager* vfs);
|
||||
|
||||
|
@ -208,6 +208,7 @@ namespace NifBullet
|
||||
}
|
||||
// files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see
|
||||
// Animation::addAnimSource). assume all nodes in the file will be animated
|
||||
// TODO: investigate whether this should and could be optimized.
|
||||
const bool isAnimated = pathFileNameStartsWithX(filename);
|
||||
|
||||
// If there's no bounding box, we'll have to generate a Bullet collision shape
|
||||
|
Loading…
x
Reference in New Issue
Block a user