forked from teamnwah/openmw-tes3coop
Handle spell glows within updatecallback
This commit is contained in:
parent
123c626f2d
commit
e132b52a69
5 changed files with 113 additions and 74 deletions
|
@ -113,7 +113,8 @@ namespace MWClass
|
||||||
bool hasKey = false;
|
bool hasKey = false;
|
||||||
std::string keyName;
|
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()->getDistanceToFacedObject() >
|
||||||
MWBase::Environment::get().getWorld()->getMaxActivationDistance())
|
MWBase::Environment::get().getWorld()->getMaxActivationDistance())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1531,11 +1531,10 @@ void CharacterController::update(float duration)
|
||||||
osg::Vec3f movement(0.f, 0.f, 0.f);
|
osg::Vec3f movement(0.f, 0.f, 0.f);
|
||||||
float speed = 0.f;
|
float speed = 0.f;
|
||||||
|
|
||||||
|
updateMagicEffects();
|
||||||
|
|
||||||
if(!cls.isActor())
|
if(!cls.isActor())
|
||||||
{
|
{
|
||||||
updateMagicEffects();
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mPtr);
|
|
||||||
animation->updateSpellGlow(duration);
|
|
||||||
if(mAnimQueue.size() > 1)
|
if(mAnimQueue.size() > 1)
|
||||||
{
|
{
|
||||||
if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
|
if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
|
||||||
|
|
|
@ -837,7 +837,7 @@ namespace MWMechanics
|
||||||
mCaster.getClass().skillUsageSucceeded(mCaster,
|
mCaster.getClass().skillUsageSucceeded(mCaster,
|
||||||
spellSchoolToSkill(school), 0);
|
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())
|
if (!mCaster.getClass().isActor())
|
||||||
playSpellCastingEffects(mId);
|
playSpellCastingEffects(mId);
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
|
||||||
|
|
||||||
#include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority
|
#include "../mwmechanics/character.hpp" // FIXME: for MWMechanics::Priority
|
||||||
|
|
||||||
|
@ -90,11 +89,18 @@ namespace
|
||||||
class GlowUpdater : public SceneUtil::StateSetUpdater
|
class GlowUpdater : public SceneUtil::StateSetUpdater
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GlowUpdater(int texUnit, osg::Vec4f color, const std::vector<osg::ref_ptr<osg::Texture2D> >& textures, bool hasDuration)
|
GlowUpdater(int texUnit, osg::Vec4f color, const std::vector<osg::ref_ptr<osg::Texture2D> >& textures,
|
||||||
|
osg::ref_ptr<osg::Node> node, float maxduration, Resource::ResourceSystem* resourcesystem, osg::Uniform* uniform)
|
||||||
: mTexUnit(texUnit)
|
: mTexUnit(texUnit)
|
||||||
, mColor(color)
|
, mColor(color)
|
||||||
, mTextures(textures)
|
, 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);
|
texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR);
|
||||||
|
|
||||||
stateset->setTextureAttributeAndModes(mTexUnit, texEnv, osg::StateAttribute::ON);
|
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)
|
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();
|
float time = nv->getFrameStamp()->getSimulationTime();
|
||||||
int index = (int)(time*16) % mTextures.size();
|
int index = (int)(time*16) % mTextures.size();
|
||||||
stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
stateset->setTextureAttribute(mTexUnit, mTextures[index], osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||||
}
|
|
||||||
|
|
||||||
bool const getHasDuration()
|
if ((mMaxDuration >= 0) && (time - mStartingTime > mMaxDuration)) // If this is a temporary glow and it has finished its duration
|
||||||
{
|
{
|
||||||
return mHasDuration;
|
osg::ref_ptr<osg::StateSet> writableStateSet = NULL;
|
||||||
}
|
if (!mNode->getStateSet())
|
||||||
|
writableStateSet = mNode->getOrCreateStateSet();
|
||||||
|
else
|
||||||
|
writableStateSet = osg::clone(mNode->getStateSet(), osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D> > const getTextures()
|
for (size_t index = 0; index < mTextures.size(); index++)
|
||||||
{
|
{
|
||||||
return mTextures;
|
writableStateSet->removeTextureAttribute(mTexUnit, mTextures[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int const getTexUnit()
|
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 isSpellGlowUpdater()
|
||||||
|
{
|
||||||
|
return (mMaxDuration >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnchantmentGlowUpdater()
|
||||||
|
{
|
||||||
|
return (mMaxDuration < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDone()
|
||||||
|
{
|
||||||
|
return mDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getTexUnit()
|
||||||
{
|
{
|
||||||
return mTexUnit;
|
return mTexUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setWatchedSpellGlow(osg::ref_ptr<GlowUpdater> watched)
|
||||||
|
{
|
||||||
|
mWatchedSpellGlow = watched;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<GlowUpdater> getWatchedSpellGlow()
|
||||||
|
{
|
||||||
|
return mWatchedSpellGlow;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mTexUnit;
|
int mTexUnit;
|
||||||
osg::Vec4f mColor;
|
osg::Vec4f mColor;
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D> > mTextures;
|
std::vector<osg::ref_ptr<osg::Texture2D> > mTextures;
|
||||||
bool mHasDuration;
|
osg::ref_ptr<osg::Node> mNode;
|
||||||
|
float mMaxDuration;
|
||||||
|
float mStartingTime;
|
||||||
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
|
bool mDone;
|
||||||
|
osg::Uniform* mUniform;
|
||||||
|
osg::ref_ptr<GlowUpdater> mWatchedSpellGlow;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeMapVisitor : public osg::NodeVisitor
|
class NodeMapVisitor : public osg::NodeVisitor
|
||||||
|
@ -358,7 +428,6 @@ namespace MWRender
|
||||||
, mHeadYawRadians(0.f)
|
, mHeadYawRadians(0.f)
|
||||||
, mHeadPitchRadians(0.f)
|
, mHeadPitchRadians(0.f)
|
||||||
, mAlpha(1.f)
|
, mAlpha(1.f)
|
||||||
, mSpellGlowDuration(0.f)
|
|
||||||
{
|
{
|
||||||
for(size_t i = 0;i < sNumBlendMasks;i++)
|
for(size_t i = 0;i < sNumBlendMasks;i++)
|
||||||
mAnimationTimePtr[i].reset(new AnimationTime);
|
mAnimationTimePtr[i].reset(new AnimationTime);
|
||||||
|
@ -1126,47 +1195,18 @@ namespace MWRender
|
||||||
};
|
};
|
||||||
|
|
||||||
void Animation::addSpellCastGlow(osg::Vec4f glowColor){
|
void Animation::addSpellCastGlow(osg::Vec4f glowColor){
|
||||||
if (mSpellGlowUpdater == NULL) // only start a new spell glow if there isn't one already
|
if (!mObjectRoot->getUpdateCallback()) // If there is no glow on object
|
||||||
addGlow(mObjectRoot, glowColor, true);
|
addGlow(mObjectRoot, glowColor, 1.5); // Glow length measured from in-game as about 1.5 seconds
|
||||||
MWBase::Environment::get().getMechanicsManager()->add(mPtr);
|
|
||||||
|
else if (dynamic_cast <GlowUpdater*>(mObjectRoot->getUpdateCallback())->isDone() == true) // If there was a temporary glow on object and it finished
|
||||||
|
addGlow(mObjectRoot, glowColor, 1.5);
|
||||||
|
|
||||||
|
else if (dynamic_cast <GlowUpdater*>(mObjectRoot->getUpdateCallback())->isEnchantmentGlowUpdater() == true
|
||||||
|
&& dynamic_cast <GlowUpdater*>(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){
|
void Animation::addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor, float glowDuration)
|
||||||
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<osg::StateSet> writableStateSet = NULL;
|
|
||||||
if (!mObjectRoot->getStateSet())
|
|
||||||
writableStateSet = mObjectRoot->getOrCreateStateSet();
|
|
||||||
else
|
|
||||||
writableStateSet = osg::clone(mObjectRoot->getStateSet(), osg::CopyOp::SHALLOW_COPY);
|
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D> > 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<osg::Node> node, osg::Vec4f glowColor, bool hasDuration)
|
|
||||||
{
|
{
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
||||||
for (int i=0; i<32; ++i)
|
for (int i=0; i<32; ++i)
|
||||||
|
@ -1187,16 +1227,29 @@ namespace MWRender
|
||||||
textures.push_back(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 <GlowUpdater*>(node->getUpdateCallback())->isSpellGlowUpdater() == true)
|
||||||
|
node->removeUpdateCallback(node->getUpdateCallback());
|
||||||
|
|
||||||
FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor;
|
FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor;
|
||||||
node->accept(findLowestUnusedTexUnitVisitor);
|
node->accept(findLowestUnusedTexUnitVisitor);
|
||||||
int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit;
|
texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit;
|
||||||
|
|
||||||
osg::ref_ptr<GlowUpdater> glowUpdater = new GlowUpdater(texUnit, glowColor, textures, hasDuration);
|
osg::Uniform* uniform = new osg::Uniform("envMapColor", glowColor);
|
||||||
|
|
||||||
if (hasDuration) // store the glowUpdater for later removal and checking if this is a spell glow
|
|
||||||
mSpellGlowUpdater = glowUpdater;
|
osg::ref_ptr<GlowUpdater> glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, mResourceSystem, uniform);
|
||||||
|
|
||||||
node->addUpdateCallback(glowUpdater);
|
node->addUpdateCallback(glowUpdater);
|
||||||
|
if (node->getUpdateCallback() &&
|
||||||
|
dynamic_cast <GlowUpdater*>(node->getUpdateCallback())->isEnchantmentGlowUpdater() == true)
|
||||||
|
if (glowDuration >= 0)
|
||||||
|
dynamic_cast <GlowUpdater*>(node->getUpdateCallback())->setWatchedSpellGlow(glowUpdater);
|
||||||
|
|
||||||
// set a texture now so that the ShaderVisitor can find it
|
// set a texture now so that the ShaderVisitor can find it
|
||||||
osg::ref_ptr<osg::StateSet> writableStateSet = NULL;
|
osg::ref_ptr<osg::StateSet> writableStateSet = NULL;
|
||||||
|
@ -1208,11 +1261,7 @@ namespace MWRender
|
||||||
node->setStateSet(writableStateSet);
|
node->setStateSet(writableStateSet);
|
||||||
}
|
}
|
||||||
writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON);
|
writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON);
|
||||||
|
writableStateSet->addUniform(uniform);
|
||||||
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);
|
mResourceSystem->getSceneManager()->recreateShaders(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
|
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class GlowUpdater;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Light;
|
struct Light;
|
||||||
|
@ -268,9 +263,6 @@ protected:
|
||||||
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
||||||
|
|
||||||
float mAlpha;
|
float mAlpha;
|
||||||
float mSpellGlowDuration;
|
|
||||||
|
|
||||||
osg::ref_ptr<GlowUpdater> mSpellGlowUpdater;
|
|
||||||
|
|
||||||
const NodeMap& getNodeMap() const;
|
const NodeMap& getNodeMap() const;
|
||||||
|
|
||||||
|
@ -325,7 +317,7 @@ protected:
|
||||||
|
|
||||||
osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
|
osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
|
||||||
|
|
||||||
void addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor, bool hasDuration = false);
|
void addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor, float glowDuration = -1);
|
||||||
|
|
||||||
/// Set the render bin for this animation's object root. May be customized by subclasses.
|
/// Set the render bin for this animation's object root. May be customized by subclasses.
|
||||||
virtual void setRenderBin();
|
virtual void setRenderBin();
|
||||||
|
@ -360,8 +352,6 @@ public:
|
||||||
void getLoopingEffects (std::vector<int>& out) const;
|
void getLoopingEffects (std::vector<int>& out) const;
|
||||||
|
|
||||||
void addSpellCastGlow(osg::Vec4f glowColor);
|
void addSpellCastGlow(osg::Vec4f glowColor);
|
||||||
void updateSpellGlow(float duration);
|
|
||||||
void removeSpellGlow();
|
|
||||||
|
|
||||||
virtual void updatePtr(const MWWorld::Ptr &ptr);
|
virtual void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue