9fc6fdee79
HTML syntax; add a few </li>
1098 lines
39 KiB
HTML
1098 lines
39 KiB
HTML
<HTML><HEAD><TITLE>Users Guide to FlightGear panel configuration</TITLE></HEAD>
|
|
<BODY>
|
|
<H1>Users Guide to FlightGear panel configuration</H1>
|
|
|
|
<CITE>
|
|
Version 0.7.7.2, July 24 2001
|
|
Author: John Check
|
|
</CITE>
|
|
|
|
<ol>
|
|
<li><A HREF="#history">Some History</A></li>
|
|
<li><A HREF="#property_manager">About The Property Manager</A></li>
|
|
<li><A HREF="#xml">XML and The Property Manager</A></li>
|
|
<li><A HREF="#load_panel">Loading Panels</A></li>
|
|
<li><A HREF="#window_geometry">Regarding Window Geometry</A></li>
|
|
<li><A HREF="#panel_architecture">Panel Architecture</A></li>
|
|
<li><A HREF="#example_panel">Example Top Level Panel Config</A></li>
|
|
<li><A HREF="#indexed_properties">Indexed Properties</A></li>
|
|
<li><A HREF="#inclusion">Inclusion</A></li>
|
|
<li><A HREF="#instrument_architecture">Instrument Architecture</A></li>
|
|
<li><A HREF="#textures">Textures</A></li>
|
|
<li><A HREF="#instrument_layers">Instrument Layers</A></li>
|
|
<li><A HREF="#transformations">Transformations</a></li>
|
|
<li><A HREF="#conditions">Conditions</A></li>
|
|
<li><A HREF="#needle_placement">About Transformations and Needle Placement</A></li>
|
|
<li><A HREF="#interpolation">Interpolation Tables</A></li>
|
|
<li><A HREF="#actions">Actions</A></li>
|
|
<li><A HREF="#more_texture">More About Textures</A></li>
|
|
<li><A HREF="#generating_textures">Generating Textures</A></li>
|
|
<li><A HREF="#contribute">Contributing Panels</A></li>
|
|
<li><A HREF="#units">Units</A></li>
|
|
</ol>
|
|
|
|
<P>
|
|
This document describes the configuration of
|
|
FlightGear flight simulator's aircraft panel display via XML.
|
|
The information was culled from the fgfs-devel@flightgear.org
|
|
mailing list and my experiences making alternate panels.
|
|
Corrections and additions are encouraged.
|
|
</P>
|
|
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="history">Some History:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
Older versions of FGFS had a hard coded display of instruments.
|
|
This was a less than ideal state of affairs due to FGFS ability
|
|
to use different aircraft models. Being primarily developed on
|
|
UNIX type systems, a modular approach is taken towards the
|
|
simulation. To date, most alternatives to the default
|
|
Cessna 172 aircraft are the product of research institutions
|
|
interested in the flight characteristics and not cosmetics.
|
|
The result of this was that one could fly the X-15 or a Boeing 747
|
|
but be limited to C172 instrumentation.
|
|
</P>
|
|
<P>
|
|
A rewrite of the panel display code was done around v0.7.5 by
|
|
developer David Megginson allowing for configuration of the panel
|
|
via XML to address this limitation. Some major changes and additions
|
|
were made during the course of version 0.7.7 necessitating a rewrite
|
|
and expansion of this document.
|
|
</P>
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="property_manager">About The Property Manager:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
While intimate knowledge of the property manager is unnecessary to create
|
|
aircraft panels, some familiarity with the concept is required.
|
|
FlightGear provides a hierarchical representation of all aspects of
|
|
the state of the running simulation that is known as the property tree.
|
|
Some properties, such as velocities, are read only. Others such as the frequencies to which the navcom radios are tuned or the position of control surfaces
|
|
can be set by various means.
|
|
</P>
|
|
<P>
|
|
FlightGear can optionally provide an interface to these properties for external
|
|
applications such as Atlas, the moving map program, or even lowly telnet via
|
|
a network socket. Data can even be routed to a serial port and connected to
|
|
say, a GPS receiver.
|
|
Aside from its usefulness in a flight training context, being able to manipulate
|
|
the property tree on a running copy of FG allows for switching components on the fly,
|
|
a positive boon for panel authors.
|
|
To see the property tree start FG with the following command line:
|
|
</P>
|
|
|
|
<PRE>
|
|
fgfs --props=socket,bi,5,localhost,5500,tcp
|
|
</PRE>
|
|
<br>
|
|
|
|
<P>
|
|
Then use telnet to connect to localhost on port 5500. You can browse the
|
|
tree as you would a filesystem.
|
|
</P>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="xml">XML And The Property Manager:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
Panel instruments interface with the property tree to get/set values as
|
|
appropriate. Properties for which FG doesn't yet provide a value can be
|
|
created by simply making them up. Values can be adjusted using the telnet
|
|
interface allowing for creation and testing of instruments while code to
|
|
drive them is being developed.
|
|
</P>
|
|
<P>
|
|
If fact, the XML configuration system allows a user to combine
|
|
components such as flight data model, aircraft exterior model,
|
|
heads up display, and of course control panel. Furthermore,
|
|
such a preconfigured aircraft.xml can be included into a scenario
|
|
with specific flight conditions. These can be manually specified or
|
|
a FG session can be saved and/or edited and reloaded later. Options specified
|
|
in these files can be overridden on the command line. For example:
|
|
</P>
|
|
|
|
<PRE>
|
|
--prop:/sim/panel/path=Aircraft/c172/Panels/c172-panel.xml
|
|
</PRE>
|
|
<br>
|
|
|
|
<P>
|
|
passed as an option, would override a panel specified elsewhere.
|
|
Property tree options all have the same format, specify the node
|
|
and supply it a value.
|
|
</P>
|
|
<p>
|
|
The order of precedence for options is thus:
|
|
</p>
|
|
|
|
<pre>
|
|
Source Location Format
|
|
------ -------- ------
|
|
command line
|
|
.fgfsrc ~/ command line options
|
|
system.fgfsrc $FG_ROOT "" ""
|
|
preferences.xml $FG_ROOT XML property list
|
|
</pre>
|
|
<br>
|
|
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="load_panel">Loading Panels on the fly:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
When editing a panel configuration, pressing Shift +F3 will reload the
|
|
panel. If your changes don't seem to be taking effect, check the console output.
|
|
It will report the success or failure of the panel reload*. Editing textures requires
|
|
restarting FGFS so the new textures can be loaded. Panels can be switched on the fly
|
|
by setting the /sim/panel/path property value and reloading.
|
|
</P>
|
|
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="window_geometry">Regarding Window Geometry:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
For the sake of simplicity the FGFS window is always considered to be 1024x768
|
|
so all x/y values for instrument placement should relative to these dimensions.
|
|
Since FG uses OpenGL 0,0 represents the lower left hand corner of the
|
|
screen. Panels may have a virtual size larger than 1024x768. Vertical scrolling is accomplished
|
|
with Shift+F5/F6. Horizontal scrolling is via Shift+F7/F8. An offset should be supplied
|
|
to set the default visible area. It is possible to place items to overlap the 3D viewport.
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="panel_architecture">Panel Architecture:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
All of the panel configuration files are XML-encoded* property lists.
|
|
The root element of each file is always named <PropertyList>. Tags are
|
|
almost always found in pairs, with the closing tag having a slash prefixing
|
|
the tag name, i.e </PropertyList>. The exception is the tag representing an aliased
|
|
property. In this case a slash is prepended to the closing angle bracket.
|
|
(see section Aliasing)
|
|
Properties must have units specified where appropriate. See section "Units"
|
|
at the end of this doc.
|
|
</P>
|
|
<P>
|
|
The top level panel configuration file is composed of a <name>, a <background>
|
|
texture and zero or more <instruments>.
|
|
</P>
|
|
<p>
|
|
[ Paths are relative to $FG_ROOT ( the installed location of FGFS data files ). ]<br>
|
|
[ Absolute paths may be used. Comments are bracketed with <!-- -->. ]
|
|
</p>
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="example_panel">Example Top Level Panel Config:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
<PRE>
|
|
<PropertyList>
|
|
<name>Example Panel</name>
|
|
<background>Aircraft/c172/Panels/Textures/panel-bg.rgb</background>
|
|
<w>1024</w> <!-- virtual width -->
|
|
<h>768</h> <!-- virtual height -->
|
|
<y-offset>-305</y-offset> <!-- hides the bottom part -->
|
|
<view-height>172</view-height> <!-- amount of overlap between 2D panel and 3D viewport -->
|
|
|
|
<instruments>
|
|
|
|
<instrument include="../Instruments/clock.xml">
|
|
<name>Chronometer</name> <!-- currently optional but strongly recommended -->
|
|
<x>150</x> <!-- required horizontal placement -->
|
|
<y>645</y> <!-- required vertical placement -->
|
|
<w>72</w> <!-- optional width specification -->
|
|
<h>72</h> <!-- optional height specification -->
|
|
</instrument>
|
|
|
|
</instruments>
|
|
|
|
</PropertyList>
|
|
</PRE>
|
|
<BR>
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="indexed_properties">Indexed Properties:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
The property manager assigns incremental indices to repeated
|
|
properties with the same parent node, so that
|
|
</P>
|
|
<PRE>
|
|
<PropertyList>
|
|
<x>1</x>
|
|
<x>2</x>
|
|
<x>3</x>
|
|
</PropertyList>
|
|
</PRE><BR>
|
|
<p>
|
|
shows up as
|
|
</P>
|
|
<PRE>
|
|
/x[0] = 1
|
|
/x[1] = 2
|
|
/x[2] = 3
|
|
</PRE><BR>
|
|
<p>
|
|
In fact, the panel I/O code insists that every instrument have the XML element
|
|
name "instrument", every layer have the name "layer", every text chunk have the
|
|
name
|
|
|
|
"chunk", every action have the name "action", and every transformation
|
|
have the name "transformation" -- this makes the XML more regular (so
|
|
that it can be created in a DTD-driven tool) and also allows us to
|
|
include other kinds of information (such as doc strings) in the lists
|
|
without causing confusion.
|
|
</P>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="inclusion">Inclusion:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
Inclusion means that a node can include another property list as if it
|
|
were a part of the current file.
|
|
To clarify how inclusion works, consider the following examples:
|
|
</P>
|
|
<p>
|
|
If bar.xml contains
|
|
</P>
|
|
<PRE>
|
|
<PropertyList>
|
|
<a>1</a>
|
|
<b>
|
|
<c>2</c>
|
|
</b>
|
|
</PropertyList>
|
|
</PRE><BR>
|
|
<p>
|
|
then the declaration
|
|
</P>
|
|
<PRE>
|
|
<foo include="../bar.xml">
|
|
</foo>
|
|
</PRE><br>
|
|
<p>
|
|
is exactly equivalent to
|
|
</P>
|
|
<PRE>
|
|
<foo>
|
|
<a>1</a>
|
|
<b>
|
|
<c>2</c>
|
|
</b>
|
|
</foo>
|
|
</PRE>
|
|
<br>
|
|
<p>
|
|
However, it is also possible to selectively override properties in the
|
|
included file. For example, if the declaration were
|
|
</p>
|
|
|
|
<PRE>
|
|
<foo include="../bar.xml">
|
|
<a>3</a>
|
|
</foo>
|
|
</PRE>
|
|
<BR>
|
|
<p>
|
|
then the property manager would see
|
|
</P>
|
|
<PRE>
|
|
<foo>
|
|
<a>3</a>
|
|
<b>
|
|
<c>2</c>
|
|
</b>
|
|
</foo>
|
|
</PRE>
|
|
<br>
|
|
<p>
|
|
with the original 'a' property's value replaced with 3.
|
|
</P>
|
|
<p>
|
|
Inclusion allows property files to be broken up and reused
|
|
arbitrarily -- for example, there might be separate texture cropping
|
|
property lists for commonly-used textures or layers, to avoid
|
|
repeating the information in each instrument file.
|
|
</P>
|
|
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="aliasing">Aliasing:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
Properties can alias other properties, similar to a symbolic link
|
|
in Unix. When the target property changes value, the new value will
|
|
show up in the aliased property as well. For example,
|
|
</p>
|
|
<PRE>
|
|
<PropertyList>
|
|
<foo>3</foo>
|
|
<bar alias="/foo"/>
|
|
</PropertyList>
|
|
</PRE>
|
|
<br>
|
|
<p>
|
|
will look the same to the application as
|
|
</p>
|
|
<PRE>
|
|
<PropertyList>
|
|
<foo>3</foo>
|
|
<bar>3</bar>
|
|
</PropertyList>
|
|
</PRE>
|
|
<br>
|
|
<p>
|
|
except that when foo changes value, bar will change too.
|
|
</p>
|
|
<p>
|
|
*IMPORTANT*
|
|
-----------
|
|
The combination of inclusions and aliases is very powerful, because it
|
|
allows for parameterized property files. However, you must keep in
|
|
mind that when an instrument is included by reference, its root is
|
|
*not* the root of the property tree, therefore aliases must be relative.
|
|
The relative location of the alias' root in the property hierarchy depends
|
|
on whether the alias is used in a layer, a switch or an action.
|
|
In lieu of snappy mnemonic, please use the following table.
|
|
</p>
|
|
<pre>
|
|
when alias
|
|
is used in go up
|
|
--------- -----
|
|
layer 5 ( ../../../../../params/foo )
|
|
switch 3 ( ../../../params/foo )
|
|
action 3 ( ../../../params/foo )
|
|
</pre>
|
|
<br>
|
|
|
|
<p>
|
|
As an example of inclusion and aliasing, consider the XML file
|
|
for the NAVCOM radio, which includes a parameter subtree at the start,
|
|
like this:
|
|
</p>
|
|
|
|
<PRE>
|
|
<PropertyList>
|
|
<params>
|
|
<comm-freq-prop>/radios/comm1/frequencies/selected-mhz</comm-freq-prop>
|
|
<nav-freq-prop>/radios/nav1/frequencies/selected-mhz</nav-freq-prop>
|
|
</params>
|
|
|
|
...
|
|
|
|
<chunk>
|
|
<type>number-value</type>
|
|
<property alias="../../../../../params/nav-freq-prop"/>
|
|
</chunk>
|
|
|
|
...
|
|
</PropertyList>
|
|
</PRE>
|
|
<br>
|
|
<P>
|
|
The same instrument file is used for navcomm1 and navcomm2 simply by
|
|
overriding the parameters at inclusion in the top level panel property list.
|
|
</P>
|
|
|
|
<pre>
|
|
<instrument include="../Instruments/navcomm.xml">
|
|
<name>NAVCOM 1 radio</name>
|
|
<params>
|
|
<comm-freq-prop>/radios/comm1/frequencies/selected-mhz</comm-freq-prop>
|
|
<nav-freq-prop>/radios/nav1/frequencies/selected-mhz</nav-freq-prop>
|
|
</params>
|
|
.....
|
|
</instrument>
|
|
|
|
<instrument include="../Instruments/navcomm.xml">
|
|
<name>NAVCOM 2 radio</name>
|
|
<params>
|
|
<comm-freq-prop>/radios/comm2/frequencies/selected-mhz</comm-freq-prop>
|
|
<nav-freq-prop>/radios/nav2/frequencies/selected-mhz</nav-freq-prop>
|
|
</params>
|
|
.....
|
|
</instrument>
|
|
</PRE>
|
|
<br>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="instrument_architecture">Instrument Architecture:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
Instruments are defined in separate configuration files. An instrument
|
|
consists of a base width and height, one or more stacked layers,
|
|
and zero or more actions. Base dimensions are specified as follows:
|
|
</p>
|
|
<pre>
|
|
<PropertyList> <!-- remember, all xml files start like this -->
|
|
<name>Airspeed Indicator</name> <!-- names are good -->
|
|
<w-base>128</w-base> <!-- required width spec-->
|
|
<h-base>128</h-base> <!-- required height spec-->
|
|
<layers> <!-- begins layers section -->
|
|
</pre>
|
|
<br>
|
|
|
|
<p>
|
|
Height and width can be overriden in the top level panel.xml by
|
|
specifying <w> and <h>. Transformations are caculated against the base size
|
|
regardless of the display size. This ensures that instruments remain calibrated.
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="textures">Textures:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
FG uses red/green/blue/alpha .rgba files for textures. Dimensions for
|
|
texture files should be power of 2 with a maximum 8:1 aspect ratio.
|
|
The lowest common denominator for maximum texture size is 256 pixels.
|
|
This is due to the limitations of certain video accelerators, most notably
|
|
those with 3Dfx chipset such as the Voodoo2.
|
|
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="instrument_layers">Instrument Layers**:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
The simplest layer is a <texture>. These can be combined in <switch> layers
|
|
</p>
|
|
<p>
|
|
<texture>
|
|
A texture layer looks like this:
|
|
</p>
|
|
<pre>
|
|
<layer> <!-- creates a layer -->
|
|
<name>face</name>
|
|
<texture> <!-- defines it as a texture layer -->
|
|
<path>Aircraft/c172/Instruments/Textures/faces-2.rgb</path>
|
|
<x1>0</x1> <!-- lower boundary for texture cropping-->
|
|
<y1>0.51</y1> <!-- left boundary for texture cropping-->
|
|
<x2>0.49</x2> <!-- upper boundary for texture cropping-->
|
|
<y2>1.0</y2> <!-- right boundary for texture cropping-->
|
|
</texture> <!-- closing texure tag -->
|
|
</layer> <!-- closing layer tag -->
|
|
</pre>
|
|
<br>
|
|
<p>
|
|
The texture cropping specification is represented as a decimal. There is a table
|
|
at the end of this document for converting from pixel coordinates to percentages.
|
|
</p>
|
|
<p>
|
|
This particular layer, being a gauge face has no transformations applied to it.
|
|
Layers with that aren't static *must* include <w> and <h> parameters to be visible.
|
|
</p>
|
|
<p>
|
|
<type> May be either text or switch..
|
|
</p>
|
|
<p>
|
|
<type>switch</type>
|
|
A switch layer is composed of two or more nested layers and will display
|
|
one of the nested layers based on a boolean property. For a simple example
|
|
of a switch see $FG_ROOT/Aircraft/c172/Instruments/brake.xml.
|
|
</p>
|
|
<pre>
|
|
<layer>
|
|
<name>Brake light</name>
|
|
<type>switch</type> <!-- define layer as a switch -->
|
|
<property>/controls/gear/brake-left</property> <!-- tie it to a property -->
|
|
<layer1> <!-- layer for true state -->
|
|
<name>on</name> <!-- label to make life easy -->
|
|
<texture> <!-- layer1 of switch is a texture layer -->
|
|
<path>Aircraft/c172/Instruments/Textures/brake.rgb</path>
|
|
<x1>0.25</x1>
|
|
<y1>0.0</y1>
|
|
<x2>0.5</x2>
|
|
<y2>0.095</y2>
|
|
</texture>
|
|
<w>64</w> <!-- required width - layer isn't static -->
|
|
<h>24</h> <!-- required height - layer isn't static -->
|
|
</layer1> <!-- close layer1 of switch -->
|
|
<layer2> <!-- layer for false state -->
|
|
<name>off</name>
|
|
<texture>
|
|
<path>Aircraft/c172/Instruments/Textures/brake.rgb</path>
|
|
<x1>0.0</x1>
|
|
<y1>0.0</y1>
|
|
<x2>0.25</x2>
|
|
<y2>0.095</y2>
|
|
</texture>
|
|
<w>64</w>
|
|
<h>24</h>
|
|
</layer2>
|
|
</layer>
|
|
</pre>
|
|
<br>
|
|
<p>
|
|
Switches can have more than 2 states. This requires nesting one switch inside another.
|
|
One could make, for example, a 3 color LED by nesting switch layers.
|
|
</p>
|
|
|
|
<p>
|
|
<type>text</type>
|
|
A text layer may be static, as in a label, generated from a property or a combination of both.
|
|
This example is a switch that contains both static and dynamic text:
|
|
</p>
|
|
|
|
<pre>
|
|
<layer1> <!-- switch layer -->
|
|
<name>display</name>
|
|
<type>text</type> <!-- type == text -->
|
|
<point-size>12</point-size> <!-- font size -->
|
|
<color> <!-- specify rgb values to color text -->
|
|
<red>1.0</red>
|
|
<green>0.5</green>
|
|
<blue>0.0</blue>
|
|
</color> <!-- close color section -->
|
|
<chunks> <!-- sections of text are referred to as chunks -->
|
|
<chunk> <!-- first chunk of text -->
|
|
<type>number-value</type> <!-- value defines it as dynamic -->
|
|
<property>/radios/nav1/dme/distance-nm</property> <!-- ties it to a property -->
|
|
<scale>0.00053995680</scale> <!-- convert between statute and nautical miles? -->
|
|
<format>%5.1f</format> <!-- define format -->
|
|
</chunk>
|
|
</chunks>
|
|
</layer1>
|
|
<layer2> <!-- switch layer -->
|
|
<name>display</name>
|
|
<type>text</type> <!-- type == text -->
|
|
<point-size>10</point-size> <!-- font size -->
|
|
<color> <!-- specify rgb values to color text -->
|
|
<red>1.0</red>
|
|
<green>0.5</green>
|
|
<blue>0.0</blue>
|
|
</color> <!-- close color section -->
|
|
<chunks> <!-- sections of text are referred to as chunks -->
|
|
<chunk> <!-- first chunk of text -->
|
|
<type>literal</type> <!-- static text -->
|
|
<text>---.--</text> <!-- fixed value -->
|
|
</chunk>
|
|
</chunks>
|
|
</layer2>
|
|
</pre>
|
|
<br>
|
|
Note that the value to be displayed can be modified using <scale> for multiplication,
|
|
<offset> for addition, and <truncate>true</truncate> for truncation. The order of
|
|
operation is always scale-offset-truncation, which may require you to adapt your formula. For instance, the
|
|
normal conversion from Fahrenheit to Celsius would be C = (F-32)*0.555555556. Because of the order
|
|
of operation above you must use the formula C = (F*0.55555556)-17.77777777.
|
|
<br>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="conditions">Conditions:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
A condition may appear in a binding (for keyboard, joystick, or panel
|
|
action) or in most parts of a panel configuration file (specifically,
|
|
for an instrument, layer, transformation, text chunk, or action). If
|
|
a condition is present, it must succeed for the component to be used
|
|
(i.e. if the condition fails, the binding will not be fired, the layer
|
|
will not be drawn, etc.). Conditions are compiled to an efficient
|
|
internal form and load time.
|
|
</p>
|
|
<p>
|
|
For example, to ensure that a layer is drawn only if the /foo/bar
|
|
property has the value "active", you would do the following:
|
|
</p>
|
|
<pre>
|
|
<layer>
|
|
<name>FooBar Layer</name>
|
|
<condition>
|
|
<equals>
|
|
<property>/foo/bar</property>
|
|
<value>active</value>
|
|
</equals>
|
|
</condition>
|
|
...
|
|
</layer>
|
|
</pre>
|
|
<p>
|
|
To draw a different layer when the /foo/bar property does not have the
|
|
value "active", you could follow with this:
|
|
</p>
|
|
<pre>
|
|
<layer>
|
|
<name>FooBar Layer</name>
|
|
<condition>
|
|
<not-equals>
|
|
<property>/foo/bar</property>
|
|
<value>active</value>
|
|
</not-equals>
|
|
</condition>
|
|
...
|
|
</layer>
|
|
</pre>
|
|
<p>
|
|
While conditions were originally created for panel designers, they
|
|
have proven to be very useful for binding input devices (such
|
|
as the keyboard or joystick), since they effectively allow any key,
|
|
axis, button, or panel action to act as a modifier for any other key,
|
|
axis, button, or panel action, and in fact, allow mind-numbingly
|
|
complicated combinations for people who like them (i.e. Emacs users).
|
|
</p>
|
|
<pre>
|
|
<!-- make 'u' a modifier key -->
|
|
<!-- could also use property-toggle to make it a toggle modifier -->
|
|
<key n="117">
|
|
<name>u</name>
|
|
<desc>Special 'u' modifier</desc>
|
|
|
|
<binding>
|
|
<command>property-assign</command>
|
|
<property>/modifiers/u</property>
|
|
<value>1</value>
|
|
</binding>
|
|
|
|
<mod-up>
|
|
<binding>
|
|
<command>property-assign</command>
|
|
<property>/modifiers/u</property>
|
|
<value>0</value>
|
|
</binding>
|
|
</mod-up>
|
|
|
|
</key>
|
|
|
|
<!-- take different actions based on the u modifier -->
|
|
<key n="118">
|
|
<name>v</name>
|
|
|
|
<binding>
|
|
<condition>
|
|
<property>/modifiers/u</property>
|
|
</condition>
|
|
<command>property-toggle</command>
|
|
<property>/foo/bar</property>
|
|
</binding>
|
|
|
|
<binding>
|
|
<condition>
|
|
<not>
|
|
<property>/modifiers/u</property>
|
|
</not>
|
|
</condition>
|
|
<command>property-toggle</command>
|
|
<property>/bar/foo</property>
|
|
</binding>
|
|
|
|
</key>
|
|
</pre>
|
|
<p>
|
|
The <condition> element acts as an implicit 'and' group for everything
|
|
contained in it. Here are the elements that can appear inside:
|
|
</p>
|
|
<pre>
|
|
<property>[name]</property>
|
|
|
|
- true if the named property returns a true boolean value (i.e. a
|
|
non-0 numeric value)
|
|
|
|
<and>[condition...]</and>
|
|
|
|
- true if all of the conditions contained in it are true
|
|
|
|
<or>[condition...]</or>
|
|
|
|
- true if any of the conditions contained in it is true
|
|
|
|
<not>[condition]</not>
|
|
|
|
- true if the condition contained in it is false
|
|
|
|
<less-than>...</less-than>
|
|
<less-than-equals>...</less-than-equals>
|
|
<equals>...</equals>
|
|
<not-equals>...</not-equals>
|
|
<greater-than>...</greater-than>
|
|
<greater-than-equals>...</greater-than-equals>
|
|
</pre>
|
|
<p>
|
|
- all of these take two child elements; the first, "property", is
|
|
the property to test; the second argument may be "property" or
|
|
"value". If it is also "property" (i.e. property[1]), the named
|
|
property's value will be used; otherwise, the literal value
|
|
provided will be used
|
|
- be warned that any string comparison other than equals/not-equals
|
|
is guaranteed to be flaky
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="transformations">Transformations:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
A transformation is a rotation, an x-shift, or a y-shift. Transformations
|
|
can be static or they can be based on properties. Static rotations are
|
|
useful for flipping textures horizontally or vertically. Transformations
|
|
based on properties are useful for driving instrument needles. I.E. rotate the
|
|
number of degrees equal to the airspeed. X and y shifts are relative to the
|
|
center of the instrument. Each specified transformation type takes an <offset>.</p><p>
|
|
Offsets are relative to the center of the instrument. A shift without an offset
|
|
has no effect. For example, let's say we have a texture that is a circle. If we
|
|
use this texture in two layers, one defined as having a size of 128x128 and
|
|
the second layer is defined as 64x64 and neither is supplied a shift and offset
|
|
the net result appears as 2 concentric circles.
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="needle_placement">About Transformations and Needle Placement:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
When describing placement of instrument needles, a transformation offset must
|
|
be applied to shift the needles fulcrum or else the needle will rotate around it's
|
|
middle. The offset will be of <type> x-shift or y-shift depending on the orientation of
|
|
the needle section in the cropped texture.
|
|
</p>
|
|
|
|
<p>
|
|
This example comes from the altimeter.xml
|
|
</p>
|
|
|
|
<pre>
|
|
<layer>
|
|
<name>long needle (hundreds)</name> <!-- the altimeter has more than one needle -->
|
|
<texture>
|
|
<path>Aircraft/c172/Instruments/Textures/misc-1.rgb</path>
|
|
<x1>0.8</x1>
|
|
<y1>0.78125</y1>
|
|
<x2>0.8375</x2>
|
|
<y2>1.0</y2>
|
|
</texture>
|
|
<w>8</w>
|
|
<h>56</h>
|
|
<transformations> <!-- begin defining transformations -->
|
|
<transformation> <!-- start definition of transformation that drives the needle -->
|
|
<type>rotation</type>
|
|
<property>/steam/altitude-ft</property> <!-- bind it to a property -->
|
|
<max>100000.0</max> <!-- upper limit of instrument -->
|
|
<scale>0.36</scale> <!-- once around == 1000 ft -->
|
|
</transformation> <!-- close this transformation -->
|
|
<transformation> <!-- this one shifts the fulcrum of the needle -->
|
|
<type>y-shift</type> <!-- y-shift relative to needle -->
|
|
<offset>24.0</offset> <!-- amount of shift -->
|
|
</transformation>
|
|
</transformations>
|
|
</layer>
|
|
</pre>
|
|
<br>
|
|
|
|
<p>
|
|
This needles has its origin in the center of the instrument. If the needles fulcrum was
|
|
towards the edge of the instrument, the transformations to place the pivot point must
|
|
precede those which drive the needle,
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="interpolation">Interpolation Tables:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
Non linear transformations are now possible via the use of interpolation tables.
|
|
</p>
|
|
|
|
<pre>
|
|
<transformation>
|
|
...
|
|
<interpolation>
|
|
<entry>
|
|
<ind>0.0</ind> <!-- raw value -->
|
|
<dep>0.0</dep> <!-- displayed value -->
|
|
</entry>
|
|
<entry>
|
|
<ind>10.0</ind>
|
|
<dep>100.0</dep>
|
|
</entry>
|
|
<entry>
|
|
<ind>20.0</ind>
|
|
<dep>-5.0</dep>
|
|
</entry>
|
|
<entry>
|
|
<ind>30.0</ind>
|
|
<dep>1000.0</dep>
|
|
</entry>
|
|
</interpolation>
|
|
</transformation>
|
|
</pre>
|
|
<br>
|
|
|
|
<p>
|
|
Of course, interpolation tables are useful for non-linear stuff, as in
|
|
the above example, but I kind-of like the idea of using them for
|
|
pretty much everything, including non-trivial linear movement -- many
|
|
instrument markings aren't evenly spaced, and the interpolation tables
|
|
are much nicer than the older min/max/scale/offset stuff and should
|
|
allow for a more realistic panel without adding a full equation parser
|
|
to the property manager.
|
|
</p>
|
|
<p>
|
|
If you want to try this out, look at the airspeed.xml file in the base
|
|
package, and uncomment the interpolation table in it for a
|
|
very funky, non-linear and totally unreliable airspeed indicator.
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="actions">Actions:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
An action is a hotspot on an instrument where something will happen
|
|
when the user clicks the left or center mouse button. Actions are
|
|
always tied to properties: they can toggle a boolean property, adjust
|
|
the value of a numeric property, or swap the values of two properties.
|
|
The x/y placement for actions specifies the origin of the lower left corner.
|
|
In the following example the first action sets up a hotspot 32 pixels wide
|
|
and 16 pixels high. It lower left corner is placed 96 pixels (relative to the
|
|
defined base size of the instrument) to the right of the center of the
|
|
instrument. It is also 32 pixels below the centerline of the instrument.
|
|
The actual knob texture over which the action is superimposed is 32x32.
|
|
Omitted here is a second action, bound to the same property, with a positive
|
|
increment value. This second action is placed to cover the other half of the
|
|
knob. The result is that clicking on the left half of the knob texture decreases
|
|
the value and clicking the right half increases the value. Also omitted here
|
|
is a second pair of actions with the same coordinates but a larger increment
|
|
value. This second pair is bound to a different mouse button. The net result
|
|
is that we have both fine and coarse adjustments in the same hotspot, each
|
|
bound to a different mouse button.
|
|
</p>
|
|
|
|
<p>
|
|
These examples come from the radio stack:
|
|
</p>
|
|
|
|
<pre>
|
|
<actions> <!-- open the actions section -->
|
|
<action> <!- first action -->
|
|
<name>small nav frequency decrease</name>
|
|
<type>adjust</type>
|
|
<button>0</button> <!-- bind it to a mouse button -->
|
|
<x>96</x> <!-- placement relative to instrument center -->
|
|
<y>-32</y>
|
|
<w>16</w> <!-- size of hotspot -->
|
|
<h>32</h>
|
|
<property>/radios/nav1/frequencies/standby-mhz</property> <!-- bind to a property -->
|
|
<increment>-0.05</increment> <!-- amount of adjustment per mouse click -->
|
|
<min>108.0</min> <!-- lower range -->
|
|
<max>117.95</max> <!-- upper range -->
|
|
<wrap>1</wrap> <!-- boolean value -- value wraps around when it hits bounds -->
|
|
</action>
|
|
<action>
|
|
<name>swap nav frequencies</name>
|
|
<type>swap</type> <!-- define type of action -->
|
|
<button>0</button>
|
|
<x>48</x>
|
|
<y>-32</y>
|
|
<w>32</w>
|
|
<h>32</h>
|
|
<property1>/radios/nav1/frequencies/selected-mhz</property1> <!-- properties to toggle between -->
|
|
<property2>/radios/nav1/frequencies/standby-mhz</property2>
|
|
</action>
|
|
<action>
|
|
<name>ident volume on/off</name>
|
|
<type>adjust</type>
|
|
<button>1</button>
|
|
<x>40</x>
|
|
<y>-24</y>
|
|
<w>16</w>
|
|
<h>16</h>
|
|
<property>/radios/nav1/ident</property> <!-- this property is for Morse code identification of nav beacons -->
|
|
<increment>1.0</increment> <!-- the increment equals the max value so this toggles on/off -->
|
|
<min>0</min>
|
|
<max>1</max>
|
|
<wrap>1</wrap> <!-- a shortcut to avoid having separate actions for on/off -->
|
|
</action>
|
|
</actions>
|
|
</pre>
|
|
<br>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="more_texture">More About Textures:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
As previously stated, the usual size instrument texture files in FGFS are 256x256
|
|
pixels, red/green/blue/alpha format. However the mechanism for specifying
|
|
texture cropping coordinates is decimal in nature. When calling a section
|
|
of a texture file the 0,0 lower left convention is used.
|
|
There is a pair of x/y coordinates defining which section of the texture
|
|
to use.
|
|
</p>
|
|
<p>
|
|
The following table can be used to calculate texture cropping specifications.
|
|
</p>
|
|
<pre>
|
|
# of divisions | width in pixels | decimal specification
|
|
per axis
|
|
1 = 256 pixels 1
|
|
2 = 128 pixels, 0.5
|
|
4 = 64 pixels, 0.25
|
|
8 = 32 pixels, 0.125
|
|
16 = 16 pixels, 0.0625
|
|
32 = 8 pixels, 0.03125
|
|
64 = 4 pixels, 0.015625
|
|
128 = 2 pixels, 0.0078125
|
|
256 = 1 pixel, 0.00390625
|
|
</pre>
|
|
<br>
|
|
|
|
<p>
|
|
The displayed size of a texture in pixels is set in the instrument
|
|
configuration file. The size of the cropped area in pixels is not
|
|
directly related to the final display size.
|
|
</p>
|
|
<p>
|
|
What that table represents is:
|
|
</p>
|
|
<p>
|
|
1 / (256 / # of pixels)
|
|
</p>
|
|
<p>
|
|
Take as an example, a section 64 pixels wide on the texture file.
|
|
256/64 = 4
|
|
1/4 = 0.25
|
|
</p>
|
|
<p>
|
|
Or lets consider 1 pixel wide
|
|
256/1 = 256
|
|
1/256 = 0.00390625
|
|
</p>
|
|
<p>
|
|
If the section starts at the extreme left of the texture, the
|
|
starting number is 0.0 and the end is 0.25
|
|
If the section *doesn't* start at the edge you need to take the starting
|
|
pixel and calculate an offset. Lets say you start 2 pixels from the
|
|
edge and you are cropping a section 64 pixels wide...
|
|
</p>
|
|
|
|
<pre>
|
|
256/2 = 128
|
|
1/128 = 0.0078125 <- this is the value for a 2 pixel wide offset
|
|
|
|
|
|
0.0078125 <- start at
|
|
0.25 <- add value for 64 px wide
|
|
0.2571825 <- end at
|
|
</pre>
|
|
<br>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="generating_textures">Generating Textures:</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
A common procedure for generating gauge faces is to use a
|
|
vector graphics package such as xfig, exporting the result as a
|
|
postscript file. 3D modeling tools may also be used and I prefer them
|
|
for pretty items such as levers, switches, bezels and so forth.
|
|
Ideally, the size of the item in the final render
|
|
should be of proportions that fit into the recommended pixel widths.
|
|
The resulting files can be imported into a graphics manipulation
|
|
package such as GIMP, et al for final processing.
|
|
</P>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="contribute">Contributing Panels And Instruments</A></H2>
|
|
<HR WIDTH="20%">
|
|
|
|
<p>
|
|
There are two main considerations when contributing panels and instruments.
|
|
Firstly, original artwork is a major plus since you as the creator can dictate the terms
|
|
of distribution. All Artwork must have a license compatible with the GPL.
|
|
Artwork of unverifiable origin is not acceptable.
|
|
Secondly, texture sizes must meet the lowest common denominator of 256e2 pixels.
|
|
Artwork from third parties may be acceptable if it meets these criteria.
|
|
</p>
|
|
|
|
<HR WIDTH="20%">
|
|
<H2><A NAME="units">UNITS:</A></H2>
|
|
<HR WIDTH="20%">
|
|
<p>
|
|
Here is a list of property names including appropriate units:
|
|
</p>
|
|
|
|
<PRE>
|
|
/autopilot/locks/nav1 => /autopilot/locks/nav[0]
|
|
/autopilot/settings/altitude += "-ft"
|
|
/autopilot/settings/climb-rate += "-fpm"
|
|
/autopilot/settings/heading-bug += "-deg"
|
|
/consumables/fuel/tank1/level => /consumables/fuel/tank[0]/level-gal_us
|
|
/consumables/fuel/tank2/level => /consumables/fuel/tank[1]/level-gal_us
|
|
/engines/engine0/cht => /engines/engine[0]/cht-degf
|
|
/engines/engine0/egt => /engines/engine[0]/egt-degf
|
|
/engines/engine0/fuel-flow => /engines/engine[0]/fuel-flow-gph
|
|
/engines/engine0/mp => /engines/engine[0]/mp-osi
|
|
/engines/engine0/rpm => /engines/engine[0]/rpm
|
|
/environment/clouds/altitude += "-ft"
|
|
/environment/magnetic-dip += "-deg"
|
|
/environment/magnetic-variation += "-deg"
|
|
/environment/visibility += "-m"
|
|
/environment/wind-down += "-fps"
|
|
/environment/wind-east += "-fps"
|
|
/environment/wind-north += "-fps"
|
|
/orientation/heading += "-deg"
|
|
/orientation/heading-magnetic += "-deg"
|
|
/orientation/pitch += "-deg"
|
|
/orientation/roll += "-deg"
|
|
/position/altitude += "-ft"
|
|
/position/altitude-agl += "-ft"
|
|
/position/latitude += "-deg"
|
|
/position/longitude += "-deg"
|
|
/radios/adf/frequencies/selected += "-khz"
|
|
/radios/adf/frequencies/standby += "-khz"
|
|
/radios/adf/rotation += "-deg"
|
|
/radios/nav1/* => /radios/nav[0]/*
|
|
/radios/nav2/* => /radios/nav[1]/*
|
|
/radios/nav[*]/dme/distance += "-nm"
|
|
/radios/nav[*]/frequencies/selected += "-mhz"
|
|
/radios/nav[*]/frequencies/standby += "-mhz"
|
|
/radios/nav[*]/radials/actual += "-deg"
|
|
/radios/nav[*]/radials/selected += "-deg"
|
|
/sim/model/h-rotation => /sim/model/heading-offset-deg
|
|
/sim/model/p-rotation => /sim/model/roll-offset-deg
|
|
/sim/model/r-rotation => /sim/model/pitch-offset-deg
|
|
/sim/model/x-offset += "-m"
|
|
/sim/model/y-offset += "-m"
|
|
/sim/model/z-offset += "-m"
|
|
/sim/view/goal-offset += "-deg"
|
|
/sim/view/offset += "-deg"
|
|
/steam/adf += "-deg"
|
|
/steam/airspeed += "-kt"
|
|
/steam/altitude += "-ft"
|
|
/steam/gyro-compass += "-deg"
|
|
/steam/gyro-compass-error += "-deg"
|
|
/steam/mag-compass += "-deg"
|
|
/steam/vertical-speed += "-fpm"
|
|
/velocities/airspeed += "-kt"
|
|
/velocities/side-slip += "-rad"
|
|
/velocities/speed-down += "-fps"
|
|
/velocities/speed-east += "-fps"
|
|
/velocities/speed-north += "-fps"
|
|
/velocities/uBody += "-fps"
|
|
/velocities/vBody += "-fps"
|
|
/velocities/wBody += "-fps"
|
|
/velocities/vertical-speed += "-fps"
|
|
</pre>
|
|
<br>
|
|
<p>
|
|
* If there are *any* XML parsing errors, the panel will fail to load,
|
|
so it's worth downloading a parser like Expat (http://www.jclark.com/xml/)
|
|
for checking your XML. FlightGear will print the location of errors, but
|
|
the messages are a little cryptic right now.
|
|
</P>
|
|
<p>
|
|
** NOTE: There is one built-in layer -- for the mag compass ribbon --
|
|
and all other layers are defined in the XML files. In the future,
|
|
there may also be built-in layers for special things like a
|
|
weather-radar display or a GPS (though the GPS could be handled with
|
|
text properties).
|
|
</p>
|
|
</BODY>
|
|
</HTML>
|