diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 6d37fa1e8..764aa13c6 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -131,6 +131,9 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool std::auto_ptr anim (new ObjectAnimation(ptr, mesh, mResourceSystem)); + if (anim->getObjectRoot()) + anim->getObjectRoot()->addCullCallback(new SceneUtil::LightListCallback); + if (ptr.getTypeName() == typeid(ESM::Light).name() && allowLight) { SceneUtil::FindByNameVisitor visitor("AttachLight"); diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 60315ba7d..5bccd53b3 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -45,122 +45,6 @@ namespace SceneUtil } }; - class CullCallback : public osg::NodeCallback - { - public: - CullCallback() - : mLightManager(NULL) - {} - CullCallback(const CullCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) - {} - CullCallback(LightManager* lightManager) - : mLightManager(lightManager) - {} - - META_Object(NifOsg, CullCallback) - - void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - osgUtil::CullVisitor* cv = static_cast(nv); - - mLightManager->prepareForCamera(cv->getCurrentCamera()); - - // Possible optimizations: - // - cull list of lights by the camera frustum - // - organize lights in a quad tree - - const std::vector& lights = mLightManager->getLights(); - - if (lights.size()) - { - - static std::map > statesets; - std::map >::iterator found = statesets.find(node); - osg::ref_ptr stateset; - if (found != statesets.end()) - { - stateset = found->second; - } - else{ - - // we do the intersections in view space - osg::BoundingSphere nodeBound = node->getBound(); - osg::Matrixf mat = *cv->getModelViewMatrix(); - transformBoundingSphere(mat, nodeBound); - - std::vector lightList; - for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - - if (lightList.size() > maxLights) - { - //std::cerr << "More than 8 lights!" << std::endl; - - // TODO: sort lights by certain criteria - - while (lightList.size() > maxLights) - lightList.pop_back(); - } - - stateset = mLightManager->getLightListStateSet(lightList); - statesets[node] = stateset; - } - - if (stateset) - cv->pushStateSet(stateset); - - traverse(node, nv); - - if (stateset) - cv->popStateSet(); - } - else - traverse(node, nv); - } - - private: - LightManager* mLightManager; - }; - - class AttachCullCallbackVisitor : public osg::NodeVisitor - { - public: - AttachCullCallbackVisitor(LightManager* lightManager) - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mLightManager(lightManager) - { - } - - virtual void apply(osg::Geode &geode) - { - if (!geode.getNumParents()) - return; - - // Not working on a Geode. Drawables are not normal children of the Geode, the traverse() call - // does not traverse the drawables, so the push/pop in the CullCallback has no effect - // Should be no longer an issue with osg trunk - osg::Node* parent = geode.getParent(0); - parent->addCullCallback(new CullCallback(mLightManager)); - } - - private: - LightManager* mLightManager; - }; - // Set on a LightSource. Adds the light source to its light manager for the current frame. // This allows us to keep track of the current lights in the scene graph without tying creation & destruction to the manager. class CollectLightCallback : public osg::NodeCallback @@ -191,7 +75,7 @@ namespace SceneUtil throw std::runtime_error("can't find parent LightManager"); } - //mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); + mLightManager->addLight(static_cast(node), osg::computeLocalToWorld(nv->getNodePath())); traverse(node, nv); } @@ -224,7 +108,6 @@ namespace SceneUtil LightManager::LightManager() : mLightsInViewSpace(false) - , mDecorated(false) , mStartLight(0) { setUpdateCallback(new LightManagerUpdateCallback); @@ -233,29 +116,16 @@ namespace SceneUtil LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) : osg::Group(copy, copyop) , mLightsInViewSpace(false) - , mDecorated(copy.mDecorated) , mStartLight(copy.mStartLight) { } - void LightManager::decorateGeodes() - { - AttachCullCallbackVisitor visitor(this); - accept(visitor); - } - void LightManager::update() { mLightsInViewSpace = false; mLights.clear(); mStateSetCache.clear(); - - if (!mDecorated) - { - decorateGeodes(); - mDecorated = true; - } } void LightManager::addLight(LightSource* lightSource, osg::Matrix worldMat) @@ -338,4 +208,90 @@ namespace SceneUtil setUpdateCallback(new CollectLightCallback); } + void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + if (!mLightManager) + { + for (unsigned int i=0;igetNodePath().size(); ++i) + { + if (LightManager* lightManager = dynamic_cast(nv->getNodePath()[i])) + { + mLightManager = lightManager; + break; + } + } + if (!mLightManager) + return; + } + + mLightManager->prepareForCamera(cv->getCurrentCamera()); + + // Possible optimizations: + // - cull list of lights by the camera frustum + // - organize lights in a quad tree + + const std::vector& lights = mLightManager->getLights(); + + if (lights.size()) + { + + static std::map > statesets; + std::map >::iterator found = statesets.find(node); + osg::ref_ptr stateset; + if (found != statesets.end()) + { + stateset = found->second; + } + else{ + + // we do the intersections in view space + osg::BoundingSphere nodeBound = node->getBound(); + osg::Matrixf mat = *cv->getModelViewMatrix(); + transformBoundingSphere(mat, nodeBound); + + std::vector lightList; + for (unsigned int i=0; i (8 - mLightManager->getStartLight()); + + if (lightList.size() > maxLights) + { + //std::cerr << "More than 8 lights!" << std::endl; + + // TODO: sort lights by certain criteria + + while (lightList.size() > maxLights) + lightList.pop_back(); + } + + stateset = mLightManager->getLightListStateSet(lightList); + statesets[node] = stateset; + } + + if (stateset) + cv->pushStateSet(stateset); + + traverse(node, nv); + + if (stateset) + cv->popStateSet(); + } + else + traverse(node, nv); + } + } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index fe5dc5082..1cd73589a 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -71,8 +71,6 @@ namespace SceneUtil void prepareForCamera(osg::Camera* cam); - void decorateGeodes(); - struct LightSourceTransform { LightSource* mLightSource; @@ -102,11 +100,28 @@ namespace SceneUtil typedef std::map > LightStateSetMap; LightStateSetMap mStateSetCache; - bool mDecorated; - int mStartLight; }; + class LightListCallback : public osg::NodeCallback + { + public: + LightListCallback() + : mLightManager(NULL) + {} + LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + {} + + META_Object(NifOsg, LightListCallback) + + void operator()(osg::Node* node, osg::NodeVisitor* nv); + + private: + LightManager* mLightManager; + }; + + } #endif