From a033ba3bd21c1c5e183477fbeeaeafd5da3c0d4c Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 12 Sep 2016 19:20:33 +0900 Subject: [PATCH] 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) {