1Users Guide to FlightGear panel configuration
2Version 0.7.7, May 16 2001
3Author: John Check <j4strngs@rockfish.net>
4
5This document is an attempt to describe the configuration of
6FlightGear flight simulator's aircraft panel display via XML.  The
7information was culled from the fgfs-devel@flightgear.org mailing list
8and my experiences making alternate panels.  Corrections and additions
9are encouraged.
10
11Some History:
12------------
13Older versions of FGFS had a hard coded display of instruments.  This
14was a less than ideal state of affairs due to FGFS ability to use
15different aircraft models. Being primarily developed on UNIX type
16systems, a modular approach is taken towards the simulation. To date,
17most alternatives to the default Cessna 172 aircraft are the product
18of research institutions interested in the flight characteristics and
19not cosmetics.  The result of this was that one could fly the X-15 or
20a Boeing 747 but be limited to C172 instrumentation.
21
22A rewrite of the panel display code was done around v0.7.5 by
23developer David Megginson allowing for configuration of the panel via
24XML to address this limitation. Some major changes and additions were
25made during the course of version 0.7.7 necessitating a rewrite and
26expansion of this document.
27
28
29About The Property Manager:
30--------------------------
31While not absolutely necessary in order to create aircraft panels,
32some familiarity with the property manager is beneficial....
33FlightGear provides a hierarchical representation of all aspects of
34the state of the running simulation that is known as the property
35tree.  Some properties, such as velocities are read only. Others such
36as the frequencies to which the navcom radios are tuned or the
37position of control surfaces can be set by various means.  FlightGear
38can optionally provide an interface to these properties for external
39applications such as Atlas, the moving map program, or even lowly
40telnet, via a network socket. Data can even be placed on a serial port
41and connected to, say a GPS receiver.  Aside from its usefulness in a
42flight training context, being able to manipulate the property tree on
43a running copy of FG allows for switching components on the fly, a
44positive boon for panel authors.  To see the property tree start FG
45with the following command line:
46
47fgfs --props=socket,bi,5,localhost,5500,tcp
48
49Then use telnet to connect to localhost on port 5500. You can browse
50the tree as you would a filesystem.
51
52XML and the Property Manager:
53----------------------------
54Panel instruments interface with the property tree to get/set values
55as appropriate. Properties for which FG doesn't yet provide a value
56can be created by simply making them up. Values can be adjusted using
57the telnet interface allowing for creation and testing of instruments
58while code to drive them is being developed.
59
60If fact, the XML configuration system allows a user to combine
61components such as flight data model, aircraft exterior model, heads
62up display, and of course control panel. Furthermore, such a
63preconfigured aircraft.xml can be included into a scenario with
64specific flight conditions. These can be manually specified or a FG
65session can be saved and/or edited and reloaded later. Options
66specified in these files can be overridden on the command line. For
67example:
68
69--prop:/sim/panel/path=Aircraft/c172/Panels/c172-panel.xml
70
71passed as an option, would override a panel specified elsewhere.
72Property tree options all have the same format, specify the node and
73supply it a value.
74
75The order of precedence for options is thus:
76
77Source          Location                Format
78------          --------                ------
79command line
80.fgfsrc         Users home directory.   command line options
81system.fgfsrc   $FG_ROOT                ""      ""
82preferences.xml $FG_ROOT                XML property list
83
84
85Loading Panels on the fly:
86-------------------------
87When editing a panel configuration, pressing Shift +F3 will reload the
88panel. If your changes don't seem to be taking effect, check the
89console output.  It will report the success or failure of the panel
90reload*. Editing textures requires restarting FGFS so the new textures
91can be loaded. Panels can be switched on the fly by setting the
92/sim/panel/path property value and reloading.
93
94Regarding Window Geometry:
95-------------------------
96For the sake of simplicity the FGFS window is always considered to be
971024x768 so all x/y values for instrument placement should relative to
98these dimensions.  Since FG uses OpenGL 0,0 represents the lower left
99hand corner of the screen. Panels may have a virtual size larger than
1001024x768. Vertical scrolling is accomplished with
101Shift+F5/F6. Horizontal scrolling is via Shift+F7/F8. An offset should
102be supplied to set the default visible area. It is possible to place
103items to overlap the 3D viewport.
104
105Panel Architecture:
106-------------------
107All of the panel configuration files are XML-encoded* property lists.
108The root element of each file is always named <PropertyList>. Tags are
109almost always found in pairs, with the closing tag having a slash
110prefixing the tag name, i.e </PropertyList>. The exception is the tag
111representing an aliased property. In this case a slash is prepended to
112the closing angle bracket.  (see section Aliasing)
113
114The top level panel configuration file is composed of a <name>, a
115<background> texture and zero or more <instruments>.Earlier versions
116required instruments to have a unique name and a path specification
117pointing to the instruments configuration file.
118
119[ Paths are relative to $FG_ROOT (the installed location of FGFS data files.) ]
120[ Absolute paths may be used.Comments are bracketed with <!-- -->.            ]
121
122Old style instrument call in top level panel.xml:
123------------------------------------------------
124  <clock>         <!-- required "unique_name" -->
125   <path>Aircraft/c172/Instruments/clock.xml</path>
126   <x>110</x>     <!-- required horizontal placement -->
127   <y>320</y>     <!-- required vertical placement -->
128   <w>72</w>      <!-- optional width specification -->
129   <h>72</h>      <!-- optional height specification -->
130  </clock>
131
132The difference between the old and new styles, while subtle, is rather
133drastic.  The old and new methods are indeed incompatible. I cover the
134old style only to acknowledge the incompatibility. This section will
135be removed after the next official FGFS release.
136
137New Style Example Top Level Panel Config:
138----------------------------------------
139<PropertyList>
140 <name>Example Panel</name>
141 <background>Aircraft/c172/Panels/Textures/panel-bg.rgb</background>
142 <w>1024</w>                      <!-- virtual width -->
143 <h>768</h>                       <!-- virtual height -->
144 <y-offset>-305</y-offset>        <!-- hides the bottom part -->
145 <view-height>172</view-height>   <!-- amount of overlap between 2D panel
146                                       and 3D viewport -->
147
148 <instruments>                    <!-- from here down is where old and new
149                                       styles break compatibility -->
150
151  <instrument include="../Instruments/clock.xml">
152   <name>Chronometer</name>   <!-- currently optional but strongly recommended -->
153   <x>150</x>                 <!-- required horizontal placement -->
154   <y>645</y>                 <!-- required vertical placement -->
155   <w>72</w>                  <!-- optional width specification -->
156   <h>72</h>                  <!-- optional height specification -->
157  </instrument>
158
159 </instruments>
160
161</PropertyList>
162
163
164Indexed Properties
165------------------
166This is a lot to do with the compatibility break so lets get it out of
167the way.  The property manager now assigns incremental indices to
168repeated properties with the same parent node, so that
169
170 <PropertyList>
171 <x>1</x>
172 <x>2</x>
173 <x>3</x>
174 </PropertyList>
175
176shows up as
177
178 /x[0] = 1
179 /x[1] = 2
180 /x[2] = 3
181
182This means that property files no longer need to make up a separate
183name for each item in a list of instruments, layers, actions,
184transformations, or text chunks. In fact, the new panel I/O code now
185insists that every instrument have the XML element name "instrument",
186every layer have the name "layer", every text chunk have the name
187"chunk", every action have the name "action", and every transformation
188have the name "transformation" -- this makes the XML more regular (so
189that it can be created in a DTD-driven tool) and also allows us to
190include other kinds of information (such as doc strings) in the lists
191without causing confusion.
192
193Inclusion:
194----------
195The property manager now supports file inclusion and aliasing.
196Inclusion means that a node can include another property file as if it
197were a part of the current file.  To clarify how inclusion works,
198consider the following examples:
199
200If bar.xml contains
201
202 <PropertyList>
203 <a>1</a>
204 <b>
205 <c>2</c>
206 </b>
207 </PropertyList>
208
209then the declaration
210
211 <foo include="../bar.xml">
212 </foo>
213
214is exactly equivalent to
215
216 <foo>
217 <a>1</a>
218 <b>
219 <c>2</c>
220 </b>
221 </foo>
222
223However, it is also possible to selectively override properties in the
224included file. For example, if the declaration were
225
226 <foo include="../bar.xml">
227 <a>3</a>
228 </foo>
229
230then the property manager would see
231
232 <foo>
233 <a>3</a>
234 <b>
235 <c>2</c>
236 </b>
237 </foo>
238
239with the original 'a' property's value replaced with 3.
240
241This new inclusion feature allows property files to be broken up and
242reused arbitrarily -- for example, there might be separate cropping
243property lists for commonly-used textures or layers, to avoid
244repeating the information in each instrument file.
245
246
247Aliasing
248--------
249Properties can now alias other properties, similar to a symbolic link
250in Unix. When the target property changes value, the new value will
251show up in the aliased property as well. For example,
252
253 <PropertyList>
254 <foo>3</foo>
255 <bar alias="/foo"/>
256 </PropertyList>
257
258will look the same to the application as
259
260 <PropertyList>
261 <foo>3</foo>
262 <bar>3</bar>
263 </PropertyList>
264
265except that when foo changes value, bar will change too.
266
267
268The combination of inclusions and aliases is very powerful, because it
269allows for parameterized property files. For example, the XML file for
270the NAVCOM radio can include a parameter subtree at the start, like
271this:
272
273 <PropertyList>
274 <params>
275 <comm-freq-prop>/radios/comm1/frequencies/selected</comm-freq-prop>
276 <nav-freq-prop>/radios/nav1/frequencies/selected</comm-freq-prop>
277 </params>
278
279 ...
280
281 <chunk>
282 <type>number-value</type>
283 <property alias="/params/nav-freq-prop"/>
284 </chunk>
285
286 ...
287 </PropertyList>
288
289Now, the same instrument file can be used for navcomm1 and navcomm2,
290for example, simply by overriding the parameters at inclusion:
291
292 <instrument include="../Instruments/navcomm.xml">
293 <params>
294 <comm-freq-prop>/radios/comm1/frequencies/selected</comm-freq-prop>
295 <nav-freq-prop>/radios/nav1/frequencies/selected</comm-freq-prop>
296 </params>
297 </instrument>
298
299 <instrument include="../Instruments/navcomm.xml">
300 <params>
301 <comm-freq-prop>/radios/comm2/frequencies/selected</comm-freq-prop>
302 <nav-freq-prop>/radios/nav2/frequencies/selected</comm-freq-prop>
303 </params>
304 </instrument>
305
306Instrument Architecture:
307-----------------------
308Instruments are defined in separate configuration files. An instrument
309consists of a base width and height, one or more stacked layers, and
310zero or more actions. Base dimensions are specified as follows:
311
312<PropertyList>                   <!-- remember, all xml files start like this -->
313 <name>Airspeed Indicator</name> <!-- names are good -->
314 <w-base>128</w-base>            <!-- required width spec-->
315 <h-base>128</h-base>            <!-- required height spec-->
316  <layers>                       <!-- begins layers section -->
317
318Height and width can be overriden in the top level panel.xml by
319specifying <w> and <h>. Transformations are caculated against the base
320size regardless of the display size. This ensures that instruments
321remain calibrated
322
323Textures:
324--------
325FG uses red/green/blue/alpha .rgba files for textures. Dimensions for
326texture files should be power of 2 with a maximum 8:1 aspect ratio.
327The lowest common denominator for maximum texture size is 256 pixels.
328This is due to the limitations of certain video accelerators, most
329notably those with 3Dfx chipset such as the Voodoo2.
330
331Instrument Layers**:
332-------------------
333The simplest layer is a <texture>. These can be combined in <switch> layers
334
335<texture>
336A texture layer looks like this:
337
338  <layer>                      <!-- creates a layer -->
339   <name>face</name>
340   <texture>                   <!-- defines it as a texture layer -->
341    <path>Aircraft/c172/Instruments/Textures/faces-2.rgb</path>
342    <x1>0</x1>                 <!-- lower boundary for texture cropping-->
343    <y1>0.51</y1>              <!-- left boundary  for texture cropping-->
344    <x2>0.49</x2>              <!-- upper boundary  for texture cropping-->
345    <y2>1.0</y2>               <!-- right boundary  for texture cropping-->
346   </texture>                  <!-- closing texure tag -->
347  </layer>                     <!-- closing layer tag -->
348
349The texture cropping specification is represented as a decimal. There
350is a table at the end of this document for converting from pixel
351coordinates to percentages.
352
353This particular layer, being a gauge face has no transformations
354applied to it.  Layers with that aren't static *must* include <w> and
355<h> parameters to be visible.
356
357<type> May be either text or switch..
358
359<type>switch</type>
360A switch layer is composed of two or more nested layers and will
361display one of the nested layers based on a boolean property. For a
362simple example of a switch see
363$FG_ROOT/Aircraft/c172/Instruments/brake.xml.
364
365  <layer>
366   <name>Brake light</name>
367   <type>switch</type>                    <!-- define layer as a switch -->
368   <property>/controls/brakes</property>  <!-- tie it to a property -->
369    <layer1>                              <!-- layer for true state -->
370     <name>on</name>                      <!-- label to make life easy -->
371     <texture>                            <!-- layer1 of switch is a texture layer -->
372     <path>Aircraft/c172/Instruments/Textures/brake.rgb</path>
373     <x1>0.25</x1>
374     <y1>0.0</y1>
375     <x2>0.5</x2>
376     <y2>0.095</y2>
377     </texture>
378     <w>64</w>                          <!-- required width - layer isn't static -->
379     <h>24</h>                          <!-- required height - layer isn't static -->
380    </layer1>                           <!-- close layer1 of switch -->
381    <layer2>                            <!-- layer for false state -->
382     <name>off</name>
383     <texture>
384     <path>Aircraft/c172/Instruments/Textures/brake.rgb</path>
385     <x1>0.0</x1>
386     <y1>0.0</y1>
387     <x2>0.25</x2>
388     <y2>0.095</y2>
389     </texture>
390     <w>64</w>
391     <h>24</h>
392   </layer2>
393  </layer>
394
395Switches can have more than 2 states. This requires nesting one switch
396inside another.  One could make, for example, a 3 color LED by nesting
397switch layers.
398
399<type>text</type>
400A text layer may be static, as in a label, generated from a property
401or a combination of both.  This example is a switch that contains both
402static and dynamic text:
403
404 <layer1>                         <!-- switch layer -->
405  <name>display</name>
406  <type>text</type>               <!-- type == text -->
407  <point-size>12</point-size>     <!-- font size -->
408  <color>                         <!-- specify rgb values to color text -->
409   <red>1.0</red>
410   <green>0.5</green>
411   <blue>0.0</blue>
412  </color>                        <!-- close color section -->
413  <chunks>                        <!-- sections of text are referred to as chunks -->
414   <chunk>                        <!-- first chunk of text -->
415    <type>number-value</type>     <!-- value defines it as dynamic -->
416    <property>/radios/nav1/dme/distance</property>    <!-- ties it to a property -->
417    <scale>0.00053995680</scale>  <!-- convert between statute and nautical miles? -->
418    <format>%5.1f</format>        <!-- define format -->
419   </chunk>
420  </chunks>
421 </layer1>
422 <layer2>                         <!-- switch layer -->
423  <name>display</name>
424  <type>text</type>               <!-- type == text -->
425  <point-size>10</point-size>     <!-- font size -->
426  <color>                         <!-- specify rgb values to color text -->
427   <red>1.0</red>
428   <green>0.5</green>
429   <blue>0.0</blue>
430  </color>                        <!-- close color section -->
431  <chunks>                        <!-- sections of text are referred to as chunks -->
432   <chunk>                        <!-- first chunk of text -->
433    <type>literal</type>          <!-- static text -->
434    <text>---.--</text>           <!-- fixed value -->
435   </chunk>
436  </chunks>
437 </layer2>
438
439
440Transformations:
441---------------
442A transformation is a rotation, an x-shift, or a
443y-shift. Transformations can be static or they can be based on
444properties. Static rotations are useful for flipping textures
445horizontally or vertically. Transformations based on properties are
446useful for driving instrument needles. I.E. rotate the number of
447degrees equal to the airspeed. X and y shifts are relative to the
448center of the instrument. Each specified transformation type takes an
449<offset>.  Offsets are relative to the center of the instrument. A
450shift without an offset has no effect. For example, let's say we have
451a texure that is a circle. If we use this texture in two layers, one
452defined as having a size of 128x128 and the second layer is defined as
45364x64 and neither is supplied a shift and offset the net result
454appears as 2 concentric circles.
455
456
457About Transformations and Needle Placement:
458------------------------------------------
459
460When describing placement of instrument needles, a transformation
461offset must be applied to shift the needles fulcrum or else the needle
462will rotate around it's middle. The offset will be of <type> x-shift
463or y-shift depending on the orientation of the needle section in the
464cropped texture.
465
466This example comes from the altimeter.xml
467
468  <layer>
469   <name>long needle (hundreds)</name>  <!-- the altimeter has more than one needle -->
470   <texture>
471    <path>Aircraft/c172/Instruments/Textures/misc-1.rgb</path>
472    <x1>0.8</x1>
473    <y1>0.78125</y1>
474    <x2>0.8375</x2>
475    <y2>1.0</y2>
476   </texture>
477   <w>8</w>
478   <h>56</h>
479   <transformations>                    <!-- begin defining transformations -->
480    <transformation>                    <!-- start definition of
481                                             transformation that drives the needle -->
482     <type>rotation</type>
483     <property>/steam/altitude</property>  <!-- bind it to a property -->
484     <max>100000.0</max>                <!-- upper limit of instrument -->
485     <scale>0.36</scale>                <!-- once around == 1000 ft -->
486    </transformation>                   <!-- close this transformation -->
487    <transformation>                    <!-- shift the fulcrum of the needle -->
488     <type>y-shift</type>               <!-- y-shift relative to needle -->
489     <offset>24.0</offset>              <!-- amount of shift -->
490    </transformation>
491   </transformations>
492  </layer>
493
494This needles has its origin in the center of the instrument. If the
495needles fulcrum was towards the edge of the instrument, the
496transformations to place the pivot point must precede those which
497drive the needle,
498
499Interpolation
500-------------
501Non linear transformations are now possible via the use of
502interpolation tables.
503
504 <transformation>
505 ...
506 <interpolation>
507 <entry>
508 <ind>0.0</ind>            <!-- raw value -->
509 <dep>0.0</dep>            <!-- displayed value -->
510 </entry>
511 <entry>
512 <ind>10.0</ind>
513 <dep>100.0</dep>
514 </entry>
515 <entry>
516 <ind>20.0</ind>
517 <dep>-5.0</dep>
518 </entry>
519 <entry>
520 <ind>30.0</ind>
521 <dep>1000.0</dep>
522 </entry>
523 </interpolation>
524 </transformation>
525
526Of course, interpolation tables are useful for non-linear stuff, as in
527the above example, but I kind-of like the idea of using them for
528pretty much everything, including non-trivial linear movement -- many
529instrument markings aren't evenly spaced, and the interpolation tables
530are much nicer than the older min/max/scale/offset stuff and should
531allow for a more realistic panel without adding a full equation parser
532to the property manager.
533
534If you want to try this out, look at the airspeed.xml file in the base
535package, and uncomment the interpolation table in it for a very funky,
536non-linear and totally unreliable airspeed indicator.
537
538
539Actions:
540-------
541An action is a hotspot on an instrument where something will happen
542when the user clicks the left or center mouse button.  Actions are
543always tied to properties: they can toggle a boolean property, adjust
544the value of a numeric property, or swap the values of two properties.
545The x/y placement for actions specifies the origin of the lower left
546corner.  In the following example the first action sets up a hotspot
54732 pixels wide and 16 pixels high. It lower left corner is placed 96
548pixels (relative to the defined base size of the instrument) to the
549right of the center of the instrument. It is also 32 pixels below the
550centerline of the instrument.  The actual knob texture over which the
551action is superimposed is 32x32.  Omitted here is a second action,
552bound to the same property, with a positive increment value. This
553second action is placed to cover the other half of the knob. The
554result is that clicking on the left half of the knob texture decreases
555the value and clicking the right half increases the value. Also
556omitted here is a second pair of actions with the same coordinates but
557a larger increment value. This second pair is bound to a different
558mouse button. The net result is that we have both fine and coarse
559adjustments in the same hotspot, each bound to a different mouse
560button.
561
562These examples come from the radio stack:
563<actions>                              <!-- open the actions section -->
564  <action>                             <!- first action -->
565   <name>small nav frequency decrease</name>
566   <type>adjust</type>
567   <button>0</button>                  <!-- bind it to a mouse button -->
568   <x>96</x>                           <!-- placement relative to instrument center -->
569   <y>-32</y>
570   <w>16</w>                           <!-- size of hotspot -->
571   <h>32</h>
572   <property>/radios/nav1/frequencies/standby</property>    <!-- bind to a property -->
573   <increment>-0.05</increment>        <!-- amount of adjustment per mouse click -->
574   <min>108.0</min>                    <!-- lower range -->
575   <max>117.95</max>                   <!-- upper range -->
576   <wrap>1</wrap>                      <!-- value wraps around when it hits bounds -->
577  </action>
578  <action>
579   <name>swap nav frequencies</name>
580   <type>swap</type>                   <!-- define type of action -->
581   <button>0</button>
582   <x>48</x>
583   <y>-32</y>
584   <w>32</w>
585   <h>32</h>
586   <property1>/radios/nav1/frequencies/selected</property1>   <!-- properties to
587   <property2>/radios/nav1/frequencies/standby</property2>         toggle between -->
588  </action>
589  <action>
590   <name>ident volume on/off</name>
591   <type>adjust</type>
592   <button>1</button>
593   <x>40</x>
594   <y>-24</y>
595   <w>16</w>
596   <h>16</h>
597   <property>/radios/nav1/ident</property>  <!-- Morse code ID of nav beacons -->
598   <increment>1.0</increment>          <!-- the increment equals the max value
599                                            so this toggles on/off -->
600   <min>0</min>
601   <max>1</max>
602   <wrap>1</wrap>                      <!-- a shortcut to avoid having separate
603                                            actions for on/off -->
604  </action>
605</actions>
606
607More About Textures:
608-------------------
609As previously stated, the usual size instrument texture files in FGFS
610are 256x256 pixels, red/green/blue/alpha format. However the mechanism
611for specifying texture cropping coordinates is decimal in nature. When
612calling a section of a texture file the 0,0 lower left convention is
613used.  There is a pair of x/y coordinates defining which section of
614the texture to use.
615
616The following table can be used to calculate texture cropping
617specifications.
618
619# of divisions | width in pixels | decimal specification
620per axis
621        1   =   256 pixels              1
622        2   =   128 pixels,             0.5
623        4   =   64 pixels,              0.25
624        8   =   32 pixels,              0.125
625        16  =   16 pixels,              0.0625
626        32  =   8 pixels,               0.03125
627        64  =   4 pixels,               0.015625
628        128 =   2 pixels,               0.0078125
629
630A common procedure for generating gauge faces is to use a vector
631graphics package such as xfig, exporting the result as a postscript
632file. 3D modeling tools may also be used and I prefer them for pretty
633items such as levers, switches, bezels and so forth.  Ideally, the
634size of the item in the final render should be of proportions that fit
635into the recommended pixel widths.  The resulting files can be
636imported into a graphics manipulation package such as GIMP, et al for
637final processing.
638
639How do I get my panels/instruments into the base package?
640-------------------------------------------------------
641Cash bribes always help ;) Seriously though, there are two main
642considerations.  Firstly, original artwork is a major plus since you
643as the creator can dictate the terms of distribution.  All Artwork must
644have a license compatible with the GPL.  Artwork of unverifiable
645origin is not acceptable.  Secondly, texture sizes must meet the
646lowest common denominator of 256e2 pixels.  Artwork from third parties
647may be acceptable if it meets these criteria.
648
649*  If there are *any* XML parsing errors, the panel will fail to load,
650   so it's worth downloading a parser like Expat (http://www.jclark.com/xml/)
651   for checking your XML. FlightGear will print the location of errors, but
652   the messages are a little cryptic right now.
653
654** NOTE: There is one built-in layer -- for the mag compass ribbon --
655   and all other layers are defined in the XML files.  In the future,
656   there may also be built-in layers for special things like a
657   weather-radar display or a GPS (though the GPS could be handled with
658   text properties).
659
660