mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 06:39:40 +00:00
Merge pull request #2476 from akortunov/arrows
Use magic glow for enchanted arrows
This commit is contained in:
commit
ed364a1e29
11 changed files with 295 additions and 240 deletions
|
@ -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…
Reference in a new issue