1
0
Fork 0

Expose pose of scenery models to Nasal load/unload scripts.

This allows Nasal code attached to scenery models access their
world position and orientation by calling _model.getPose().

Also ensure models are attached to the scenegraph before Nasal
load scripts are called. This ensures that the world position
and orientation are available upon executing the load script.
This commit is contained in:
Thomas Geymayer 2013-03-23 12:53:17 +01:00
parent eba03b5e46
commit 913727239d
4 changed files with 87 additions and 31 deletions

View file

@ -3,8 +3,13 @@
#include "NasalSys.hxx" #include "NasalSys.hxx"
#include <Main/globals.hxx> #include <Main/globals.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <osg/Transform>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <algorithm> #include <algorithm>
@ -18,6 +23,48 @@
unsigned int FGNasalModelData::_max_module_id = 0; unsigned int FGNasalModelData::_max_module_id = 0;
FGNasalModelDataList FGNasalModelData::_loaded_models; FGNasalModelDataList FGNasalModelData::_loaded_models;
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,
const nasal::CallContext& ctx )
{
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();
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
FGNasalModelData::FGNasalModelData( SGPropertyNode *root, FGNasalModelData::FGNasalModelData( SGPropertyNode *root,
const std::string& path, const std::string& path,
@ -43,24 +90,33 @@ FGNasalModelData::~FGNasalModelData()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void FGNasalModelData::load() void FGNasalModelData::load()
{ {
std::stringstream m; std::stringstream m;
m << "__model" << _module_id; m << "__model" << _module_id;
_module = m.str(); _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.
nasalSys->getGlobals().createHash(_module).set("_module_id", _module_id);
naRef arg[2]; SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
arg[0] = nasalSys->propNodeGhost(_root);
arg[1] = nasalSys->propNodeGhost(_prop); const char *s = _load ? _load->getStringValue() : "";
nasalSys->createModule(_module.c_str(), _path.c_str(), s, strlen(s), FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
_root, 2, arg);
// 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);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -143,7 +199,7 @@ void FGNasalModelDataProxy::modelLoaded( const std::string& path,
if ((!load) && (!unload)) if ((!load) && (!unload))
return; return;
_data = new FGNasalModelData(_root, path, prop, load, unload, branch); _data = new FGNasalModelData(_root, path, prop, load, unload, branch);
// register Nasal module to be created and loaded in the main thread. // register Nasal module to be created and loaded in the main thread.

View file

@ -76,16 +76,6 @@ naRef to_nasal_helper(naContext c, flightgear::Approach* iap)
return nasal::to_nasal(c, iap->ident()); return nasal::to_nasal(c, iap->ident());
} }
//------------------------------------------------------------------------------
naRef to_nasal_helper(naContext c, const SGGeod& pos)
{
nasal::Hash hash(c);
hash.set("lat", pos.getLatitudeDeg());
hash.set("lon", pos.getLongitudeDeg());
hash.set("elevation", pos.getElevationM());
return hash.get_naRef();
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static naRef f_navaid_course(naContext, FGNavRecord& nav) static naRef f_navaid_course(naContext, FGNavRecord& nav)
{ {

View file

@ -844,8 +844,11 @@ void FGNasalSys::update(double)
if (!_loadList.empty()) if (!_loadList.empty())
{ {
// process Nasal load hook (only one per update loop to avoid excessive lags) if( _delay_load )
_loadList.pop()->load(); _delay_load = false;
else
// process Nasal load hook (only one per update loop to avoid excessive lags)
_loadList.pop()->load();
} }
else else
if (!_unloadList.empty()) if (!_unloadList.empty())
@ -1240,7 +1243,9 @@ naRef FGNasalSys::removeListener(naContext c, int argc, naRef* args)
void FGNasalSys::registerToLoad(FGNasalModelData *data) void FGNasalSys::registerToLoad(FGNasalModelData *data)
{ {
_loadList.push(data); if( _loadList.empty() )
_delay_load = true;
_loadList.push(data);
} }
void FGNasalSys::registerToUnload(FGNasalModelData *data) void FGNasalSys::registerToUnload(FGNasalModelData *data)

View file

@ -134,6 +134,11 @@ private:
SGLockedQueue<SGSharedPtr<FGNasalModelData> > _loadList; SGLockedQueue<SGSharedPtr<FGNasalModelData> > _loadList;
SGLockedQueue<SGSharedPtr<FGNasalModelData> > _unloadList; SGLockedQueue<SGSharedPtr<FGNasalModelData> > _unloadList;
// Delay removing items of the _loadList to ensure the are already attached
// to the scene graph (eg. enables to retrieve world position in load
// callback).
bool _delay_load;
// //
// FGTimer subclass for handling Nasal timer callbacks. // FGTimer subclass for handling Nasal timer callbacks.
// See the implementation of the settimer() extension function for // See the implementation of the settimer() extension function for