1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 15:29:55 +00:00

Merge branch 'vfs_normalized_path_16' into 'master'

Use normalized path in multiple places and fix additional animation sources loading (#8138)

See merge request OpenMW/openmw!4398
This commit is contained in:
psi29a 2024-10-07 20:02:54 +00:00
commit 974c0ce158
7 changed files with 65 additions and 49 deletions

View file

@ -28,16 +28,17 @@
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>
#include <components/esm3/loadrace.hpp> #include <components/esm3/loadrace.hpp>
#include <components/esm4/loadligh.hpp> #include <components/esm4/loadligh.hpp>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/misc/pathhelpers.hpp> #include <components/misc/pathhelpers.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/sceneutil/lightcommon.hpp>
#include <components/sceneutil/keyframe.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
#include <components/vfs/recursivedirectoryiterator.hpp> #include <components/vfs/recursivedirectoryiterator.hpp>
#include <components/sceneutil/keyframe.hpp>
#include <components/sceneutil/lightcommon.hpp>
#include <components/sceneutil/lightmanager.hpp> #include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/lightutil.hpp> #include <components/sceneutil/lightutil.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
@ -657,16 +658,24 @@ namespace MWRender
return mKeyframes->mTextKeys; return mKeyframes->mTextKeys;
} }
void Animation::loadAllAnimationsInFolder(const std::string& model, const std::string& baseModel) void Animation::loadAdditionalAnimations(VFS::Path::NormalizedView model, const std::string& baseModel)
{ {
std::string animationPath = model; constexpr VFS::Path::NormalizedView meshes("meshes/");
if (animationPath.find("meshes") == 0) if (!model.value().starts_with(meshes.value()))
{ return;
animationPath.replace(0, 6, "animations");
}
animationPath.replace(animationPath.size() - 3, 3, "/");
for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) std::string path(model.value());
constexpr VFS::Path::NormalizedView animations("animations/");
path.replace(0, meshes.value().size(), animations.value());
const std::string::size_type extensionStart = path.find_last_of(VFS::Path::extensionSeparator);
if (extensionStart == std::string::npos)
return;
path.replace(extensionStart, path.size() - extensionStart, "/");
for (const VFS::Path::Normalized& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(path))
{ {
if (Misc::getFileExtension(name) == "kf") if (Misc::getFileExtension(name) == "kf")
{ {
@ -677,15 +686,15 @@ namespace MWRender
void Animation::addAnimSource(std::string_view model, const std::string& baseModel) void Animation::addAnimSource(std::string_view model, const std::string& baseModel)
{ {
std::string kfname = Misc::StringUtils::lowerCase(model); VFS::Path::Normalized kfname(model);
if (kfname.ends_with(".nif")) if (Misc::getFileExtension(kfname) == "nif")
kfname.replace(kfname.size() - 4, 4, ".kf"); kfname.changeExtension("kf");
addSingleAnimSource(kfname, baseModel); addSingleAnimSource(kfname, baseModel);
if (Settings::game().mUseAdditionalAnimSources) if (Settings::game().mUseAdditionalAnimSources)
loadAllAnimationsInFolder(kfname, baseModel); loadAdditionalAnimations(kfname, baseModel);
} }
std::shared_ptr<Animation::AnimSource> Animation::addSingleAnimSource( std::shared_ptr<Animation::AnimSource> Animation::addSingleAnimSource(

View file

@ -15,6 +15,7 @@
#include <components/sceneutil/nodecallback.hpp> #include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/textkeymap.hpp> #include <components/sceneutil/textkeymap.hpp>
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/vfs/pathutil.hpp>
#include <map> #include <map>
#include <span> #include <span>
@ -281,7 +282,7 @@ namespace MWRender
*/ */
void setObjectRoot(const std::string& model, bool forceskeleton, bool baseonly, bool isCreature); void setObjectRoot(const std::string& model, bool forceskeleton, bool baseonly, bool isCreature);
void loadAllAnimationsInFolder(const std::string& model, const std::string& baseModel); void loadAdditionalAnimations(VFS::Path::NormalizedView model, const std::string& baseModel);
/** Adds the keyframe controllers in the specified model as a new animation source. /** Adds the keyframe controllers in the specified model as a new animation source.
* @note Later added animation sources have the highest priority when it comes to finding a particular * @note Later added animation sources have the highest priority when it comes to finding a particular

View file

@ -456,8 +456,8 @@ namespace MWRender
mHeadModel.clear(); mHeadModel.clear();
mHairModel.clear(); mHairModel.clear();
const ESM::RefId& headName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHead") : mNpc->mHead; const ESM::RefId headName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHead") : mNpc->mHead;
const ESM::RefId& hairName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHair") : mNpc->mHair; const ESM::RefId hairName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHair") : mNpc->mHair;
if (!headName.empty()) if (!headName.empty())
{ {
@ -647,7 +647,8 @@ namespace MWRender
{ {
const ESM::Light* light = part.get<ESM::Light>()->mBase; const ESM::Light* light = part.get<ESM::Light>()->mBase;
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
Misc::ResourceHelpers::correctMeshPath(light->mModel), false, nullptr, true); VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(light->mModel)), false, nullptr,
true);
if (mObjectParts[ESM::PRT_Shield]) if (mObjectParts[ESM::PRT_Shield])
addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light)); addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light));
} }
@ -667,7 +668,7 @@ namespace MWRender
{ {
if (const ESM::BodyPart* bodypart = parts[part]) if (const ESM::BodyPart* bodypart = parts[part])
addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part), -1, 1, addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part), -1, 1,
Misc::ResourceHelpers::correctMeshPath(bodypart->mModel)); VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(bodypart->mModel)));
} }
} }
@ -675,10 +676,10 @@ namespace MWRender
attachArrow(); attachArrow();
} }
PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, std::string_view bonename, PartHolderPtr NpcAnimation::insertBoundedPart(VFS::Path::NormalizedView model, std::string_view bonename,
std::string_view bonefilter, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight) std::string_view bonefilter, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight)
{ {
osg::ref_ptr<osg::Node> attached = attach(VFS::Path::toNormalized(model), bonename, bonefilter, isLight); osg::ref_ptr<osg::Node> attached = attach(model, bonename, bonefilter, isLight);
if (enchantedGlow) if (enchantedGlow)
mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, *glowColor); mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, *glowColor);
@ -748,7 +749,7 @@ namespace MWRender
} }
bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority,
const std::string& mesh, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight) VFS::Path::NormalizedView mesh, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight)
{ {
if (priority <= mPartPriorities[type]) if (priority <= mPartPriorities[type])
return false; return false;
@ -897,7 +898,8 @@ namespace MWRender
if (bodypart) if (bodypart)
addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part.mPart), group, priority, addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part.mPart), group, priority,
Misc::ResourceHelpers::correctMeshPath(bodypart->mModel), enchantedGlow, glowColor); VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(bodypart->mModel)), enchantedGlow,
glowColor);
else else
reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority); reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority);
} }
@ -943,7 +945,7 @@ namespace MWRender
if (weapon != inv.end()) if (weapon != inv.end())
{ {
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon); osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
std::string mesh = weapon->getClass().getCorrectedModel(*weapon); const VFS::Path::Normalized mesh = weapon->getClass().getCorrectedModel(*weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh,
!weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
@ -1003,7 +1005,7 @@ namespace MWRender
if (show && iter != inv.end()) if (show && iter != inv.end())
{ {
osg::Vec4f glowColor = iter->getClass().getEnchantmentColor(*iter); osg::Vec4f glowColor = iter->getClass().getEnchantmentColor(*iter);
std::string mesh = iter->getClass().getCorrectedModel(*iter); VFS::Path::Normalized mesh = iter->getClass().getCorrectedModel(*iter);
// For shields we must try to use the body part model // For shields we must try to use the body part model
if (iter->getType() == ESM::Armor::sRecordId) if (iter->getType() == ESM::Armor::sRecordId)
{ {

View file

@ -1,13 +1,14 @@
#ifndef GAME_RENDER_NPCANIMATION_H #ifndef GAME_RENDER_NPCANIMATION_H
#define GAME_RENDER_NPCANIMATION_H #define GAME_RENDER_NPCANIMATION_H
#include "actoranimation.hpp"
#include "animation.hpp" #include "animation.hpp"
#include "weaponanimation.hpp"
#include <components/vfs/pathutil.hpp>
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "actoranimation.hpp"
#include "weaponanimation.hpp"
#include <array> #include <array>
namespace ESM namespace ESM
@ -50,8 +51,8 @@ namespace MWRender
std::array<MWSound::Sound*, ESM::PRT_Count> mSounds; std::array<MWSound::Sound*, ESM::PRT_Count> mSounds;
const ESM::NPC* mNpc; const ESM::NPC* mNpc;
std::string mHeadModel; VFS::Path::Normalized mHeadModel;
std::string mHairModel; VFS::Path::Normalized mHairModel;
ViewMode mViewMode; ViewMode mViewMode;
bool mShowWeapons; bool mShowWeapons;
bool mShowCarriedLeft; bool mShowCarriedLeft;
@ -83,14 +84,15 @@ namespace MWRender
NpcType getNpcType() const; NpcType getNpcType() const;
PartHolderPtr insertBoundedPart(const std::string& model, std::string_view bonename, PartHolderPtr insertBoundedPart(VFS::Path::NormalizedView model, std::string_view bonename,
std::string_view bonefilter, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight); std::string_view bonefilter, bool enchantedGlow, osg::Vec4f* glowColor, bool isLight);
void removeIndividualPart(ESM::PartReferenceType type); void removeIndividualPart(ESM::PartReferenceType type);
void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority);
bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string& mesh, bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority,
bool enchantedGlow = false, osg::Vec4f* glowColor = nullptr, bool isLight = false); VFS::Path::NormalizedView mesh, bool enchantedGlow = false, osg::Vec4f* glowColor = nullptr,
bool isLight = false);
void removePartGroup(int group); void removePartGroup(int group);
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference>& parts, void addPartGroup(int group, int priority, const std::vector<ESM::PartReference>& parts,
bool enchantedGlow = false, osg::Vec4f* glowColor = nullptr); bool enchantedGlow = false, osg::Vec4f* glowColor = nullptr);

View file

@ -189,7 +189,7 @@ namespace MWWorld
float mRotateSpeed; float mRotateSpeed;
}; };
void ProjectileManager::createModel(State& state, const std::string& model, const osg::Vec3f& pos, void ProjectileManager::createModel(State& state, VFS::Path::NormalizedView model, const osg::Vec3f& pos,
const osg::Quat& orient, bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, const std::string& texture) const osg::Quat& orient, bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, const std::string& texture)
{ {
state.mNode = new osg::PositionAttitudeTransform; state.mNode = new osg::PositionAttitudeTransform;
@ -207,8 +207,7 @@ namespace MWWorld
attachTo = rotateNode; attachTo = rotateNode;
} }
osg::ref_ptr<osg::Node> projectile osg::ref_ptr<osg::Node> projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo);
= mResourceSystem->getSceneManager()->getInstance(VFS::Path::toNormalized(model), attachTo);
if (state.mIdMagic.size() > 1) if (state.mIdMagic.size() > 1)
{ {
@ -315,7 +314,7 @@ namespace MWWorld
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
auto model = ptr.getClass().getCorrectedModel(ptr); VFS::Path::Normalized model = ptr.getClass().getCorrectedModel(ptr);
createModel(state, model, pos, orient, true, true, lightDiffuseColor, texture); createModel(state, model, pos, orient, true, true, lightDiffuseColor, texture);
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
@ -355,7 +354,7 @@ namespace MWWorld
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), projectile.getCellRef().getRefId()); MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), projectile.getCellRef().getRefId());
MWWorld::Ptr ptr = ref.getPtr(); MWWorld::Ptr ptr = ref.getPtr();
const auto model = ptr.getClass().getCorrectedModel(ptr); const VFS::Path::Normalized model = ptr.getClass().getCorrectedModel(ptr);
createModel(state, model, pos, orient, false, false, osg::Vec4(0, 0, 0, 0)); createModel(state, model, pos, orient, false, false, osg::Vec4(0, 0, 0, 0));
if (!ptr.getClass().getEnchantment(ptr).empty()) if (!ptr.getClass().getEnchantment(ptr).empty())
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr)); SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
@ -695,7 +694,7 @@ namespace MWWorld
state.mAttackStrength = esm.mAttackStrength; state.mAttackStrength = esm.mAttackStrength;
state.mToDelete = false; state.mToDelete = false;
std::string model; VFS::Path::Normalized model;
try try
{ {
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), esm.mId); MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), esm.mId);
@ -750,7 +749,7 @@ namespace MWWorld
// file's effect list, which is already trimmed of non-projectile // file's effect list, which is already trimmed of non-projectile
// effects. We need to use the stored value. // effects. We need to use the stored value.
std::string model; VFS::Path::Normalized model;
try try
{ {
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), state.mIdMagic.at(0)); MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), state.mIdMagic.at(0));

View file

@ -7,6 +7,7 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <components/esm3/effectlist.hpp> #include <components/esm3/effectlist.hpp>
#include <components/vfs/pathutil.hpp>
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
@ -135,7 +136,7 @@ namespace MWWorld
void moveProjectiles(float dt); void moveProjectiles(float dt);
void moveMagicBolts(float dt); void moveMagicBolts(float dt);
void createModel(State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, void createModel(State& state, VFS::Path::NormalizedView model, const osg::Vec3f& pos, const osg::Quat& orient,
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, const std::string& texture = ""); bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, const std::string& texture = "");
void update(State& state, float duration); void update(State& state, float duration);

View file

@ -16,28 +16,30 @@
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/texturetype.hpp> #include <components/sceneutil/texturetype.hpp>
#include <components/vfs/pathutil.hpp>
namespace SceneUtil namespace SceneUtil
{ {
namespace namespace
{ {
std::array<std::string, 32> generateGlowTextureNames() std::array<VFS::Path::Normalized, 32> generateGlowTextureNames()
{ {
std::array<std::string, 32> result; constexpr VFS::Path::NormalizedView prefix("textures/magicitem");
std::array<VFS::Path::Normalized, 32> result;
for (std::size_t i = 0; i < result.size(); ++i) for (std::size_t i = 0; i < result.size(); ++i)
{ {
std::stringstream stream; std::stringstream stream;
stream << "textures/magicitem/caust"; stream << "caust";
stream << std::setw(2); stream << std::setw(2);
stream << std::setfill('0'); stream << std::setfill('0');
stream << i; stream << i;
stream << ".dds"; stream << ".dds";
result[i] = std::move(stream).str(); result[i] = prefix / VFS::Path::Normalized(std::move(stream).str());
} }
return result; return result;
} }
const std::array<std::string, 32> glowTextureNames = generateGlowTextureNames(); const std::array<VFS::Path::Normalized, 32> glowTextureNames = generateGlowTextureNames();
struct FindLowestUnusedTexUnitVisitor : public osg::NodeVisitor struct FindLowestUnusedTexUnitVisitor : public osg::NodeVisitor
{ {
@ -219,9 +221,9 @@ namespace SceneUtil
const osg::Vec4f& glowColor, float glowDuration) const osg::Vec4f& glowColor, float glowDuration)
{ {
std::vector<osg::ref_ptr<osg::Texture2D>> textures; std::vector<osg::ref_ptr<osg::Texture2D>> textures;
for (const std::string& name : glowTextureNames) for (const VFS::Path::Normalized& name : glowTextureNames)
{ {
osg::ref_ptr<osg::Image> image = resourceSystem->getImageManager()->getImage(VFS::Path::toNormalized(name)); osg::ref_ptr<osg::Image> image = resourceSystem->getImageManager()->getImage(name);
osg::ref_ptr<osg::Texture2D> tex(new osg::Texture2D(image)); osg::ref_ptr<osg::Texture2D> tex(new osg::Texture2D(image));
tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT);
tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT);