Make actors with non-portable lights in inventory glow (Closes #2042, #3338)

pull/75/head
MiroslavR 8 years ago
parent 5c94e2324f
commit 11565b5966

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin renderbin actoranimation
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

@ -0,0 +1,155 @@
#include "actoranimation.hpp"
#include <utility>
#include <osg/Node>
#include <osg/Group>
#include <osg/Vec4f>
#include <components/esm/loadligh.hpp>
#include <components/esm/loadcell.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/lightutil.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "vismask.hpp"
namespace MWRender
{
ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableListener)
: Animation(ptr, parentNode, resourceSystem),
mListenerDisabled(disableListener)
{
MWWorld::ContainerStore& store = mPtr.getClass().getContainerStore(mPtr);
for (MWWorld::ContainerStoreIterator iter = store.begin(MWWorld::ContainerStore::Type_Light); iter != store.end(); ++iter)
{
const ESM::Light* light = iter->get<ESM::Light>()->mBase;
if (!(light->mData.mFlags & ESM::Light::Carry))
{
addHiddenItemLight(*iter, light);
}
}
if (!mListenerDisabled)
store.setContListener(this);
}
ActorAnimation::~ActorAnimation()
{
if (!mListenerDisabled && mPtr.getRefData().getCustomData() && mPtr.getClass().getContainerStore(mPtr).getContListener() == this)
mPtr.getClass().getContainerStore(mPtr).setContListener(NULL);
for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter)
{
mInsert->removeChild(iter->second);
}
}
void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)
{
if (item.getTypeName() == typeid(ESM::Light).name())
{
const ESM::Light* light = item.get<ESM::Light>()->mBase;
if (!(light->mData.mFlags & ESM::Light::Carry))
{
addHiddenItemLight(item, light);
}
}
}
void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/)
{
if (item.getTypeName() == typeid(ESM::Light).name())
{
ItemLightMap::iterator iter = mItemLights.find(item);
if (iter != mItemLights.end())
{
if (!item.getRefData().getCount())
{
removeHiddenItemLight(item);
}
}
}
}
void ActorAnimation::objectRootReset()
{
if (SceneUtil::LightListCallback* callback = findLightListCallback())
{
for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter)
{
callback->getIgnoredLightSources().insert(iter->second);
}
}
}
void ActorAnimation::addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight)
{
if (mItemLights.find(item) != mItemLights.end())
return;
const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback();
static bool outQuadInLin = fallback->getFallbackBool("LightAttenuation_OutQuadInLin");
static bool useQuadratic = fallback->getFallbackBool("LightAttenuation_UseQuadratic");
static float quadraticValue = fallback->getFallbackFloat("LightAttenuation_QuadraticValue");
static float quadraticRadiusMult = fallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult");
static bool useLinear = fallback->getFallbackBool("LightAttenuation_UseLinear");
static float linearRadiusMult = fallback->getFallbackFloat("LightAttenuation_LinearRadiusMult");
static float linearValue = fallback->getFallbackFloat("LightAttenuation_LinearValue");
bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior();
osg::Vec4f ambient(1,1,1,1);
osg::ref_ptr<SceneUtil::LightSource> lightSource = SceneUtil::createLightSource(esmLight, Mask_Lighting, exterior, outQuadInLin,
useQuadratic, quadraticValue, quadraticRadiusMult, useLinear, linearRadiusMult, linearValue, ambient);
mInsert->addChild(lightSource);
if (SceneUtil::LightListCallback* callback = findLightListCallback())
callback->getIgnoredLightSources().insert(lightSource.get());
mItemLights.insert(std::make_pair(item, lightSource));
}
void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item)
{
ItemLightMap::iterator iter = mItemLights.find(item);
if (iter == mItemLights.end())
return;
if (SceneUtil::LightListCallback* callback = findLightListCallback())
{
std::set<SceneUtil::LightSource*>::iterator ignoredIter = callback->getIgnoredLightSources().find(iter->second.get());
if (ignoredIter != callback->getIgnoredLightSources().end())
callback->getIgnoredLightSources().erase(ignoredIter);
}
mInsert->removeChild(iter->second);
mItemLights.erase(iter);
}
SceneUtil::LightListCallback* ActorAnimation::findLightListCallback()
{
if (osg::Callback* callback = mObjectRoot->getCullCallback())
{
do
{
if (SceneUtil::LightListCallback* lightListCallback = dynamic_cast<SceneUtil::LightListCallback *>(callback))
return lightListCallback;
}
while ((callback = callback->getNestedCallback()));
}
return NULL;
}
}

@ -0,0 +1,58 @@
#ifndef GAME_RENDER_ACTORANIMATION_H
#define GAME_RENDER_ACTORANIMATION_H
#include <map>
#include <osg/ref_ptr>
#include "../mwworld/containerstore.hpp"
#include "animation.hpp"
namespace osg
{
class Node;
}
namespace MWWorld
{
class ConstPtr;
}
namespace SceneUtil
{
class LightSource;
class LightListCallback;
}
namespace MWRender
{
class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
{
public:
ActorAnimation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableListener=false);
virtual ~ActorAnimation();
virtual void itemAdded(const MWWorld::ConstPtr& item, int count);
virtual void itemRemoved(const MWWorld::ConstPtr& item, int count);
protected:
virtual void objectRootReset();
private:
void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight);
void removeHiddenItemLight(const MWWorld::ConstPtr& item);
SceneUtil::LightListCallback* findLightListCallback();
typedef std::map<MWWorld::ConstPtr, osg::ref_ptr<SceneUtil::LightSource> > ItemLightMap;
ItemLightMap mItemLights;
bool mListenerDisabled;
};
}
#endif

@ -1151,6 +1151,8 @@ namespace MWRender
} }
mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); mObjectRoot->addCullCallback(new SceneUtil::LightListCallback);
objectRootReset();
} }
osg::Group* Animation::getObjectRoot() osg::Group* Animation::getObjectRoot()

@ -307,6 +307,8 @@ protected:
*/ */
void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature);
virtual void objectRootReset() {}
/** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif
* file extension will be replaced with .kf. * file extension will be replaced with .kf.
* @note Later added animation sources have the highest priority when it comes to finding a particular animation. * @note Later added animation sources have the highest priority when it comes to finding a particular animation.

@ -18,7 +18,7 @@ namespace MWRender
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
const std::string& model, Resource::ResourceSystem* resourceSystem) const std::string& model, Resource::ResourceSystem* resourceSystem)
: Animation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem) : ActorAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>(); MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
@ -34,7 +34,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem)
: Animation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem) : ActorAnimation(ptr, osg::ref_ptr<osg::Group>(ptr.getRefData().getBaseNode()), resourceSystem)
, mShowWeapons(false) , mShowWeapons(false)
, mShowCarriedLeft(false) , mShowCarriedLeft(false)
{ {
@ -48,7 +48,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
addAnimSource("meshes\\xbase_anim.nif"); addAnimSource("meshes\\xbase_anim.nif");
addAnimSource(model); addAnimSource(model);
mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
updateParts(); updateParts();
} }

@ -1,7 +1,7 @@
#ifndef GAME_RENDER_CREATUREANIMATION_H #ifndef GAME_RENDER_CREATUREANIMATION_H
#define GAME_RENDER_CREATUREANIMATION_H #define GAME_RENDER_CREATUREANIMATION_H
#include "animation.hpp" #include "actoranimation.hpp"
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
@ -12,7 +12,7 @@ namespace MWWorld
namespace MWRender namespace MWRender
{ {
class CreatureAnimation : public Animation class CreatureAnimation : public ActorAnimation
{ {
public: public:
CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);
@ -22,7 +22,7 @@ namespace MWRender
// For creatures with weapons and shields // For creatures with weapons and shields
// Animation is already virtual anyway, so might as well make a separate class. // Animation is already virtual anyway, so might as well make a separate class.
// Most creatures don't need weapons/shields, so this will save some memory. // Most creatures don't need weapons/shields, so this will save some memory.
class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener class CreatureWeaponAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{ {
public: public:
CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem);

@ -16,6 +16,7 @@
#include <components/sceneutil/attach.hpp> #include <components/sceneutil/attach.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include <components/nifosg/nifloader.hpp> // TextKeyMapHolder #include <components/nifosg/nifloader.hpp> // TextKeyMapHolder
@ -272,8 +273,8 @@ NpcAnimation::~NpcAnimation()
// No need to getInventoryStore() to reset, if none exists // No need to getInventoryStore() to reset, if none exists
// This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged()
// all from within this destructor. ouch! // all from within this destructor. ouch!
&& mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getInvListener() == this)
mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(NULL, mPtr);
// do not detach (delete) parts yet, this is done so the background thread can handle the deletion // do not detach (delete) parts yet, this is done so the background thread can handle the deletion
for(size_t i = 0;i < ESM::PRT_Count;i++) for(size_t i = 0;i < ESM::PRT_Count;i++)
@ -285,7 +286,7 @@ NpcAnimation::~NpcAnimation()
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem, NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView)
: Animation(ptr, parentNode, resourceSystem), : ActorAnimation(ptr, parentNode, resourceSystem, disableListener),
mListenerDisabled(disableListener), mListenerDisabled(disableListener),
mViewMode(viewMode), mViewMode(viewMode),
mShowWeapons(false), mShowWeapons(false),
@ -310,7 +311,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
updateNpcBase(); updateNpcBase();
if (!disableListener) if (!disableListener)
mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr);
} }
void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)

@ -5,6 +5,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "actoranimation.hpp"
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
namespace ESM namespace ESM
@ -19,7 +20,7 @@ namespace MWRender
class NeckController; class NeckController;
class HeadAnimationTime; class HeadAnimationTime;
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener class NpcAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener
{ {
public: public:
virtual void equipmentChanged(); virtual void equipmentChanged();

@ -136,6 +136,17 @@ int MWWorld::ContainerStore::count(const std::string &id)
return total; return total;
} }
MWWorld::ContainerStoreListener* MWWorld::ContainerStore::getContListener() const
{
return mListener;
}
void MWWorld::ContainerStore::setContListener(MWWorld::ContainerStoreListener* listener)
{
mListener = listener;
}
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::unstack(const Ptr &ptr, const Ptr& container, int count)
{ {
if (ptr.getRefData().getCount() <= count) if (ptr.getRefData().getCount() <= count)
@ -292,6 +303,9 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1); item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1);
} }
if (mListener)
mListener->itemAdded(item, count);
return it; return it;
} }
@ -398,6 +412,9 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
flagAsModified(); flagAsModified();
if (mListener)
mListener->itemRemoved(item, count - toRemove);
// number of removed items // number of removed items
return count - toRemove; return count - toRemove;
} }

@ -31,6 +31,13 @@ namespace MWWorld
{ {
class ContainerStoreIterator; class ContainerStoreIterator;
class ContainerStoreListener
{
public:
virtual void itemAdded(const ConstPtr& item, int count) {}
virtual void itemRemoved(const ConstPtr& item, int count) {}
};
class ContainerStore class ContainerStore
{ {
public: public:
@ -73,6 +80,8 @@ namespace MWWorld
///< Stores result of levelled item spawns. <(refId, spawningGroup), count> ///< Stores result of levelled item spawns. <(refId, spawningGroup), count>
/// This is used to restock levelled items(s) if the old item was sold. /// This is used to restock levelled items(s) if the old item was sold.
ContainerStoreListener* mListener;
mutable float mCachedWeight; mutable float mCachedWeight;
mutable bool mWeightUpToDate; mutable bool mWeightUpToDate;
ContainerStoreIterator addImp (const Ptr& ptr, int count); ContainerStoreIterator addImp (const Ptr& ptr, int count);
@ -143,6 +152,9 @@ namespace MWWorld
/// @return How many items with refID \a id are in this container? /// @return How many items with refID \a id are in this container?
int count (const std::string& id); int count (const std::string& id);
ContainerStoreListener* getContListener() const;
void setContListener(ContainerStoreListener* listener);
protected: protected:
ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count);
///< Add the item to this container (do not try to stack it onto existing items) ///< Add the item to this container (do not try to stack it onto existing items)

@ -606,12 +606,12 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(con
return unstack(item, actor, item.getRefData().getCount() - count); return unstack(item, actor, item.getRefData().getCount() - count);
} }
MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener()
{ {
return mListener; return mListener;
} }
void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) void MWWorld::InventoryStore::setInvListener(InventoryStoreListener *listener, const Ptr& actor)
{ {
mListener = listener; mListener = listener;
updateMagicEffects(actor); updateMagicEffects(actor);

@ -197,10 +197,10 @@ namespace MWWorld
/// in the slot (they can be re-stacked so its count may be different /// in the slot (they can be re-stacked so its count may be different
/// than the requested count). /// than the requested count).
void setListener (InventoryStoreListener* listener, const Ptr& actor); void setInvListener (InventoryStoreListener* listener, const Ptr& actor);
///< Set a listener for various events, see \a InventoryStoreListener ///< Set a listener for various events, see \a InventoryStoreListener
InventoryStoreListener* getListener(); InventoryStoreListener* getInvListener();
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);

@ -359,6 +359,10 @@ namespace SceneUtil
for (unsigned int i=0; i<lights.size(); ++i) for (unsigned int i=0; i<lights.size(); ++i)
{ {
const LightManager::LightSourceViewBound& l = lights[i]; const LightManager::LightSourceViewBound& l = lights[i];
if (mIgnoredLightSources.count(l.mLightSource))
continue;
if (l.mViewBound.intersects(nodeBound)) if (l.mViewBound.intersects(nodeBound))
mLightList.push_back(&l); mLightList.push_back(&l);
} }

@ -1,6 +1,8 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H #ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H #define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#include <set>
#include <osg/Light> #include <osg/Light>
#include <osg/Group> #include <osg/Group>
@ -157,16 +159,20 @@ namespace SceneUtil
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop)
, mLightManager(copy.mLightManager) , mLightManager(copy.mLightManager)
, mLastFrameNumber(0) , mLastFrameNumber(0)
, mIgnoredLightSources(copy.mIgnoredLightSources)
{} {}
META_Object(SceneUtil, LightListCallback) META_Object(SceneUtil, LightListCallback)
void operator()(osg::Node* node, osg::NodeVisitor* nv); void operator()(osg::Node* node, osg::NodeVisitor* nv);
std::set<SceneUtil::LightSource*>& getIgnoredLightSources() { return mIgnoredLightSources; }
private: private:
LightManager* mLightManager; LightManager* mLightManager;
unsigned int mLastFrameNumber; unsigned int mLastFrameNumber;
LightManager::LightList mLightList; LightManager::LightList mLightList;
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
}; };
} }

@ -36,7 +36,6 @@ namespace SceneUtil
light->setLinearAttenuation(linearAttenuation); light->setLinearAttenuation(linearAttenuation);
light->setQuadraticAttenuation(quadraticAttenuation); light->setQuadraticAttenuation(quadraticAttenuation);
light->setConstantAttenuation(0.f); light->setConstantAttenuation(0.f);
} }
void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, void addLight (osg::Group* node, const ESM::Light* esmLight, unsigned int partsysMask, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic,
@ -68,6 +67,14 @@ namespace SceneUtil
attachTo = trans; attachTo = trans;
} }
osg::ref_ptr<LightSource> lightSource = createLightSource(esmLight, lightMask, isExterior, outQuadInLin, useQuadratic, quadraticValue,
quadraticRadiusMult, useLinear, linearRadiusMult, linearValue);
attachTo->addChild(lightSource);
}
osg::ref_ptr<LightSource> createLightSource(const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue,
float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue, const osg::Vec4f& ambient)
{
osg::ref_ptr<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource); osg::ref_ptr<SceneUtil::LightSource> lightSource (new SceneUtil::LightSource);
osg::ref_ptr<osg::Light> light (new osg::Light); osg::ref_ptr<osg::Light> light (new osg::Light);
lightSource->setNodeMask(lightMask); lightSource->setNodeMask(lightMask);
@ -85,7 +92,7 @@ namespace SceneUtil
diffuse.a() = 1; diffuse.a() = 1;
} }
light->setDiffuse(diffuse); light->setDiffuse(diffuse);
light->setAmbient(osg::Vec4f(0,0,0,1)); light->setAmbient(ambient);
light->setSpecular(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0));
lightSource->setLight(light); lightSource->setLight(light);
@ -103,7 +110,6 @@ namespace SceneUtil
lightSource->addUpdateCallback(ctrl); lightSource->addUpdateCallback(ctrl);
attachTo->addChild(lightSource); return lightSource;
} }
} }

@ -1,6 +1,9 @@
#ifndef OPENMW_COMPONENTS_LIGHTUTIL_H #ifndef OPENMW_COMPONENTS_LIGHTUTIL_H
#define OPENMW_COMPONENTS_LIGHTUTIL_H #define OPENMW_COMPONENTS_LIGHTUTIL_H
#include <osg/ref_ptr>
#include <osg/Vec4f>
namespace osg namespace osg
{ {
class Group; class Group;
@ -13,6 +16,7 @@ namespace ESM
namespace SceneUtil namespace SceneUtil
{ {
class LightSource;
/// @brief Convert an ESM::Light to a SceneUtil::LightSource, and add it to a sub graph. /// @brief Convert an ESM::Light to a SceneUtil::LightSource, and add it to a sub graph.
/// @note If the sub graph contains a node named "AttachLight" (case insensitive), then the light is added to that. /// @note If the sub graph contains a node named "AttachLight" (case insensitive), then the light is added to that.
@ -27,6 +31,15 @@ namespace SceneUtil
float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult,
float linearValue); float linearValue);
/// @brief Convert an ESM::Light to a SceneUtil::LightSource, and return it.
/// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc.
/// @param lightMask Mask to assign to the newly created LightSource.
/// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use.
/// @param ambient Ambient component of the light.
/// @par Attenuation parameters come from the game INI file.
osg::ref_ptr<LightSource> createLightSource (const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, bool outQuadInLin, bool useQuadratic,
float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue, const osg::Vec4f& ambient=osg::Vec4f(0,0,0,1));
} }
#endif #endif

Loading…
Cancel
Save