Howto:Create animation XML files from Nasal: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
Line 81: Line 81:
This is identical to how the property tree internally works already: /sim/foo is equivalent to /sim/foo[0]
This is identical to how the property tree internally works already: /sim/foo is equivalent to /sim/foo[0]
If you don't understand how this works, please take a look at $FG_ROOT/Docs: http://gitorious.org/fg/fgdata/blobs/master/Docs/README.xmlpanel#line162
If you don't understand how this works, please take a look at $FG_ROOT/Docs: http://gitorious.org/fg/fgdata/blobs/master/Docs/README.xmlpanel#line162
If you want this to be even easier, you could use the props.nas module, because its methods have support for adding indices automatically.


Next, you could add a handful of helpers (or even a class wrapping animations) to make things a bit easier.
Next, you could add a handful of helpers (or even a class wrapping animations) to make things a bit easier.

Revision as of 15:18, 5 February 2012

This article is a stub. You can help the wiki by expanding it.

Objective: Use Nasal scripting to dynamically create an XML file by using the setprop() API call to set up your XML file's PropertyList-encoded structure and then writing the result to the file system using the write_properties() wrapper found in $FG_ROOT/Nasal/io.nas.

There are two wrappers provided: read_properties() and write_properties. These are wrappers for the corresponding fgcommands "load-xml" and "save-xml".

So, you don't need to look into the low level XML processing routines, you can directly use these PropertyList-wrappers - these allow you to directly dump a property tree sub branch to an XML file. So you can create your structure dynamically using setprop() and at the end use the write_properties() wrapper to write the resulting XML file to disk. That should save you some time.


Background

In general, this shouldn't really be necessary - because XML files are meant to be created and edited manually. On the other hand, due to the lack of a simple 2D drawing API accessible from Nasal, more and more complex "glass cockpit"-style instruments are getting implemented using the XML-based approach. These files (often more than 100-200 kbytes in size) contain fairly repetitive markup that could (and should) be created procedurally in an automated fashion. So, the approach suggested here is to use a separate Nasal script to create the required XML markup dynamically, rather than having to copy/paste and customize hundreds of XML animations manually using a text editor.

Getting started

The following piece of Nasal creates a new XML file:

 var location= "/temp/test/foo"; # location in the global FG property tree
 var filename="test.xml"; # location in the local file system (will be OVERWRITTEN/DELETED!)
 setprop(location, "hello world");
 io.write_properties(filename, location);


The created output is:

 <?xml version="1.0"?>
 <PropertyList>
  <temp>
   <test>
    <foo>hello world</foo>
   </test>
  </temp>

Once you understand how this works, you can dynamically create PropertyList-encoded XML files for your instruments. Consider the following XML file containing a single animation:

       <path>vsd.ac</path>
       <animation>
          <type>select</type>
          <object-name>vsd</object-name>
          <condition>
             <greater-than-equals>
                <property>systems/electrical/outputs/efis</property>
                <value>9</value>
             </greater-than-equals>
          </condition>
       </animation>

Now, to create this snippet of XML procedurally, you can use this piece of Nasal:

    var location = "/temp/test/";
    var filename="xmltest.xml";
    setprop(location~"path", "vsd.ac");
    setprop(location~"animation/type", "select");
    setprop(location~"animation/object-name", "vsd");
    setprop(location~"animation/condition/greather-than-equals/property", "systems/electrical/outputs/efis");
    setprop(location~"animation/condition/greather-than-equals/value", "9");
    io.write_properties(filename, location);


Note that multiple setprop() calls like this would obviously overwrite the previous animation, so you would need to use explicit indices here:

  • animation[0]
  • animation[1]
  • animation[2]

This also holds true for any child nodes:

  • object-name[0]
  • object-name[1]
  • object-name[2]
  • object-name[3]

This is identical to how the property tree internally works already: /sim/foo is equivalent to /sim/foo[0] If you don't understand how this works, please take a look at $FG_ROOT/Docs: http://gitorious.org/fg/fgdata/blobs/master/Docs/README.xmlpanel#line162

If you want this to be even easier, you could use the props.nas module, because its methods have support for adding indices automatically.

Next, you could add a handful of helpers (or even a class wrapping animations) to make things a bit easier. Anybody interested in coming up with an OOP wrapper for this, should look into using the props.nas module available in $FG_ROOT/Nasal.

If you already have some prefabricated XML file that you'd like to continue using, then you could also just automate the creation of certain animations and save them in a separate file. This is supported by including a PropertyList file in another file using the "include" attribute:

 <PropertyList>
  <animation include="vsd.xml"/>
 </PropertyList>


 <?xml version="1.0"?>
  <PropertyList>
   <foo include="someotherfile.xml"/>
  </PropertyList>
<?xml version="1.0"?>
<PropertyList>
    <bla>data</bla>
</PropertyList>

This would result in /foo/bla=data

Some additional info is available in $FG_ROOT/Docs:


There is also support for customizing included files (overriding certain properties with custom defaults): http://gitorious.org/fg/fgdata/blobs/master/Docs/README.xmlpanel#line245

Related