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