Merge pull request #2476 from akortunov/arrows

Use magic glow for enchanted arrows
pull/541/head
Alexei Dobrohotov 5 years ago committed by GitHub
commit ed364a1e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -158,6 +158,7 @@
Feature #5051: Provide a separate textures for scrollbars
Feature #5094: Unix like console hotkeys
Feature #5098: Allow user controller bindings
Feature #5122: Use magic glow for enchanted arrows
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption
Task #4789: Optimize cell transitions

@ -79,7 +79,7 @@ PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std:
return PartHolderPtr();
if (enchantedGlow)
addGlow(instance, *glowColor);
mGlowUpdater = SceneUtil::addEnchantedGlow(instance, mResourceSystem, *glowColor);
return PartHolderPtr(new PartHolder(instance));
}
@ -238,7 +238,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
{
if (showHolsteredWeapons)
{
osg::Vec4f glowColor = getEnchantmentColor(*weapon);
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor);
if (mScabbard)
resetControllers(mScabbard->getNode());
@ -271,8 +271,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
if (isEnchanted)
{
osg::Vec4f glowColor = getEnchantmentColor(*weapon);
addGlow(weaponNode, glowColor);
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
mGlowUpdater = SceneUtil::addEnchantedGlow(weaponNode, mResourceSystem, glowColor);
}
}
}
@ -347,15 +347,18 @@ void ActorAnimation::updateQuiver()
}
// Add new ones
osg::Vec4f glowColor = getEnchantmentColor(*ammo);
osg::Vec4f glowColor = ammo->getClass().getEnchantmentColor(*ammo);
std::string model = ammo->getClass().getModel(*ammo);
for (unsigned int i=0; i<ammoCount; ++i)
{
osg::ref_ptr<osg::Group> arrowNode = ammoNode->getChild(i)->asGroup();
osg::ref_ptr<osg::Node> arrow = mResourceSystem->getSceneManager()->getInstance(model, arrowNode);
if (!ammo->getClass().getEnchantment(*ammo).empty())
addGlow(arrow, glowColor);
}
// Assign GlowUpdater for ammo sheathing bone itself to do not attach it to every arrow
ammoNode->setUpdateCallback(nullptr);
if (ammoCount > 0 && !ammo->getClass().getEnchantment(*ammo).empty())
SceneUtil::addEnchantedGlow(ammoNode, mResourceSystem, glowColor);
}
void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)

@ -3,8 +3,6 @@
#include <iomanip>
#include <limits>
#include <osg/TexGen>
#include <osg/TexEnvCombine>
#include <osg/MatrixTransform>
#include <osg/BlendFunc>
#include <osg/Material>
@ -16,10 +14,8 @@
#include <components/debug/debuglog.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/misc/constants.hpp>
@ -519,135 +515,6 @@ namespace MWRender
float mAlpha;
};
class GlowUpdater : public SceneUtil::StateSetUpdater
{
public:
GlowUpdater(int texUnit, const osg::Vec4f& color, const std::vector<osg::ref_ptr<osg::Texture2D> >& textures,
osg::Node* 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)
{
if (mDone)
removeTexture(stateset);
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));
}
}
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){
this->reset();
setDefaults(stateset);
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
{
removeTexture(stateset);
this->reset();
mDone = true;
mResourceSystem->getSceneManager()->recreateShaders(mNode);
}
if (mOriginalDuration < 0) // if this glowupdater was originally a permanent glow
{
mDuration = mOriginalDuration;
mStartingTime = 0;
mColor = mOriginalColor;
this->reset();
setDefaults(stateset);
}
}
}
bool isPermanentGlowUpdater()
{
return (mDuration < 0);
}
bool isDone()
{
return mDone;
}
void setColor(const 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<osg::ref_ptr<osg::Texture2D> > mTextures;
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;
Resource::ResourceSystem* mResourceSystem;
bool mColorChanged;
bool mDone;
};
struct Animation::AnimSource
{
osg::ref_ptr<const NifOsg::KeyframeHolder> mKeyframes;
@ -1574,25 +1441,6 @@ namespace MWRender
return mObjectRoot.get();
}
class FindLowestUnusedTexUnitVisitor : public osg::NodeVisitor
{
public:
FindLowestUnusedTexUnitVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mLowestUnusedTexUnit(0)
{
}
virtual void apply(osg::Node& node)
{
if (osg::StateSet* stateset = node.getStateSet())
mLowestUnusedTexUnit = std::max(mLowestUnusedTexUnit, int(stateset->getTextureAttributeList().size()));
traverse(node);
}
int mLowestUnusedTexUnit;
};
void Animation::addSpellCastGlow(const ESM::MagicEffect *effect, float glowDuration)
{
osg::Vec4f glowColor(1,1,1,1);
@ -1611,78 +1459,10 @@ namespace MWRender
mGlowUpdater->setDuration(glowDuration);
}
else
addGlow(mObjectRoot, glowColor, glowDuration);
mGlowUpdater = SceneUtil::addEnchantedGlow(mObjectRoot, mResourceSystem, glowColor, glowDuration);
}
}
void Animation::addGlow(osg::ref_ptr<osg::Node> node, osg::Vec4f glowColor, float glowDuration)
{
std::vector<osg::ref_ptr<osg::Texture2D> > 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<osg::Image> image = mResourceSystem->getImageManager()->getImage(stream.str());
osg::ref_ptr<osg::Texture2D> 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;
osg::ref_ptr<GlowUpdater> 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<osg::StateSet> writableStateSet = nullptr;
if (!node->getStateSet())
writableStateSet = node->getOrCreateStateSet();
else
{
writableStateSet = new osg::StateSet(*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
osg::Vec4f Animation::getEnchantmentColor(const MWWorld::ConstPtr& item) const
{
osg::Vec4f result(1,1,1,1);
std::string enchantmentName = item.getClass().getEnchantment(item);
if (enchantmentName.empty())
return result;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentName);
if (!enchantment)
return result;
assert (enchantment->mEffects.mList.size());
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().search(
enchantment->mEffects.mList.front().mEffectID);
if (!magicEffect)
return result;
result.x() = magicEffect->mData.mRed / 255.f;
result.y() = magicEffect->mData.mGreen / 255.f;
result.z() = magicEffect->mData.mBlue / 255.f;
return result;
}
void Animation::addExtraLight(osg::ref_ptr<osg::Group> parent, const ESM::Light *esmLight)
{
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
@ -2001,7 +1781,7 @@ namespace MWRender
addAnimSource(model, model);
if (!ptr.getClass().getEnchantment(ptr).empty())
addGlow(mObjectRoot, getEnchantmentColor(ptr));
mGlowUpdater = SceneUtil::addEnchantedGlow(mObjectRoot, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
}
if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight)
addExtraLight(getOrCreateObjectRoot(), ptr.get<ESM::Light>()->mBase);

@ -4,6 +4,7 @@
#include "../mwworld/ptr.hpp"
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/util.hpp>
namespace ESM
{
@ -34,7 +35,6 @@ namespace MWRender
class ResetAccumRootCallback;
class RotateController;
class GlowUpdater;
class TransparencyUpdater;
class EffectAnimationTime : public SceneUtil::ControllerSource
@ -266,7 +266,7 @@ protected:
bool mHasMagicEffects;
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
osg::ref_ptr<GlowUpdater> mGlowUpdater;
osg::ref_ptr<SceneUtil::GlowUpdater> mGlowUpdater;
osg::ref_ptr<TransparencyUpdater> mTransparencyUpdater;
float mAlpha;
@ -330,10 +330,6 @@ protected:
*/
virtual void addControllers();
osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
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.
virtual void setRenderBin();

@ -132,7 +132,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
scene.reset(new PartHolder(attached));
if (!item.getClass().getEnchantment(item).empty())
addGlow(attached, getEnchantmentColor(item));
mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, item.getClass().getEnchantmentColor(item));
// Crossbows start out with a bolt attached
// FIXME: code duplicated from NpcAnimation
@ -173,6 +173,16 @@ bool CreatureWeaponAnimation::isArrowAttached() const
void CreatureWeaponAnimation::attachArrow()
{
WeaponAnimation::attachArrow(mPtr);
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
if (ammo != inv.end() && !ammo->getClass().getEnchantment(*ammo).empty())
{
osg::Group* bone = getArrowBone();
if (bone != nullptr && bone->getNumChildren())
SceneUtil::addEnchantedGlow(bone->getChild(0), mResourceSystem, ammo->getClass().getEnchantmentColor(*ammo));
}
updateQuiver();
}

@ -572,7 +572,7 @@ void NpcAnimation::updateParts()
int prio = 1;
bool enchantedGlow = !store->getClass().getEnchantment(*store).empty();
osg::Vec4f glowColor = getEnchantmentColor(*store);
osg::Vec4f glowColor = store->getClass().getEnchantmentColor(*store);
if(store->getTypeName() == typeid(ESM::Clothing).name())
{
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
@ -664,7 +664,7 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st
osg::ref_ptr<osg::Node> attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, found->second);
if (enchantedGlow)
addGlow(attached, *glowColor);
mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, *glowColor);
return PartHolderPtr(new PartHolder(attached));
}
@ -897,7 +897,7 @@ void NpcAnimation::showWeapons(bool showWeapon)
MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon != inv.end())
{
osg::Vec4f glowColor = getEnchantmentColor(*weapon);
osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon);
std::string mesh = weapon->getClass().getModel(*weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
@ -931,7 +931,7 @@ void NpcAnimation::showCarriedLeft(bool show)
MWWorld::ConstContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
if(show && iter != inv.end())
{
osg::Vec4f glowColor = getEnchantmentColor(*iter);
osg::Vec4f glowColor = iter->getClass().getEnchantmentColor(*iter);
std::string mesh = iter->getClass().getModel(*iter);
if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor))
@ -947,6 +947,16 @@ void NpcAnimation::showCarriedLeft(bool show)
void NpcAnimation::attachArrow()
{
WeaponAnimation::attachArrow(mPtr);
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
if (ammo != inv.end() && !ammo->getClass().getEnchantment(*ammo).empty())
{
osg::Group* bone = getArrowBone();
if (bone != nullptr && bone->getNumChildren())
SceneUtil::addEnchantedGlow(bone->getChild(0), mResourceSystem, ammo->getClass().getEnchantmentColor(*ammo));
}
updateQuiver();
}

@ -507,4 +507,28 @@ namespace MWWorld
{
throw std::runtime_error("class does not support armor ratings");
}
osg::Vec4f Class::getEnchantmentColor(const MWWorld::ConstPtr& item) const
{
osg::Vec4f result(1,1,1,1);
std::string enchantmentName = item.getClass().getEnchantment(item);
if (enchantmentName.empty())
return result;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentName);
if (!enchantment)
return result;
assert (enchantment->mEffects.mList.size());
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().search(
enchantment->mEffects.mList.front().mEffectID);
if (!magicEffect)
return result;
result.x() = magicEffect->mData.mRed / 255.f;
result.y() = magicEffect->mData.mGreen / 255.f;
result.z() = magicEffect->mData.mBlue / 255.f;
return result;
}
}

@ -6,6 +6,8 @@
#include <string>
#include <vector>
#include <osg/Vec4f>
#include "ptr.hpp"
namespace ESM
@ -367,6 +369,8 @@ namespace MWWorld
/// Get the effective armor rating, factoring in the actor's skills, for the given armor.
virtual float getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const;
virtual osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
};
}

@ -323,6 +323,8 @@ namespace MWWorld
MWWorld::Ptr ptr = ref.getPtr();
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, osg::Vec4(0,0,0,0));
if (!ptr.getClass().getEnchantment(ptr).empty())
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
mProjectiles.push_back(state);
}

@ -1,10 +1,151 @@
#include "util.hpp"
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/TexGen>
#include <osg/TexEnvCombine>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
namespace SceneUtil
{
class FindLowestUnusedTexUnitVisitor : public osg::NodeVisitor
{
public:
FindLowestUnusedTexUnitVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mLowestUnusedTexUnit(0)
{
}
virtual void apply(osg::Node& node)
{
if (osg::StateSet* stateset = node.getStateSet())
mLowestUnusedTexUnit = std::max(mLowestUnusedTexUnit, int(stateset->getTextureAttributeList().size()));
traverse(node);
}
int mLowestUnusedTexUnit;
};
GlowUpdater::GlowUpdater(int texUnit, const osg::Vec4f& color, const std::vector<osg::ref_ptr<osg::Texture2D> >& textures,
osg::Node* 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)
{
}
void GlowUpdater::setDefaults(osg::StateSet *stateset)
{
if (mDone)
removeTexture(stateset);
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));
}
}
void GlowUpdater::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();
}
void GlowUpdater::apply(osg::StateSet *stateset, osg::NodeVisitor *nv)
{
if (mColorChanged){
this->reset();
setDefaults(stateset);
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
{
removeTexture(stateset);
this->reset();
mDone = true;
mResourceSystem->getSceneManager()->recreateShaders(mNode);
}
if (mOriginalDuration < 0) // if this glowupdater was originally a permanent glow
{
mDuration = mOriginalDuration;
mStartingTime = 0;
mColor = mOriginalColor;
this->reset();
setDefaults(stateset);
}
}
}
bool GlowUpdater::isPermanentGlowUpdater()
{
return (mDuration < 0);
}
bool GlowUpdater::isDone()
{
return mDone;
}
void GlowUpdater::setColor(const osg::Vec4f& color)
{
mColor = color;
mColorChanged = true;
}
void GlowUpdater::setDuration(float duration)
{
mDuration = duration;
}
void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere)
{
osg::BoundingSphere::vec_type xdash = bsphere._center;
@ -73,4 +214,48 @@ bool hasUserDescription(const osg::Node* node, const std::string pattern)
return false;
}
osg::ref_ptr<GlowUpdater> addEnchantedGlow(osg::ref_ptr<osg::Node> node, Resource::ResourceSystem* resourceSystem, osg::Vec4f glowColor, float glowDuration)
{
std::vector<osg::ref_ptr<osg::Texture2D> > 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<osg::Image> image = resourceSystem->getImageManager()->getImage(stream.str());
osg::ref_ptr<osg::Texture2D> 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);
resourceSystem->getSceneManager()->applyFilterSettings(tex);
textures.push_back(tex);
}
FindLowestUnusedTexUnitVisitor findLowestUnusedTexUnitVisitor;
node->accept(findLowestUnusedTexUnitVisitor);
int texUnit = findLowestUnusedTexUnitVisitor.mLowestUnusedTexUnit;
osg::ref_ptr<GlowUpdater> glowUpdater = new GlowUpdater(texUnit, glowColor, textures, node, glowDuration, resourceSystem);
node->addUpdateCallback(glowUpdater);
// set a texture now so that the ShaderVisitor can find it
osg::ref_ptr<osg::StateSet> writableStateSet = nullptr;
if (!node->getStateSet())
writableStateSet = node->getOrCreateStateSet();
else
{
writableStateSet = new osg::StateSet(*node->getStateSet(), osg::CopyOp::SHALLOW_COPY);
node->setStateSet(writableStateSet);
}
writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON);
writableStateSet->addUniform(new osg::Uniform("envMapColor", glowColor));
resourceSystem->getSceneManager()->recreateShaders(node);
return glowUpdater;
}
}

@ -3,10 +3,48 @@
#include <osg/Matrix>
#include <osg/BoundingSphere>
#include <osg/NodeCallback>
#include <osg/Texture2D>
#include <osg/Vec4f>
#include <components/resource/resourcesystem.hpp>
#include "statesetupdater.hpp"
namespace SceneUtil
{
class GlowUpdater : public SceneUtil::StateSetUpdater
{
public:
GlowUpdater(int texUnit, const osg::Vec4f& color, const std::vector<osg::ref_ptr<osg::Texture2D> >& textures,
osg::Node* node, float duration, Resource::ResourceSystem* resourcesystem);
virtual void setDefaults(osg::StateSet *stateset);
void removeTexture(osg::StateSet* stateset);
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
bool isPermanentGlowUpdater();
bool isDone();
void setColor(const osg::Vec4f& color);
void setDuration(float 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<osg::ref_ptr<osg::Texture2D> > mTextures;
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;
Resource::ResourceSystem* mResourceSystem;
bool mColorChanged;
bool mDone;
};
// Transform a bounding sphere by a matrix
// based off private code in osg::Transform
@ -20,6 +58,8 @@ namespace SceneUtil
float makeOsgColorComponent (unsigned int value, unsigned int shift);
bool hasUserDescription(const osg::Node* node, const std::string pattern);
osg::ref_ptr<GlowUpdater> addEnchantedGlow(osg::ref_ptr<osg::Node> node, Resource::ResourceSystem* resourceSystem, osg::Vec4f glowColor, float glowDuration=-1);
}
#endif

Loading…
Cancel
Save