From dca7b4beb7b970310e87951721838341a47284a7 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 16 Jul 2016 22:47:33 +0900 Subject: [PATCH 01/14] Make non-actors also play spell casting sounds --- apps/openmw/mwmechanics/character.cpp | 35 ++++------------------- apps/openmw/mwmechanics/character.hpp | 2 -- apps/openmw/mwmechanics/spellcasting.cpp | 36 ++++++++++++++++++++++++ apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07aba2f7d..e65195531 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -44,6 +44,7 @@ #include "creaturestats.hpp" #include "security.hpp" #include "actorutil.hpp" +#include "spellcasting.hpp" namespace { @@ -961,34 +962,6 @@ void CharacterController::updateIdleStormState(bool inwater) } } -void CharacterController::castSpell(const std::string &spellid) -{ - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; - - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Spell *spell = store.get().find(spellid); - const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); - - const ESM::MagicEffect *effect; - effect = store.get().find(effectentry.mEffectID); - - const ESM::Static* castStatic; - if (!effect->mCasting.empty()) - castStatic = store.get().find (effect->mCasting); - else - castStatic = store.get().find ("VFX_DefaultCast"); - - mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); - - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(!effect->mCastSound.empty()) - sndMgr->playSound3D(mPtr, effect->mCastSound, 1.0f, 1.0f); - else - sndMgr->playSound3D(mPtr, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); -} - bool CharacterController::updateCreatureState() { const MWWorld::Class &cls = mPtr.getClass(); @@ -1020,7 +993,8 @@ bool CharacterController::updateCreatureState() const std::string spellid = stats.getSpells().getSelectedSpell(); if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr)) { - castSpell(spellid); + MWMechanics::CastSpell cast(mPtr, NULL); + cast.playSpellCastingEffects(spellid); if (!mAnimation->hasAnimation("spellcast")) MWBase::Environment::get().getWorld()->castSpell(mPtr); // No "release" text key to use, so cast immediately @@ -1248,7 +1222,8 @@ bool CharacterController::updateWeaponState() if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr)) { - castSpell(spellid); + MWMechanics::CastSpell cast(mPtr, NULL); + cast.playSpellCastingEffects(spellid); const ESM::Spell *spell = store.get().find(spellid); const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 190e171b3..d5dc5fe28 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -214,8 +214,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener void updateHeadTracking(float duration); - void castSpell(const std::string& spellid); - void updateMagicEffects(); void playDeath(float startpoint, CharacterState death); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 52815816e..e5f221a02 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -836,6 +836,10 @@ namespace MWMechanics if (mCaster == getPlayer() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); + + // A non-actor doesn't have casting animation so it plays its spell casting effects here + if (!mCaster.getClass().isActor()) + playSpellCastingEffects(mId); inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self); @@ -930,6 +934,38 @@ namespace MWMechanics return true; } + void CastSpell::playSpellCastingEffects(const std::string &spellid){ + + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Spell *spell = store.get().find(spellid); + const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0); + + const ESM::MagicEffect *effect; + effect = store.get().find(effectentry.mEffectID); + + if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a visual casting effect + { + const ESM::Static* castStatic; + if (!effect->mCasting.empty()) + castStatic = store.get().find (effect->mCasting); + else + castStatic = store.get().find ("VFX_DefaultCast"); + + MWBase::Environment::get().getWorld()->getAnimation(mCaster)->addEffect( + "meshes\\" + castStatic->mModel, effect->mIndex); + } + + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; + + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + if(!effect->mCastSound.empty()) + sndMgr->playSound3D(mCaster, effect->mCastSound, 1.0f, 1.0f); + else + sndMgr->playSound3D(mCaster, schools[effect->mData.mSchool]+" cast", 1.0f, 1.0f); + } + int getEffectiveEnchantmentCastCost(float castCost, const MWWorld::Ptr &actor) { /* diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index ae20a39d0..aba263b01 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -92,6 +92,8 @@ namespace MWMechanics /// @note Auto detects if spell, ingredient or potion bool cast (const std::string& id); + void playSpellCastingEffects(const std::string &spellid); + /// @note \a target can be any type of object, not just actors. /// @note \a caster can be any type of object, or even an empty object. void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, From 3841a8fb40e4fb1c0fe8c76d966ffe6e1ed5e2f8 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 2 Aug 2016 21:37:39 +0900 Subject: [PATCH 02/14] Make non-actors glow when they cast spells --- apps/openmw/mwmechanics/character.cpp | 5 +- apps/openmw/mwmechanics/spellcasting.cpp | 15 +++++- apps/openmw/mwrender/animation.cpp | 68 ++++++++++++++++++++++-- apps/openmw/mwrender/animation.hpp | 15 +++++- 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e65195531..e7a211c60 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1531,10 +1531,11 @@ void CharacterController::update(float duration) osg::Vec3f movement(0.f, 0.f, 0.f); float speed = 0.f; - updateMagicEffects(); - if(!cls.isActor()) { + updateMagicEffects(); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mPtr); + animation->updateSpellGlow(duration); if(mAnimQueue.size() > 1) { if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e5f221a02..d038fb946 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -943,6 +943,8 @@ namespace MWMechanics const ESM::MagicEffect *effect; effect = store.get().find(effectentry.mEffectID); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); + if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a visual casting effect { const ESM::Static* castStatic; @@ -951,8 +953,17 @@ namespace MWMechanics else castStatic = store.get().find ("VFX_DefaultCast"); - MWBase::Environment::get().getWorld()->getAnimation(mCaster)->addEffect( - "meshes\\" + castStatic->mModel, effect->mIndex); + animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex); + } + + if (!mCaster.getClass().isActor()) + { + osg::Vec4f glowcolor(1,1,1,1); + glowcolor.x() = effect->mData.mRed / 255.f; + glowcolor.y() = effect->mData.mGreen / 255.f; + glowcolor.z() = effect->mData.mBlue / 255.f; + + animation->addSpellCastGlow(glowcolor); } static const std::string schools[] = { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3f09dffc5..85c94e37d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,6 +38,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority @@ -89,10 +90,11 @@ namespace class GlowUpdater : public SceneUtil::StateSetUpdater { public: - GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures) + GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, bool hasDuration) : mTexUnit(texUnit) , mColor(color) , mTextures(textures) + , mHasDuration(hasDuration) { } @@ -122,10 +124,26 @@ namespace stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } + bool const getHasDuration() + { + return mHasDuration; + } + + std::vector > const getTextures() + { + return mTextures; + } + + int const getTexUnit() + { + return mTexUnit; + } + private: int mTexUnit; osg::Vec4f mColor; std::vector > mTextures; + bool mHasDuration; }; class NodeMapVisitor : public osg::NodeVisitor @@ -340,6 +358,7 @@ namespace MWRender , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) , mAlpha(1.f) + , mSpellGlowDuration(0.f) { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -1106,7 +1125,44 @@ namespace MWRender int mLowestUnusedTexUnit; }; - void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor) + void Animation::addSpellCastGlow(osg::Vec4f glowColor){ + addGlow(mObjectRoot, glowColor, true); + MWBase::Environment::get().getMechanicsManager()->add(mPtr); + } + + void Animation::updateSpellGlow(float duration){ + if (mGlowUpdater != NULL && (mGlowUpdater->getHasDuration())) + mSpellGlowDuration += duration; + if (mSpellGlowDuration >= 1.5f) // length of spell glow effect was measured from original game as around 1.5 seconds + removeSpellGlow(); + } + + void Animation::removeSpellGlow() + { + osg::ref_ptr writableStateSet = NULL; + if (!mObjectRoot->getStateSet()) + writableStateSet = mObjectRoot->getOrCreateStateSet(); + else + writableStateSet = osg::clone(mObjectRoot->getStateSet(), osg::CopyOp::SHALLOW_COPY); + + std::vector > Textures = mGlowUpdater->getTextures(); + int TexUnit = mGlowUpdater->getTexUnit(); + mObjectRoot->removeUpdateCallback(mGlowUpdater); + mGlowUpdater = NULL; + + for (size_t index = 0; index < Textures.size(); index++) + { + writableStateSet->setTextureAttribute(TexUnit, Textures[index], osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + writableStateSet->removeTextureAttribute(TexUnit, Textures[index]); + } + + mObjectRoot->setStateSet(writableStateSet); + writableStateSet->removeUniform(mUniform); + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); + mSpellGlowDuration = 0.f; + } + + void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor, bool hasDuration) { std::vector > textures; for (int i=0; i<32; ++i) @@ -1130,8 +1186,9 @@ namespace MWRender FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - osg::ref_ptr glowupdater (new GlowUpdater(texUnit, glowColor, textures)); - node->addUpdateCallback(glowupdater); + mGlowUpdater = new GlowUpdater(texUnit, glowColor, textures, hasDuration); + //osg::ref_ptr glowupdater (new GlowUpdater(texUnit, glowColor, textures)); + node->addUpdateCallback(mGlowUpdater); // set a texture now so that the ShaderVisitor can find it osg::ref_ptr writableStateSet = NULL; @@ -1143,7 +1200,8 @@ namespace MWRender node->setStateSet(writableStateSet); } writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); + mUniform = new osg::Uniform("envMapColor", glowColor); + writableStateSet->addUniform(mUniform); mResourceSystem->getSceneManager()->recreateShaders(node); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ad9d4ab4a..9ca9d9552 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,11 @@ #include +namespace +{ + class GlowUpdater; +} + namespace ESM { struct Light; @@ -263,6 +268,10 @@ protected: osg::ref_ptr mGlowLight; float mAlpha; + float mSpellGlowDuration; + + osg::ref_ptr mGlowUpdater; + osg::Uniform* mUniform; const NodeMap& getNodeMap() const; @@ -317,7 +326,7 @@ protected: osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const; - void addGlow(osg::ref_ptr node, osg::Vec4f glowColor); + void addGlow(osg::ref_ptr node, osg::Vec4f glowColor, bool hasDuration = false); /// Set the render bin for this animation's object root. May be customized by subclasses. virtual void setRenderBin(); @@ -351,6 +360,10 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out) const; + void addSpellCastGlow(osg::Vec4f glowColor); + void updateSpellGlow(float duration); + void removeSpellGlow(); + virtual void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim) const; From 57138b416e4816b3b982e081b5b653e8ac0eac47 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 2 Aug 2016 22:15:48 +0900 Subject: [PATCH 03/14] Fix spell glows to only run one at a time --- apps/openmw/mwrender/animation.cpp | 35 ++++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 3 +-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 85c94e37d..736ba8956 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1126,12 +1126,13 @@ namespace MWRender }; void Animation::addSpellCastGlow(osg::Vec4f glowColor){ - addGlow(mObjectRoot, glowColor, true); + if (mSpellGlowUpdater == NULL) // only start a new spell glow if there isn't one already + addGlow(mObjectRoot, glowColor, true); MWBase::Environment::get().getMechanicsManager()->add(mPtr); } void Animation::updateSpellGlow(float duration){ - if (mGlowUpdater != NULL && (mGlowUpdater->getHasDuration())) + if (mSpellGlowUpdater != NULL) mSpellGlowDuration += duration; if (mSpellGlowDuration >= 1.5f) // length of spell glow effect was measured from original game as around 1.5 seconds removeSpellGlow(); @@ -1145,10 +1146,10 @@ namespace MWRender else writableStateSet = osg::clone(mObjectRoot->getStateSet(), osg::CopyOp::SHALLOW_COPY); - std::vector > Textures = mGlowUpdater->getTextures(); - int TexUnit = mGlowUpdater->getTexUnit(); - mObjectRoot->removeUpdateCallback(mGlowUpdater); - mGlowUpdater = NULL; + std::vector > Textures = mSpellGlowUpdater->getTextures(); + int TexUnit = mSpellGlowUpdater->getTexUnit(); + mObjectRoot->removeUpdateCallback(mSpellGlowUpdater); + mSpellGlowUpdater = NULL; for (size_t index = 0; index < Textures.size(); index++) { @@ -1157,7 +1158,10 @@ namespace MWRender } mObjectRoot->setStateSet(writableStateSet); - writableStateSet->removeUniform(mUniform); + if (writableStateSet->getUniform("envMapColor2")) // if we added a second uniform, remove that one instead of the original + writableStateSet->removeUniform("envMapColor2"); + else + writableStateSet->removeUniform("envMapColor"); mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); mSpellGlowDuration = 0.f; } @@ -1186,9 +1190,13 @@ namespace MWRender FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - mGlowUpdater = new GlowUpdater(texUnit, glowColor, textures, hasDuration); - //osg::ref_ptr glowupdater (new GlowUpdater(texUnit, glowColor, textures)); - node->addUpdateCallback(mGlowUpdater); + + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, hasDuration); + + if (hasDuration) // store the glowUpdater for later removal and checking if this is a spell glow + mSpellGlowUpdater = glowUpdater; + + node->addUpdateCallback(glowUpdater); // set a texture now so that the ShaderVisitor can find it osg::ref_ptr writableStateSet = NULL; @@ -1200,8 +1208,11 @@ namespace MWRender node->setStateSet(writableStateSet); } writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - mUniform = new osg::Uniform("envMapColor", glowColor); - writableStateSet->addUniform(mUniform); + + if (hasDuration && writableStateSet->getUniform("envMapColor")) // if we are adding a spell glow to something with an enchantment glow + writableStateSet->addUniform(new osg::Uniform("envMapColor2", glowColor)); + else + writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); mResourceSystem->getSceneManager()->recreateShaders(node); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 9ca9d9552..30e2de601 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -270,8 +270,7 @@ protected: float mAlpha; float mSpellGlowDuration; - osg::ref_ptr mGlowUpdater; - osg::Uniform* mUniform; + osg::ref_ptr mSpellGlowUpdater; const NodeMap& getNodeMap() const; From 123c626f2d6bf32326e3a2f843ca904d9cdfc0d5 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 3 Aug 2016 02:45:42 +0900 Subject: [PATCH 04/14] Add glow when using telekinesis on doors --- apps/openmw/mwclass/door.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index a54b64897..effdcf547 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -25,6 +25,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/animation.hpp" #include "../mwmechanics/actorutil.hpp" @@ -112,6 +113,24 @@ namespace MWClass bool hasKey = false; std::string keyName; + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && // assuming player is using telekinesis + MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > + MWBase::Environment::get().getWorld()->getMaxActivationDistance()) + { + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); + + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::MagicEffect *effect; + effect = store.get().find(59); + + osg::Vec4f glowcolor(1,1,1,1); + glowcolor.x() = effect->mData.mRed / 255.f; + glowcolor.y() = effect->mData.mGreen / 255.f; + glowcolor.z() = effect->mData.mBlue / 255.f; + + animation->addSpellCastGlow(glowcolor); // TODO: Telekinesis glow should only be as long as the door animation + } + // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); Misc::StringUtils::lowerCaseInPlace(keyId); From e132b52a694e9b1e0053d2b1d012315ab63ba58f Mon Sep 17 00:00:00 2001 From: Allofich Date: Sun, 7 Aug 2016 03:08:46 +0900 Subject: [PATCH 05/14] Handle spell glows within updatecallback --- apps/openmw/mwclass/door.cpp | 3 +- apps/openmw/mwmechanics/character.cpp | 5 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 165 +++++++++++++++-------- apps/openmw/mwrender/animation.hpp | 12 +- 5 files changed, 113 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index effdcf547..01520a331 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -113,7 +113,8 @@ namespace MWClass bool hasKey = false; std::string keyName; - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && // assuming player is using telekinesis + // make door glow if player activates it with telekinesis + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e7a211c60..e65195531 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1531,11 +1531,10 @@ void CharacterController::update(float duration) osg::Vec3f movement(0.f, 0.f, 0.f); float speed = 0.f; + updateMagicEffects(); + if(!cls.isActor()) { - updateMagicEffects(); - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mPtr); - animation->updateSpellGlow(duration); if(mAnimQueue.size() > 1) { if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d038fb946..bef720764 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -837,7 +837,7 @@ namespace MWMechanics mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); - // A non-actor doesn't have casting animation so it plays its spell casting effects here + // A non-actor doesn't play its effects from a character controller, so play spell casting effects here if (!mCaster.getClass().isActor()) playSpellCastingEffects(mId); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 736ba8956..71b569285 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,7 +38,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority @@ -90,11 +89,18 @@ namespace class GlowUpdater : public SceneUtil::StateSetUpdater { public: - GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, bool hasDuration) + GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, + osg::ref_ptr node, float maxduration, Resource::ResourceSystem* resourcesystem, osg::Uniform* uniform) : mTexUnit(texUnit) , mColor(color) , mTextures(textures) - , mHasDuration(hasDuration) + , mNode(node) + , mMaxDuration(maxduration) + , mStartingTime(0) + , mResourceSystem(resourcesystem) + , mDone(false) + , mUniform(uniform) + , mWatchedSpellGlow(NULL) { } @@ -115,35 +121,99 @@ namespace texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); + + // Reduce the texture list back down by one when a temporary glow finishes + // to allow FindLowestUnusedTexUnitVisitor to choose the same texunit again. + if (mDone) + stateset->getTextureAttributeList().resize(stateset->getTextureAttributeList().size() - 1); } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { + if (mDone) + return; + + // If there is a permanent enchantment glow already on this object, give the + // permanent glow a pointer to a temporary glow added in a nested update callback + // The permanent glow will remove the temporary glow when it finishes, allowing + // the permanent glow to display its glow texture cycling properly. + if (mWatchedSpellGlow != NULL && mWatchedSpellGlow->isDone()) + { + mNode->removeUpdateCallback(mWatchedSpellGlow); + mWatchedSpellGlow = NULL; + } + + // Set the starting time to measure glow duration from if this is a temporary glow + if ((mMaxDuration >= 0) && mStartingTime == 0) + mStartingTime = nv->getFrameStamp()->getSimulationTime(); + float time = nv->getFrameStamp()->getSimulationTime(); int index = (int)(time*16) % mTextures.size(); stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + if ((mMaxDuration >= 0) && (time - mStartingTime > mMaxDuration)) // If this is a temporary glow and it has finished its duration + { + osg::ref_ptr writableStateSet = NULL; + if (!mNode->getStateSet()) + writableStateSet = mNode->getOrCreateStateSet(); + else + writableStateSet = osg::clone(mNode->getStateSet(), osg::CopyOp::SHALLOW_COPY); + + for (size_t index = 0; index < mTextures.size(); index++) + { + writableStateSet->removeTextureAttribute(mTexUnit, mTextures[index]); + } + + writableStateSet->removeUniform(mUniform); // remove the uniform given to the temporary glow in addglow() + mNode->setStateSet(writableStateSet); + + this->reset(); // without this a texture from the glow will continue to show on the object + mResourceSystem->getSceneManager()->recreateShaders(mNode); + mDone = true; + } } - bool const getHasDuration() + bool isSpellGlowUpdater() { - return mHasDuration; + return (mMaxDuration >= 0); } - std::vector > const getTextures() + bool isEnchantmentGlowUpdater() { - return mTextures; + return (mMaxDuration < 0); } - int const getTexUnit() + bool isDone() + { + return mDone; + } + + int getTexUnit() { return mTexUnit; } + void setWatchedSpellGlow(osg::ref_ptr watched) + { + mWatchedSpellGlow = watched; + } + + osg::ref_ptr getWatchedSpellGlow() + { + return mWatchedSpellGlow; + } + private: int mTexUnit; osg::Vec4f mColor; std::vector > mTextures; - bool mHasDuration; + osg::ref_ptr mNode; + float mMaxDuration; + float mStartingTime; + Resource::ResourceSystem* mResourceSystem; + bool mDone; + osg::Uniform* mUniform; + osg::ref_ptr mWatchedSpellGlow; }; class NodeMapVisitor : public osg::NodeVisitor @@ -358,7 +428,6 @@ namespace MWRender , mHeadYawRadians(0.f) , mHeadPitchRadians(0.f) , mAlpha(1.f) - , mSpellGlowDuration(0.f) { for(size_t i = 0;i < sNumBlendMasks;i++) mAnimationTimePtr[i].reset(new AnimationTime); @@ -1126,47 +1195,18 @@ namespace MWRender }; void Animation::addSpellCastGlow(osg::Vec4f glowColor){ - if (mSpellGlowUpdater == NULL) // only start a new spell glow if there isn't one already - addGlow(mObjectRoot, glowColor, true); - MWBase::Environment::get().getMechanicsManager()->add(mPtr); + if (!mObjectRoot->getUpdateCallback()) // If there is no glow on object + addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from in-game as about 1.5 seconds + + else if (dynamic_cast (mObjectRoot->getUpdateCallback())->isDone() == true) // If there was a temporary glow on object and it finished + addGlow(mObjectRoot, glowColor, 1.5); + + else if (dynamic_cast (mObjectRoot->getUpdateCallback())->isEnchantmentGlowUpdater() == true + && dynamic_cast (mObjectRoot->getUpdateCallback())->getWatchedSpellGlow() == NULL) // If there is a permanent enchantment glow on object and no temporary glow is running + addGlow(mObjectRoot, glowColor, 1.5); } - void Animation::updateSpellGlow(float duration){ - if (mSpellGlowUpdater != NULL) - mSpellGlowDuration += duration; - if (mSpellGlowDuration >= 1.5f) // length of spell glow effect was measured from original game as around 1.5 seconds - removeSpellGlow(); - } - - void Animation::removeSpellGlow() - { - osg::ref_ptr writableStateSet = NULL; - if (!mObjectRoot->getStateSet()) - writableStateSet = mObjectRoot->getOrCreateStateSet(); - else - writableStateSet = osg::clone(mObjectRoot->getStateSet(), osg::CopyOp::SHALLOW_COPY); - - std::vector > Textures = mSpellGlowUpdater->getTextures(); - int TexUnit = mSpellGlowUpdater->getTexUnit(); - mObjectRoot->removeUpdateCallback(mSpellGlowUpdater); - mSpellGlowUpdater = NULL; - - for (size_t index = 0; index < Textures.size(); index++) - { - writableStateSet->setTextureAttribute(TexUnit, Textures[index], osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); - writableStateSet->removeTextureAttribute(TexUnit, Textures[index]); - } - - mObjectRoot->setStateSet(writableStateSet); - if (writableStateSet->getUniform("envMapColor2")) // if we added a second uniform, remove that one instead of the original - writableStateSet->removeUniform("envMapColor2"); - else - writableStateSet->removeUniform("envMapColor"); - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); - mSpellGlowDuration = 0.f; - } - - void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor, bool hasDuration) + void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor, float glowDuration) { std::vector > textures; for (int i=0; i<32; ++i) @@ -1187,16 +1227,29 @@ namespace MWRender textures.push_back(tex); } + int texUnit; + + // If we have a spell glow updater left over from this object prevously casting a spell, + // and there was no permanent glow updater on the object to watch it and remove it, we + // remove it here. + if (node->getUpdateCallback() && + dynamic_cast (node->getUpdateCallback())->isSpellGlowUpdater() == true) + node->removeUpdateCallback(node->getUpdateCallback()); + FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); - int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; + texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; + + osg::Uniform* uniform = new osg::Uniform("envMapColor", glowColor); - osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, hasDuration); - if (hasDuration) // store the glowUpdater for later removal and checking if this is a spell glow - mSpellGlowUpdater = glowUpdater; + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem, uniform); node->addUpdateCallback(glowUpdater); + if (node->getUpdateCallback() && + dynamic_cast (node->getUpdateCallback())->isEnchantmentGlowUpdater() == true) + if (glowDuration >= 0) + dynamic_cast (node->getUpdateCallback())->setWatchedSpellGlow(glowUpdater); // set a texture now so that the ShaderVisitor can find it osg::ref_ptr writableStateSet = NULL; @@ -1208,11 +1261,7 @@ namespace MWRender node->setStateSet(writableStateSet); } writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - - if (hasDuration && writableStateSet->getUniform("envMapColor")) // if we are adding a spell glow to something with an enchantment glow - writableStateSet->addUniform(new osg::Uniform("envMapColor2", glowColor)); - else - writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); + writableStateSet->addUniform(uniform); mResourceSystem->getSceneManager()->recreateShaders(node); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 30e2de601..96bd0c03e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,11 +5,6 @@ #include -namespace -{ - class GlowUpdater; -} - namespace ESM { struct Light; @@ -268,9 +263,6 @@ protected: osg::ref_ptr mGlowLight; float mAlpha; - float mSpellGlowDuration; - - osg::ref_ptr mSpellGlowUpdater; const NodeMap& getNodeMap() const; @@ -325,7 +317,7 @@ protected: osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const; - void addGlow(osg::ref_ptr node, osg::Vec4f glowColor, bool hasDuration = false); + void addGlow(osg::ref_ptr node, osg::Vec4f glowColor, float glowDuration = -1); /// Set the render bin for this animation's object root. May be customized by subclasses. virtual void setRenderBin(); @@ -360,8 +352,6 @@ public: void getLoopingEffects (std::vector& out) const; void addSpellCastGlow(osg::Vec4f glowColor); - void updateSpellGlow(float duration); - void removeSpellGlow(); virtual void updatePtr(const MWWorld::Ptr &ptr); From 35c14bb9bb2a1940fc708ad8e12275ca3fb94355 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 8 Aug 2016 21:55:56 +0900 Subject: [PATCH 06/14] Minor rewrite, make "open" spells play glow effect --- apps/openmw/mwclass/door.cpp | 10 +++------- apps/openmw/mwmechanics/spellcasting.cpp | 19 +++++++++---------- apps/openmw/mwrender/animation.cpp | 12 +++++++++--- apps/openmw/mwrender/animation.hpp | 3 ++- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 01520a331..255f38dd9 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -122,14 +122,10 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const ESM::MagicEffect *effect; - effect = store.get().find(59); + int index = effect->effectStringToId("sEffectTelekinesis"); + effect = store.get().find(index); - osg::Vec4f glowcolor(1,1,1,1); - glowcolor.x() = effect->mData.mRed / 255.f; - glowcolor.y() = effect->mData.mGreen / 255.f; - glowcolor.z() = effect->mData.mBlue / 255.f; - - animation->addSpellCastGlow(glowcolor); // TODO: Telekinesis glow should only be as long as the door animation + animation->addSpellCastGlow(effect); // TODO: Telekinesis glow should only be as long as the door animation } // make key id lowercase diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index bef720764..4c6a4c02d 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -584,6 +584,12 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Open) { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::MagicEffect *magiceffect; + magiceffect = store.get().find(effectId); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); + animation->addSpellCastGlow(magiceffect); + if (target.getCellRef().getLockLevel() <= magnitude) { if (target.getCellRef().getLockLevel() > 0) @@ -837,7 +843,7 @@ namespace MWMechanics mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); - // A non-actor doesn't play its effects from a character controller, so play spell casting effects here + // A non-actor doesn't play its spell cast effects from a character controller, so play them here if (!mCaster.getClass().isActor()) playSpellCastingEffects(mId); @@ -945,7 +951,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 visual casting effect + if (mCaster.getClass().isActor()) // TODO: Non-actors (except for large statics?) should also create a spell cast vfx { const ESM::Static* castStatic; if (!effect->mCasting.empty()) @@ -957,14 +963,7 @@ namespace MWMechanics } if (!mCaster.getClass().isActor()) - { - osg::Vec4f glowcolor(1,1,1,1); - glowcolor.x() = effect->mData.mRed / 255.f; - glowcolor.y() = effect->mData.mGreen / 255.f; - glowcolor.z() = effect->mData.mBlue / 255.f; - - animation->addSpellCastGlow(glowcolor); - } + animation->addSpellCastGlow(effect); static const std::string schools[] = { "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 71b569285..0470cfe8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -159,9 +159,9 @@ namespace else writableStateSet = osg::clone(mNode->getStateSet(), osg::CopyOp::SHALLOW_COPY); - for (size_t index = 0; index < mTextures.size(); index++) + for (size_t i = 0; i < mTextures.size(); i++) { - writableStateSet->removeTextureAttribute(mTexUnit, mTextures[index]); + writableStateSet->removeTextureAttribute(mTexUnit, mTextures[i]); } writableStateSet->removeUniform(mUniform); // remove the uniform given to the temporary glow in addglow() @@ -1194,7 +1194,13 @@ namespace MWRender int mLowestUnusedTexUnit; }; - void Animation::addSpellCastGlow(osg::Vec4f glowColor){ + void Animation::addSpellCastGlow(const ESM::MagicEffect *effect){ + + osg::Vec4f glowColor = {1,1,1,1}; + glowColor.x() = effect->mData.mRed / 255.f; + glowColor.y() = effect->mData.mGreen / 255.f; + glowColor.z() = effect->mData.mBlue / 255.f; + if (!mObjectRoot->getUpdateCallback()) // If there is no glow on object addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from in-game as about 1.5 seconds diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 96bd0c03e..2fddc55c3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -8,6 +8,7 @@ namespace ESM { struct Light; + struct MagicEffect; } namespace Resource @@ -351,7 +352,7 @@ public: void removeEffect (int effectId); void getLoopingEffects (std::vector& out) const; - void addSpellCastGlow(osg::Vec4f glowColor); + void addSpellCastGlow(const ESM::MagicEffect *effect); virtual void updatePtr(const MWWorld::Ptr &ptr); From 1910128e9cbc23309dcdad92d86f2d53f3079dd9 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 9 Aug 2016 00:32:55 +0900 Subject: [PATCH 07/14] Don't remove uniform when spell glow ends --- apps/openmw/mwrender/animation.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0470cfe8c..d2f88250d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -90,7 +90,7 @@ namespace { public: GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, - osg::ref_ptr node, float maxduration, Resource::ResourceSystem* resourcesystem, osg::Uniform* uniform) + osg::ref_ptr node, float maxduration, Resource::ResourceSystem* resourcesystem) : mTexUnit(texUnit) , mColor(color) , mTextures(textures) @@ -99,7 +99,6 @@ namespace , mStartingTime(0) , mResourceSystem(resourcesystem) , mDone(false) - , mUniform(uniform) , mWatchedSpellGlow(NULL) { } @@ -139,8 +138,8 @@ namespace // the permanent glow to display its glow texture cycling properly. if (mWatchedSpellGlow != NULL && mWatchedSpellGlow->isDone()) { - mNode->removeUpdateCallback(mWatchedSpellGlow); - mWatchedSpellGlow = NULL; + mNode->removeUpdateCallback(mWatchedSpellGlow); + mWatchedSpellGlow = NULL; } // Set the starting time to measure glow duration from if this is a temporary glow @@ -160,15 +159,11 @@ namespace writableStateSet = osg::clone(mNode->getStateSet(), osg::CopyOp::SHALLOW_COPY); for (size_t i = 0; i < mTextures.size(); i++) - { writableStateSet->removeTextureAttribute(mTexUnit, mTextures[i]); - } - writableStateSet->removeUniform(mUniform); // remove the uniform given to the temporary glow in addglow() mNode->setStateSet(writableStateSet); - this->reset(); // without this a texture from the glow will continue to show on the object - mResourceSystem->getSceneManager()->recreateShaders(mNode); + mResourceSystem->getSceneManager()->recreateShaders(mNode); mDone = true; } } @@ -212,7 +207,6 @@ namespace float mStartingTime; Resource::ResourceSystem* mResourceSystem; bool mDone; - osg::Uniform* mUniform; osg::ref_ptr mWatchedSpellGlow; }; @@ -1246,10 +1240,7 @@ namespace MWRender node->accept(findLowestUnusedTexUnitVisitor); texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - osg::Uniform* uniform = new osg::Uniform("envMapColor", glowColor); - - - osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem, uniform); + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); node->addUpdateCallback(glowUpdater); if (node->getUpdateCallback() && @@ -1267,7 +1258,7 @@ namespace MWRender node->setStateSet(writableStateSet); } writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - writableStateSet->addUniform(uniform); + writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); mResourceSystem->getSceneManager()->recreateShaders(node); } From cad41599cf7245d7ad596f708a216e7032b1a5b3 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 9 Aug 2016 02:03:13 +0900 Subject: [PATCH 08/14] Fix travis build error and warnings --- apps/openmw/mwclass/door.cpp | 7 +++---- apps/openmw/mwrender/animation.cpp | 7 +------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 255f38dd9..8ed6bdca8 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -120,10 +120,9 @@ namespace MWClass { MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::MagicEffect *effect; - int index = effect->effectStringToId("sEffectTelekinesis"); - effect = store.get().find(index); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis"); + const ESM::MagicEffect *effect = store.get().find(index); animation->addSpellCastGlow(effect); // TODO: Telekinesis glow should only be as long as the door animation } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d2f88250d..7ed521935 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -183,11 +183,6 @@ namespace return mDone; } - int getTexUnit() - { - return mTexUnit; - } - void setWatchedSpellGlow(osg::ref_ptr watched) { mWatchedSpellGlow = watched; @@ -1190,7 +1185,7 @@ namespace MWRender void Animation::addSpellCastGlow(const ESM::MagicEffect *effect){ - osg::Vec4f glowColor = {1,1,1,1}; + osg::Vec4f glowColor(1,1,1,1); glowColor.x() = effect->mData.mRed / 255.f; glowColor.y() = effect->mData.mGreen / 255.f; glowColor.z() = effect->mData.mBlue / 255.f; From 775162ccdf9d16c8d7647fe7f62954a03a3ae7b8 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 9 Aug 2016 22:41:03 +0900 Subject: [PATCH 09/14] Rewrite spell glow implementation --- apps/openmw/mwmechanics/spellcasting.cpp | 11 +- apps/openmw/mwrender/animation.cpp | 277 +++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 + 3 files changed, 142 insertions(+), 148 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 4c6a4c02d..84467f953 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -572,6 +572,11 @@ namespace MWMechanics short effectId = effect.mId; if (target.getClass().canLock(target)) { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::MagicEffect *magiceffect; + magiceffect = store.get().find(effectId); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); + animation->addSpellCastGlow(magiceffect); if (effectId == ESM::MagicEffect::Lock) { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude @@ -584,12 +589,6 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Open) { - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::MagicEffect *magiceffect; - magiceffect = store.get().find(effectId); - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); - animation->addSpellCastGlow(magiceffect); - if (target.getCellRef().getLockLevel() <= magnitude) { if (target.getCellRef().getLockLevel() > 0) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7ed521935..96fa1b53b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -86,125 +86,6 @@ namespace std::vector > mToRemove; }; - class GlowUpdater : public SceneUtil::StateSetUpdater - { - public: - GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, - osg::ref_ptr node, float maxduration, Resource::ResourceSystem* resourcesystem) - : mTexUnit(texUnit) - , mColor(color) - , mTextures(textures) - , mNode(node) - , mMaxDuration(maxduration) - , mStartingTime(0) - , mResourceSystem(resourcesystem) - , mDone(false) - , mWatchedSpellGlow(NULL) - { - } - - virtual void setDefaults(osg::StateSet *stateset) - { - stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); - - osg::TexGen* texGen = new osg::TexGen; - texGen->setMode(osg::TexGen::SPHERE_MAP); - - stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setConstantColor(mColor); - texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); - texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); - - stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); - - // Reduce the texture list back down by one when a temporary glow finishes - // to allow FindLowestUnusedTexUnitVisitor to choose the same texunit again. - if (mDone) - stateset->getTextureAttributeList().resize(stateset->getTextureAttributeList().size() - 1); - } - - virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) - { - if (mDone) - return; - - // If there is a permanent enchantment glow already on this object, give the - // permanent glow a pointer to a temporary glow added in a nested update callback - // The permanent glow will remove the temporary glow when it finishes, allowing - // the permanent glow to display its glow texture cycling properly. - if (mWatchedSpellGlow != NULL && mWatchedSpellGlow->isDone()) - { - mNode->removeUpdateCallback(mWatchedSpellGlow); - mWatchedSpellGlow = NULL; - } - - // Set the starting time to measure glow duration from if this is a temporary glow - if ((mMaxDuration >= 0) && mStartingTime == 0) - mStartingTime = nv->getFrameStamp()->getSimulationTime(); - - float time = nv->getFrameStamp()->getSimulationTime(); - int index = (int)(time*16) % mTextures.size(); - stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - if ((mMaxDuration >= 0) && (time - mStartingTime > mMaxDuration)) // If this is a temporary glow and it has finished its duration - { - osg::ref_ptr writableStateSet = NULL; - if (!mNode->getStateSet()) - writableStateSet = mNode->getOrCreateStateSet(); - else - writableStateSet = osg::clone(mNode->getStateSet(), osg::CopyOp::SHALLOW_COPY); - - for (size_t i = 0; i < mTextures.size(); i++) - writableStateSet->removeTextureAttribute(mTexUnit, mTextures[i]); - - mNode->setStateSet(writableStateSet); - this->reset(); // without this a texture from the glow will continue to show on the object - mResourceSystem->getSceneManager()->recreateShaders(mNode); - mDone = true; - } - } - - bool isSpellGlowUpdater() - { - return (mMaxDuration >= 0); - } - - bool isEnchantmentGlowUpdater() - { - return (mMaxDuration < 0); - } - - bool isDone() - { - return mDone; - } - - void setWatchedSpellGlow(osg::ref_ptr watched) - { - mWatchedSpellGlow = watched; - } - - osg::ref_ptr getWatchedSpellGlow() - { - return mWatchedSpellGlow; - } - - private: - int mTexUnit; - osg::Vec4f mColor; - std::vector > mTextures; - osg::ref_ptr mNode; - float mMaxDuration; - float mStartingTime; - Resource::ResourceSystem* mResourceSystem; - bool mDone; - osg::ref_ptr mWatchedSpellGlow; - }; - class NodeMapVisitor : public osg::NodeVisitor { public: @@ -366,6 +247,124 @@ namespace namespace MWRender { + class GlowUpdater : public SceneUtil::StateSetUpdater + { + public: + GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, + osg::ref_ptr node, float duration, Resource::ResourceSystem* resourcesystem) + : mTexUnit(texUnit) + , mColor(color) + , mOriginalColor(color) + , mTextures(textures) + , mNode(node) + , mDuration(duration) + , mOriginalDuration(duration) + , mStartingTime(0) + , mResourceSystem(resourcesystem) + , mColorChanged(false) + , mDone(false) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); + + osg::TexGen* texGen = new osg::TexGen; + texGen->setMode(osg::TexGen::SPHERE_MAP); + + stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(mColor); + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); + + stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); + + // Reduce the texture list back down by one when a temporary glow finishes + // to allow FindLowestUnusedTexUnitVisitor to choose the same texunit again. + if (mDone) + stateset->getTextureAttributeList().resize(stateset->getTextureAttributeList().size() - 1); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + if (mColorChanged){ + this->reset(); + setDefaults(stateset); + mResourceSystem->getSceneManager()->recreateShaders(mNode); + mColorChanged = false; + } + if (mDone) + return; + + // Set the starting time to measure glow duration from if this is a temporary glow + if ((mDuration >= 0) && mStartingTime == 0) + mStartingTime = nv->getFrameStamp()->getSimulationTime(); + + float time = nv->getFrameStamp()->getSimulationTime(); + int index = (int)(time*16) % mTextures.size(); + stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + if ((mDuration >= 0) && (time - mStartingTime > mDuration)) // If this is a temporary glow and it has finished its duration + { + if (mOriginalDuration >= 0) // if this glowupdater was a temporary glow since its creation + { + for (size_t i = 0; i < mTextures.size(); i++) + stateset->removeTextureAttribute(mTexUnit, mTextures[i]); + this->reset(); + mDone = true; + } + if (mOriginalDuration < 0) // if this glowupdater was originally a permanent glow + { + mDuration = mOriginalDuration; + mStartingTime = 0; + mColor = mOriginalColor; + this->reset(); + setDefaults(stateset); + stateset->addUniform(new osg::Uniform("envMapColor", mColor)); + } + mResourceSystem->getSceneManager()->recreateShaders(mNode); + } + } + + bool isPermanentGlowUpdater() + { + return (mDuration < 0); + } + + bool isDone() + { + return mDone; + } + + void setColor(osg::Vec4f color) + { + mColor = color; + mColorChanged = true; + } + + void setDuration(float duration) + { + mDuration = duration; + } + + private: + int mTexUnit; + osg::Vec4f mColor; + osg::Vec4f mOriginalColor; // for restoring the color of a permanent glow after a temporary glow on the object finishes + std::vector > mTextures; + osg::ref_ptr mNode; + float mDuration; + float mOriginalDuration; // for recording that this is originally a permanent glow if it is changed to a temporary one + float mStartingTime; + Resource::ResourceSystem* mResourceSystem; + bool mColorChanged; + bool mDone; + }; struct Animation::AnimSource { @@ -1190,14 +1189,10 @@ namespace MWRender glowColor.y() = effect->mData.mGreen / 255.f; glowColor.z() = effect->mData.mBlue / 255.f; - if (!mObjectRoot->getUpdateCallback()) // If there is no glow on object + if (!mGlowUpdater) // If there is no glow on object addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from in-game as about 1.5 seconds - else if (dynamic_cast (mObjectRoot->getUpdateCallback())->isDone() == true) // If there was a temporary glow on object and it finished - addGlow(mObjectRoot, glowColor, 1.5); - - else if (dynamic_cast (mObjectRoot->getUpdateCallback())->isEnchantmentGlowUpdater() == true - && dynamic_cast (mObjectRoot->getUpdateCallback())->getWatchedSpellGlow() == NULL) // If there is a permanent enchantment glow on object and no temporary glow is running + else if (mGlowUpdater->isDone() || (mGlowUpdater->isPermanentGlowUpdater() == true)) addGlow(mObjectRoot, glowColor, 1.5); } @@ -1220,28 +1215,26 @@ namespace MWRender tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); mResourceSystem->getSceneManager()->applyFilterSettings(tex); textures.push_back(tex); - } + } - int texUnit; - - // If we have a spell glow updater left over from this object prevously casting a spell, - // and there was no permanent glow updater on the object to watch it and remove it, we - // remove it here. - if (node->getUpdateCallback() && - dynamic_cast (node->getUpdateCallback())->isSpellGlowUpdater() == true) - node->removeUpdateCallback(node->getUpdateCallback()); + if (mGlowUpdater && mGlowUpdater->isDone()) + node->removeUpdateCallback(mGlowUpdater); FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); - texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - - osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); + int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - node->addUpdateCallback(glowUpdater); - if (node->getUpdateCallback() && - dynamic_cast (node->getUpdateCallback())->isEnchantmentGlowUpdater() == true) - if (glowDuration >= 0) - dynamic_cast (node->getUpdateCallback())->setWatchedSpellGlow(glowUpdater); + if (mGlowUpdater && mGlowUpdater->isPermanentGlowUpdater()) + { + mGlowUpdater->setColor(glowColor); + mGlowUpdater->setDuration(glowDuration); + } + else + { + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); + mGlowUpdater = glowUpdater; + node->addUpdateCallback(glowUpdater); + } // set a texture now so that the ShaderVisitor can find it osg::ref_ptr writableStateSet = NULL; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2fddc55c3..a837a26ae 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,6 +33,7 @@ namespace MWRender class ResetAccumRootCallback; class RotateController; +class GlowUpdater; class EffectAnimationTime : public SceneUtil::ControllerSource { @@ -262,6 +263,7 @@ protected: float mHeadPitchRadians; osg::ref_ptr mGlowLight; + osg::ref_ptr mGlowUpdater; float mAlpha; From 9b2cb2fb8c9d341abe906eb4be9e928411646342 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 9 Aug 2016 23:50:24 +0900 Subject: [PATCH 10/14] Cleanups --- apps/openmw/mwmechanics/spellcasting.cpp | 15 +++++--- apps/openmw/mwrender/animation.cpp | 48 ++++++++++++------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 84467f953..edaae221a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -571,14 +571,13 @@ namespace MWMechanics { short effectId = effect.mId; if (target.getClass().canLock(target)) - { - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::MagicEffect *magiceffect; - magiceffect = store.get().find(effectId); - MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); - animation->addSpellCastGlow(magiceffect); + { if (effectId == ESM::MagicEffect::Lock) { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::MagicEffect *magiceffect = store.get().find(effectId); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); + animation->addSpellCastGlow(magiceffect); if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { if (caster == getPlayer()) @@ -589,6 +588,10 @@ namespace MWMechanics } else if (effectId == ESM::MagicEffect::Open) { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::MagicEffect *magiceffect = store.get().find(effectId); + MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); + animation->addSpellCastGlow(magiceffect); if (target.getCellRef().getLockLevel() <= magnitude) { if (target.getCellRef().getLockLevel() > 0) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 96fa1b53b..bfd5c3647 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -268,26 +268,29 @@ namespace MWRender virtual void setDefaults(osg::StateSet *stateset) { - stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); - - osg::TexGen* texGen = new osg::TexGen; - texGen->setMode(osg::TexGen::SPHERE_MAP); - - stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - - osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; - texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); - texEnv->setConstantColor(mColor); - texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); - texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); - - stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); - - // Reduce the texture list back down by one when a temporary glow finishes - // to allow FindLowestUnusedTexUnitVisitor to choose the same texunit again. if (mDone) - stateset->getTextureAttributeList().resize(stateset->getTextureAttributeList().size() - 1); + { + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXTURE); + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXGEN); + } + else + { + stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); + osg::TexGen* texGen = new osg::TexGen; + texGen->setMode(osg::TexGen::SPHERE_MAP); + + stateset->setTextureAttributeAndModes(mTexUnit, texGen, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(mColor); + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR); + + stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON); + stateset->addUniform(new osg::Uniform("envMapColor", mColor)); + } } virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) @@ -295,7 +298,6 @@ namespace MWRender if (mColorChanged){ this->reset(); setDefaults(stateset); - mResourceSystem->getSceneManager()->recreateShaders(mNode); mColorChanged = false; } if (mDone) @@ -313,10 +315,10 @@ namespace MWRender { if (mOriginalDuration >= 0) // if this glowupdater was a temporary glow since its creation { - for (size_t i = 0; i < mTextures.size(); i++) - stateset->removeTextureAttribute(mTexUnit, mTextures[i]); + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXTURE); this->reset(); mDone = true; + mResourceSystem->getSceneManager()->recreateShaders(mNode); } if (mOriginalDuration < 0) // if this glowupdater was originally a permanent glow { @@ -325,9 +327,7 @@ namespace MWRender mColor = mOriginalColor; this->reset(); setDefaults(stateset); - stateset->addUniform(new osg::Uniform("envMapColor", mColor)); } - mResourceSystem->getSceneManager()->recreateShaders(mNode); } } From 4b9aff7a03d0117fc0f096d6989282ac26f67b53 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 10 Aug 2016 00:43:14 +0900 Subject: [PATCH 11/14] Glowupdater fix when using shaders --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 74 ++++++++++++------------ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index edaae221a..c55ae67f2 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -571,7 +571,7 @@ namespace MWMechanics { short effectId = effect.mId; if (target.getClass().canLock(target)) - { + { if (effectId == ESM::MagicEffect::Lock) { const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index bfd5c3647..4996ad2a8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1182,8 +1182,8 @@ namespace MWRender int mLowestUnusedTexUnit; }; - void Animation::addSpellCastGlow(const ESM::MagicEffect *effect){ - + void Animation::addSpellCastGlow(const ESM::MagicEffect *effect) + { osg::Vec4f glowColor(1,1,1,1); glowColor.x() = effect->mData.mRed / 255.f; glowColor.y() = effect->mData.mGreen / 255.f; @@ -1197,28 +1197,9 @@ namespace MWRender } void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor, float glowDuration) - { - std::vector > textures; - for (int i=0; i<32; ++i) - { - std::stringstream stream; - stream << "textures/magicitem/caust"; - stream << std::setw(2); - stream << std::setfill('0'); - stream << i; - stream << ".dds"; - - osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(stream.str()); - osg::ref_ptr tex (new osg::Texture2D(image)); - tex->setName("envMap"); - tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); - tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); - mResourceSystem->getSceneManager()->applyFilterSettings(tex); - textures.push_back(tex); - } - + { if (mGlowUpdater && mGlowUpdater->isDone()) - node->removeUpdateCallback(mGlowUpdater); + node->removeUpdateCallback(mGlowUpdater); FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); @@ -1230,25 +1211,44 @@ namespace MWRender mGlowUpdater->setDuration(glowDuration); } else - { + { + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::stringstream stream; + stream << "textures/magicitem/caust"; + stream << std::setw(2); + stream << std::setfill('0'); + stream << i; + stream << ".dds"; + + osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(stream.str()); + osg::ref_ptr tex (new osg::Texture2D(image)); + tex->setName("envMap"); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); + mResourceSystem->getSceneManager()->applyFilterSettings(tex); + textures.push_back(tex); + } + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); mGlowUpdater = glowUpdater; node->addUpdateCallback(glowUpdater); - } + - // set a texture now so that the ShaderVisitor can find it - osg::ref_ptr writableStateSet = NULL; - if (!node->getStateSet()) - writableStateSet = node->getOrCreateStateSet(); - else - { - writableStateSet = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY); - node->setStateSet(writableStateSet); + // set a texture now so that the ShaderVisitor can find it + osg::ref_ptr writableStateSet = NULL; + if (!node->getStateSet()) + writableStateSet = node->getOrCreateStateSet(); + else + { + writableStateSet = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY); + node->setStateSet(writableStateSet); + } + writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); + writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); + mResourceSystem->getSceneManager()->recreateShaders(node); } - writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); - - mResourceSystem->getSceneManager()->recreateShaders(node); } // TODO: Should not be here From 67f31d948e54fc1f3e9b7d9895eb1a20f575fb38 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 10 Aug 2016 01:11:14 +0900 Subject: [PATCH 12/14] Add removeTexture method --- apps/openmw/mwrender/animation.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4996ad2a8..77375b410 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -269,10 +269,7 @@ namespace MWRender virtual void setDefaults(osg::StateSet *stateset) { if (mDone) - { - stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXTURE); - stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXGEN); - } + removeTexture(stateset); else { stateset->setTextureMode(mTexUnit, GL_TEXTURE_2D, osg::StateAttribute::ON); @@ -293,6 +290,19 @@ namespace MWRender } } + void removeTexture(osg::StateSet* stateset) + { + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXTURE); + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXGEN); + stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXENV); + stateset->removeTextureMode(mTexUnit, GL_TEXTURE_2D); + stateset->removeUniform("envMapColor"); + + osg::StateSet::TextureAttributeList& list = stateset->getTextureAttributeList(); + while (list.size() && list.rbegin()->empty()) + list.pop_back(); + } + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { if (mColorChanged){ @@ -315,7 +325,7 @@ namespace MWRender { if (mOriginalDuration >= 0) // if this glowupdater was a temporary glow since its creation { - stateset->removeTextureAttribute(mTexUnit, osg::StateAttribute::TEXTURE); + removeTexture(stateset); this->reset(); mDone = true; mResourceSystem->getSceneManager()->recreateShaders(mNode); From 1c76c93ed80f7bd7504f2ceee96ad2feb04addb7 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 10 Aug 2016 01:35:22 +0900 Subject: [PATCH 13/14] Use raw pointer to node in glowupdater --- apps/openmw/mwrender/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 77375b410..6329b5f5d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -251,7 +251,7 @@ namespace MWRender { public: GlowUpdater(int texUnit, osg::Vec4f color, const std::vector >& textures, - osg::ref_ptr node, float duration, Resource::ResourceSystem* resourcesystem) + osg::Node* node, float duration, Resource::ResourceSystem* resourcesystem) : mTexUnit(texUnit) , mColor(color) , mOriginalColor(color) @@ -367,7 +367,7 @@ namespace MWRender osg::Vec4f mColor; osg::Vec4f mOriginalColor; // for restoring the color of a permanent glow after a temporary glow on the object finishes std::vector > mTextures; - osg::ref_ptr mNode; + osg::Node* mNode; float mDuration; float mOriginalDuration; // for recording that this is originally a permanent glow if it is changed to a temporary one float mStartingTime; @@ -1200,7 +1200,7 @@ namespace MWRender glowColor.z() = effect->mData.mBlue / 255.f; if (!mGlowUpdater) // If there is no glow on object - addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from in-game as about 1.5 seconds + addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from original engine as about 1.5 seconds else if (mGlowUpdater->isDone() || (mGlowUpdater->isPermanentGlowUpdater() == true)) addGlow(mObjectRoot, glowColor, 1.5); From 83b715734f280ef7a0d8b9abb7de476fd8f881d6 Mon Sep 17 00:00:00 2001 From: Allofich Date: Wed, 10 Aug 2016 02:50:30 +0900 Subject: [PATCH 14/14] Move part of addGlow() to addSpellCastGlow() --- apps/openmw/mwrender/animation.cpp | 94 ++++++++++++++---------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6329b5f5d..e5614f3f8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1199,66 +1199,62 @@ namespace MWRender glowColor.y() = effect->mData.mGreen / 255.f; glowColor.z() = effect->mData.mBlue / 255.f; - if (!mGlowUpdater) // If there is no glow on object - addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from original engine as about 1.5 seconds + if (!mGlowUpdater || (mGlowUpdater->isDone() || (mGlowUpdater->isPermanentGlowUpdater() == true))) + { + if (mGlowUpdater && mGlowUpdater->isDone()) + mObjectRoot->removeUpdateCallback(mGlowUpdater); - else if (mGlowUpdater->isDone() || (mGlowUpdater->isPermanentGlowUpdater() == true)) - addGlow(mObjectRoot, glowColor, 1.5); + if (mGlowUpdater && mGlowUpdater->isPermanentGlowUpdater()) + { + mGlowUpdater->setColor(glowColor); + mGlowUpdater->setDuration(1.5); // Glow length measured from original engine as about 1.5 seconds + } + else + addGlow(mObjectRoot, glowColor, 1.5); + } } void Animation::addGlow(osg::ref_ptr node, osg::Vec4f glowColor, float glowDuration) - { - if (mGlowUpdater && mGlowUpdater->isDone()) - node->removeUpdateCallback(mGlowUpdater); + { + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::stringstream stream; + stream << "textures/magicitem/caust"; + stream << std::setw(2); + stream << std::setfill('0'); + stream << i; + stream << ".dds"; + + osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(stream.str()); + osg::ref_ptr tex (new osg::Texture2D(image)); + tex->setName("envMap"); + tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); + tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); + mResourceSystem->getSceneManager()->applyFilterSettings(tex); + textures.push_back(tex); + } FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor; node->accept(findLowestUnusedTexUnitVisitor); int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit; - if (mGlowUpdater && mGlowUpdater->isPermanentGlowUpdater()) - { - mGlowUpdater->setColor(glowColor); - mGlowUpdater->setDuration(glowDuration); - } - else - { - std::vector > textures; - for (int i=0; i<32; ++i) - { - std::stringstream stream; - stream << "textures/magicitem/caust"; - stream << std::setw(2); - stream << std::setfill('0'); - stream << i; - stream << ".dds"; - - osg::ref_ptr image = mResourceSystem->getImageManager()->getImage(stream.str()); - osg::ref_ptr tex (new osg::Texture2D(image)); - tex->setName("envMap"); - tex->setWrap(osg::Texture::WRAP_S, osg::Texture2D::REPEAT); - tex->setWrap(osg::Texture::WRAP_T, osg::Texture2D::REPEAT); - mResourceSystem->getSceneManager()->applyFilterSettings(tex); - textures.push_back(tex); - } - - osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); - mGlowUpdater = glowUpdater; - node->addUpdateCallback(glowUpdater); + osg::ref_ptr glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem); + mGlowUpdater = glowUpdater; + node->addUpdateCallback(glowUpdater); - - // set a texture now so that the ShaderVisitor can find it - osg::ref_ptr writableStateSet = NULL; - if (!node->getStateSet()) - writableStateSet = node->getOrCreateStateSet(); - else - { - writableStateSet = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY); - node->setStateSet(writableStateSet); - } - writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); - writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); - mResourceSystem->getSceneManager()->recreateShaders(node); + // set a texture now so that the ShaderVisitor can find it + osg::ref_ptr writableStateSet = NULL; + if (!node->getStateSet()) + writableStateSet = node->getOrCreateStateSet(); + else + { + writableStateSet = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY); + node->setStateSet(writableStateSet); } + writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON); + writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor)); + mResourceSystem->getSceneManager()->recreateShaders(node); } // TODO: Should not be here