Merge branch 'next' of git://gitorious.org/fg/simgear into next

This commit is contained in:
Erik Hofman 2011-11-10 10:29:07 +01:00
commit 40fc2907a1
12 changed files with 136 additions and 256 deletions

View File

@ -105,7 +105,7 @@ else()
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
find_package(ALUT 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) endif(SIMGEAR_HEADLESS)
if(JPEG_FACTORY) if(JPEG_FACTORY)

View File

@ -1,10 +1,9 @@
[This file is mirrored in both the FlightGear and SimGear packages.] [This file is mirrored in both the FlightGear and SimGear packages.]
You *must* have OpenSceneGraph (OSG) installed to build this version of You *must* have OpenSceneGraph (OSG) installed to build this version of
FlightGear. FlightGear.
Notice that FlightGear 1.9.0 requires at least version 2.7.8. Using earlier Notice that FlightGear 2.6.0 requires at least version 3.0.0.
versions of OSG will yield serious rendering bugs.
You can get the latest version of OSG from: You can get the latest version of OSG from:
@ -22,6 +21,6 @@ ccmake .
[ While running ccmake: press 'c' to configure, press 'c' once more, and [ While running ccmake: press 'c' to configure, press 'c' once more, and
then press 'g' to generate and exit ] then press 'g' to generate and exit ]
make make
sudo make install sudo make install

View File

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

View File

@ -46,6 +46,7 @@
#include <osg/Material> #include <osg/Material>
#include <osg/Math> #include <osg/Math>
#include <osg/PolygonMode> #include <osg/PolygonMode>
#include <osg/PolygonOffset>
#include <osg/Program> #include <osg/Program>
#include <osg/Referenced> #include <osg/Referenced>
#include <osg/RenderInfo> #include <osg/RenderInfo>
@ -1059,6 +1060,34 @@ struct PolygonModeBuilder : public PassAttributeBuilder
InstallAttributeBuilder<PolygonModeBuilder> installPolygonMode("polygon-mode"); InstallAttributeBuilder<PolygonModeBuilder> installPolygonMode("polygon-mode");
struct PolygonOffsetBuilder : public PassAttributeBuilder
{
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const SGReaderWriterXMLOptions* options)
{
if (!isAttributeActive(effect, prop))
return;
const SGPropertyNode* factor
= getEffectPropertyChild(effect, prop, "factor");
const SGPropertyNode* units
= getEffectPropertyChild(effect, prop, "units");
ref_ptr<PolygonOffset> polyoffset = new PolygonOffset;
polyoffset->setFactor(factor->getFloatValue());
polyoffset->setUnits(units->getFloatValue());
SG_LOG(SG_INPUT, SG_BULK,
"Set PolygonOffset to " << polyoffset->getFactor() << polyoffset->getUnits() );
pass->setAttributeAndModes(polyoffset.get(),
StateAttribute::OVERRIDE|StateAttribute::ON);
}
};
InstallAttributeBuilder<PolygonOffsetBuilder> installPolygonOffset("polygon-offset");
struct VertexProgramTwoSideBuilder : public PassAttributeBuilder struct VertexProgramTwoSideBuilder : public PassAttributeBuilder
{ {
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,

View File

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

View File

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

View File

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

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 <simgear/scene/util/SGNodeMasks.hxx>
#include "modellib.hxx" #include "modellib.hxx"
#include "SGPagedLOD.hxx"
#include "SGReaderWriterXML.hxx" #include "SGReaderWriterXML.hxx"
#include "SGReaderWriterXMLOptions.hxx" #include "SGReaderWriterXMLOptions.hxx"

View File

@ -21,6 +21,8 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <osg/PagedLOD>
#include <osg/ProxyNode>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <osgDB/WriteFile> #include <osgDB/WriteFile>
#include <osgDB/Registry> #include <osgDB/Registry>
@ -32,7 +34,6 @@
#include <simgear/scene/model/ModelRegistry.hxx> #include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/misc/ResourceManager.hxx> #include <simgear/misc/ResourceManager.hxx>
#include "SGPagedLOD.hxx"
#include "SGReaderWriterXML.hxx" #include "SGReaderWriterXML.hxx"
#include "SGReaderWriterXMLOptions.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); osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
static_propRoot = root; static_propRoot = root;
SGPagedLOD::setRenderingCache(root->getBoolValue("/sim/rendering/cache",true));
} }
void SGModelLib::setPanelFunc(panel_func pf) 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* osg::Node*
SGModelLib::loadPagedModel(const string &path, SGPropertyNode *prop_root, SGModelLib::loadPagedModel(const string &path, SGPropertyNode *prop_root,
SGModelData *data) SGModelData *data)
{ {
SGPagedLOD *plod = new SGPagedLOD; osg::PagedLOD *plod = new osg::PagedLOD;
plod->setName("Paged LOD for \"" + path + "\""); plod->setName("Paged LOD for \"" + path + "\"");
plod->setFileName(0, path); plod->setFileName(0, path);
plod->setRange(0, 0.0, 50.0*SG_NM_TO_METER); 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->setPropRoot(prop_root ? prop_root: static_propRoot.get());
opt->setModelData(data); opt->setModelData(data);
opt->setLoadPanel(static_panelFunc); opt->setLoadPanel(static_panelFunc);
if (boost::iends_with(path, ".ac")) if (SGPath(path).lower_extension() == "ac")
opt->setInstantiateEffects(true); 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; return plod;
} }

View File

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