2013-02-09 15:33:05 +00:00
|
|
|
|
|
|
|
#include "NasalModelData.hxx"
|
2013-03-21 01:16:01 +01:00
|
|
|
#include "NasalSys.hxx"
|
|
|
|
#include <Main/globals.hxx>
|
2013-02-09 15:33:05 +00:00
|
|
|
|
2013-03-23 12:53:17 +01:00
|
|
|
#include <simgear/math/SGMath.hxx>
|
|
|
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
|
|
|
#include <simgear/scene/util/OsgMath.hxx>
|
2013-02-09 15:33:05 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
|
2013-03-23 12:53:17 +01:00
|
|
|
#include <osg/Transform>
|
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
#include <boost/bind.hpp>
|
2013-02-09 15:33:05 +00:00
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring> // for strlen
|
2013-02-09 15:33:05 +00:00
|
|
|
|
|
|
|
// FGNasalModelData class. If sgLoad3DModel() is called with a pointer to
|
|
|
|
// such a class, then it lets modelLoaded() run the <load> script, and the
|
|
|
|
// destructor the <unload> script. The latter happens when the model branch
|
|
|
|
// is removed from the scene graph.
|
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
unsigned int FGNasalModelData::_max_module_id = 0;
|
|
|
|
FGNasalModelDataList FGNasalModelData::_loaded_models;
|
|
|
|
|
2013-03-23 12:53:17 +01:00
|
|
|
typedef osg::ref_ptr<osg::Node> NodeRef;
|
|
|
|
typedef nasal::Ghost<NodeRef> NasalNode;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get position (lat, lon, elevation) and orientation (heading, pitch, roll) of
|
|
|
|
* model.
|
|
|
|
*/
|
|
|
|
static naRef f_node_getPose( const osg::Node& node,
|
2013-04-01 13:33:54 +02:00
|
|
|
const nasal::CallContext& ctx )
|
2013-03-23 12:53:17 +01:00
|
|
|
{
|
|
|
|
osg::NodePathList parent_paths = node.getParentalNodePaths();
|
|
|
|
for( osg::NodePathList::const_iterator path = parent_paths.begin();
|
|
|
|
path != parent_paths.end();
|
|
|
|
++path )
|
|
|
|
{
|
|
|
|
osg::Matrix local_to_world = osg::computeLocalToWorld(*path);
|
|
|
|
if( !local_to_world.valid() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SGGeod coord = SGGeod::fromCart( toSG(local_to_world.getTrans()) );
|
|
|
|
if( !coord.isValid() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
osg::Matrix local_frame = makeZUpFrameRelative(coord),
|
|
|
|
inv_local;
|
|
|
|
inv_local.invert_4x3(local_frame);
|
|
|
|
local_to_world.postMult(inv_local);
|
|
|
|
|
|
|
|
SGQuatd rotate = toSG(local_to_world.getRotate());
|
|
|
|
double hdg, pitch, roll;
|
|
|
|
rotate.getEulerDeg(hdg, pitch, roll);
|
|
|
|
|
|
|
|
nasal::Hash pose(ctx.to_nasal(coord), ctx.c);
|
|
|
|
pose.set("heading", hdg);
|
|
|
|
pose.set("pitch", pitch);
|
|
|
|
pose.set("roll", roll);
|
|
|
|
return pose.get_naRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
return naNil();
|
|
|
|
}
|
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
|
|
|
|
const std::string& path,
|
|
|
|
SGPropertyNode *prop,
|
|
|
|
SGPropertyNode* load,
|
|
|
|
SGPropertyNode* unload,
|
|
|
|
osg::Node* branch ):
|
|
|
|
_path(path),
|
|
|
|
_root(root), _prop(prop),
|
|
|
|
_load(load), _unload(unload),
|
|
|
|
_branch(branch),
|
|
|
|
_module_id( _max_module_id++ )
|
|
|
|
{
|
|
|
|
_loaded_models.push_back(this);
|
2013-10-17 11:48:01 +02:00
|
|
|
|
|
|
|
SG_LOG
|
|
|
|
(
|
|
|
|
SG_NASAL,
|
|
|
|
SG_INFO,
|
|
|
|
"New model with attached script(s) (branch = " << branch << ")"
|
|
|
|
);
|
2013-03-21 01:16:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
FGNasalModelData::~FGNasalModelData()
|
|
|
|
{
|
|
|
|
_loaded_models.remove(this);
|
2013-10-17 11:48:01 +02:00
|
|
|
|
|
|
|
SG_LOG
|
|
|
|
(
|
|
|
|
SG_NASAL,
|
|
|
|
SG_INFO,
|
|
|
|
"Removed model with script(s) (branch = " << _branch << ")"
|
|
|
|
);
|
2013-03-21 01:16:01 +01:00
|
|
|
}
|
2013-02-09 15:33:05 +00:00
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
//------------------------------------------------------------------------------
|
2013-02-09 15:33:05 +00:00
|
|
|
void FGNasalModelData::load()
|
|
|
|
{
|
2013-03-23 12:53:17 +01:00
|
|
|
std::stringstream m;
|
|
|
|
m << "__model" << _module_id;
|
|
|
|
_module = m.str();
|
|
|
|
|
|
|
|
SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
|
|
|
|
|
|
|
|
const char *s = _load ? _load->getStringValue() : "";
|
|
|
|
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
|
|
|
|
|
|
|
// Add _module_id to script local hash to allow placing canvasses on objects
|
|
|
|
// inside the model.
|
|
|
|
nasal::Hash module = nasalSys->getGlobals().createHash(_module);
|
|
|
|
module.set("_module_id", _module_id);
|
|
|
|
|
|
|
|
if( !NasalNode::isInit() )
|
|
|
|
{
|
|
|
|
NasalNode::init("osg.Node")
|
|
|
|
.method("getPose", &f_node_getPose);
|
|
|
|
}
|
|
|
|
|
|
|
|
module.set("_model", NodeRef(_branch));
|
|
|
|
|
|
|
|
naRef arg[2];
|
|
|
|
arg[0] = nasalSys->propNodeGhost(_root);
|
|
|
|
arg[1] = nasalSys->propNodeGhost(_prop);
|
|
|
|
nasalSys->createModule(_module.c_str(), _path.c_str(), s, strlen(s),
|
|
|
|
_root, 2, arg);
|
2013-02-09 15:33:05 +00:00
|
|
|
}
|
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
//------------------------------------------------------------------------------
|
2013-02-09 15:33:05 +00:00
|
|
|
void FGNasalModelData::unload()
|
|
|
|
{
|
|
|
|
if (_module.empty())
|
|
|
|
return;
|
2013-03-21 01:16:01 +01:00
|
|
|
|
2013-02-09 15:33:05 +00:00
|
|
|
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
|
|
|
if(!nasalSys) {
|
|
|
|
SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
|
|
|
|
"without Nasal subsystem present.");
|
|
|
|
return;
|
|
|
|
}
|
2013-03-21 01:16:01 +01:00
|
|
|
|
2013-02-09 15:33:05 +00:00
|
|
|
SG_LOG(SG_NASAL, SG_DEBUG, "Unloading nasal module " << _module.c_str());
|
2013-03-21 01:16:01 +01:00
|
|
|
|
2013-02-09 15:33:05 +00:00
|
|
|
if (_unload)
|
|
|
|
{
|
|
|
|
const char *s = _unload->getStringValue();
|
|
|
|
nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _root);
|
|
|
|
}
|
2013-03-21 01:16:01 +01:00
|
|
|
|
2013-02-09 15:33:05 +00:00
|
|
|
nasalSys->deleteModule(_module.c_str());
|
|
|
|
}
|
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
osg::Node* FGNasalModelData::getNode()
|
|
|
|
{
|
|
|
|
return _branch;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
|
|
|
|
{
|
|
|
|
FGNasalModelDataList::iterator it = std::find_if
|
|
|
|
(
|
|
|
|
_loaded_models.begin(),
|
|
|
|
_loaded_models.end(),
|
|
|
|
boost::bind(&FGNasalModelData::_module_id, _1) == id
|
|
|
|
);
|
|
|
|
|
|
|
|
if( it != _loaded_models.end() )
|
|
|
|
return *it;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
FGNasalModelDataProxy::~FGNasalModelDataProxy()
|
|
|
|
{
|
|
|
|
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
|
|
|
// when necessary, register Nasal module to be destroyed/unloaded
|
|
|
|
// in the main thread.
|
|
|
|
if ((_data.valid())&&(nasalSys))
|
|
|
|
nasalSys->registerToUnload(_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void FGNasalModelDataProxy::modelLoaded( const std::string& path,
|
|
|
|
SGPropertyNode *prop,
|
|
|
|
osg::Node *branch )
|
2013-02-09 15:33:05 +00:00
|
|
|
{
|
|
|
|
if(!prop)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SGPropertyNode *nasal = prop->getNode("nasal");
|
|
|
|
if(!nasal)
|
|
|
|
return;
|
|
|
|
|
2013-10-17 11:48:01 +02:00
|
|
|
FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
|
|
|
|
if(!nasalSys)
|
|
|
|
{
|
|
|
|
SG_LOG
|
|
|
|
(
|
|
|
|
SG_NASAL,
|
|
|
|
SG_WARN,
|
|
|
|
"Can not load model script(s) (Nasal subsystem not available)."
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-09 15:33:05 +00:00
|
|
|
SGPropertyNode* load = nasal->getNode("load");
|
|
|
|
SGPropertyNode* unload = nasal->getNode("unload");
|
|
|
|
|
|
|
|
if ((!load) && (!unload))
|
|
|
|
return;
|
2013-03-23 12:53:17 +01:00
|
|
|
|
2013-03-21 01:16:01 +01:00
|
|
|
_data = new FGNasalModelData(_root, path, prop, load, unload, branch);
|
2013-02-09 15:33:05 +00:00
|
|
|
|
|
|
|
// register Nasal module to be created and loaded in the main thread.
|
|
|
|
nasalSys->registerToLoad(_data);
|
|
|
|
}
|