From 3841a8fb40e4fb1c0fe8c76d966ffe6e1ed5e2f8 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 2 Aug 2016 21:37:39 +0900 Subject: [PATCH] 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;