From: timoore Date: Sat, 22 Mar 2008 09:30:26 +0000 (+0000) Subject: model paging patch from Till Busch X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=9dc1b5f6f56c6fecdcfefc2a0a75695a89f323a2;p=simgear.git model paging patch from Till Busch 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 --- diff --git a/simgear/constants.h b/simgear/constants.h index 3d8a82fb..b6fd7a90 100644 --- a/simgear/constants.h +++ b/simgear/constants.h @@ -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 diff --git a/simgear/scene/material/matmodel.cxx b/simgear/scene/material/matmodel.cxx index 70850edc..b2a4152d 100644 --- a/simgear/scene/material/matmodel.cxx +++ b/simgear/scene/material/matmodel.cxx @@ -48,6 +48,8 @@ SG_USING_STD(map); #include "matmodel.hxx" +using namespace simgear; + //////////////////////////////////////////////////////////////////////// // 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) diff --git a/simgear/scene/material/matmodel.hxx b/simgear/scene/material/matmodel.hxx index 982e89a9..12ff23dd 100644 --- a/simgear/scene/material/matmodel.hxx +++ b/simgear/scene/material/matmodel.hxx @@ -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 _paths; mutable vector > _models; diff --git a/simgear/scene/model/CheckSceneryVisitor.cxx b/simgear/scene/model/CheckSceneryVisitor.cxx new file mode 100644 index 00000000..d6fdd129 --- /dev/null +++ b/simgear/scene/model/CheckSceneryVisitor.cxx @@ -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 + +#include + +#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(&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 index 00000000..c89fc18b --- /dev/null +++ b/simgear/scene/model/CheckSceneryVisitor.hxx @@ -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 +#include + +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 _viewMatrices; +}; + +} + +#endif diff --git a/simgear/scene/model/Makefile.am b/simgear/scene/model/Makefile.am index db102d9e..51ff3921 100644 --- a/simgear/scene/model/Makefile.am +++ b/simgear/scene/model/Makefile.am @@ -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 index 00000000..ee68b499 --- /dev/null +++ b/simgear/scene/model/SGPagedLOD.cxx @@ -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 + +#include + +#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 d = dynamic_cast(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(_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 index 00000000..d45c1bb1 --- /dev/null +++ b/simgear/scene/model/SGPagedLOD.hxx @@ -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 +#include +#include + +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 _readerWriterOptions; + SGPropertyNode_ptr _props; +}; +} +#endif diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx new file mode 100644 index 00000000..656818a9 --- /dev/null +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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(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(node)); + osg::Switch* s = static_cast(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 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 model; + osg::ref_ptr 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 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 model_nodes = props->getChildren("model"); + for (unsigned i = 0; i < model_nodes.size(); i++) { + SGPropertyNode_ptr sub_props = model_nodes[i]; + + osg::ref_ptr 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 submodel_final=submodel.get(); + SGPropertyNode *offs = sub_props->getNode("offsets", false); + if (offs) { + osg::Matrix res_matrix; + osg::ref_ptr 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 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 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 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 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 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 index 00000000..2d92c3ef --- /dev/null +++ b/simgear/scene/model/SGReaderWriterXML.hxx @@ -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 +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 index 00000000..b9f46542 --- /dev/null +++ b/simgear/scene/model/SGReaderWriterXMLOptions.hxx @@ -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 +#include + +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 _model_data; +}; + +} +#endif diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index fd4962c0..cdd50861 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -7,38 +7,21 @@ #include #endif -#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include -#include -#include #include #include #include #include -#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(node)); - osg::Switch* s = static_cast(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 mCondition; -}; - - -//////////////////////////////////////////////////////////////////////// -// 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 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 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 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 model_nodes = props.getChildren("model"); - for (unsigned i = 0; i < model_nodes.size(); i++) { - SGPropertyNode_ptr node = model_nodes[i]; - osg::ref_ptr 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 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 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 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 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 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 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 diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index db7f6638..1de3bf40 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -23,63 +23,6 @@ SG_USING_STD(set); #include #include -#include - - -// 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 &name_nodes, - SGPropertyNode *prop_root, - SGPropertyNode_ptr node, - double sim_time_sec, - SGPath &texture_path, - set &ignore_branches ); osg::Texture2D* SGLoadTexture2D(bool staticTexture, const std::string& path, diff --git a/simgear/scene/model/modellib.cxx b/simgear/scene/model/modellib.cxx index 70216e06..5cb6965d 100644 --- a/simgear/scene/model/modellib.cxx +++ b/simgear/scene/model/modellib.cxx @@ -1,47 +1,103 @@ -// 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 #endif -#include +#include +#include +#include + +#include #include -#include +#include +#include -#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 g_readerWriter_XML_Proxy; +ModelRegistryCallbackProxy g_xmlCallbackProxy("xml"); + //////////////////////////////////////////////////////////////////////// // 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 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 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 opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions())); + opt->setPropRoot(prop_root); + opt->setModelData(data); + plod->setReaderWriterOptions(opt.get()); + return plod; +} // end of modellib.cxx diff --git a/simgear/scene/model/modellib.hxx b/simgear/scene/model/modellib.hxx index b5613bc6..b2d038eb 100644 --- a/simgear/scene/model/modellib.hxx +++ b/simgear/scene/model/modellib.hxx @@ -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 @@ -9,38 +24,77 @@ #include // for SG_USING_STD -#include #include STL_STRING -#include #include #include -#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 diff --git a/simgear/scene/tgdb/userdata.cxx b/simgear/scene/tgdb/userdata.cxx index c1956edd..5413c8df 100644 --- a/simgear/scene/tgdb/userdata.cxx +++ b/simgear/scene/tgdb/userdata.cxx @@ -45,10 +45,7 @@ // 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 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); -// } -} diff --git a/simgear/scene/tgdb/userdata.hxx b/simgear/scene/tgdb/userdata.hxx index d60d54a4..b487ddad 100644 --- a/simgear/scene/tgdb/userdata.hxx +++ b/simgear/scene/tgdb/userdata.hxx @@ -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 diff --git a/simgear/structure/subsystem_mgr.hxx b/simgear/structure/subsystem_mgr.hxx index c5823e9a..996846f9 100644 --- a/simgear/structure/subsystem_mgr.hxx +++ b/simgear/structure/subsystem_mgr.hxx @@ -135,7 +135,7 @@ typedef vector::iterator eventTimeVecIterator; * subsystems may also override the suspend() and resume() methods to * take different actions.

*/ -class SGSubsystem +class SGSubsystem : public SGReferenced { public: