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
This commit is contained in:
timoore
2008-03-22 09:30:26 +00:00
parent 55c1ac36e3
commit 9dc1b5f6f5
18 changed files with 889 additions and 656 deletions

View 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

View File

@@ -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)

View 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;

View File

@@ -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();
}
}

View File

@@ -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

View 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

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View 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;
};
////////////////////////////////////////////////////////////////////////
// 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

View 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,

View File

@@ -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 <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");
////////////////////////////////////////////////////////////////////////
// Implementation of SGModelLib.
////////////////////////////////////////////////////////////////////////
void SGModelLib::init(const string &root_dir)
{
osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
}
SGModelLib::SGModelLib ()
SGModelLib::SGModelLib()
{
}
SGModelLib::~SGModelLib ()
{
}
void
SGModelLib::flush1()
SGModelLib::~SGModelLib()
{
}
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,
SGModelData *data)
{
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->setModelData(data);
osg::Node *n = readNodeFile(path, opt.get());
if(data)
data->modelLoaded(path, data->getProperties(), n);
return n;
}
osg::Node*
SGModelLib::loadModel(const string &path,
SGPropertyNode *prop_root,
panel_func pf)
{
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

View 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
@@ -9,38 +24,77 @@
#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 *);
SGModelLib ();
virtual ~SGModelLib ();
virtual void flush1();
static void init(const string &root_dir);
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 );
// 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;
virtual void setProps(SGPropertyNode *p)
{ _props = p; }
SGPropertyNode *getProperties()
{ return _props; }
protected:
SGPropertyNode_ptr _props;
};
}
#endif // _SG_MODEL_LIB_HXX

View File

@@ -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<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);
// }
}

View 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

View 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: