Move texture filtering settings to SceneManager

Practical benefits:

- Filter settings are now applied to native OSG format models. These models do not use TextureManager::getTexture2D since the model itself specifies a Texture.
- The GUI render manager will be able to use its own separate textures, making it easier to turn off filtering for them.
pull/893/head
scrawl 9 years ago
parent b06730ac61
commit 5b972ee777

@ -20,7 +20,7 @@
#include <components/sdlutil/imagetosurface.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/compiler/extensions0.hpp>
@ -448,8 +448,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);
mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get()));
mResourceSystem->getTextureManager()->setUnRefImageDataAfterApply(true);
mResourceSystem->getTextureManager()->setFilterSettings(
mResourceSystem->getSceneManager()->setUnRefImageDataAfterApply(true);
mResourceSystem->getSceneManager()->setFilterSettings(
Settings::Manager::getString("texture mag filter", "General"),
Settings::Manager::getString("texture min filter", "General"),
Settings::Manager::getString("texture mipmap", "General"),

@ -1059,7 +1059,9 @@ namespace MWRender
stream << i;
stream << ".dds";
textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT));
osg::ref_ptr<osg::Texture2D> tex = mResourceSystem->getTextureManager()->getTexture2D(stream.str(), osg::Texture2D::REPEAT, osg::Texture2D::REPEAT);
mResourceSystem->getSceneManager()->applyFilterSettings(tex);
textures.push_back(tex);
}
osg::ref_ptr<GlowUpdater> glowupdater (new GlowUpdater(glowColor, textures));

@ -776,7 +776,7 @@ namespace MWRender
void RenderingManager::updateTextureFiltering()
{
mResourceSystem->getTextureManager()->setFilterSettings(
mResourceSystem->getSceneManager()->setFilterSettings(
Settings::Manager::getString("texture mag filter", "General"),
Settings::Manager::getString("texture min filter", "General"),
Settings::Manager::getString("texture mipmap", "General"),

@ -305,6 +305,8 @@ namespace NifOsg
META_Object(NifOsg, FlipController)
std::vector<osg::ref_ptr<osg::Texture2D> >& getTextures() { return mTextures; }
virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv);
};

@ -9,6 +9,8 @@
#include <osgUtil/IncrementalCompileOperation>
#include <osgViewer/Viewer>
#include <osgDB/SharedStateManager>
#include <osgDB/Registry>
@ -19,6 +21,7 @@
#include <components/sceneutil/clone.hpp>
#include <components/sceneutil/util.hpp>
#include <components/sceneutil/controller.hpp>
#include "texturemanager.hpp"
#include "niffilemanager.hpp"
@ -105,10 +108,123 @@ namespace
namespace Resource
{
/// Set texture filtering settings on textures contained in a FlipController.
class SetFilterSettingsControllerVisitor : public SceneUtil::ControllerVisitor
{
public:
SetFilterSettingsControllerVisitor(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy)
: mMinFilter(minFilter)
, mMagFilter(magFilter)
, mMaxAnisotropy(maxAnisotropy)
{
}
virtual void visit(osg::Node& node, SceneUtil::Controller& ctrl)
{
if (NifOsg::FlipController* flipctrl = dynamic_cast<NifOsg::FlipController*>(&ctrl))
{
for (std::vector<osg::ref_ptr<osg::Texture2D> >::iterator it = flipctrl->getTextures().begin(); it != flipctrl->getTextures().end(); ++it)
{
osg::Texture* tex = *it;
tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
tex->setMaxAnisotropy(mMaxAnisotropy);
mTexturesProcessed.insert(tex);
}
}
}
const std::set<osg::ref_ptr<osg::Texture> >& getTexturesProcessed()
{
return mTexturesProcessed;
}
private:
osg::Texture::FilterMode mMinFilter;
osg::Texture::FilterMode mMagFilter;
int mMaxAnisotropy;
std::set<osg::ref_ptr<osg::Texture> > mTexturesProcessed;
};
/// Set texture filtering settings on textures contained in StateSets.
class SetFilterSettingsVisitor : public osg::NodeVisitor
{
public:
SetFilterSettingsVisitor(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mMinFilter(minFilter)
, mMagFilter(magFilter)
, mMaxAnisotropy(maxAnisotropy)
{
}
virtual void apply(osg::Node& node)
{
osg::StateSet* stateset = node.getStateSet();
if (stateset)
apply(stateset);
traverse(node);
}
virtual void apply(osg::Geode& geode)
{
osg::StateSet* stateset = geode.getStateSet();
if (stateset)
apply(stateset);
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drw = geode.getDrawable(i);
stateset = drw->getStateSet();
if (stateset)
apply(stateset);
}
}
void apply(osg::StateSet* stateset)
{
const osg::StateSet::TextureAttributeList& texAttributes = stateset->getTextureAttributeList();
for(unsigned int unit=0;unit<texAttributes.size();++unit)
{
osg::StateAttribute *texture = stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE);
apply(texture);
}
}
void apply(osg::StateAttribute* attr)
{
osg::Texture* tex = attr->asTexture();
if (tex)
{
tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
tex->setMaxAnisotropy(mMaxAnisotropy);
mTexturesProcessed.insert(tex);
}
}
const std::set<osg::ref_ptr<osg::Texture> >& getTexturesProcessed()
{
return mTexturesProcessed;
}
private:
osg::Texture::FilterMode mMinFilter;
osg::Texture::FilterMode mMagFilter;
int mMaxAnisotropy;
std::set<osg::ref_ptr<osg::Texture> > mTexturesProcessed;
};
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager, Resource::NifFileManager* nifFileManager)
: mVFS(vfs)
, mTextureManager(textureManager)
, mNifFileManager(nifFileManager)
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
, mMagFilter(osg::Texture::LINEAR)
, mMaxAnisotropy(1)
, mUnRefImageDataAfterApply(false)
, mParticleSystemMask(~0u)
{
}
@ -219,6 +335,17 @@ namespace Resource
throw;
}
// set filtering settings
SetFilterSettingsVisitor setFilterSettingsVisitor(mMinFilter, mMagFilter, mMaxAnisotropy);
loaded->accept(setFilterSettingsVisitor);
SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy);
loaded->accept(setFilterSettingsControllerVisitor);
// remember which textures we set a filtering setting on so we can re-apply it when the setting changes
mTexturesWithFilterSetting.insert(setFilterSettingsVisitor.getTexturesProcessed().begin(), setFilterSettingsVisitor.getTexturesProcessed().end());
mTexturesWithFilterSetting.insert(setFilterSettingsControllerVisitor.getTexturesProcessed().begin(), setFilterSettingsControllerVisitor.getTexturesProcessed().end());
// share state
osgDB::Registry::instance()->getOrCreateSharedStateManager()->share(loaded.get());
if (mIncrementalCompileOperation)
@ -285,4 +412,84 @@ namespace Resource
mParticleSystemMask = mask;
}
void SceneManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter,
const std::string &mipmap, int maxAnisotropy,
osgViewer::Viewer *viewer)
{
osg::Texture::FilterMode min = osg::Texture::LINEAR;
osg::Texture::FilterMode mag = osg::Texture::LINEAR;
if(magfilter == "nearest")
mag = osg::Texture::NEAREST;
else if(magfilter != "linear")
std::cerr<< "Invalid texture mag filter: "<<magfilter <<std::endl;
if(minfilter == "nearest")
min = osg::Texture::NEAREST;
else if(minfilter != "linear")
std::cerr<< "Invalid texture min filter: "<<minfilter <<std::endl;
if(mipmap == "nearest")
{
if(min == osg::Texture::NEAREST)
min = osg::Texture::NEAREST_MIPMAP_NEAREST;
else if(min == osg::Texture::LINEAR)
min = osg::Texture::LINEAR_MIPMAP_NEAREST;
}
else if(mipmap != "none")
{
if(mipmap != "linear")
std::cerr<< "Invalid texture mipmap: "<<mipmap <<std::endl;
if(min == osg::Texture::NEAREST)
min = osg::Texture::NEAREST_MIPMAP_LINEAR;
else if(min == osg::Texture::LINEAR)
min = osg::Texture::LINEAR_MIPMAP_LINEAR;
}
if(viewer) viewer->stopThreading();
setFilterSettings(min, mag, maxAnisotropy);
if(viewer) viewer->startThreading();
}
void SceneManager::applyFilterSettings(osg::Texture *tex)
{
tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
tex->setMaxAnisotropy(mMaxAnisotropy);
mTexturesWithFilterSetting.insert(tex);
}
void SceneManager::setUnRefImageDataAfterApply(bool unref)
{
mUnRefImageDataAfterApply = unref;
}
void SceneManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy)
{
mMinFilter = minFilter;
mMagFilter = magFilter;
mMaxAnisotropy = std::max(1, maxAnisotropy);
for (std::set<osg::ref_ptr<osg::Texture> >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end(); ++it)
{
(*it)->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
(*it)->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
(*it)->setMaxAnisotropy(mMaxAnisotropy);
}
}
void SceneManager::clearCache()
{
// clear textures that are no longer referenced
for (std::set<osg::ref_ptr<osg::Texture> >::const_iterator it = mTexturesWithFilterSetting.begin(); it != mTexturesWithFilterSetting.end();)
{
osg::Texture* tex = *it;
if (tex->referenceCount() <= 1)
mTexturesWithFilterSetting.erase(it++);
else
++it;
}
}
}

@ -6,6 +6,7 @@
#include <osg/ref_ptr>
#include <osg/Node>
#include <osg/Texture>
namespace Resource
{
@ -23,6 +24,11 @@ namespace osgUtil
class IncrementalCompileOperation;
}
namespace osgViewer
{
class Viewer;
}
namespace Resource
{
@ -69,11 +75,30 @@ namespace Resource
/// @param mask The node mask to apply to loaded particle system nodes.
void setParticleSystemMask(unsigned int mask);
void setFilterSettings(const std::string &magfilter, const std::string &minfilter,
const std::string &mipmap, int maxAnisotropy,
osgViewer::Viewer *viewer);
/// Apply filter settings to the given texture. Note, when loading an object through this scene manager (i.e. calling getTemplate / createInstance)
/// the filter settings are applied automatically. This method is provided for textures that were created outside of the SceneManager.
void applyFilterSettings (osg::Texture* tex);
/// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts,
/// otherwise should be disabled to reduce memory usage.
void setUnRefImageDataAfterApply(bool unref);
void clearCache();
private:
const VFS::Manager* mVFS;
Resource::TextureManager* mTextureManager;
Resource::NifFileManager* mNifFileManager;
osg::Texture::FilterMode mMinFilter;
osg::Texture::FilterMode mMagFilter;
int mMaxAnisotropy;
bool mUnRefImageDataAfterApply;
osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation;
unsigned int mParticleSystemMask;
@ -82,8 +107,14 @@ namespace Resource
typedef std::map<std::string, osg::ref_ptr<const osg::Node> > Index;
Index mIndex;
std::set<osg::ref_ptr<osg::Texture> > mTexturesWithFilterSetting;
SceneManager(const SceneManager&);
void operator = (const SceneManager&);
/// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first!
void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy);
};
}

@ -3,7 +3,6 @@
#include <osgDB/Registry>
#include <osg/GLExtensions>
#include <osg/Version>
#include <osgViewer/Viewer>
#include <stdexcept>
@ -47,11 +46,7 @@ namespace Resource
TextureManager::TextureManager(const VFS::Manager *vfs)
: mVFS(vfs)
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
, mMagFilter(osg::Texture::LINEAR)
, mMaxAnisotropy(1)
, mWarningTexture(createWarningTexture())
, mUnRefImageDataAfterApply(false)
{
}
@ -61,88 +56,6 @@ namespace Resource
}
void TextureManager::setUnRefImageDataAfterApply(bool unref)
{
mUnRefImageDataAfterApply = unref;
}
void TextureManager::setFilterSettings(const std::string &magfilter, const std::string &minfilter,
const std::string &mipmap, int maxAnisotropy,
osgViewer::Viewer *viewer)
{
osg::Texture::FilterMode min = osg::Texture::LINEAR;
osg::Texture::FilterMode mag = osg::Texture::LINEAR;
if(magfilter == "nearest")
mag = osg::Texture::NEAREST;
else if(magfilter != "linear")
std::cerr<< "Invalid texture mag filter: "<<magfilter <<std::endl;
if(minfilter == "nearest")
min = osg::Texture::NEAREST;
else if(minfilter != "linear")
std::cerr<< "Invalid texture min filter: "<<minfilter <<std::endl;
if(mipmap == "nearest")
{
if(min == osg::Texture::NEAREST)
min = osg::Texture::NEAREST_MIPMAP_NEAREST;
else if(min == osg::Texture::LINEAR)
min = osg::Texture::LINEAR_MIPMAP_NEAREST;
}
else if(mipmap != "none")
{
if(mipmap != "linear")
std::cerr<< "Invalid texture mipmap: "<<mipmap <<std::endl;
if(min == osg::Texture::NEAREST)
min = osg::Texture::NEAREST_MIPMAP_LINEAR;
else if(min == osg::Texture::LINEAR)
min = osg::Texture::LINEAR_MIPMAP_LINEAR;
}
if(viewer) viewer->stopThreading();
setFilterSettings(min, mag, maxAnisotropy);
if(viewer) viewer->startThreading();
}
void TextureManager::setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode magFilter, int maxAnisotropy)
{
mMinFilter = minFilter;
mMagFilter = magFilter;
mMaxAnisotropy = std::max(1, maxAnisotropy);
for (std::map<MapKey, osg::ref_ptr<osg::Texture2D> >::iterator it = mTextures.begin(); it != mTextures.end(); ++it)
{
osg::ref_ptr<osg::Texture2D> tex = it->second;
// Keep mip-mapping disabled if the texture creator explicitely requested no mipmapping.
osg::Texture::FilterMode oldMin = tex->getFilter(osg::Texture::MIN_FILTER);
if (oldMin == osg::Texture::LINEAR || oldMin == osg::Texture::NEAREST)
{
osg::Texture::FilterMode newMin = osg::Texture::LINEAR;
switch (mMinFilter)
{
case osg::Texture::LINEAR:
case osg::Texture::LINEAR_MIPMAP_LINEAR:
case osg::Texture::LINEAR_MIPMAP_NEAREST:
newMin = osg::Texture::LINEAR;
break;
case osg::Texture::NEAREST:
case osg::Texture::NEAREST_MIPMAP_LINEAR:
case osg::Texture::NEAREST_MIPMAP_NEAREST:
newMin = osg::Texture::NEAREST;
break;
}
tex->setFilter(osg::Texture::MIN_FILTER, newMin);
}
else
tex->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
tex->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
tex->setMaxAnisotropy(static_cast<float>(mMaxAnisotropy));
}
}
/*
osg::ref_ptr<osg::Image> TextureManager::getImage(const std::string &filename)
{
@ -295,11 +208,6 @@ namespace Resource
texture->setImage(image);
texture->setWrap(osg::Texture::WRAP_S, wrapS);
texture->setWrap(osg::Texture::WRAP_T, wrapT);
texture->setFilter(osg::Texture::MIN_FILTER, mMinFilter);
texture->setFilter(osg::Texture::MAG_FILTER, mMagFilter);
texture->setMaxAnisotropy(mMaxAnisotropy);
texture->setUnRefImageDataAfterApply(mUnRefImageDataAfterApply);
mTextures.insert(std::make_pair(key, texture));
return texture;

@ -28,14 +28,6 @@ namespace Resource
TextureManager(const VFS::Manager* vfs);
~TextureManager();
void setFilterSettings(const std::string &magfilter, const std::string &minfilter,
const std::string &mipmap, int maxAnisotropy,
osgViewer::Viewer *view);
/// Keep a copy of the texture data around in system memory? This is needed when using multiple graphics contexts,
/// otherwise should be disabled to reduce memory usage.
void setUnRefImageDataAfterApply(bool unref);
/// Create or retrieve a Texture2D using the specified image filename, and wrap parameters.
/// Returns the dummy texture if the given texture is not found.
osg::ref_ptr<osg::Texture2D> getTexture2D(const std::string& filename, osg::Texture::WrapMode wrapS, osg::Texture::WrapMode wrapT);
@ -50,10 +42,6 @@ namespace Resource
private:
const VFS::Manager* mVFS;
osg::Texture::FilterMode mMinFilter;
osg::Texture::FilterMode mMagFilter;
int mMaxAnisotropy;
typedef std::pair<std::pair<int, int>, std::string> MapKey;
std::map<std::string, osg::ref_ptr<osg::Image> > mImages;
@ -62,11 +50,6 @@ namespace Resource
osg::ref_ptr<osg::Texture2D> mWarningTexture;
bool mUnRefImageDataAfterApply;
/// @warning It is unsafe to call this function when a draw thread is using the textures. Call stopThreading() first!
void setFilterSettings(osg::Texture::FilterMode minFilter, osg::Texture::FilterMode maxFilter, int maxAnisotropy);
TextureManager(const TextureManager&);
void operator = (const TextureManager&);
};

Loading…
Cancel
Save