]> git.mxchange.org Git - simgear.git/commitdiff
model paging patch from Till Busch
authortimoore <timoore>
Sat, 22 Mar 2008 09:30:26 +0000 (09:30 +0000)
committertimoore <timoore>
Sat, 22 Mar 2008 09:30:26 +0000 (09:30 +0000)
Comments from Till:
I started the project at the end of february with a simple idea: move all
3d-model loading to the DatabasePager-thread. my first attempts looked
promising, though they were a little too optimistic (or naive?). the patch
has evolved a lot since.

currently it does the following things:
1. revive SGModelLib, move functions for xml-model-loading there

2. replace all calls to sgLoad3dModel with calls to either
SGModelLib::loadModel() or SGModelLib::loadPagedModel()
almost all models will be loaded by the DatabasePager. the few exceptions are:
your own plane, shared models in scenery, random objects, AIBallistic models.

3. simplify mode-loading functions (avoid passing around fg_root)

4. avoid supurious MatrixTransform nodes in loaded models

5. fix some memory leaks

18 files changed:
simgear/constants.h
simgear/scene/material/matmodel.cxx
simgear/scene/material/matmodel.hxx
simgear/scene/model/CheckSceneryVisitor.cxx [new file with mode: 0644]
simgear/scene/model/CheckSceneryVisitor.hxx [new file with mode: 0644]
simgear/scene/model/Makefile.am
simgear/scene/model/SGPagedLOD.cxx [new file with mode: 0644]
simgear/scene/model/SGPagedLOD.hxx [new file with mode: 0644]
simgear/scene/model/SGReaderWriterXML.cxx [new file with mode: 0644]
simgear/scene/model/SGReaderWriterXML.hxx [new file with mode: 0644]
simgear/scene/model/SGReaderWriterXMLOptions.hxx [new file with mode: 0644]
simgear/scene/model/model.cxx
simgear/scene/model/model.hxx
simgear/scene/model/modellib.cxx
simgear/scene/model/modellib.hxx
simgear/scene/tgdb/userdata.cxx
simgear/scene/tgdb/userdata.hxx
simgear/structure/subsystem_mgr.hxx

index 3d8a82fb75af27c2df218e78bec61486333b0430..b6fd7a909affd3c208f4ccba1fb6bdf60ba7f2fa 100644 (file)
@@ -75,6 +75,8 @@
  *  6378.165 but this is probably close enough */
 #define SG_EARTH_RAD 6378.155
 
+// Maximum terrain elevation from sea level
+#define SG_MAX_ELEVATION_M 9000.0
 
 // Earth parameters for WGS 84, taken from LaRCsim/ls_constants.h
 
index 70850edc2a30fd6e3d50fd9ee2c5908371a8237d..b2a4152d8ebc5601e88d81566ea8b39a7189df1d 100644 (file)
@@ -48,6 +48,8 @@ SG_USING_STD(map);
 
 #include "matmodel.hxx"
 
+using namespace simgear;
+
 \f
 ////////////////////////////////////////////////////////////////////////
 // Local static functions.
@@ -115,27 +117,19 @@ SGMatModel::~SGMatModel ()
 }
 
 int
-SGMatModel::get_model_count( SGModelLib *modellib,
-                             const string &fg_root,
-                             SGPropertyNode *prop_root,
-                             double sim_time_sec )
+SGMatModel::get_model_count( SGPropertyNode *prop_root )
 {
-  load_models( modellib, fg_root, prop_root, sim_time_sec );
+  load_models( prop_root );
   return _models.size();
 }
 
 inline void
-SGMatModel::load_models ( SGModelLib *modellib,
-                          const string &fg_root,
-                          SGPropertyNode *prop_root,
-                          double sim_time_sec )
+SGMatModel::load_models( SGPropertyNode *prop_root )
 {
                                // Load model only on demand
   if (!_models_loaded) {
     for (unsigned int i = 0; i < _paths.size(); i++) {
-      osg::Node *entity = modellib->load_model( fg_root, _paths[i],
-                                                prop_root, sim_time_sec,
-                                                /*cache_object*/ true );
+      osg::Node *entity = SGModelLib::loadModel(_paths[i], prop_root);
       if (entity != 0) {
         // FIXME: this stuff can be handled
         // in the XML wrapper as well (at least,
@@ -167,22 +161,16 @@ SGMatModel::load_models ( SGModelLib *modellib,
 
 osg::Node*
 SGMatModel::get_model( int index,
-                       SGModelLib *modellib,
-                       const string &fg_root,
-                       SGPropertyNode *prop_root,
-                       double sim_time_sec )
+                       SGPropertyNode *prop_root )
 {
-  load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
+  load_models( prop_root ); // comment this out if preloading models
   return _models[index].get();
 }
 
 osg::Node*
-SGMatModel::get_random_model( SGModelLib *modellib,
-                              const string &fg_root,
-                              SGPropertyNode *prop_root,
-                              double sim_time_sec )
+SGMatModel::get_random_model( SGPropertyNode *prop_root )
 {
-  load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
+  load_models( prop_root ); // comment this out if preloading models
   int nModels = _models.size();
   int index = int(sg_random() * nModels);
   if (index >= nModels)
index 982e89a95293015d6183071865df50ce5309d7ba..12ff23dd210d66ee8dff456365db782295808b95 100644 (file)
@@ -46,7 +46,6 @@ SG_USING_STD(string);
 
 
 class SGMatModelGroup;
-class SGModelLib;
 
 
 /**
@@ -76,10 +75,7 @@ public:
      *
      * @return The number of variant models.
      */
-    int get_model_count( SGModelLib *modellib,
-                         const string &fg_root,
-                         SGPropertyNode *prop_root,
-                         double sim_time_sec );
+    int get_model_count( SGPropertyNode *prop_root );
 
 
     /**
@@ -88,11 +84,7 @@ public:
      * @param index The index of the model.
      * @return The model.
      */
-     osg::Node *get_model( int index,
-                          SGModelLib *modellib,
-                          const string &fg_root,
-                          SGPropertyNode *prop_root,
-                          double sim_time_sec );
+     osg::Node *get_model( int index, SGPropertyNode *prop_root );
 
 
     /**
@@ -100,10 +92,7 @@ public:
      *
      * @return A randomly select model from the variants.
      */
-    osg::Node *get_random_model( SGModelLib *modellib,
-                                 const string &fg_root,
-                                 SGPropertyNode *prop_root,
-                                 double sim_time_sec );
+    osg::Node *get_random_model( SGPropertyNode *prop_root );
 
 
     /**
@@ -151,10 +140,7 @@ private:
      * This class uses lazy loading so that models won't be held
      * in memory for materials that are never referenced.
      */
-    void load_models( SGModelLib *modellib,
-                      const string &fg_root,
-                      SGPropertyNode *prop_root,
-                      double sim_time_sec );
+    void load_models( SGPropertyNode *prop_root );
 
     vector<string> _paths;
     mutable vector<osg::ref_ptr<osg::Node> > _models;
diff --git a/simgear/scene/model/CheckSceneryVisitor.cxx b/simgear/scene/model/CheckSceneryVisitor.cxx
new file mode 100644 (file)
index 0000000..d6fdd12
--- /dev/null
@@ -0,0 +1,70 @@
+// 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.
+
+#include <osg/Transform>
+
+#include <simgear/debug/logstream.hxx>
+
+#include "CheckSceneryVisitor.hxx"
+#include "SGPagedLOD.hxx"
+
+using namespace simgear;
+
+CheckSceneryVisitor::CheckSceneryVisitor(osgDB::DatabasePager* dbp, osg::Vec3 &position, double range)
+:osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR,
+                  osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
+_loaded(true), _position(position), _range(range), _dbp(dbp)
+{
+    _viewMatrices.push_back(osg::Matrix::identity());
+}
+
+void CheckSceneryVisitor::apply(osg::Node& node)
+{
+    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);
+                setLoaded(false);
+            }
+        }
+    }
+    traverse(node);
+}
+
+void CheckSceneryVisitor::apply(osg::Transform &node)
+{
+    osg::Matrix currMatrix = _viewMatrices.back();
+    bool pushMatrix = node.computeLocalToWorldMatrix(currMatrix, this);
+
+    if (pushMatrix) {
+        _viewMatrices.push_back(currMatrix);
+    }
+    traverse(node);
+    if (pushMatrix) {
+        _viewMatrices.pop_back();
+    }
+}
diff --git a/simgear/scene/model/CheckSceneryVisitor.hxx b/simgear/scene/model/CheckSceneryVisitor.hxx
new file mode 100644 (file)
index 0000000..c89fc18
--- /dev/null
@@ -0,0 +1,68 @@
+// 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 CHECKSCENERYVISITOR_HXX
+#define CHECKSCENERYVISITOR_HXX
+
+#include <osg/NodeVisitor>
+#include <osg/fast_back_stack>
+
+namespace osgDB {
+class DatabasePager;
+}
+
+
+namespace simgear
+{
+
+class SGPagedLOD;
+
+// Checks the scene graph for SGPagedLODs 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.
+
+class CheckSceneryVisitor : public osg::NodeVisitor
+{
+public:
+    CheckSceneryVisitor(osgDB::DatabasePager* dbp, osg::Vec3 &position, double range);
+
+    virtual void apply(osg::Node& node);
+    virtual void apply(osg::PagedLOD& node);
+    virtual void apply(osg::Transform& node);
+
+    bool isLoaded() const {
+        return _loaded;
+    }
+    void setLoaded(bool l) {
+        _loaded=l;
+    }
+    const osg::Vec3 &getPosition() const {
+        return _position;
+    }
+
+private:
+    osg::Vec3 _position;
+    double _range;
+    bool _loaded;
+    osgDB::DatabasePager* _dbp;
+
+    osg::fast_back_stack<osg::Matrix> _viewMatrices;
+};
+
+}
+
+#endif
index db102d9ea50f8a2df3d7dbd83fdfa4dd9f691dad..51ff3921f93cf7c7556f91bb17d8c5770d6b88dc 100644 (file)
@@ -14,9 +14,13 @@ include_HEADERS = \
        persparam.hxx \
        placement.hxx \
        placementtrans.hxx \
+       CheckSceneryVisitor.hxx \
        SGClipGroup.hxx \
        SGMaterialAnimation.hxx \
        SGOffsetTransform.hxx \
+       SGPagedLOD.hxx \
+       SGReaderWriterXML.hxx \
+       SGReaderWriterXMLOptions.hxx \
        SGRotateTransform.hxx \
        SGScaleTransform.hxx \
        SGTranslateTransform.hxx
@@ -32,9 +36,12 @@ libsgmodel_a_SOURCES = \
        placement.cxx \
        placementtrans.cxx \
        shadanim.cxx \
+       CheckSceneryVisitor.cxx \
        SGClipGroup.cxx \
        SGMaterialAnimation.cxx \
        SGOffsetTransform.cxx \
+       SGPagedLOD.cxx \
+       SGReaderWriterXML.cxx \
        SGRotateTransform.cxx \
        SGScaleTransform.cxx \
        SGTranslateTransform.cxx
diff --git a/simgear/scene/model/SGPagedLOD.cxx b/simgear/scene/model/SGPagedLOD.cxx
new file mode 100644 (file)
index 0000000..ee68b49
--- /dev/null
@@ -0,0 +1,74 @@
+// 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.
+
+#include <osgDB/ReadFile>
+
+#include <simgear/debug/logstream.hxx>
+
+#include "modellib.hxx"
+#include "SGReaderWriterXMLOptions.hxx"
+#include "SGPagedLOD.hxx"
+
+using namespace osg;
+using namespace simgear;
+
+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),
+        _readerWriterOptions(plod._readerWriterOptions)
+{
+}
+
+bool SGPagedLOD::addChild(osg::Node *child)
+{
+    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::addChild(" << getFileName(getNumChildren()) << ")");
+    if (!PagedLOD::addChild(child))
+        return false;
+
+    // if the model was an .xml-file it will have UserData set
+    osg::ref_ptr<SGModelData> d = dynamic_cast<SGModelData*>(child->getUserData());
+    if (d.valid())
+        d->modelLoaded(getFileName(getNumChildren()-1), d->getProperties(), this);
+    else // this calls modelLoaded for non-xml models
+    {
+        SGReaderWriterXMLOptions *o=dynamic_cast<SGReaderWriterXMLOptions*>(_readerWriterOptions.get());
+        if(o)
+        {
+            d = o->getModelData();
+            if(d.valid())
+                d->modelLoaded(getFileName(getNumChildren()-1), 0, this);
+        }
+    }
+    return true;
+}
+
+void SGPagedLOD::forceLoad(osgDB::DatabasePager *dbp)
+{
+    //SG_LOG(SG_GENERAL, SG_ALERT, "SGPagedLOD::forceLoad(" << getFileName(getNumChildren()) << ")");
+    setTimeStamp(getNumChildren(),0);
+    double priority=1.0;
+    dbp->requestNodeFile(getFileName(getNumChildren()),this,priority,0, _readerWriterOptions.get());
+}
+
diff --git a/simgear/scene/model/SGPagedLOD.hxx b/simgear/scene/model/SGPagedLOD.hxx
new file mode 100644 (file)
index 0000000..d45c1bb
--- /dev/null
@@ -0,0 +1,62 @@
+// 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 <osg/PagedLOD>
+#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(osg, PagedLOD);
+
+    // virtual void traverse(osg::NodeVisitor& nv);
+    virtual void forceLoad(osgDB::DatabasePager* dbp);
+
+    // reimplemented to notify the loading through ModelData
+    bool addChild(osg::Node *child);
+
+    void setReaderWriterOptions(osgDB::ReaderWriter::Options *o) {
+        _readerWriterOptions=o;
+        _readerWriterOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_NONE);
+    }
+
+    osgDB::ReaderWriter::Options * getReaderWriterOptions() {
+        return _readerWriterOptions.get();
+    }
+
+protected:
+    virtual ~SGPagedLOD();
+    osg::ref_ptr<osgDB::ReaderWriter::Options> _readerWriterOptions;
+    SGPropertyNode_ptr _props;
+};
+}
+#endif
diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx
new file mode 100644 (file)
index 0000000..656818a
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright (C) 2007 Tim Moore timoore@redhat.com
+// 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.
+//
+
+#include <osgDB/WriteFile>
+#include <osgDB/Registry>
+#include <osg/Switch>
+#include <osgDB/FileNameUtils>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/exception.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/props/condition.hxx>
+#include <simgear/scene/util/SGNodeMasks.hxx>
+
+#include "modellib.hxx"
+#include "SGPagedLOD.hxx"
+#include "SGReaderWriterXML.hxx"
+#include "SGReaderWriterXMLOptions.hxx"
+
+#include "animation.hxx"
+#include "particles.hxx"
+#include "model.hxx"
+
+#include "SGReaderWriterXMLOptions.hxx"
+#include "SGReaderWriterXML.hxx"
+
+using namespace simgear;
+
+osg::Node *
+sgLoad3DModel_internal(const string &path,
+                       SGPropertyNode *prop_root,
+                       SGModelData *data=0,
+                       osg::Node *(*load_panel)(SGPropertyNode *) = 0);
+
+const char* SGReaderWriterXML::className() const
+{
+    return "XML database reader";
+}
+
+bool SGReaderWriterXML::acceptsExtension(const std::string& extension) const
+{
+    return (osgDB::equalCaseInsensitive(extension, "xml"));
+}
+
+osgDB::ReaderWriter::ReadResult
+SGReaderWriterXML::readNode(const std::string& fileName,
+                            const osgDB::ReaderWriter::Options* options) const
+{
+    // SG_LOG(SG_GENERAL, SG_ALERT, "SGReaderWriterXML::readNode(" << fileName << ")");
+
+    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
+    if (!acceptsExtension(ext))
+        return ReadResult::FILE_NOT_HANDLED;
+
+    const SGReaderWriterXMLOptions* xmlOptions
+    = dynamic_cast<const SGReaderWriterXMLOptions*>(options);
+
+    string fg_root;
+    SGPropertyNode *prop_root=0;
+    osg::Node *(*load_panel)(SGPropertyNode *)=0;
+    SGModelData *model_data=0;
+    SGPath externalTexturePath;
+
+    if (xmlOptions) {
+        prop_root = xmlOptions->getPropRoot();
+        load_panel = xmlOptions->getLoadPanel();
+        model_data = xmlOptions->getModelData();
+    }
+
+    fg_root=osgDB::Registry::instance()->getDataFilePathList().front();
+
+    osg::Node *result=0;
+
+    try {
+        result=sgLoad3DModel_internal(fileName, prop_root, model_data, load_panel);
+    } catch (const sg_throwable &t) {
+        SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage());
+        result=new osg::Node;
+    }
+    if (result)
+        return result;
+    else
+        return ReadResult::FILE_NOT_HANDLED;
+}
+
+class SGSwitchUpdateCallback : public osg::NodeCallback
+{
+public:
+    SGSwitchUpdateCallback(SGCondition* condition) :
+            mCondition(condition) {}
+    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
+        assert(dynamic_cast<osg::Switch*>(node));
+        osg::Switch* s = static_cast<osg::Switch*>(node);
+
+        if (mCondition && mCondition->test()) {
+            s->setAllChildrenOn();
+            // note, callback is responsible for scenegraph traversal so
+            // should always include call traverse(node,nv) to ensure
+            // that the rest of cullbacks and the scene graph are traversed.
+            traverse(node, nv);
+        } else
+            s->setAllChildrenOff();
+    }
+
+private:
+    SGSharedPtr<SGCondition> mCondition;
+};
+
+osg::Node *
+sgLoad3DModel_internal(const string &path,
+                       SGPropertyNode *prop_root,
+                       SGModelData *data,
+                       osg::Node *(*load_panel)(SGPropertyNode *))
+{
+    string fg_root=osgDB::Registry::instance()->getDataFilePathList().front();
+    osg::ref_ptr<osg::Node> model;
+    osg::ref_ptr<osg::Group> group;
+    SGPropertyNode_ptr props = new SGPropertyNode;
+
+    // Load the 3D object itself
+    SGPath modelpath = path, texturepath = path;
+    if ( !ulIsAbsolutePathName( path.c_str() ) ) {
+        SGPath tmp = fg_root;
+        tmp.append(modelpath.str());
+        modelpath = texturepath = tmp;
+    }
+
+    // Check for an XML wrapper
+    if (modelpath.str().substr(modelpath.str().size() - 4, 4) == ".xml") {
+        try {
+            readProperties(modelpath.str(), props);
+        } catch (const sg_throwable &t) {
+            SG_LOG(SG_INPUT, SG_ALERT, "Failed to load xml: " << t.getFormattedMessage());
+            throw;
+        }
+        if (props->hasValue("/path")) {
+            modelpath = modelpath.dir();
+            modelpath.append(props->getStringValue("/path"));
+            if (props->hasValue("/texture-path")) {
+                texturepath = texturepath.dir();
+                texturepath.append(props->getStringValue("/texture-path"));
+            }
+        } else {
+            model = new osg::Node;
+        }
+    }
+
+    osg::ref_ptr<osgDB::ReaderWriter::Options> options
+    = new osgDB::ReaderWriter::Options(*osgDB::Registry::instance()
+                                       ->getOptions());
+
+    // Assume that textures are in
+    // the same location as the XML file.
+    if (!model) {
+        if (texturepath.extension() != "")
+            texturepath = texturepath.dir();
+
+        options->setDatabasePath(texturepath.str());
+        model = osgDB::readNodeFile(modelpath.str(), options.get());
+        if (model == 0)
+            throw sg_io_exception("Failed to load 3D model",
+                                  sg_location(modelpath.str()));
+    }
+
+    bool needTransform=false;
+    // Set up the alignment node if needed
+    SGPropertyNode *offsets = props->getNode("offsets", false);
+    if (offsets) {
+        needTransform=true;
+        osg::MatrixTransform *alignmainmodel = new osg::MatrixTransform;
+        osg::Matrix res_matrix;
+        res_matrix.makeRotate(
+            offsets->getFloatValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+            osg::Vec3(0, 1, 0),
+            offsets->getFloatValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+            osg::Vec3(1, 0, 0),
+            offsets->getFloatValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+            osg::Vec3(0, 0, 1));
+
+        osg::Matrix tmat;
+        tmat.makeTranslate(offsets->getFloatValue("x-m", 0.0),
+                           offsets->getFloatValue("y-m", 0.0),
+                           offsets->getFloatValue("z-m", 0.0));
+        alignmainmodel->setMatrix(res_matrix*tmat);
+        group = alignmainmodel;
+    }
+    if (!group) {
+        group = new osg::Group;
+    }
+    group->addChild(model.get());
+
+    // Load sub-models
+    vector<SGPropertyNode_ptr> model_nodes = props->getChildren("model");
+    for (unsigned i = 0; i < model_nodes.size(); i++) {
+        SGPropertyNode_ptr sub_props = model_nodes[i];
+
+        osg::ref_ptr<osg::Node> submodel;
+        const char* submodelFileName = sub_props->getStringValue("path");
+        try {
+            submodel = sgLoad3DModel_internal(submodelFileName, prop_root, 0, load_panel);
+        } catch (const sg_throwable &t) {
+            SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage());
+            throw;
+        }
+
+        osg::ref_ptr<osg::Node> submodel_final=submodel.get();
+        SGPropertyNode *offs = sub_props->getNode("offsets", false);
+        if (offs) {
+            osg::Matrix res_matrix;
+            osg::ref_ptr<osg::MatrixTransform> align = new osg::MatrixTransform;
+            res_matrix.makeIdentity();
+            res_matrix.makeRotate(
+                offs->getDoubleValue("pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+                osg::Vec3(0, 1, 0),
+                offs->getDoubleValue("roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+                osg::Vec3(1, 0, 0),
+                offs->getDoubleValue("heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
+                osg::Vec3(0, 0, 1));
+
+            osg::Matrix tmat;
+            tmat.makeIdentity();
+            tmat.makeTranslate(offs->getDoubleValue("x-m", 0),
+                               offs->getDoubleValue("y-m", 0),
+                               offs->getDoubleValue("z-m", 0));
+            align->setMatrix(res_matrix*tmat);
+            align->addChild(submodel.get());
+            submodel_final=align.get();
+        }
+        submodel_final->setName(sub_props->getStringValue("name", ""));
+
+        SGPropertyNode *cond = sub_props->getNode("condition", false);
+        if (cond) {
+            osg::ref_ptr<osg::Switch> sw = new osg::Switch;
+            sw->setUpdateCallback(new SGSwitchUpdateCallback(sgReadCondition(prop_root, cond)));
+            group->addChild(sw.get());
+            sw->addChild(submodel_final.get());
+            sw->setName("submodel condition switch");
+        } else {
+            group->addChild(submodel_final.get());
+        }
+    } // end of submodel loading
+
+    if ( load_panel ) {
+        // Load panels
+        vector<SGPropertyNode_ptr> panel_nodes = props->getChildren("panel");
+        for (unsigned i = 0; i < panel_nodes.size(); i++) {
+            SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel");
+            osg::ref_ptr<osg::Node> panel = load_panel(panel_nodes[i]);
+            if (panel_nodes[i]->hasValue("name"))
+                panel->setName((char *)panel_nodes[i]->getStringValue("name"));
+            group->addChild(panel.get());
+        }
+    }
+
+    std::vector<SGPropertyNode_ptr> particle_nodes;
+    particle_nodes = props->getChildren("particlesystem");
+    for (unsigned i = 0; i < particle_nodes.size(); ++i) {
+        if (i==0) {
+            if (texturepath.extension() != "")
+                texturepath = texturepath.dir();
+
+            options->setDatabasePath(texturepath.str());
+        }
+        group->addChild(Particles::appendParticles(particle_nodes[i],
+                        prop_root,
+                        options.get()));
+    }
+
+    if (data) {
+        SGPropertyNode *nasal = props->getNode("nasal", false);
+        data->setProps(nasal);
+        group->setUserData(data);
+        //data->modelLoaded(path, nasal, group.get());
+    }
+
+    std::vector<SGPropertyNode_ptr> animation_nodes;
+    animation_nodes = props->getChildren("animation");
+    for (unsigned i = 0; i < animation_nodes.size(); ++i)
+        /// OSGFIXME: duh, why not only model?????
+        SGAnimation::animate(group.get(), animation_nodes[i], prop_root,
+                             options.get());
+
+    if (props->hasChild("debug-outfile")) {
+        std::string outputfile = props->getStringValue("debug-outfile",
+                                 "debug-model.osg");
+        osgDB::writeNodeFile(*group, outputfile);
+    }
+    if (!needTransform && group->getNumChildren() < 2) {
+        model = group->getChild(0);
+        group->removeChild(model.get());
+        model->setUserData(group->getUserData());
+        return model.release();
+    }
+
+    return group.release();
+}
+
diff --git a/simgear/scene/model/SGReaderWriterXML.hxx b/simgear/scene/model/SGReaderWriterXML.hxx
new file mode 100644 (file)
index 0000000..2d92c3e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006-2007 Tim Moore timoore@redhat.com
+ * 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 SGREADERWRITERXML_HXX
+#define SGREADERWRITERXML_HXX 1
+#include <osgDB/Registry>
+namespace simgear
+{
+
+class SGReaderWriterXML : public osgDB::ReaderWriter
+{
+public:
+    virtual const char* className() const;
+
+    virtual bool acceptsExtension(const std::string& extension) const;
+
+    virtual ReadResult readNode(const std::string& fileName,
+                                const osgDB::ReaderWriter::Options* options)
+    const;
+};
+
+}
+#endif
+
diff --git a/simgear/scene/model/SGReaderWriterXMLOptions.hxx b/simgear/scene/model/SGReaderWriterXMLOptions.hxx
new file mode 100644 (file)
index 0000000..b9f4654
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (C) 2007 Tim Moore timoore@redhat.com
+// 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 SGREADERWRITERXMLOPTIONS_HXX
+#define SGREADERWRITERXMLOPTIONS_HXX 1
+
+#include <osgDB/ReaderWriter>
+#include <simgear/props/props.hxx>
+
+class SGPropertyNode;
+
+namespace simgear
+{
+class SGModelData;
+
+class SGReaderWriterXMLOptions : public osgDB::ReaderWriter::Options
+{
+public:
+    typedef osg::Node *(*panel_func)(SGPropertyNode *);
+
+    SGReaderWriterXMLOptions():
+            osgDB::ReaderWriter::Options(),
+            _prop_root(0),
+            _load_panel(0),
+            _model_data(0) {}
+
+    SGReaderWriterXMLOptions(const std::string& str):
+            osgDB::ReaderWriter::Options(str),
+            _prop_root(0),
+            _load_panel(0),
+            _model_data(0) {}
+
+    SGReaderWriterXMLOptions(const SGReaderWriterXMLOptions& options,
+                             const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
+            osgDB::ReaderWriter::Options(options, copyop),
+            _prop_root(options._prop_root),
+            _load_panel(options._load_panel),
+            _model_data(options._model_data) {}
+
+    SGReaderWriterXMLOptions(const osgDB::ReaderWriter::Options& options,
+                             const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
+            osgDB::ReaderWriter::Options(options, copyop),
+            _prop_root(0),
+            _load_panel(0),
+            _model_data(0) {}
+
+    SGPropertyNode *getPropRoot() const {
+        return _prop_root;
+    }
+    panel_func getLoadPanel() const {
+        return _load_panel;
+    }
+    SGModelData *getModelData() const {
+        return _model_data.get();
+    }
+
+    void setPropRoot(SGPropertyNode *p) {
+        _prop_root=p;
+    }
+    void setLoadPanel(panel_func pf) {
+        _load_panel=pf;
+    }
+    void setModelData(SGModelData *d) {
+        _model_data=d;
+    }
+
+protected:
+    virtual ~SGReaderWriterXMLOptions() {}
+
+    SGPropertyNode_ptr _prop_root;
+    osg::Node *(*_load_panel)(SGPropertyNode *);
+    osg::ref_ptr<SGModelData> _model_data;
+};
+
+}
+#endif
index fd4962c097050e642dad956e57ecccac21cd8a51..cdd50861c478979587126563c501018b54eb4856 100644 (file)
@@ -7,38 +7,21 @@
 #include <simgear_config.h>
 #endif
 
-#include <osg/observer_ptr>
 #include <osg/ref_ptr>
-#include <osg/Group>
-#include <osg/NodeCallback>
-#include <osg/Switch>
-#include <osg/MatrixTransform>
-#include <osgDB/Archive>
-#include <osgDB/FileNameUtils>
-#include <osgDB/FileUtils>
 #include <osgDB/ReadFile>
-#include <osgDB/WriteFile>
-#include <osgDB/Registry>
 #include <osgDB/SharedStateManager>
-#include <osgUtil/Optimizer>
 
 #include <simgear/scene/util/SGSceneFeatures.hxx>
-#include <simgear/scene/util/SGStateAttributeVisitor.hxx>
-#include <simgear/scene/util/SGTextureStateAttributeVisitor.hxx>
 
 #include <simgear/structure/exception.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/props/props_io.hxx>
 #include <simgear/props/condition.hxx>
 
-#include "animation.hxx"
 #include "model.hxx"
-#include "particles.hxx"
 
 SG_USING_STD(vector);
 
-using namespace simgear;
-
 osg::Texture2D*
 SGLoadTexture2D(bool staticTexture, const std::string& path,
                 const osgDB::ReaderWriter::Options* options,
@@ -96,200 +79,4 @@ SGLoadTexture2D(bool staticTexture, const std::string& path,
   return texture.release();
 }
 
-class SGSwitchUpdateCallback : public osg::NodeCallback {
-public:
-  SGSwitchUpdateCallback(SGCondition* condition) :
-    mCondition(condition) {}
-  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-  { 
-    assert(dynamic_cast<osg::Switch*>(node));
-    osg::Switch* s = static_cast<osg::Switch*>(node);
-
-    if (mCondition && mCondition->test()) {
-      s->setAllChildrenOn();
-      // note, callback is responsible for scenegraph traversal so
-      // should always include call traverse(node,nv) to ensure 
-      // that the rest of cullbacks and the scene graph are traversed.
-      traverse(node, nv);
-    } else
-      s->setAllChildrenOff();
-  }
-
-private:
-  SGSharedPtr<SGCondition> mCondition;
-};
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Global functions.
-////////////////////////////////////////////////////////////////////////
-
-osg::Node *
-sgLoad3DModel( const string &fg_root, const string &path,
-               SGPropertyNode *prop_root,
-               double sim_time_sec, osg::Node *(*load_panel)(SGPropertyNode *),
-               SGModelData *data,
-               const SGPath& externalTexturePath )
-{
-  osg::ref_ptr<osg::Node> model;
-  SGPropertyNode props;
-
-  // Load the 3D aircraft object itself
-  SGPath modelpath = path, texturepath = path;
-  if ( !ulIsAbsolutePathName( path.c_str() ) ) {
-    SGPath tmp = fg_root;
-    tmp.append(modelpath.str());
-    modelpath = texturepath = tmp;
-  }
-
-  // Check for an XML wrapper
-  if (modelpath.str().substr(modelpath.str().size() - 4, 4) == ".xml") {
-    readProperties(modelpath.str(), &props);
-    if (props.hasValue("/path")) {
-      modelpath = modelpath.dir();
-      modelpath.append(props.getStringValue("/path"));
-      if (props.hasValue("/texture-path")) {
-        texturepath = texturepath.dir();
-        texturepath.append(props.getStringValue("/texture-path"));
-      }
-    } else {
-      if (!model)
-        model = new osg::Switch;
-    }
-  }
-
-  osg::ref_ptr<osgDB::ReaderWriter::Options> options
-      = new osgDB::ReaderWriter::Options(*osgDB::Registry::instance()
-                                         ->getOptions());
-
-  // Assume that textures are in
-  // the same location as the XML file.
-  if (!model) {
-      if (texturepath.extension() != "")
-          texturepath = texturepath.dir();
-
-      options->setDatabasePath(texturepath.str());
-      if (!externalTexturePath.str().empty())
-          options->getDatabasePathList().push_back(externalTexturePath.str());
-
-      model = osgDB::readNodeFile(modelpath.str(), options.get());
-      if (model == 0)
-          throw sg_io_exception("Failed to load 3D model", 
-                                sg_location(modelpath.str()));
-  }
-
-  // Set up the alignment node
-  osg::ref_ptr<osg::MatrixTransform> alignmainmodel = new osg::MatrixTransform;
-  alignmainmodel->addChild(model.get());
-  osg::Matrix res_matrix;
-  res_matrix.makeRotate(
-    props.getFloatValue("/offsets/pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-    osg::Vec3(0, 1, 0),
-    props.getFloatValue("/offsets/roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-    osg::Vec3(1, 0, 0),
-    props.getFloatValue("/offsets/heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-    osg::Vec3(0, 0, 1));
-
-  osg::Matrix tmat;
-  tmat.makeTranslate(props.getFloatValue("/offsets/x-m", 0.0),
-                     props.getFloatValue("/offsets/y-m", 0.0),
-                     props.getFloatValue("/offsets/z-m", 0.0));
-  alignmainmodel->setMatrix(res_matrix*tmat);
-
-  // Load sub-models
-  vector<SGPropertyNode_ptr> model_nodes = props.getChildren("model");
-  for (unsigned i = 0; i < model_nodes.size(); i++) {
-    SGPropertyNode_ptr node = model_nodes[i];
-    osg::ref_ptr<osg::MatrixTransform> align = new osg::MatrixTransform;
-    res_matrix.makeIdentity();
-    res_matrix.makeRotate(
-      node->getDoubleValue("offsets/pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-      osg::Vec3(0, 1, 0),
-      node->getDoubleValue("offsets/roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-      osg::Vec3(1, 0, 0),
-      node->getDoubleValue("offsets/heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
-      osg::Vec3(0, 0, 1));
-    
-    tmat.makeIdentity();
-    tmat.makeTranslate(node->getDoubleValue("offsets/x-m", 0),
-                       node->getDoubleValue("offsets/y-m", 0),
-                       node->getDoubleValue("offsets/z-m", 0));
-    align->setMatrix(res_matrix*tmat);
-
-    osg::ref_ptr<osg::Node> kid;
-    const char* submodel = node->getStringValue("path");
-    try {
-      kid = sgLoad3DModel( fg_root, submodel, prop_root, sim_time_sec, load_panel );
-
-    } catch (const sg_throwable &t) {
-      SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage());
-      throw;
-    }
-    align->addChild(kid.get());
-
-    align->setName(node->getStringValue("name", ""));
-
-    SGPropertyNode *cond = node->getNode("condition", false);
-    if (cond) {
-      osg::ref_ptr<osg::Switch> sw = new osg::Switch;
-      sw->setUpdateCallback(new SGSwitchUpdateCallback(sgReadCondition(prop_root, cond)));
-      alignmainmodel->addChild(sw.get());
-      sw->addChild(align.get());
-      sw->setName("submodel condition switch");
-    } else {
-      alignmainmodel->addChild(align.get());
-    }
-  }
-
-  if ( load_panel ) {
-    // Load panels
-    vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
-    for (unsigned i = 0; i < panel_nodes.size(); i++) {
-        SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel");
-        osg::ref_ptr<osg::Node> panel = load_panel(panel_nodes[i]);
-        if (panel_nodes[i]->hasValue("name"))
-            panel->setName((char *)panel_nodes[i]->getStringValue("name"));
-        alignmainmodel->addChild(panel.get());
-    }
-  }
-
-  std::vector<SGPropertyNode_ptr> particle_nodes;
-  particle_nodes = props.getChildren("particlesystem");
-  for (unsigned i = 0; i < particle_nodes.size(); ++i)
-  {
-    if(i==0)
-    {
-      if (texturepath.extension() != "")
-          texturepath = texturepath.dir();
-
-      options->setDatabasePath(texturepath.str());
-      if (!externalTexturePath.str().empty())
-          options->getDatabasePathList().push_back(externalTexturePath.str());
-    }
-    alignmainmodel.get()->addChild(Particles::appendParticles(particle_nodes[i],
-                                                              prop_root,
-                                                              options.get()));
-  }
-
-  if (data) {
-    alignmainmodel->setUserData(data);
-    data->modelLoaded(path, &props, alignmainmodel.get());
-  }
-
-  std::vector<SGPropertyNode_ptr> animation_nodes;
-  animation_nodes = props.getChildren("animation");
-  for (unsigned i = 0; i < animation_nodes.size(); ++i)
-    /// OSGFIXME: duh, why not only model?????
-    SGAnimation::animate(alignmainmodel.get(), animation_nodes[i], prop_root,
-                         options.get());
-
-  if (props.hasChild("debug-outfile")) {
-    std::string outputfile = props.getStringValue("debug-outfile",
-                                                  "debug-model.osg");
-    osgDB::writeNodeFile(*alignmainmodel, outputfile);
-  }
-
-  return alignmainmodel.release();
-}
-
 // end of model.cxx
index db7f663806d48a006f21aba6d4167cb922c7b159..1de3bf40c0e77d99b845bf5cf923e688762e669d 100644 (file)
@@ -23,63 +23,6 @@ SG_USING_STD(set);
 #include <osgDB/ReaderWriter>
 
 #include <simgear/misc/sg_path.hxx>
-#include <simgear/props/props.hxx>
-
-
-// Has anyone done anything *really* stupid, like making min and max macros?
-#ifdef min
-#undef min
-#endif
-#ifdef max
-#undef max
-#endif
-
-
-/**
- * Abstract class for adding data to the scene graph.  modelLoaded() is
- * called by sgLoad3DModel() after the model was loaded, and the destructor
- * when the branch is removed from the graph.
- */
-class SGModelData : public osg::Referenced {
-public:
-    virtual ~SGModelData() {}
-    virtual void modelLoaded( const string& path, SGPropertyNode *prop,
-                              osg::Node*branch) = 0;
-};
-
-
-/**
- * Load a 3D model with or without XML wrapper.  Note, this version
- * Does not know about or load the panel/cockpit information.  Use the
- * "model_panel.hxx" version if you want to load an aircraft
- * (i.e. ownship) with a panel.
- *
- * If the path ends in ".xml", then it will be used as a property-
- * list wrapper to add animations to the model.
- *
- * Subsystems should not normally invoke this function directly;
- * instead, they should use the FGModelLoader declared in loader.hxx.
- */
-osg::Node*
-sgLoad3DModel( const string& fg_root, const string &path,
-               SGPropertyNode *prop_root, double sim_time_sec,
-               osg::Node *(*load_panel)(SGPropertyNode *) = 0,
-               SGModelData *data = 0,
-               const SGPath& texturePath = SGPath() );
-
-
-/**
- * Make the animation
- */
-void
-sgMakeAnimation( osg::Node* model,
-                 const char * name,
-                 vector<SGPropertyNode_ptr> &name_nodes,
-                 SGPropertyNode *prop_root,
-                 SGPropertyNode_ptr node,
-                 double sim_time_sec,
-                 SGPath &texture_path,
-                 set<osg::Node*> &ignore_branches );
 
 osg::Texture2D*
 SGLoadTexture2D(bool staticTexture, const std::string& path,
index 70216e066827d35440658c955d942c35289735ee..5cb6965d08df3dac6e8179f2641f4308e9aadc17 100644 (file)
-// modellib.cxx - implement an SSG model library.
+// 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 <simgear/compiler.h>
+#include <osgDB/ReadFile>
+#include <osgDB/WriteFile>
+#include <osgDB/Registry>
+
+#include <simgear/constants.h>
 #include <simgear/props/props.hxx>
-#include <simgear/scene/util/SGNodeMasks.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/scene/model/ModelRegistry.hxx>
 
-#include "model.hxx"
-#include "animation.hxx"
+#include "SGPagedLOD.hxx"
+#include "SGReaderWriterXML.hxx"
+#include "SGReaderWriterXMLOptions.hxx"
 
+//#include "model.hxx"
 #include "modellib.hxx"
 
 
+using namespace simgear;
+
+osgDB::RegisterReaderWriterProxy<SGReaderWriterXML> g_readerWriter_XML_Proxy;
+ModelRegistryCallbackProxy<LoadOnlyCallback> g_xmlCallbackProxy("xml");
+
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGModelLib.
 ////////////////////////////////////////////////////////////////////////
+void SGModelLib::init(const string &root_dir)
+{
+    osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
+}
 
-SGModelLib::SGModelLib ()
+SGModelLib::SGModelLib()
 {
 }
 
-SGModelLib::~SGModelLib ()
+SGModelLib::~SGModelLib()
 {
 }
 
-void
-SGModelLib::flush1()
+osg::Node*
+SGModelLib::loadModel(const string &path,
+                       SGPropertyNode *prop_root,
+                       SGModelData *data)
 {
+    osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
+    opt->setPropRoot(prop_root);
+    opt->setModelData(data);
+    osg::Node *n = readNodeFile(path, opt.get());
+    if(data)
+        data->modelLoaded(path, data->getProperties(), n);
+    return n;
+
 }
 
 osg::Node*
-SGModelLib::load_model( const string &fg_root,
-                           const string &path,
-                           SGPropertyNode *prop_root,
-                           double sim_time_sec,
-                           bool cache_object,
-                           SGModelData *data )
+SGModelLib::loadModel(const string &path,
+                                SGPropertyNode *prop_root,
+                                panel_func pf)
 {
-  return sgLoad3DModel(fg_root, path, prop_root, sim_time_sec, 0, data );
+    osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
+    opt->setPropRoot(prop_root);
+    opt->setLoadPanel(pf);
+    return readNodeFile(path, opt.get());
 }
 
+osg::Node*
+SGModelLib::loadPagedModel(const string &path,
+                           SGPropertyNode *prop_root,
+                           SGModelData *data)
+{
+    SGPagedLOD *plod = new SGPagedLOD;
+    plod->setFileName(0, path);
+    plod->setRange(0, 0.0, 50.0*SG_NM_TO_METER);
+
+    osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
+    opt->setPropRoot(prop_root);
+    opt->setModelData(data);
+    plod->setReaderWriterOptions(opt.get());
+    return plod;
+}
 
 // end of modellib.cxx
index b5613bc6483c013df309cf67eb0e783df4a68355..b2d038ebefbed27023d20f68f610a50a9ee4c02c 100644 (file)
@@ -1,4 +1,19 @@
-// modellib.cxx - implement an SSG model library.
+// 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 _SG_MODEL_LIB_HXX
 #define _SG_MODEL_LIB_HXX 1
 
 #include <simgear/compiler.h>  // for SG_USING_STD
 
-#include <map>
 #include STL_STRING
 
-#include <osg/ref_ptr>
 #include <osg/Node>
 
 #include <simgear/props/props.hxx>
-#include "model.hxx"
 
 SG_USING_STD(map);
 SG_USING_STD(string);
 
+namespace simgear {
+
+class SGModelData; // defined below
 
 /**
  * Class for loading and managing models with XML wrappers.
  */
 class SGModelLib
 {
+public:
+    typedef osg::Node *(*panel_func)(SGPropertyNode *);
+
+    static void init(const string &root_dir);
+
+    // Load a 3D model (any format)
+    // data->modelLoaded() will be called after the model is loaded
+    static osg::Node* loadModel(const string &path,
+                                SGPropertyNode *prop_root,
+                                SGModelData *data=0);
+
+    // Load a 3D model (any format)
+    // with a panel_func to load a panel
+    static osg::Node* loadModel(const string &path,
+                                SGPropertyNode *prop_root,
+                                panel_func pf);
+
+    // 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.
+    static osg::Node* loadPagedModel(const string &path,
+                                     SGPropertyNode *prop_root,
+                                     SGModelData *data=0);
 
+protected:
+    SGModelLib();
+    ~SGModelLib ();
+};
+
+
+/**
+ * Abstract class for adding data to the scene graph.  modelLoaded() is
+ * called after the model was loaded, and the destructor when the branch
+ * is removed from the scene graph.
+ */
+class SGModelData : public osg::Referenced {
 public:
+    virtual ~SGModelData() {}
+    virtual void modelLoaded( const string& path, SGPropertyNode *prop,
+                              osg::Node*branch) = 0;
 
-    SGModelLib ();
-    virtual ~SGModelLib ();
-    virtual void flush1();
+    virtual void setProps(SGPropertyNode *p)
+        { _props = p; }
 
-    virtual osg::Node *load_model( const string &fg_root,
-                                   const string &path,
-                                   SGPropertyNode *prop_root,
-                                   double sim_time_sec,
-                                   bool cache_object,
-                                   SGModelData *data = 0 );
+    SGPropertyNode *getProperties()
+        { return _props; }
+protected:
+    SGPropertyNode_ptr _props;
 };
 
+}
 
 #endif // _SG_MODEL_LIB_HXX
index c1956edd3fdfb9251cc228555a642aa90683cc8c..5413c8df0608aedd2be7b3fedce876527b945801 100644 (file)
 // building / drawing any scenery.
 
 static bool _inited = false;
-static SGModelLib *modellib = NULL;
-static string model_root = "";
 static SGPropertyNode *root_props = NULL;
-static double sim_time_sec = 0.0;
 
 // Because BTG files are now loaded through the osgDB::Registry, there
 // are no symbols referenced by FlightGear in this library other than
@@ -58,21 +55,17 @@ static double sim_time_sec = 0.0;
 // to be sucked in.
 osgDB::RegisterReaderWriterProxy<SGReaderWriterBTG> g_readerWriter_BTG_Proxy;
 
-void sgUserDataInit( SGModelLib *m, const string &r,
-                     SGPropertyNode *p, double t ) {
+void sgUserDataInit( SGPropertyNode *p ) {
     _inited = true;
-    modellib = m;
-    model_root = r;
     root_props = p;
-    sim_time_sec = t;
 }
 
  osg::Node* sgGetRandomModel(SGMatModel *obj) {
-   return obj->get_random_model(modellib, model_root, root_props, sim_time_sec);
+   return obj->get_random_model( root_props );
  }
 
 osg::Node* sgGetModel(int i, SGMatModel *obj) {
-   return obj->get_model(i, modellib, model_root, root_props, sim_time_sec);
+   return obj->get_model(i, root_props );
  }
 
 static void random_pt_inside_tri( float *res,
@@ -91,257 +84,3 @@ static void random_pt_inside_tri( float *res,
     res[2] = n1[2]*a + n2[2]*b + n3[2]*c;
 }
 
-
-/**
- * Fill in a triangle with randomly-placed objects.
- *
- * This method is invoked by a callback when the triangle is in range
- * but not yet populated.
- *
- */
-
-void SGTriUserData::fill_in_triangle ()
-{
-                                // generate a repeatable random seed
-    sg_srandom(seed);
-
-    int nObjects = object_group->get_object_count();
-
-    for (int i = 0; i < nObjects; i++) {
-      SGMatModel * object = object_group->get_object(i);
-      double num = area / object->get_coverage_m2();
-
-      // place an object each unit of area
-      while ( num > 1.0 ) {
-          add_object_to_triangle(object);
-          num -= 1.0;
-      }
-      // for partial units of area, use a zombie door method to
-      // create the proper random chance of an object being created
-      // for this triangle
-      if ( num > 0.0 ) {
-        if ( sg_random() <= num ) {
-          // a zombie made it through our door
-                add_object_to_triangle(object);
-        }
-      }
-    }
-}
-
-void SGTriUserData::add_object_to_triangle (SGMatModel * object)
-{
-    // Set up the random heading if required.
-    double hdg_deg = 0;
-    if (object->get_heading_type() == SGMatModel::HEADING_RANDOM)
-        hdg_deg = sg_random() * 360;
-
-#if 0
-    // OSGFIXME
-    sgMat4 mat;
-    makeWorldMatrix(mat, hdg_deg);
-
-    ssgTransform * pos = new ssgTransform;
-    pos->setTransform(mat);
-    // the parameters to get_random_model() are set in local static
-    // data via the ssgUserDataInit() function.  This function must be
-    // called before any scenery is drawn.
-    pos->addKid( object->get_random_model( modellib, model_root,
-                                           root_props, sim_time_sec )
-                 );
-    branch->addKid(pos);
-#endif
-}
-
-void SGTriUserData::makeWorldMatrix (sgMat4 mat, double hdg_deg )
-{
-  // OSGFIXME
-//     if (hdg_deg == 0) {
-//         mat[0][0] =  leafData->sin_lat * leafData->cos_lon;
-//         mat[0][1] =  leafData->sin_lat * leafData->sin_lon;
-//         mat[0][2] = -leafData->cos_lat;
-//         mat[0][3] =  SG_ZERO;
-
-//         mat[1][0] =  -leafData->sin_lon;
-//         mat[1][1] =  leafData->cos_lon;
-//         mat[1][2] =  SG_ZERO;
-//         mat[1][3] =  SG_ZERO;
-//     } else {
-//         float sin_hdg = sin( hdg_deg * SGD_DEGREES_TO_RADIANS ) ;
-//         float cos_hdg = cos( hdg_deg * SGD_DEGREES_TO_RADIANS ) ;
-//         mat[0][0] =  cos_hdg * leafData->sin_lat * leafData->cos_lon - sin_hdg * leafData->sin_lon;
-//         mat[0][1] =  cos_hdg * leafData->sin_lat * leafData->sin_lon + sin_hdg * leafData->cos_lon;
-//         mat[0][2] = -cos_hdg * leafData->cos_lat;
-//         mat[0][3] =  SG_ZERO;
-
-//         mat[1][0] = -sin_hdg * leafData->sin_lat * leafData->cos_lon - cos_hdg * leafData->sin_lon;
-//         mat[1][1] = -sin_hdg * leafData->sin_lat * leafData->sin_lon + cos_hdg * leafData->cos_lon;
-//         mat[1][2] =  sin_hdg * leafData->cos_lat;
-//         mat[1][3] =  SG_ZERO;
-//     }
-
-//     mat[2][0] = leafData->cos_lat * leafData->cos_lon;
-//     mat[2][1] = leafData->cos_lat * leafData->sin_lon;
-//     mat[2][2] = leafData->sin_lat;
-//     mat[2][3] = SG_ZERO;
-
-//     // translate to random point in triangle
-//     sgVec3 result;
-//     random_pt_inside_tri(result, p1, p2, p3);
-//     sgSubVec3(mat[3], result, center);
-
-//     mat[3][3] = SG_ONE ;
-}
-
-/**
- * SSG callback for an in-range triangle of randomly-placed objects.
- *
- * This pretraversal callback is attached to a branch that is traversed
- * only when a triangle is in range.  If the triangle is not currently
- * populated with randomly-placed objects, this callback will populate
- * it.
- *
- * @param entity The entity to which the callback is attached (not used).
- * @param mask The entity's traversal mask (not used).
- * @return Always 1, to allow traversal and culling to continue.
- */
-// static int
-// tri_in_range_callback (ssgEntity * entity, int mask)
-// {
-//   SGTriUserData * data = (SGTriUserData *)entity->getUserData();
-//   if (!data->is_filled_in) {
-//         data->fill_in_triangle();
-//     data->is_filled_in = true;
-//   }
-//   return 1;
-// }
-
-
-/**
- * SSG callback for an out-of-range triangle of randomly-placed objects.
- *
- * This pretraversal callback is attached to a branch that is traversed
- * only when a triangle is out of range.  If the triangle is currently
- * populated with randomly-placed objects, the objects will be removed.
- *
- *
- * @param entity The entity to which the callback is attached (not used).
- * @param mask The entity's traversal mask (not used).
- * @return Always 0, to prevent any further traversal or culling.
- */
-// static int
-// tri_out_of_range_callback (ssgEntity * entity, int mask)
-// {
-//   SGTriUserData * data = (SGTriUserData *)entity->getUserData();
-//   if (data->is_filled_in) {
-//     data->branch->removeAllKids();
-//     data->is_filled_in = false;
-//   }
-//   return 0;
-// }
-
-
-/**
- * Calculate the bounding radius of a triangle from its center.
- *
- * @param center The triangle center.
- * @param p1 The first point in the triangle.
- * @param p2 The second point in the triangle.
- * @param p3 The third point in the triangle.
- * @return The greatest distance any point lies from the center.
- */
-// static inline float
-// get_bounding_radius( sgVec3 center, float *p1, float *p2, float *p3)
-// {
-//    return sqrt( SG_MAX3( sgDistanceSquaredVec3(center, p1),
-//                          sgDistanceSquaredVec3(center, p2),
-//                          sgDistanceSquaredVec3(center, p3) ) );
-// }
-
-
-/**
- * Set up a triangle for randomly-placed objects.
- *
- * No objects will be added unless the triangle comes into range.
- *
- */
-
-void SGLeafUserData::setup_triangle (int i )
-{
-//     short n1, n2, n3;
-//     leaf->getTriangle(i, &n1, &n2, &n3);
-
-//     float * p1 = leaf->getVertex(n1);
-//     float * p2 = leaf->getVertex(n2);
-//     float * p3 = leaf->getVertex(n3);
-
-//                                 // Set up a single center point for LOD
-//     sgVec3 center;
-//     sgSetVec3(center,
-//               (p1[0] + p2[0] + p3[0]) / 3.0,
-//               (p1[1] + p2[1] + p3[1]) / 3.0,
-//               (p1[2] + p2[2] + p3[2]) / 3.0);
-//     double area = sgTriArea(p1, p2, p3);
-      
-//                                 // maximum radius of an object from center.
-//     double bounding_radius = get_bounding_radius(center, p1, p2, p3);
-
-//                                 // Set up a transformation to the center
-//                                 // point, so that everything else can
-//                                 // be specified relative to it.
-//     ssgTransform * location = new ssgTransform;
-//     sgMat4 TRANS;
-//     sgMakeTransMat4(TRANS, center);
-//     location->setTransform(TRANS);
-//     branch->addKid(location);
-
-//                                 // Iterate through all the object types.
-//     int num_groups = mat->get_object_group_count();
-//     for (int j = 0; j < num_groups; j++) {
-//                                 // Look up the random object.
-//         SGMatModelGroup * group = mat->get_object_group(j);
-
-//                                 // Set up the range selector for the entire
-//                                 // triangle; note that we use the object
-//                                 // range plus the bounding radius here, to
-//                                 // allow for objects far from the center.
-//         float ranges[] = { 0,
-//                           group->get_range_m() + bounding_radius,
-//                 SG_MAX };
-//         ssgRangeSelector * lod = new ssgRangeSelector;
-//         lod->setRanges(ranges, 3);
-//         location->addKid(lod);
-
-//                                 // Create the in-range and out-of-range
-//                                 // branches.
-//         ssgBranch * in_range = new ssgBranch;
-//         ssgBranch * out_of_range = new ssgBranch;
-
-//                                 // Set up the user data for if/when
-//                                 // the random objects in this triangle
-//                                 // are filled in.
-//         SGTriUserData * data = new SGTriUserData;
-//         data->is_filled_in = false;
-//         data->p1 = p1;
-//         data->p2 = p2;
-//         data->p3 = p3;
-//         sgCopyVec3 (data->center, center);
-//         data->area = area;
-//         data->object_group = group;
-//         data->branch = in_range;
-//         data->leafData = this;
-//         data->seed = (unsigned int)(p1[0] * j);
-
-//                                 // Set up the in-range node.
-//         in_range->setUserData(data);
-//         in_range->setTravCallback(SSG_CALLBACK_PRETRAV,
-//                                  tri_in_range_callback);
-//         lod->addKid(in_range);
-
-//                                 // Set up the out-of-range node.
-//         out_of_range->setUserData(data);
-//         out_of_range->setTravCallback(SSG_CALLBACK_PRETRAV,
-//                                       tri_out_of_range_callback);
-//         out_of_range->addKid(new SGDummyBSphereEntity(bounding_radius));
-//         lod->addKid(out_of_range);
-//     }
-}
index d60d54a4d821251bbb1c08cb63ffa746bb8630d6..b487ddad329a7c8f8f0c0fb97e551608fbe1149e 100644 (file)
@@ -49,58 +49,11 @@ class SGPropertyNode;
  * following values (needed by the model loader callback at draw time)
  * before drawing any scenery.
  */
-void sgUserDataInit( SGModelLib *m, const string &r,
-                     SGPropertyNode *p, double t );
+void sgUserDataInit(SGPropertyNode *p);
 
 /**
  * Get a random model.
  */
 osg::Node* sgGetRandomModel(SGMatModel *obj);
 
-/**
- * Get a specific model.
- */
-osg::Node* sgGetModel(int i, SGMatModel *obj);
-
-/**
- * User data for populating leaves when they come in range.
- */
-class SGLeafUserData : public osg::Referenced
-{
-public:
-    bool is_filled_in;
-    osg::Geometry *leaf;
-    SGMaterial *mat;
-    osg::Group *branch;
-    float sin_lat;
-    float cos_lat;
-    float sin_lon;
-    float cos_lon;
-
-    void setup_triangle( int i );
-};
-
-
-/**
- * User data for populating triangles when they come in range.
- */
-class SGTriUserData : public osg::Referenced
-{
-public:
-    bool is_filled_in;
-    float * p1;
-    float * p2;
-    float * p3;
-    osg::Vec3 center;
-    double area;
-    SGMatModelGroup * object_group;
-    osg::Group * branch;
-    SGLeafUserData * leafData;
-    unsigned int seed;
-
-    void fill_in_triangle();
-    void add_object_to_triangle(SGMatModel * object);
-    void makeWorldMatrix (sgMat4 ROT, double hdg_deg );
-};
-
 #endif // _SG_USERDATA_HXX
index c5823e9a25bfc23939897069bc73de880c1a6b1a..996846f9f3f62902e0ad91882a4f64b2e6bd69e1 100644 (file)
@@ -135,7 +135,7 @@ typedef vector<TimingInfo>::iterator eventTimeVecIterator;
  * subsystems may also override the suspend() and resume() methods to
  * take different actions.</p>
  */
-class SGSubsystem
+class SGSubsystem : public SGReferenced
 {
 public: