]> git.mxchange.org Git - flightgear.git/commitdiff
Expose pose of scenery models to Nasal load/unload scripts.
authorThomas Geymayer <tomgey@gmail.com>
Sat, 23 Mar 2013 11:53:17 +0000 (12:53 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Sat, 23 Mar 2013 11:54:45 +0000 (12:54 +0100)
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
src/Scripting/NasalPositioned_cppbind.cxx
src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx

index 24033c527f69d559b4cf640592cd13ed64cc72d3..2181cb17f6b36ac8324ade2c6725892c9b73b7a3 100644 (file)
@@ -3,8 +3,13 @@
 #include "NasalSys.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 <osg/Transform>
+
 #include <boost/bind.hpp>
 
 #include <algorithm>
 unsigned int FGNasalModelData::_max_module_id = 0;
 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,
                                     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);
-
-    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);
+  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);
 }
 
 //------------------------------------------------------------------------------
@@ -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.
index f37f5a26e127b31dec1c1c41eb9909b9435a9ce3..34162e17ff829cd04e41ba08fd8ce8f2d481f31a 100644 (file)
@@ -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)
 {
index 1ba313bcba981638bb06965cd4b2b9a01c439ada..a0ebb47046efce309adcfe9d1e8099755b3ad224 100644 (file)
@@ -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)
index b2c569e6a325d52e5b36fe487c1771782600701b..973730e4770f99eb19b77eb9ff0012e195ce6dab 100644 (file)
@@ -134,6 +134,11 @@ private:
     SGLockedQueue<SGSharedPtr<FGNasalModelData> > _loadList;
     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.
     // See the implementation of the settimer() extension function for