modellib: Add method for deferred model loading.

Add method that schedules a ProxyNode to do
just deferred model loading instead of full scenery paging.
Add support for ProxyNodes to CheckSceneryVisitor.
Use PagedLOD instead of our own derived method.
This commit is contained in:
Mathias Froehlich 2011-11-08 21:11:28 +01:00
parent a543560f7d
commit ad079b8ed4
10 changed files with 104 additions and 252 deletions

View File

@ -105,7 +105,7 @@ else()
find_package(OpenGL REQUIRED)
find_package(OpenAL REQUIRED)
find_package(ALUT REQUIRED)
find_package(OpenSceneGraph 2.8.1 REQUIRED osgText osgSim osgDB osgParticle osgUtil)
find_package(OpenSceneGraph 3.0.0 REQUIRED osgText osgSim osgDB osgParticle osgUtil)
endif(SIMGEAR_HEADLESS)
if(JPEG_FACTORY)

View File

@ -1139,14 +1139,6 @@
RelativePath="..\..\simgear\scene\model\SGOffsetTransform.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGPagedLOD.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGPagedLOD.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\model\SGReaderWriterXML.cxx"
>

View File

@ -9,7 +9,6 @@ set(HEADERS
SGInteractionAnimation.hxx
SGMaterialAnimation.hxx
SGOffsetTransform.hxx
SGPagedLOD.hxx
SGReaderWriterXML.hxx
SGReaderWriterXMLOptions.hxx
SGRotateTransform.hxx
@ -32,7 +31,6 @@ set(SOURCES
SGInteractionAnimation.cxx
SGMaterialAnimation.cxx
SGOffsetTransform.cxx
SGPagedLOD.cxx
SGReaderWriterXML.cxx
SGRotateTransform.cxx
SGScaleTransform.cxx

View File

@ -1,4 +1,5 @@
// Copyright (C) 2008 Till Busch buti@bux.at
// Copyright (C) 2011 Mathias Froehlich
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@ -19,11 +20,12 @@
#endif
#include <osg/Transform>
#include <osg/ProxyNode>
#include <osgDB/DatabasePager>
#include <simgear/debug/logstream.hxx>
#include "CheckSceneryVisitor.hxx"
#include "SGPagedLOD.hxx"
#include <simgear/math/SGMath.hxx>
@ -33,9 +35,10 @@ CheckSceneryVisitor::CheckSceneryVisitor(osgDB::DatabasePager* dbp, const osg::V
osg::FrameStamp* framestamp)
:osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR,
osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_position(position), _range(range), _loaded(true), _dbp(dbp), _framestamp(framestamp)
_position(position), _range(range), _loaded(true), _matrix(osg::Matrix::identity())
{
_viewMatrices.push_back(osg::Matrix::identity());
setDatabaseRequestHandler(dbp);
setFrameStamp(framestamp);
}
void CheckSceneryVisitor::apply(osg::Node& node)
@ -43,20 +46,53 @@ void CheckSceneryVisitor::apply(osg::Node& node)
traverse(node);
}
void CheckSceneryVisitor::apply(osg::ProxyNode& node)
{
osg::Vec3 pos = node.getCenter() * _matrix;
double dist = (pos - _position).length();
if (dist < _range) {
for (unsigned i = 0; i < node.getNumFileNames(); ++i) {
if (node.getFileName(i).empty())
continue;
// Check if this is already loaded.
if (i < node.getNumChildren() && node.getChild(i))
continue;
// if the DatabasePager would load LODs while the splashscreen
// is there, we could just wait for the models to be loaded
// by only setting setLoaded(false) here
osg::NodePath nodePath = getNodePath();
DatabaseRequestHandler* db = getDatabaseRequestHandler();
const osg::FrameStamp* fs = getFrameStamp();
db->requestNodeFile(node.getFileName(i), nodePath, 1.0 /*priority*/, fs,
node.getDatabaseRequest(i), node.getDatabaseOptions());
setLoaded(false);
}
}
traverse(node);
}
void CheckSceneryVisitor::apply(osg::PagedLOD& node)
{
SGPagedLOD *sgplod = dynamic_cast<SGPagedLOD*>(&node);
if (sgplod) {
osg::Vec3 pos = sgplod->getCenter() * _viewMatrices.back();
double dist = (pos-_position).length();
if (dist < _range) {
if (sgplod->getNumChildren() < 1) {
// if the DatabasePager would load LODs while the splashscreen
// is there, we could just wait for the models to be loaded
// by only setting setLoaded(false) here
sgplod->forceLoad(_dbp,_framestamp, getNodePath());
setLoaded(false);
}
osg::Vec3 pos = node.getCenter() * _matrix;
double dist = (pos - _position).length();
if (dist < _range) {
for (unsigned i = 0; i < node.getNumFileNames(); ++i) {
if (node.getFileName(i).empty())
continue;
// Check if this is already loaded.
if (i < node.getNumChildren() && node.getChild(i))
continue;
// if the DatabasePager would load LODs while the splashscreen
// is there, we could just wait for the models to be loaded
// by only setting setLoaded(false) here
osg::NodePath nodePath = getNodePath();
DatabaseRequestHandler* db = getDatabaseRequestHandler();
const osg::FrameStamp* fs = getFrameStamp();
db->requestNodeFile(node.getFileName(i), nodePath, 1.0 /*priority*/, fs,
node.getDatabaseRequest(i), node.getDatabaseOptions());
setLoaded(false);
}
}
traverse(node);
@ -64,14 +100,8 @@ void CheckSceneryVisitor::apply(osg::PagedLOD& node)
void CheckSceneryVisitor::apply(osg::Transform &node)
{
osg::Matrix currMatrix = _viewMatrices.back();
bool pushMatrix = node.computeLocalToWorldMatrix(currMatrix, this);
if (pushMatrix) {
_viewMatrices.push_back(currMatrix);
}
osg::Matrix matrix = _matrix;
node.computeLocalToWorldMatrix(_matrix, this);
traverse(node);
if (pushMatrix) {
_viewMatrices.pop_back();
}
_matrix = matrix;
}

View File

@ -1,4 +1,5 @@
// Copyright (C) 2008 Till Busch buti@bux.at
// Copyright (C) 2011 Mathias Froehlich
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@ -18,7 +19,6 @@
#define CHECKSCENERYVISITOR_HXX
#include <osg/NodeVisitor>
#include <osg/fast_back_stack>
namespace osgDB {
class DatabasePager;
@ -28,9 +28,7 @@ class DatabasePager;
namespace simgear
{
class SGPagedLOD;
// Checks the scene graph for SGPagedLODs that are within range
// Checks the scene graph for PagedLOD or ProxyNodes that are within range
// (compared to postion) and injects them into the DatabasePager.
// After visiting, isLoaded() returns true if all models in range
// are available.
@ -41,6 +39,7 @@ public:
CheckSceneryVisitor(osgDB::DatabasePager* dbp, const osg::Vec3 &position, double range, osg::FrameStamp* framestamp);
virtual void apply(osg::Node& node);
virtual void apply(osg::ProxyNode& node);
virtual void apply(osg::PagedLOD& node);
virtual void apply(osg::Transform& node);
@ -58,10 +57,7 @@ private:
osg::Vec3 _position;
double _range;
bool _loaded;
osgDB::DatabasePager* _dbp;
osg::FrameStamp* _framestamp;
osg::fast_back_stack<osg::Matrix> _viewMatrices;
osg::Matrix _matrix;
};
}

View File

@ -1,123 +0,0 @@
// Copyright (C) 2008 Till Busch buti@bux.at
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <osgDB/ReadFile>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
#include <osgDB/DatabasePager>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/OSGVersion.hxx>
#include "modellib.hxx"
#include "SGReaderWriterXMLOptions.hxx"
#include "SGPagedLOD.hxx"
#include <simgear/math/SGMath.hxx>
using namespace osg;
using namespace simgear;
bool SGPagedLOD::_cache = true;
SGPagedLOD::SGPagedLOD()
: PagedLOD()
{
}
SGPagedLOD::~SGPagedLOD()
{
//SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::~SGPagedLOD(" << getFileName(0) << ")");
}
SGPagedLOD::SGPagedLOD(const SGPagedLOD& plod,const CopyOp& copyop)
: osg::PagedLOD(plod, copyop)
#if !SG_PAGEDLOD_HAS_OPTIONS
, _readerWriterOptions(plod._readerWriterOptions)
#endif
{
}
void
SGPagedLOD::setReaderWriterOptions(osgDB::ReaderWriter::Options *options)
{
if (_cache)
options->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
else
options->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_NONE);
#if SG_PAGEDLOD_HAS_OPTIONS
setDatabaseOptions(options);
#else
_readerWriterOptions = options;
#endif
}
bool SGPagedLOD::addChild(osg::Node *child)
{
if (!PagedLOD::addChild(child))
return false;
setRadius(getBound().radius());
setCenter(getBound().center());
return true;
}
// Work around interface change in osgDB::DatabasePager::requestNodeFile
struct NodePathProxy
{
NodePathProxy(NodePath& nodePath)
: _nodePath(nodePath)
{
}
operator Group* () { return static_cast<Group*>(_nodePath.back()); }
operator NodePath& () { return _nodePath; }
NodePath& _nodePath;
};
void SGPagedLOD::forceLoad(osgDB::DatabasePager *dbp, FrameStamp* framestamp,
NodePath& path)
{
//SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::forceLoad(" <<
//getFileName(getNumChildren()) << ")");
unsigned childNum = getNumChildren();
setTimeStamp(childNum, 0);
double priority=1.0;
dbp->requestNodeFile(getFileName(childNum), NodePathProxy(path),
priority, framestamp,
getDatabaseRequest(childNum),
getReaderWriterOptions());
}
bool SGPagedLOD_writeLocalData(const Object& obj, osgDB::Output& fw)
{
return true;
}
namespace
{
osgDB::RegisterDotOsgWrapperProxy sgPagedLODProxy
(
new SGPagedLOD,
"simgear::SGPagedLOD",
"Object Node LOD PagedLOD SGPagedLOD Group",
0,
&SGPagedLOD_writeLocalData
);
}

View File

@ -1,75 +0,0 @@
// Copyright (C) 2008 Till Busch buti@bux.at
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef SGPAGEDLOD_HXX
#define SGPAGEDLOD_HXX 1
#include <simgear/structure/OSGVersion.hxx>
#define SG_PAGEDLOD_HAS_OPTIONS \
(SG_OSG_VERSION >= 29005)
#include <osg/PagedLOD>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <simgear/props/props.hxx>
namespace osgDB {
class DatabasePager;
}
namespace simgear
{
class SGPagedLOD : public osg::PagedLOD
{
public:
SGPagedLOD();
SGPagedLOD(const SGPagedLOD&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Node(simgear, SGPagedLOD);
// virtual void traverse(osg::NodeVisitor& nv);
virtual void forceLoad(osgDB::DatabasePager* dbp,
osg::FrameStamp* framestamp,
osg::NodePath& path);
// reimplemented to notify the loading through ModelData
bool addChild(osg::Node *child);
void setReaderWriterOptions(osgDB::ReaderWriter::Options *options);
osgDB::ReaderWriter::Options* getReaderWriterOptions() {
#if SG_PAGEDLOD_HAS_OPTIONS
return static_cast<osgDB::ReaderWriter::Options*>(getDatabaseOptions());
#else
return _readerWriterOptions.get();
#endif
}
static void setRenderingCache(bool cache) {_cache = cache;}
protected:
virtual ~SGPagedLOD();
#if !SG_PAGEDLOD_HAS_OPTIONS
osg::ref_ptr<osgDB::ReaderWriter::Options> _readerWriterOptions;
#endif
private:
static bool _cache;
};
}
#endif

View File

@ -42,7 +42,6 @@
#include <simgear/scene/util/SGNodeMasks.hxx>
#include "modellib.hxx"
#include "SGPagedLOD.hxx"
#include "SGReaderWriterXML.hxx"
#include "SGReaderWriterXMLOptions.hxx"

View File

@ -21,6 +21,8 @@
#include <boost/algorithm/string.hpp>
#include <osg/PagedLOD>
#include <osg/ProxyNode>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
@ -32,7 +34,6 @@
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include "SGPagedLOD.hxx"
#include "SGReaderWriterXML.hxx"
#include "SGReaderWriterXMLOptions.hxx"
@ -56,7 +57,6 @@ void SGModelLib::init(const string &root_dir, SGPropertyNode* root)
{
osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
static_propRoot = root;
SGPagedLOD::setRenderingCache(root->getBoolValue("/sim/rendering/cache",true));
}
void SGModelLib::setPanelFunc(panel_func pf)
@ -122,11 +122,36 @@ SGModelLib::loadModel(const string &path,
}
osg::Node*
SGModelLib::loadDeferedModel(const string &path, SGPropertyNode *prop_root,
SGModelData *data)
{
osg::ProxyNode* proxyNode = new osg::ProxyNode;
proxyNode->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
proxyNode->setFileName(0, path);
osg::ref_ptr<SGReaderWriterXMLOptions> opt
= new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()
->getOptions()));
opt->setPropRoot(prop_root ? prop_root: static_propRoot.get());
opt->setModelData(data);
opt->setLoadPanel(static_panelFunc);
if (SGPath(path).lower_extension() == "ac")
opt->setInstantiateEffects(true);
if (!prop_root || prop_root->getBoolValue("/sim/rendering/cache", true))
opt->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
else
opt->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_NONE);
proxyNode->setDatabaseOptions(opt.get());
return proxyNode;
}
osg::Node*
SGModelLib::loadPagedModel(const string &path, SGPropertyNode *prop_root,
SGModelData *data)
{
SGPagedLOD *plod = new SGPagedLOD;
osg::PagedLOD *plod = new osg::PagedLOD;
plod->setName("Paged LOD for \"" + path + "\"");
plod->setFileName(0, path);
plod->setRange(0, 0.0, 50.0*SG_NM_TO_METER);
@ -137,9 +162,13 @@ SGModelLib::loadPagedModel(const string &path, SGPropertyNode *prop_root,
opt->setPropRoot(prop_root ? prop_root: static_propRoot.get());
opt->setModelData(data);
opt->setLoadPanel(static_panelFunc);
if (boost::iends_with(path, ".ac"))
if (SGPath(path).lower_extension() == "ac")
opt->setInstantiateEffects(true);
plod->setReaderWriterOptions(opt.get());
if (!prop_root || prop_root->getBoolValue("/sim/rendering/cache", true))
opt->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
else
opt->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_NONE);
plod->setDatabaseOptions(opt.get());
return plod;
}

View File

@ -55,11 +55,17 @@ public:
SGModelData *data=0, bool load2DPanels=false);
// Load a 3D model (any format) through the DatabasePager.
// Most models should be loaded using this function!
// This function will initially return an SGPagedLOD node.
// data->modelLoaded() will be called after the model is loaded and
// connected to the scene graph. See AIModelData on how to use this.
// NOTE: AIModelData uses observer_ptr to avoid circular references.
// This function initially just returns a proxy node that refers to
// the model file. Once the viewer steps onto that node the
// model will be loaded.
static osg::Node* loadDeferedModel(const std::string &path,
SGPropertyNode *prop_root = NULL,
SGModelData *data=0);
// Load a 3D model (any format) through the DatabasePager.
// This function initially just returns a PagedLOD node that refers to
// the model file. Once the viewer steps onto that node the
// model will be loaded. When the viewer does no longer reference this
// node for a long time the node is unloaded again.
static osg::Node* loadPagedModel(const std::string &path,
SGPropertyNode *prop_root = NULL,
SGModelData *data=0);