From 11565b59665bab0824801e296a4386163842fd94 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 8 Oct 2016 03:49:50 +0200 Subject: [PATCH] Make actors with non-portable lights in inventory glow (Closes #2042, #3338) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/actoranimation.cpp | 155 +++++++++++++++++++++ apps/openmw/mwrender/actoranimation.hpp | 58 ++++++++ apps/openmw/mwrender/animation.cpp | 2 + apps/openmw/mwrender/animation.hpp | 2 + apps/openmw/mwrender/creatureanimation.cpp | 6 +- apps/openmw/mwrender/creatureanimation.hpp | 6 +- apps/openmw/mwrender/npcanimation.cpp | 9 +- apps/openmw/mwrender/npcanimation.hpp | 3 +- apps/openmw/mwworld/containerstore.cpp | 17 +++ apps/openmw/mwworld/containerstore.hpp | 12 ++ apps/openmw/mwworld/inventorystore.cpp | 4 +- apps/openmw/mwworld/inventorystore.hpp | 4 +- components/sceneutil/lightmanager.cpp | 4 + components/sceneutil/lightmanager.hpp | 6 + components/sceneutil/lightutil.cpp | 14 +- components/sceneutil/lightutil.hpp | 13 ++ 17 files changed, 297 insertions(+), 20 deletions(-) create mode 100644 apps/openmw/mwrender/actoranimation.cpp create mode 100644 apps/openmw/mwrender/actoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index aba2a6af4..58dc2e8e5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,7 +23,7 @@ add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation - renderbin + renderbin actoranimation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp new file mode 100644 index 000000000..1a3285713 --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -0,0 +1,155 @@ +#include "actoranimation.hpp" + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#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 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()->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()->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 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::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(callback)) + return lightListCallback; + } + while ((callback = callback->getNestedCallback())); + } + return NULL; +} + +} diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp new file mode 100644 index 000000000..e08df54f2 --- /dev/null +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_RENDER_ACTORANIMATION_H +#define GAME_RENDER_ACTORANIMATION_H + +#include + +#include + +#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 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 > ItemLightMap; + ItemLightMap mItemLights; + + bool mListenerDisabled; +}; + +} + +#endif diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 709780307..e4855064a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1151,6 +1151,8 @@ namespace MWRender } mObjectRoot->addCullCallback(new SceneUtil::LightListCallback); + + objectRootReset(); } osg::Group* Animation::getObjectRoot() diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 089d0d85b..cf6afd613 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -307,6 +307,8 @@ protected: */ 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 * file extension will be replaced with .kf. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 669d0d8a1..a095d5dd4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -18,7 +18,7 @@ namespace MWRender CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) - : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) + : ActorAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) { MWWorld::LiveCellRef *ref = mPtr.get(); @@ -34,7 +34,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem) - : Animation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) + : ActorAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), resourceSystem) , mShowWeapons(false) , mShowCarriedLeft(false) { @@ -48,7 +48,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const addAnimSource("meshes\\xbase_anim.nif"); addAnimSource(model); - mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); + mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); updateParts(); } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index a62160253..bf813075e 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -1,7 +1,7 @@ #ifndef GAME_RENDER_CREATUREANIMATION_H #define GAME_RENDER_CREATUREANIMATION_H -#include "animation.hpp" +#include "actoranimation.hpp" #include "weaponanimation.hpp" #include "../mwworld/inventorystore.hpp" @@ -12,7 +12,7 @@ namespace MWWorld namespace MWRender { - class CreatureAnimation : public Animation + class CreatureAnimation : public ActorAnimation { public: CreatureAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); @@ -22,7 +22,7 @@ namespace MWRender // For creatures with weapons and shields // 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. - class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener + class CreatureWeaponAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const std::string& model, Resource::ResourceSystem* resourceSystem); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 64cc6d26c..8574939af 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // TextKeyMapHolder @@ -272,8 +273,8 @@ NpcAnimation::~NpcAnimation() // No need to getInventoryStore() to reset, if none exists // This is to avoid triggering the listener via ensureCustomData()->autoEquip()->fireEquipmentChanged() // all from within this destructor. ouch! - && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getListener() == this) - mPtr.getClass().getInventoryStore(mPtr).setListener(NULL, mPtr); + && mPtr.getRefData().getCustomData() && mPtr.getClass().getInventoryStore(mPtr).getInvListener() == this) + mPtr.getClass().getInventoryStore(mPtr).setInvListener(NULL, mPtr); // 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++) @@ -285,7 +286,7 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem, bool disableListener, bool disableSounds, ViewMode viewMode, float firstPersonFieldOfView) - : Animation(ptr, parentNode, resourceSystem), + : ActorAnimation(ptr, parentNode, resourceSystem, disableListener), mListenerDisabled(disableListener), mViewMode(viewMode), mShowWeapons(false), @@ -310,7 +311,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr par updateNpcBase(); if (!disableListener) - mPtr.getClass().getInventoryStore(mPtr).setListener(this, mPtr); + mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); } void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 9134f8f5f..892851890 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -5,6 +5,7 @@ #include "../mwworld/inventorystore.hpp" +#include "actoranimation.hpp" #include "weaponanimation.hpp" namespace ESM @@ -19,7 +20,7 @@ namespace MWRender class NeckController; class HeadAnimationTime; -class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener +class NpcAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener { public: virtual void equipmentChanged(); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7eb7c31c7..112325892 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -136,6 +136,17 @@ int MWWorld::ContainerStore::count(const std::string &id) 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) { if (ptr.getRefData().getCount() <= count) @@ -292,6 +303,9 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr item.getRefData().getLocals().setVarByInt(script, "onpcadd", 1); } + if (mListener) + mListener->itemAdded(item, count); + return it; } @@ -398,6 +412,9 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor flagAsModified(); + if (mListener) + mListener->itemRemoved(item, count - toRemove); + // number of removed items return count - toRemove; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 6a8fc4761..0c95d2dba 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -31,6 +31,13 @@ namespace MWWorld { class ContainerStoreIterator; + class ContainerStoreListener + { + public: + virtual void itemAdded(const ConstPtr& item, int count) {} + virtual void itemRemoved(const ConstPtr& item, int count) {} + }; + class ContainerStore { public: @@ -73,6 +80,8 @@ namespace MWWorld ///< Stores result of levelled item spawns. <(refId, spawningGroup), count> /// This is used to restock levelled items(s) if the old item was sold. + ContainerStoreListener* mListener; + mutable float mCachedWeight; mutable bool mWeightUpToDate; 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? int count (const std::string& id); + ContainerStoreListener* getContListener() const; + void setContListener(ContainerStoreListener* listener); + protected: ContainerStoreIterator addNewStack (const ConstPtr& ptr, int count); ///< Add the item to this container (do not try to stack it onto existing items) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2c25029da..aa6880a49 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -606,12 +606,12 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItemQuantity(con return unstack(item, actor, item.getRefData().getCount() - count); } -MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getListener() +MWWorld::InventoryStoreListener* MWWorld::InventoryStore::getInvListener() { return mListener; } -void MWWorld::InventoryStore::setListener(InventoryStoreListener *listener, const Ptr& actor) +void MWWorld::InventoryStore::setInvListener(InventoryStoreListener *listener, const Ptr& actor) { mListener = listener; updateMagicEffects(actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 152176fbe..9e0a8d5b6 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -197,10 +197,10 @@ namespace MWWorld /// in the slot (they can be re-stacked so its count may be different /// 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 - InventoryStoreListener* getListener(); + InventoryStoreListener* getInvListener(); void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index f7c0573a4..906da5967 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -359,6 +359,10 @@ namespace SceneUtil for (unsigned int i=0; i + #include #include @@ -157,16 +159,20 @@ namespace SceneUtil : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) , mLightManager(copy.mLightManager) , mLastFrameNumber(0) + , mIgnoredLightSources(copy.mIgnoredLightSources) {} META_Object(SceneUtil, LightListCallback) void operator()(osg::Node* node, osg::NodeVisitor* nv); + std::set& getIgnoredLightSources() { return mIgnoredLightSources; } + private: LightManager* mLightManager; unsigned int mLastFrameNumber; LightManager::LightList mLightList; + std::set mIgnoredLightSources; }; } diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 6499c54b1..5ad9bd6dc 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -36,7 +36,6 @@ namespace SceneUtil light->setLinearAttenuation(linearAttenuation); light->setQuadraticAttenuation(quadraticAttenuation); 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, @@ -68,6 +67,14 @@ namespace SceneUtil attachTo = trans; } + osg::ref_ptr lightSource = createLightSource(esmLight, lightMask, isExterior, outQuadInLin, useQuadratic, quadraticValue, + quadraticRadiusMult, useLinear, linearRadiusMult, linearValue); + attachTo->addChild(lightSource); + } + + osg::ref_ptr 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 lightSource (new SceneUtil::LightSource); osg::ref_ptr light (new osg::Light); lightSource->setNodeMask(lightMask); @@ -85,7 +92,7 @@ namespace SceneUtil diffuse.a() = 1; } light->setDiffuse(diffuse); - light->setAmbient(osg::Vec4f(0,0,0,1)); + light->setAmbient(ambient); light->setSpecular(osg::Vec4f(0,0,0,0)); lightSource->setLight(light); @@ -103,7 +110,6 @@ namespace SceneUtil lightSource->addUpdateCallback(ctrl); - attachTo->addChild(lightSource); + return lightSource; } - } diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp index d6c970340..95172e239 100644 --- a/components/sceneutil/lightutil.hpp +++ b/components/sceneutil/lightutil.hpp @@ -1,6 +1,9 @@ #ifndef OPENMW_COMPONENTS_LIGHTUTIL_H #define OPENMW_COMPONENTS_LIGHTUTIL_H +#include +#include + namespace osg { class Group; @@ -13,6 +16,7 @@ namespace ESM namespace SceneUtil { + class LightSource; /// @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. @@ -27,6 +31,15 @@ namespace SceneUtil float quadraticValue, float quadraticRadiusMult, bool useLinear, float linearRadiusMult, 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 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