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
pull/3236/head
psi29a 3 months ago
commit 974c0ce158

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

@ -15,6 +15,7 @@
#include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/textkeymap.hpp>
#include <components/sceneutil/util.hpp>
#include <components/vfs/pathutil.hpp>
#include <map>
#include <span>
@ -281,7 +282,7 @@ namespace MWRender
*/
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.
* @note Later added animation sources have the highest priority when it comes to finding a particular

@ -456,8 +456,8 @@ namespace MWRender
mHeadModel.clear();
mHairModel.clear();
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 headName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHead") : mNpc->mHead;
const ESM::RefId hairName = isWerewolf ? ESM::RefId::stringRefId("WerewolfHair") : mNpc->mHair;
if (!headName.empty())
{
@ -647,7 +647,8 @@ namespace MWRender
{
const ESM::Light* light = part.get<ESM::Light>()->mBase;
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])
addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light));
}
@ -667,7 +668,7 @@ namespace MWRender
{
if (const ESM::BodyPart* bodypart = parts[part])
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();
}
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)
{
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)
mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, *glowColor);
@ -748,7 +749,7 @@ namespace MWRender
}
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])
return false;
@ -897,7 +898,8 @@ namespace MWRender
if (bodypart)
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
reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority);
}
@ -943,7 +945,7 @@ namespace MWRender
if (weapon != inv.end())
{
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,
!weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
@ -1003,7 +1005,7 @@ namespace MWRender
if (show && iter != inv.end())
{
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
if (iter->getType() == ESM::Armor::sRecordId)
{

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

@ -189,7 +189,7 @@ namespace MWWorld
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)
{
state.mNode = new osg::PositionAttitudeTransform;
@ -207,8 +207,7 @@ namespace MWWorld
attachTo = rotateNode;
}
osg::ref_ptr<osg::Node> projectile
= mResourceSystem->getSceneManager()->getInstance(VFS::Path::toNormalized(model), attachTo);
osg::ref_ptr<osg::Node> projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo);
if (state.mIdMagic.size() > 1)
{
@ -315,7 +314,7 @@ namespace MWWorld
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);
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
@ -355,7 +354,7 @@ namespace MWWorld
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), projectile.getCellRef().getRefId());
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));
if (!ptr.getClass().getEnchantment(ptr).empty())
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
@ -695,7 +694,7 @@ namespace MWWorld
state.mAttackStrength = esm.mAttackStrength;
state.mToDelete = false;
std::string model;
VFS::Path::Normalized model;
try
{
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
// effects. We need to use the stored value.
std::string model;
VFS::Path::Normalized model;
try
{
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), state.mIdMagic.at(0));

@ -7,6 +7,7 @@
#include <osg/ref_ptr>
#include <components/esm3/effectlist.hpp>
#include <components/vfs/pathutil.hpp>
#include "../mwbase/soundmanager.hpp"
@ -135,7 +136,7 @@ namespace MWWorld
void moveProjectiles(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 = "");
void update(State& state, float duration);

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

Loading…
Cancel
Save