--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Using Nasal with FlightGear</title>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<link rel="stylesheet" href="nasal.css">
+</head>
+<body>
+
+<h1>Using Nasal with FlightGear</h1>
+
+<p>This document is a tutorial on how to interface Nasal scripts
+with FlightGear. It is not an introduction to the Nasal language
+itself. For that, see Andy's <a
+href="http://www.plausible.org/nasal/">Nasal website</a> at <a
+href="http://www.plausible.org/nasal/">http://www.plausible.org/nasal</a>.
+The information there is sparse, but you should have it ready for
+reference while reading this document.
+
+<h2>Basic Nasal/FlightGear Integration</h2>
+
+<h3>Calling Nasal from Configuration File Bindings</h3>
+
+Nasal scripts can be used as FGBinding objects, and can therefore
+appear anywhere in a configuration file (keyboard, mouse and joystick
+bindings, etc...) that accepts a <code><binding></code> tag.
+The relevant command type is "nasal", and you place your Nasal code
+inside of the <code><script></code> tag:
+
+<pre>
+<binding>
+ <command>nasal</command>
+ <script>
+ print("Binding Invoked!");
+ </script>
+</binding>
+</pre>
+
+<p>The code above invokes the <code>print()</code> function. This is
+a simple extension function that simply prints out its arguments, in
+order, to the FlightGear console as a single-line log entry. It is
+useful for debugging, but little else.
+
+<p>Some command have SGPropertyNode arguments. This argument is
+available as a <code>props.Node</code> object and is returned from the
+built-in <code>cmdarg()</code> function. See below for full
+documentation, but as an example the following "joystick axis" binding
+will print the current axis value to the console:
+
+<pre>
+<binding>
+ <command>nasal</command>
+ <script>print(cmdarg().getNode("value").getValue());</script>
+</binding>
+</pre>
+
+<p>Note that the current implementation parses the Nasal code inside
+the <code><script></code> tag each time it is run. This means
+that you should avoid placing large code blocks inside a
+<code><script></code> tag for performance reasons. It also
+means that any local variables you set inside the script will be lost
+the next time it is run. See the discussion about namespaces and
+Nasal source files below for more information.
+
+<h3>Setting and Inspecting FlightGear Properties</h3>
+
+<h4>getprop() and setprop()</h4>
+
+<p>You can use <code>getprop()</code> and <code>setprop()</code>
+functions to interact with the global property tree. They work as you
+would expect. For example, the following Nasal code copies the value
+of the "/sim/foo" property to the "/sim/bar" property:
+
+<pre>setprop("/sim/bar", getprop("/sim/foo"));</pre>
+
+<p>Note that Nasal's notion of "type" is coarser than that of the
+SGPropertyNode class. Numers and strings come out of
+<code>getprop()</code> as Nasal scalars, of course, and boolean
+properties are converted to a numeric 1 or 0 by
+<code>getprop()</code>. But <b>all</b> non-string values passed to
+<code>setprop()</code> become doubles in the property tree. The
+props.Node interface (see below) provides the ability to set explicit
+types in the property tree.
+
+<p>A useful feature of getprop and setprop that you should be aware of
+is that they both accept variable numbers of arguments. These are
+concatenated together to form a property tree path internally within
+the function. This avoids the need for extensive string concatenation
+in the script for the common case where you are acting on a variable
+property root. That is, you can do:
+
+<pre>
+ThisAircraft = "/sim/my/aircraft/properties";
+setprop(ThisAircraft, "crashed", 0);
+</pre>
+
+to set the property "/sim/my/aircraft/properties/crashed" to false.
+This feature is useful for writing Nasal functions that will work on
+parameterized property trees.
+
+<h4>The props module</h4>
+
+<p>Think of the <code>getprop()</code> and <code>setprop()</code>
+functions as equivalents of the <code>fgGet*()</code> and
+<code>fgSet*()</code> C++ functions. They provide simple and easy
+access to the global property tree.
+
+<p>For some situations, however, you need finer control over the
+property nodes. For these situations you can use the props module,
+which provides a <code>Node</code> class similar to the SimGear
+<code>SGPropertyNode</code> class. The global tree is available as a
+<code>Node</code> object named <code>props.globals</code>. You can
+use the <code>getNode()</code> method on it to retrieve an arbitrary
+sub-node. The children of any given node can be inspected with
+<code>getChild()</code> and <code>getChildren()</code> methods. And
+of course its name, index, and value can be accessed with appropriate
+methods. See the reference below for complete documentation.
+
+<p>As seen above in the discussion on <code>fgcommand()</code>, you
+can also create new, "rootless" <code>Node</code> objects using
+<code>props.Node.new()</code>.
+
+<p>The most powerful method on a Node object is
+<code>setValues()</code>. This takes a Nasal hash table as its only
+argument, and initializes properties under the node using the
+key/value pairs in the hash. This works with vectors (i.e. indexed
+properties) and recursively, essentially making a deep copy of a Nasal
+object in the property tree.
+
+<p>For debugging (and amusement) purposes, the <code>props</code>
+modules also defines a <code>dump()</code> function which recursively
+prints the state of a property node to the console. Try
+<code>props.dump(props.globals)</code> to see it walk the entire tree.
+
+<h3>Invoking FlightGear Commands from Nasal</h3>
+
+<p>Just as Nasal code can be run as a command binding from the
+property tree, existing FlightGear commands can be invoked by Nasal
+code using the <code>fgcommand()</code> function. The first argument
+to this function is a string, equivalent to what you would place
+inside the <code><command></code> tag in a property binding.
+
+The second argument specifies the property tree that will be passed as
+the "arguments" to the command. It can be a either a string
+specifying a path in the global property tree or a props.Node object.
+Example:
+
+<pre>
+# Use a temporary property in the global tree
+ShowDialog = func {
+ setprop("/nasal/tmp/dialog-args/dialog-name", arg[0];
+ fgcommand("dialog-show", "/nasal/tmp/dialog-args");
+}
+
+# Does the same thing, but with a rootless Node object
+ShowDialog = func {
+ fgcommand("dialog-show", props.Node.new({dialog-name : arg[0]});
+}
+</pre>
+
+These both define a <code>ShowDialog()</code> function, which pops up
+a named dialog from the <fgroot>/gui/dialogs directory. Calling
+<code>ShowDialog("autopilot")</code> will therefore pop up the
+autopilot dialog just as if it had been bound to a key.
+
+<p>The first variant uses a "temporary" property tree in the global
+property space to hold the arguments. The second creates a new
+<code>props.Node</code> object instead. Note that
+<code>props.Node.new()</code> accepts a hash table as its argument and
+uses that to initialize the returned property tree.
+
+<h3>Writing extended Nasal code in source files</h3>
+
+<p>Nasal is a "real" language, with real namespaces and modules. What
+"really" happens when you run a script binding is that the script is
+treated as a function body and bound (lexically, in the functional
+programming sense) to a single global namespace. It is as if it were
+enclosed in a <code>func { ... }</code> expression and executed inside
+a "file" containing all the global symbols.
+
+<p>Some symbols in the global namespace are built-in extension
+functions, like the print/getprop/setprop we have already seen.
+Others are objects (or hash tables -- they are the same thing in
+Nasal). These objects act as namespaces and can contain code of their
+own. One such example is the math library. The built-in math
+functions live in their own namespace and are accessible as
+<code>math.sin()</code>, <code>math.cos()</code>, etc...
+
+<p>The global namespace itself is available as a module named
+"globals". This allows you to create new symbols in the global
+namespace if you desire (be careful!) and to otherwise inspect its
+contents. It's just a hash table, after all. The following code will
+print all the symbols found in the global namespace:
+
+<pre>
+print("These are the symbols found in the global namespace:");
+foreach(i; keys(globals)) { print(" ", i); }
+</pre>
+
+<p>You can write your own modules, too. The mechanism is very simple:
+merely create a file with a ".nas" extension in the Nasal directory of
+your FlightGear base package. FlightGear will read, parse and execute
+these files during initialization, and create a module of the same
+name for use by your scripts. So you can write, say, a "mouse.nas"
+script. Functions defined therein are available to your script
+bindings (and any other nasal code on the system) as members of the
+global "mouse" object. So you can define bindings that do things like
+<code>mouse.handleXAxis(offset)</code> to call functions defined in
+the mouse.nas file (remember that "offset" is an automatically
+initialized variable containing the binding's offset argument).
+
+<h3>Including Nasal Code from Configuration Files</h3>
+
+<p>Nasal modules can also be imported from the property tree at
+initialization. This is useful for applications like
+aircraft-specific scripts that need to be loaded only when that
+aircraft is active. The usage is simple: the Nasal interpreter
+creates a module for every property node child of "/nasal" that it
+finds at initialization time. Example:
+
+<pre>
+<nasal>
+ <c172>
+ <file>Aircraft/c172/c172.nas</file>
+ </c172>
+</nasal>
+</pre>
+
+This creates a module named "c172" and loads the contents of the
+Aircraft/c172/c172.nas file into it. The module name is, by default,
+the same as the property node. But this can be overridden with the
+<code><module></code> tag. This trick can be useful if you need
+to load extra script source into a previously-initialized module.
+
+<p>You can also write literal Nasal scripts inside the property files
+by including it in a <code><script></code> tag. This sample
+uses the <code><module></code> tag to add an extra function to
+the math library.
+
+<pre>
+<nasal>
+ <c172-tmp1> <!-- Use a unique, dummy name -->
+ <module>math</module>
+ <script><[CDATA[
+
+ # The math library doesn't include this, because Andy is a pedant
+ # and thinks it's dangerous. But the c172 code just *has* to have
+ # it.
+ atan = func { return atan2(arg[0], 1) }
+
+ ]]></script>
+ </c172-tmp1>
+</nasal>
+</pre>
+
+Note the use of a CDATA declaration. This is required to properly
+escape XML special characters like "<code><</code>". As it
+happens, this code doesn't use them. But the CDATA is good practice
+nonetheless.
+
+<h3>Function Reference</h3>
+
+<p>These are the built-in extension functions available to all Nasal
+code in FlightGear. Be sure to examine the <a
+href="http://www.plausible.org/nasal/doc.html">core Nasal
+documentation</a> at the <a
+href="http://www.plausible.org/nasal">Nasal site</a> as well. Only
+FlightGear-specific library code is documented here:
+
+<h4>Global Functions</h4>
+
+<dl>
+
+<dt>rand()
+<dd>Returns a random number in the range [0:1) (that is, 0.0 is a
+ possible return value, but 1.0 is not).
+
+<dt>getprop()
+<dd>The arguments are concatenated to form a path to a global
+ property node. Returns the value of that node, or nil if it does
+ not exist.
+
+<dt>setprop()
+<dd>The final argument specifies a value to set. The remaining
+ arguments are concatenated to form a property path as in
+ getprop().
+
+<dt>print()
+<dd>The arguments are printed, in order, to the FlightGear console.
+ A newline is appended by the logging code, none is
+ required.
+
+<dt>fgcommand()
+<dd>The first argument is a string specifying a FlightGear command to
+ execute (e.g. "show-dialog"). The second is a property sub-tree
+ (either a global path string or a props.Node object) which will be
+ passed to the command as arguments.
+
+<dt>settimer()
+<dd>The first argument is a Nasal expression which evaluates to a
+ Nasal function object (it can be either a symbol name for a
+ function or a literal <code>func { ... }</code>
+ expression. The second argument is a (floating point) number
+ specifying a delta time in seconds. Some time after that delta
+ time has elapsed, the specified function will be invoked. Exact
+ timing will depend on the frame rate of the simulator.
+
+<dt>interpolate()
+<dd>The first argument specifies a property. It can be either a
+ string representing a global property name or a
+ <code>props.Node</code> object. The remaining arguments specify
+ pairs of value/delta-time numbers. The property is interpolated
+ smoothly from its current value to the new value over the
+ specified time delta, in seconds. Multiple value pairs can be
+ used to indicate successive values or to acheive a piecewise
+ linear approximation to a non-linear function. This function
+ cancels any preexisting interpolation for that property, so
+ <code>interpolate("/sim/countdown", 0, 0)</code> has the
+ effect of cancelling interpolation of "/sim/countdown" and setting
+ its value to zero.
+</dl>
+
+<h4>Property Module</h4>
+
+<dl>
+<dt>Node
+<dd>The <code>props.Node</code> class wraps a SGPropertyNode object,
+ either in or outside of the global property tree. It supports the
+ following methods:
+<dl>
+<dt>getType()
+<dd>Returns the "type" of the SGPropertyNode object. The return value
+is a string; one of: NONE, ALIAS, BOOL, INT, LONG, FLOAT, DOUBLE,
+STRING or UNSPECIFIED.
+<dt>getName()
+<dd>Returns the name of the property node.
+<dt>getIndex()
+<dd>Returns the child index of the property node.
+<dt>getValue()
+<dd>Returns the current value of the node, or nil if it has none.
+<dt>setValue()
+<dd>Sets the current value as either a string or a double, depending
+on the internal type of the argument.
+<dt>setIntValue()
+<dd>Sets the current value, forcing the type to INT
+<dt>setBoolValue()
+<dd>Sets the current value, forcing the type to BOOL
+<dt>setDoubleValue()
+<dd>Sets the current value, forcing the type to DOUBLE
+<dt>getParent()
+<dd>Returns a Node object representing this node's parent, or nil if
+it has none.
+<dt>getChild()
+<dd>Returns a named child, or nil if it does not exist. If multiple
+children with that name exist, returns the one with an index of zero.
+<dt>getChildren()
+<dd>Returns a vector containing all the node's children.
+<dt>removeChild()
+<dd>Removes a child by name (first argument) and index (second argument).
+<dt>getNode()
+<dd>Returns a Node specified by its "relative path" to this node, or
+nil if none exists. The optional second argument, if true, causes the
+node to be created if it does not exist.
+<dt>setValues()
+<dd>Takes a hash as argument, and sets all the key/value pairs in the
+hash as property subnodes of the object. This works recursively, with
+sub-hashes and vectors; thus making a deep copy of the Nasal hash in
+the property tree.
+</dl>
+
+<dt>props.Node.new()
+<dd>Static "constructor" function returning a new, rootless
+ <code>Node</code> object. Takes a hash argument to initialize the
+ new node via setValues().
+
+<dt>props.globals
+<dd>This is a <code>Node</code> object representing the root of the
+ global property tree; the Nasal equivalent of
+ <code>globals->get_props()</code>
+
+<dt>props.dump()
+<dd>This method prints out a "dump" of the state of a single
+ <code>Node</code> object and all of its children to the console.
+ Very useful for debugging and exploration.
+
+</dl>
+
+<h2>Integrating C++ code and Nasal</h2>
+
+<h3>Calling Nasal from C++</h3>
+
+<p>The FGNasalSys object has a <code>parseAndRun()</code> method to
+which you can pass arbitrary Nasal source code for immediate
+execution:
+
+<pre>
+FGNasalSys n = (FGNasalSys*)globals->get_subsystem("nasal");
+if(! n->parseAndRun("print('This script was called from C++!')"))
+ SG_LOG(SG_GENERAL, SG_ALERT, "My Nasal code failed :(");
+</pre>
+
+<p>You can also use <code>parseScript()</code> to get a pointer to a
+<code>FGNasalScript</code> object. This object supports a
+<code>call()</code> method which you can use to invoke the script
+later on, at a time of your choosing. If you will be invoking the
+script multiple times, this mechanism can be more efficient because it
+avoids the parsing and code generation overhead for the successive
+calls.
+
+<pre>
+FGNasalSys n = (FGNasalSys*)globals->get_subsystem("nasal");
+FGNasalScript* script = n->parseScript("print('Spam!')"))
+if(!script) SG_LOG(SG_GENERAL, SG_ALERT, "My Nasal code failed :(");
+
+...
+
+for(int i=0; i<1000; i++)
+ script->call(); // Spam the console
+</pre>
+
+<p>Note that there is no way to inspect the return value of the
+function that you called. It simply returns a boolean indicating
+successful execution. Handling of "native" Nasal data structures has
+to be done via the Nasal extension API. See below.
+
+<h3>Calling C++ from Nasal</h3>
+
+<p>You have three options for invoking C++ code from Nasal. The first
+two take advantage of pre-existing FlightGear mechanisms for
+registering "callback" handlers for specific events.
+
+<p>If your task is sufficiently general, you should consider defining
+it as a new FGCommand using the existing interface. This can be
+invoked efficiently from both Nasal code (using the fgcommand()
+function) and existing property bindings, and is very easy to do.
+Simply define a handler function which takes a property tree as an
+argument and returns a bool (to indicate successful execution), and
+register it during initialization with the global command manager:
+
+<pre>
+// Define your handler function:
+bool my_new_command(SGPropertyNode* arg) { ... }
+
+ ...
+ // And register it in your initialization code:
+ globals->get_commands()->addCommand("my-new-command", my_new_command);
+ ...
+</pre>
+
+<p>This mechanism works well when your C++ code is a "global" function
+that you will want to call from many locations with potentially
+differing data. For some applications, however, you want to register
+a handler that will be called only by code involved with computations
+on a single data set.
+
+<p>For this, there is the property listener interface. You can create
+a subclass of SGPropertyChangeListener which implements the
+valueChange, childAdded and/or childRemoved methods and associate it
+with a specific property node in the global tree. You can then
+"invoke" this handler from Nasal code (or from anywhere else) by
+simply setting the property value.
+
+<p>I haven't tested the property listener interface, and it requires
+somewhat more typing to implement; so I will include no example here.
+It is also rather rarely used by existing FlightGear code (the
+property picker GUI is the only significant application I could find).
+
+<h3>Extending Nasal</h3>
+
+<p>This is the third mechanism for invoking C++ (strictly C, in this
+case) code from Nasal. This is the API you must use if you want to
+inspect and/or modify Nasal data structures, or create a function
+object that will be visible to Nasal scripts as a callable function.
+Unfortunately, there really isn't space here to document this API
+fully. For now, examin the <code>nasal.h</code> header which defines
+it, and the <code>lib.c</code> and <code>mathlib.c</code> source files
+which implement the existing built-in library functions. The
+FlightGear-specific extension functions in <code>NasalSys.cxx</code>
+and <code>nasal-props.cxx</code> are also good examples.
+
+<p>But for most purposes, consider the first two mechanisms instead.
+FlightGear's general inter-module communication mechanism is the
+property tree, which is exposed from both Nasal and C++ code already.
+A Nasal extension function, by definition, is useful only to Nasal
+code. Even worse, data structures definied by a Nasal interface are
+completely invisible to the C++ world.
+</body>
+</html>