From fe3a033642f21393bc267afa4edcc373c9d5f80b Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 8 Sep 2016 01:39:46 +0900 Subject: [PATCH 01/14] Use particle textures for spell projectiles --- apps/openmw/mwmechanics/spellcasting.cpp | 1 - apps/openmw/mwworld/projectilemanager.cpp | 24 +++++++++++++++++------ apps/openmw/mwworld/projectilemanager.hpp | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 95f2d940f..f484ff223 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -30,7 +30,6 @@ namespace MWMechanics { - ESM::Skill::SkillEnum spellSchoolToSkill(int school) { std::map schoolSkillMap; // maps spell school to skill id diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 844800a41..3ded606a6 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -30,6 +30,7 @@ #include "../mwrender/animation.hpp" #include "../mwrender/vismask.hpp" #include "../mwrender/renderingmanager.hpp" +#include "../mwrender/util.hpp" #include "../mwsound/sound.hpp" @@ -37,7 +38,7 @@ namespace { - ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, const ESM::EffectList& effects) + ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, const ESM::EffectList& effects) { int count = 0; ESM::EffectList projectileEffects; @@ -72,6 +73,13 @@ namespace if (count != 0) speed /= count; + + if (projectileEffects.mList.size() == 1) + { + const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( + effects.mList.begin()->mEffectID); + texture = magicEffect->mParticle; + } if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects { @@ -126,7 +134,7 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -168,6 +176,7 @@ namespace MWWorld SceneUtil::AssignControllerSourcesVisitor assignVisitor (state.mEffectAnimationTime); state.mNode->accept(assignVisitor); + MWRender::overrideTexture(texture, mResourceSystem, state.mNode); } void ProjectileManager::update(State& state, float duration) @@ -206,7 +215,9 @@ namespace MWWorld state.mActorId = -1; state.mStack = stack; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, effects); + std::string texture = ""; + + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, effects); // Non-projectile should have been removed by getMagicBoltData if (state.mEffects.mList.empty()) @@ -215,7 +226,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, true); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) @@ -485,7 +496,8 @@ namespace MWWorld state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; state.mStack = esm.mStack; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, esm.mEffects); + std::string color = ""; + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, color, esm.mEffects); state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as // projectile effects, so we can't calculate it from the save // file's effect list, which is already trimmed of non-projectile @@ -503,7 +515,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, color); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 55ce0cd12..a8769fcf9 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,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, bool rotate); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From 502a758eff947ab17e6b4adb0d844240c8167bb1 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 8 Sep 2016 01:53:57 +0900 Subject: [PATCH 02/14] Use particle texture for "hit" effects --- apps/openmw/mwmechanics/spellcasting.cpp | 7 ++++++- apps/openmw/mwworld/worldimp.cpp | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f484ff223..1b040fad8 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -541,12 +541,17 @@ namespace MWMechanics else castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); + std::string texture = ""; + + if (!magicEffect->mParticle.empty() && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) + texture = magicEffect->mParticle; + // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) - anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 82f99b7ea..1b8334559 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3163,7 +3163,11 @@ namespace MWWorld const ESM::MagicEffect* effect = getStore().get().find(effectIt->mEffectID); if ((effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()) || effectIt->mRange != rangeType) +<<<<<<< fe3a033642f21393bc267afa4edcc373c9d5f80b continue; // Not right range type, or not area effect and hit an actor +======= + continue; // Not right range type +>>>>>>> Use particle texture for "hit" effects // Spawn the explosion orb effect const ESM::Static* areaStatic; From 85349da26c0cbe90b97d1f7ddca7cdfa827379b6 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 8 Sep 2016 02:24:47 +0900 Subject: [PATCH 03/14] Add comments --- apps/openmw/mwmechanics/spellcasting.cpp | 1 + apps/openmw/mwworld/projectilemanager.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1b040fad8..e9719d517 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -543,6 +543,7 @@ namespace MWMechanics std::string texture = ""; + // Use particle textures for non-harmful effects if (!magicEffect->mParticle.empty() && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) texture = magicEffect->mParticle; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3ded606a6..07a40a03e 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -74,7 +74,8 @@ namespace if (count != 0) speed /= count; - if (projectileEffects.mList.size() == 1) + // in the original engine, the particle texture is only used if there is only one projectile + if (projectileEffects.mList.size() == 1) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( effects.mList.begin()->mEffectID); From bca477ca8a5c45ffa13fff811863b39ebfb5c54d Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 8 Sep 2016 18:43:26 +0900 Subject: [PATCH 04/14] Apply particle textures like original engine does --- apps/openmw/mwmechanics/spellcasting.cpp | 13 ++++++++++--- apps/openmw/mwworld/projectilemanager.cpp | 5 ++++- apps/openmw/mwworld/worldimp.cpp | 14 ++++++++------ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e9719d517..1388d5f57 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -543,8 +543,9 @@ namespace MWMechanics std::string texture = ""; - // Use particle textures for non-harmful effects - if (!magicEffect->mParticle.empty() && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) + // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + if (magicEffect->mHit.empty() || magicEffect->mHit == "VFX_DefaultHit" || magicEffect->mHit == "VFX_MysticismHit" + || magicEffect->mHit == "VFX_SoulTrapHit") texture = magicEffect->mParticle; // TODO: VFX are no longer active after saving/reloading the game @@ -939,12 +940,18 @@ namespace MWMechanics if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a spell cast vfx { const ESM::Static* castStatic; + std::string texture = ""; + if (!effect->mCasting.empty()) castStatic = store.get().find (effect->mCasting); else castStatic = store.get().find ("VFX_DefaultCast"); - animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); + // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + if (effect->mCasting.empty() || effect->mCasting == "VFX_DefaultCast" || effect->mCasting == "VFX_ShieldCast") + texture = effect->mParticle; + + animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); } if (!mCaster.getClass().isActor()) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 07a40a03e..277ac5869 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -79,7 +79,10 @@ namespace { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( effects.mList.begin()->mEffectID); - texture = magicEffect->mParticle; + + // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + if (magicEffect->mBolt.empty() || magicEffect->mBolt == "VFX_DefaultBolt" || magicEffect->mBolt == "VFX_DestructBolt") + texture = magicEffect->mParticle; } if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1b8334559..d3e6db328 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3163,11 +3163,7 @@ namespace MWWorld const ESM::MagicEffect* effect = getStore().get().find(effectIt->mEffectID); if ((effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()) || effectIt->mRange != rangeType) -<<<<<<< fe3a033642f21393bc267afa4edcc373c9d5f80b continue; // Not right range type, or not area effect and hit an actor -======= - continue; // Not right range type ->>>>>>> Use particle texture for "hit" effects // Spawn the explosion orb effect const ESM::Static* areaStatic; @@ -3176,13 +3172,19 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); + std::string texture = ""; + + // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + if (effect->mArea.empty() || effect->mArea == "VFX_DefaultArea") + texture = effect->mParticle; + if (effectIt->mArea <= 0) { - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, 1.0f); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, 1.0f); continue; } else - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea * 2)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectIt->mArea * 2)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { From f31342894a449a71c82560ea85037cf3a4a7821f Mon Sep 17 00:00:00 2001 From: Allofich Date: Fri, 9 Sep 2016 00:02:24 +0900 Subject: [PATCH 05/14] Put simpler condition first --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d3e6db328..25ed74d0c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3162,7 +3162,7 @@ namespace MWWorld { const ESM::MagicEffect* effect = getStore().get().find(effectIt->mEffectID); - if ((effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor()) || effectIt->mRange != rangeType) + if (effectIt->mRange != rangeType || (effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor())) continue; // Not right range type, or not area effect and hit an actor // Spawn the explosion orb effect From 368828b217b313c080780666896a94e26ac1290f Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 10 Sep 2016 01:38:05 +0900 Subject: [PATCH 06/14] Update TODO comments --- apps/openmw/mwmechanics/spellcasting.cpp | 6 +++--- apps/openmw/mwworld/projectilemanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1388d5f57..0f7d982ab 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -543,7 +543,7 @@ namespace MWMechanics std::string texture = ""; - // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. if (magicEffect->mHit.empty() || magicEffect->mHit == "VFX_DefaultHit" || magicEffect->mHit == "VFX_MysticismHit" || magicEffect->mHit == "VFX_SoulTrapHit") texture = magicEffect->mParticle; @@ -937,7 +937,7 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a spell cast vfx + if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx { const ESM::Static* castStatic; std::string texture = ""; @@ -947,7 +947,7 @@ namespace MWMechanics else castStatic = store.get().find ("VFX_DefaultCast"); - // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. if (effect->mCasting.empty() || effect->mCasting == "VFX_DefaultCast" || effect->mCasting == "VFX_ShieldCast") texture = effect->mParticle; diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 277ac5869..befc6e1da 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -80,7 +80,7 @@ namespace const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( effects.mList.begin()->mEffectID); - // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. if (magicEffect->mBolt.empty() || magicEffect->mBolt == "VFX_DefaultBolt" || magicEffect->mBolt == "VFX_DestructBolt") texture = magicEffect->mParticle; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 25ed74d0c..3b67164b3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3174,7 +3174,7 @@ namespace MWWorld std::string texture = ""; - // TODO: Choosing whether to apply the override texture should be chosen based on nodes in the .NIF file. + // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. if (effect->mArea.empty() || effect->mArea == "VFX_DefaultArea") texture = effect->mParticle; From a033ba3bd21c1c5e183477fbeeaeafd5da3c0d4c Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 12 Sep 2016 19:20:33 +0900 Subject: [PATCH 07/14] Override spell textures by NiTexturingProperty --- apps/openmw/mwmechanics/character.cpp | 6 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 12 ++----- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/effectmanager.cpp | 2 +- apps/openmw/mwrender/util.cpp | 41 ++++++++++++++++++++++- apps/openmw/mwrender/util.hpp | 2 ++ apps/openmw/mwworld/projectilemanager.cpp | 18 +++++----- apps/openmw/mwworld/worldimp.cpp | 6 +--- components/nifosg/nifloader.cpp | 26 ++++++++++++-- 9 files changed, 80 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bb8929f8b..894538bc8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1235,10 +1235,8 @@ bool CharacterController::updateWeaponState() MWMechanics::CastSpell cast(mPtr, NULL); cast.playSpellCastingEffects(spellid); - const ESM::Spell *spell = store.get().find(spellid); - - const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.at(spell->mEffects.mList.size() - 1); - + const ESM::Spell *spell = store.get().find(spellid); + const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back(); const ESM::MagicEffect *effect; effect = store.get().find(lastEffect.mEffectID); // use last effect of list for color of VFX_Hands diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 0f7d982ab..60e9783df 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -541,12 +541,7 @@ namespace MWMechanics else castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); - std::string texture = ""; - - // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. - if (magicEffect->mHit.empty() || magicEffect->mHit == "VFX_DefaultHit" || magicEffect->mHit == "VFX_MysticismHit" - || magicEffect->mHit == "VFX_SoulTrapHit") - texture = magicEffect->mParticle; + std::string texture = magicEffect->mParticle; // TODO: VFX are no longer active after saving/reloading the game bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; @@ -940,16 +935,13 @@ namespace MWMechanics if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx { const ESM::Static* castStatic; - std::string texture = ""; if (!effect->mCasting.empty()) castStatic = store.get().find (effect->mCasting); else castStatic = store.get().find ("VFX_DefaultCast"); - // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. - if (effect->mCasting.empty() || effect->mCasting == "VFX_DefaultCast" || effect->mCasting == "VFX_ShieldCast") - texture = effect->mParticle; + std::string texture = effect->mParticle; animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 386a4a53b..709780307 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1342,7 +1342,7 @@ namespace MWRender SceneUtil::AssignControllerSourcesVisitor assignVisitor(boost::shared_ptr(params.mAnimTime)); node->accept(assignVisitor); - overrideTexture(texture, mResourceSystem, node); + overrideFirstRootTexture(texture, mResourceSystem, node); // TODO: in vanilla morrowind the effect is scaled based on the host object's bounding box. diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index e2773f2dc..5f0213046 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -46,7 +46,7 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); node->accept(assignVisitor); - overrideTexture(textureOverride, mResourceSystem, node); + overrideFirstRootTexture(textureOverride, mResourceSystem, node); mParentNode->addChild(trans); mResourceSystem->getSceneManager()->notifyAttached(node); diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index cb1953c61..868003157 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -1,14 +1,53 @@ #include "util.hpp" #include +#include #include #include #include +#include namespace MWRender { +class TextureOverrideVisitor : public osg::NodeVisitor + { + public: + TextureOverrideVisitor(size_t refID, std::string texture, Resource::ResourceSystem* resourcesystem) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mRefID(refID) + , mTexture(texture) + , mResourcesystem(resourcesystem) + { + } + + virtual void apply(osg::Node& node) + { + int index; + osg::ref_ptr nodePtr(&node); + if (node.getUserValue("NiTexturingPropertyIndex", index)) + { + if (mRefID == index) + overrideTexture(mTexture, mResourcesystem, nodePtr); + } + traverse(node); + } + int mRefID; + std::string mTexture; + Resource::ResourceSystem* mResourcesystem; +}; + +void overrideFirstRootTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) +{ + int index; + if (node->getUserValue("overrideIndex", index)) + { + TextureOverrideVisitor overrideVisitor(index, texture, resourceSystem); + node->accept(overrideVisitor); + } +} + void overrideTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) { if (texture.empty()) @@ -26,7 +65,7 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou else stateset = new osg::StateSet; - stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); + stateset->setTextureAttribute(0, tex, osg::StateAttribute::PROTECTED); node->setStateSet(stateset); } diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index 815e34596..06f053d94 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -17,6 +17,8 @@ namespace Resource namespace MWRender { + void overrideFirstRootTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node); + void overrideTexture(const std::string& texture, Resource::ResourceSystem* resourceSystem, osg::ref_ptr node); // Node callback to entirely skip the traversal. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index befc6e1da..a86750250 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -74,15 +74,12 @@ namespace if (count != 0) speed /= count; - // in the original engine, the particle texture is only used if there is only one projectile + // the particle texture is only used if there is only one projectile if (projectileEffects.mList.size() == 1) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( effects.mList.begin()->mEffectID); - - // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. - if (magicEffect->mBolt.empty() || magicEffect->mBolt == "VFX_DefaultBolt" || magicEffect->mBolt == "VFX_DestructBolt") - texture = magicEffect->mParticle; + texture = magicEffect->mParticle; } if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects @@ -155,7 +152,7 @@ namespace MWWorld attachTo = rotateNode; } - mResourceSystem->getSceneManager()->getInstance(model, attachTo); + osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) @@ -180,7 +177,8 @@ namespace MWWorld SceneUtil::AssignControllerSourcesVisitor assignVisitor (state.mEffectAnimationTime); state.mNode->accept(assignVisitor); - MWRender::overrideTexture(texture, mResourceSystem, state.mNode); + + MWRender::overrideFirstRootTexture(texture, mResourceSystem, projectile); } void ProjectileManager::update(State& state, float duration) @@ -500,8 +498,8 @@ namespace MWWorld state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; state.mStack = esm.mStack; - std::string color = ""; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, color, esm.mEffects); + std::string texture = ""; + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, esm.mEffects); state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as // projectile effects, so we can't calculate it from the save // file's effect list, which is already trimmed of non-projectile @@ -519,7 +517,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, color); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3b67164b3..49a7a1abc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3172,11 +3172,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - std::string texture = ""; - - // TODO: Applying the override texture should depend on texture properties in the .NIF file and not use special cases. - if (effect->mArea.empty() || effect->mArea == "VFX_DefaultArea") - texture = effect->mParticle; + std::string texture = effect->mParticle; if (effectIt->mArea <= 0) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c08cd8391..6ab481dd4 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // resource #include @@ -368,13 +369,32 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags, bool isRootNode) { const Nif::PropertyList& props = nifNode->props; - for (size_t i = 0; i recType == Nif::RC_NiTexturingProperty) + { + int index = props[i].getPtr()->recIndex; + applyTo->setUserValue("overrideIndex", index); + foundFirstRootTexturingProperty = true; + } + else if (props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) + { + int index = props[i].getPtr()->recIndex; + applyTo->setUserValue("NiTexturingPropertyIndex", index); + } handleProperty(props[i].getPtr(), applyTo, composite, imageManager, boundTextures, animflags); + } } } @@ -631,7 +651,7 @@ namespace NifOsg osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); + applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags, node == rootNode); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { From 01774c656cd8afd9b75d1c2c181e4169e344c0bf Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 14 Sep 2016 23:18:29 +0900 Subject: [PATCH 08/14] Fix for blood effect texture overrides --- apps/openmw/mwrender/effectmanager.cpp | 7 +++++-- apps/openmw/mwrender/effectmanager.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/util.cpp | 2 +- apps/openmw/mwrender/util.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 2 +- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 5f0213046..340a855fb 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -25,7 +25,7 @@ EffectManager::~EffectManager() clear(); } -void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale) +void EffectManager::addEffect(const std::string &model, const std::string& textureOverride, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) { osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model); @@ -46,7 +46,10 @@ void EffectManager::addEffect(const std::string &model, const std::string& textu SceneUtil::AssignControllerSourcesVisitor assignVisitor(effect.mAnimTime); node->accept(assignVisitor); - overrideFirstRootTexture(textureOverride, mResourceSystem, node); + if (isMagicVFX) + overrideFirstRootTexture(textureOverride, mResourceSystem, node); + else + overrideTexture(textureOverride, mResourceSystem, node); mParentNode->addChild(trans); mResourceSystem->getSceneManager()->notifyAttached(node); diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index 6d7aaaf4f..83acc4c60 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -33,7 +33,7 @@ namespace MWRender ~EffectManager(); /// Add an effect. When it's finished playing, it will be removed automatically. - void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale); + void addEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true); void update(float dt); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d74bac0b3..c237f2320 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -742,9 +742,9 @@ namespace MWRender mObjects->updatePtr(old, updated); } - void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale) + void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) { - mEffectManager->addEffect(model, texture, worldPosition, scale); + mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX); } void RenderingManager::notifyWorldSpaceChanged() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f5245be98..3be01931a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -138,7 +138,7 @@ namespace MWRender SkyManager* getSkyManager(); - void spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale = 1.f); + void spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale = 1.f, bool isMagicVFX = true); /// Clear all savegame-specific data void clear(); diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index 868003157..06453e0ce 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -65,7 +65,7 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou else stateset = new osg::StateSet; - stateset->setTextureAttribute(0, tex, osg::StateAttribute::PROTECTED); + stateset->setTextureAttribute(0, tex, osg::StateAttribute::OVERRIDE); node->setStateSet(stateset); } diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index 06f053d94..eebcfd9b0 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -17,6 +17,8 @@ namespace Resource namespace MWRender { + // Overrides the texture of nodes in the mesh that had the same NiTexturingProperty as the first NiTexturingProperty of the .NIF file's root node, + // if it had a NiTexturingProperty. Used for applying "particle textures" to magic effects. void overrideFirstRootTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node); void overrideTexture(const std::string& texture, Resource::ResourceSystem* resourceSystem, osg::ref_ptr node); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 49a7a1abc..b5ef7de52 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3145,7 +3145,7 @@ namespace MWWorld modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); - mRendering->spawnEffect(model, texture, worldPosition); + mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false); } void World::spawnEffect(const std::string &model, const std::string &textureOverride, const osg::Vec3f &worldPos) From 527bbd52433a9727740fe6f9336dfafff5948789 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 15 Sep 2016 00:09:40 +0900 Subject: [PATCH 09/14] Change size_t to int for consistency --- apps/openmw/mwrender/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index 06453e0ce..dbb990584 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -14,7 +14,7 @@ namespace MWRender class TextureOverrideVisitor : public osg::NodeVisitor { public: - TextureOverrideVisitor(size_t refID, std::string texture, Resource::ResourceSystem* resourcesystem) + TextureOverrideVisitor(int refID, std::string texture, Resource::ResourceSystem* resourcesystem) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mRefID(refID) , mTexture(texture) From dc8ff5e49b87b48d2150c381874385db13e3fad0 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 15 Sep 2016 00:22:09 +0900 Subject: [PATCH 10/14] Play all sfx and use particle textures for permanent enchantments --- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b1f506e11..e94c25e58 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -994,7 +994,7 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) - addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); + addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", magicEffect->mParticle); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e8a4d1c4d..326e96bb3 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -415,7 +415,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Basically we don't want sounds when the actor is first loaded, // the items should appear as if they'd always been equipped. mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip, - !mFirstAutoEquip && effectIt == enchantment.mEffects.mList.begin()); + !mFirstAutoEquip); } if (magnitude) From 7eb62b5d3a07826a97770caca53115b1015ce6f0 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 15 Sep 2016 01:44:53 +0900 Subject: [PATCH 11/14] Initialize speed for magic projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index a86750250..2f8576bda 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -41,6 +41,7 @@ namespace ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, const ESM::EffectList& effects) { int count = 0; + speed = 0.0f; ESM::EffectList projectileEffects; for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) From 5aad1d81f4a3ffa4be4616f0eb537fd2ab458405 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 15 Sep 2016 23:41:20 +0900 Subject: [PATCH 12/14] Remove no longer used parameter --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 3 +-- apps/openmw/mwworld/inventorystore.hpp | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e94c25e58..64cc6d26c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -970,12 +970,12 @@ Resource::ResourceSystem* NpcAnimation::getResourceSystem() return mResourceSystem; } -void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound) +void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew) { // During first auto equip, we don't play any sounds. // Basically we don't want sounds when the actor is first loaded, // the items should appear as if they'd always been equipped. - if (playSound) + if (isNew) { static const std::string schools[] = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index baf9c8c24..9134f8f5f 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -23,7 +23,7 @@ class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::I { public: virtual void equipmentChanged(); - virtual void permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound); + virtual void permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew); public: typedef std::map PartBoneMap; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 326e96bb3..2c25029da 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -414,8 +414,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // During first auto equip, we don't play any sounds. // Basically we don't want sounds when the actor is first loaded, // the items should appear as if they'd always been equipped. - mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip, - !mFirstAutoEquip); + mListener->permanentEffectAdded(magicEffect, !mFirstAutoEquip); } if (magnitude) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 2d7c9f6e9..152176fbe 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -32,7 +32,7 @@ namespace MWWorld * If it isn't new, non-looping VFX should not be played. * @param playSound Play effect sound? */ - virtual void permanentEffectAdded (const ESM::MagicEffect *magicEffect, bool isNew, bool playSound) {} + virtual void permanentEffectAdded (const ESM::MagicEffect *magicEffect, bool isNew) {} }; From be96ff1fd169ef73d079240169c15c1f264e8280 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sun, 18 Sep 2016 01:57:47 +0900 Subject: [PATCH 13/14] Remove redundant parameter --- components/nifosg/nifloader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6ab481dd4..5557a4d63 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -369,7 +369,7 @@ namespace NifOsg return created; } - void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags, bool isRootNode) + void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; bool foundFirstRootTexturingProperty = false; @@ -382,7 +382,7 @@ namespace NifOsg // effect "particle texture" is used. For non-root nodes we keep setting until we have the highest // numbered one, which is the one that displays in the game and can be overridden if it matches the // lowest one on the root. - if (!foundFirstRootTexturingProperty && isRootNode && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) + if (!foundFirstRootTexturingProperty && nifNode->parent == NULL && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) { int index = props[i].getPtr()->recIndex; applyTo->setUserValue("overrideIndex", index); @@ -651,7 +651,7 @@ namespace NifOsg osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; - applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags, node == rootNode); + applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) { From a8e9f2df675337e93e2ff73f56e248d6810c537e Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 19 Sep 2016 04:44:30 +0900 Subject: [PATCH 14/14] Cleanup --- apps/openmw/mwrender/util.cpp | 16 +++++----------- components/nifosg/nifloader.cpp | 23 ++++++++++------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index dbb990584..aa8aaccbc 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -14,9 +14,8 @@ namespace MWRender class TextureOverrideVisitor : public osg::NodeVisitor { public: - TextureOverrideVisitor(int refID, std::string texture, Resource::ResourceSystem* resourcesystem) + TextureOverrideVisitor(std::string texture, Resource::ResourceSystem* resourcesystem) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mRefID(refID) , mTexture(texture) , mResourcesystem(resourcesystem) { @@ -26,26 +25,21 @@ class TextureOverrideVisitor : public osg::NodeVisitor { int index; osg::ref_ptr nodePtr(&node); - if (node.getUserValue("NiTexturingPropertyIndex", index)) + if (node.getUserValue("overrideFx", index)) { - if (mRefID == index) + if (index == 1) overrideTexture(mTexture, mResourcesystem, nodePtr); } traverse(node); } - int mRefID; std::string mTexture; Resource::ResourceSystem* mResourcesystem; }; void overrideFirstRootTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) { - int index; - if (node->getUserValue("overrideIndex", index)) - { - TextureOverrideVisitor overrideVisitor(index, texture, resourceSystem); - node->accept(overrideVisitor); - } + TextureOverrideVisitor overrideVisitor(texture, resourceSystem); + node->accept(overrideVisitor); } void overrideTexture(const std::string &texture, Resource::ResourceSystem *resourceSystem, osg::ref_ptr node) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5557a4d63..7823b3634 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -277,11 +277,13 @@ namespace NifOsg public: /// @param filename used for warning messages. LoaderImpl(const std::string& filename) - : mFilename(filename) + : mFilename(filename), mFirstRootTextureIndex(-1), mFoundFirstRootTexturingProperty(false) { } std::string mFilename; + size_t mFirstRootTextureIndex; + bool mFoundFirstRootTexturingProperty; static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) { @@ -372,26 +374,21 @@ namespace NifOsg void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager, std::vector& boundTextures, int animflags) { const Nif::PropertyList& props = nifNode->props; - bool foundFirstRootTexturingProperty = false; for (size_t i = 0; i parent == NULL && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) + // Get the lowest numbered recIndex of the NiTexturingProperty root node. + // This is what is overridden when a spell effect "particle texture" is used. + if (nifNode->parent == NULL && !mFoundFirstRootTexturingProperty && props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) { - int index = props[i].getPtr()->recIndex; - applyTo->setUserValue("overrideIndex", index); - foundFirstRootTexturingProperty = true; + mFirstRootTextureIndex = props[i].getPtr()->recIndex; + mFoundFirstRootTexturingProperty = true; } else if (props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) { - int index = props[i].getPtr()->recIndex; - applyTo->setUserValue("NiTexturingPropertyIndex", index); + if (props[i].getPtr()->recIndex == mFirstRootTextureIndex) + applyTo->setUserValue("overrideFx", 1); } handleProperty(props[i].getPtr(), applyTo, composite, imageManager, boundTextures, animflags); }