From 913727239d6776c0508d206f395e16c265413ec3 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sat, 23 Mar 2013 12:53:17 +0100 Subject: [PATCH] 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. --- src/Scripting/NasalModelData.cxx | 92 ++++++++++++++++++----- src/Scripting/NasalPositioned_cppbind.cxx | 10 --- src/Scripting/NasalSys.cxx | 11 ++- src/Scripting/NasalSys.hxx | 5 ++ 4 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/Scripting/NasalModelData.cxx b/src/Scripting/NasalModelData.cxx index 24033c527..2181cb17f 100644 --- a/src/Scripting/NasalModelData.cxx +++ b/src/Scripting/NasalModelData.cxx @@ -3,8 +3,13 @@ #include "NasalSys.hxx" #include
+#include +#include +#include #include +#include + #include #include @@ -18,6 +23,48 @@ unsigned int FGNasalModelData::_max_module_id = 0; FGNasalModelDataList FGNasalModelData::_loaded_models; +typedef osg::ref_ptr NodeRef; +typedef nasal::Ghost 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, const std::string& path, @@ -43,24 +90,33 @@ FGNasalModelData::~FGNasalModelData() //------------------------------------------------------------------------------ void FGNasalModelData::load() { - 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. - nasalSys->getGlobals().createHash(_module).set("_module_id", _module_id); + std::stringstream m; + m << "__model" << _module_id; + _module = m.str(); - 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); + 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); } //------------------------------------------------------------------------------ @@ -143,7 +199,7 @@ void FGNasalModelDataProxy::modelLoaded( const std::string& path, if ((!load) && (!unload)) return; - + _data = new FGNasalModelData(_root, path, prop, load, unload, branch); // register Nasal module to be created and loaded in the main thread. diff --git a/src/Scripting/NasalPositioned_cppbind.cxx b/src/Scripting/NasalPositioned_cppbind.cxx index f37f5a26e..34162e17f 100644 --- a/src/Scripting/NasalPositioned_cppbind.cxx +++ b/src/Scripting/NasalPositioned_cppbind.cxx @@ -76,16 +76,6 @@ naRef to_nasal_helper(naContext c, flightgear::Approach* iap) 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) { diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 1ba313bcb..a0ebb4704 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -844,8 +844,11 @@ void FGNasalSys::update(double) if (!_loadList.empty()) { - // process Nasal load hook (only one per update loop to avoid excessive lags) - _loadList.pop()->load(); + if( _delay_load ) + _delay_load = false; + else + // process Nasal load hook (only one per update loop to avoid excessive lags) + _loadList.pop()->load(); } else if (!_unloadList.empty()) @@ -1240,7 +1243,9 @@ naRef FGNasalSys::removeListener(naContext c, int argc, naRef* args) void FGNasalSys::registerToLoad(FGNasalModelData *data) { - _loadList.push(data); + if( _loadList.empty() ) + _delay_load = true; + _loadList.push(data); } void FGNasalSys::registerToUnload(FGNasalModelData *data) diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx index b2c569e6a..973730e47 100644 --- a/src/Scripting/NasalSys.hxx +++ b/src/Scripting/NasalSys.hxx @@ -134,6 +134,11 @@ private: SGLockedQueue > _loadList; SGLockedQueue > _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. // See the implementation of the settimer() extension function for