OBJ8 Specification

This is the OBJ8 File Format Specification, (c) 2005 Laminar Research, All Rights Reserved

Revision History 12/3/09    Added normal maps and parameterized lights for 940 6/16/09    Added new manipulators for 930b13 4/28/09    ATTR_light_level edited 4/06/09    Fixed Typos 2/04/09    Updated for X-Plane 930 9/25/08    Updated for X-Plane 920 12/26/07   Updated for X-Plane 9 4/05/07    Clarified use of custom lights 7/12/06    Revised for X-Plane 850 9/16/05    Initial Draft

The initial OBJ8 format was supported starting in X-Plane 816. X-Plane 850, 900, and 920 extended the format.

CHANGES FOR 940
The following features are available in X-Plane 940:
 * TEXTURE_NORMAL for attaching noraml and specular maps to an object.
 * LIGHT_PARAM for customized lights.

CHANGES FOR 930
The following features are available in X-Plane 930:
 * ATTR_light_level and ATTR_light_level_reset
 * ATR_draw_enable/disable
 * ATTR_solid_camera/no_solid_camera

CHANGES FOR 920
The following features are available in X-Plane 920 and later.
 * Manipulators

CHANGES FOR 900
The following features are available in X-Plane 9 and later.
 * Key Frames
 * Panel Regions
 * Deck-style hard surfaces

CHANGES FOR 850
The following features are available only in X-Plane 850 and later.
 * Custom and named lights.
 * Layer groups.
 * More control of blending and hard surfaces.
 * Show/hide animation commands

FILE TYPE AND COMPATIBILITY
X-Plane 8 and 9 object files (OBJ8) are text files that consist of records (one per line) describing a single 3-d model.

OBJ8 is not meant to be forward compatible; it is assumed that when the file format is extended, readers written to this specification will not be able to meaningfully display the future model file (which may depend on new features).

OBJ8 is meant to be backward compatible; it is assumed that readers of a future OBJ8 revision will continue to read current OBJ8 files.

COORDINATE SYSTEM AND GEOMETRY
OBJ8 models are specified in meters. In their native orientation, the positive Y axis points up, the positive X axis points east, and the positive Z axis points south. (This is a right-handed coordinate system.) The point 0,0,0 is a point on the ground where the object has been placed in x-plane scenery. The X-Plane scenery file referencing the object may rotate the object clockwise around the Y axis.

STATE PLUS COMMANDS
An X-Plane 8/9 model is specified via commands, which build the model in a certain order. There are four kinds of fundamental commands:
 * Geometry commands create geometry, to be drawn in the order they are created.
 * State commands affect how future geometry is drawn.
 * Action commands have an affect on the sim.
 * Animation commands change the shape of the subsequent geometry in real-time.

State has 'memory'. For example, all geometry is drawn with only the front visible, until you set the drawing state to "two-sided mode". At this point, all geometry is drawn with both sides visible until the drawing state is set to "one-sided" mode again.

State change is more than just a way to specify how to draw certain geometry; state change actually affects drawing performance in the simulator. The simulator must stop bulk-drawing geometry to change state, so minimizing the number of state commands will generally improve performance.

Because X-Plane does not reorder geometry commands it is up to the writer to maximize performance by minimizing state commands within the scope of the flexibility of geometry order. Generally speaking, the number of commands (not counting the various tables) is a good proxy for the efficiency of your object--fewer commands is more efficient.

TABLES
The geometry data (locations, texture coordinates, normals, etc.) for an OBJ8 model are stored in tables, separate from the command section. Table data may be shared in any order desired by the author.

There are three separate geometry tables for triangles, lines, and point lights. There is also a separate index table that provides index numbers into the geometry or line tables for lines and lights. This second level of indexing allows a contiguous range of indices to refer to a smaller set of shared points. A single triangle command then dispatches a contiguous index range. Lights are not indexed; the light command refers directly to consecutive light table points.

ATTRIBUTES
Attributes refer to properties global to the entire object. Right now the only attributes are the main and lit texture names.

OBJ7 NOTE: unlike OBJ8, night lighting is not automatically loaded by looking for a _LIT file. A light map must be specifically indicated.

LEVEL OF DETAIL
An OBJ8 model consists of one or more "level of detail". A level of detail can be thought of as a fully self-contained independent model within the object that shares all of the table data and attributes of the OBJ8 model. At any one time, only one LOD is ever drawn.

LODs are specified for ranges in meters (this range is the range of the viewer to the object). This allows you to change the appearance of an object to a simpler model when viewing from far away.

State is fully independent for LODs. In other words, if you set two-sided drawing in one LOD, the first triangle in the next LOD will be one-sided again automatically.

If you do not specify any LODs, the entire model is treated as a single LOD, whose range is calculated automatically by X-Plane.

ANIMATION
With OBJ8 it is possible to animate models. Animation is done by specifying transformations of ranges of geometry.

Animation is specified by pairs of begin/end animation commands. These commands may be nested to form hierarchical animations. Zero or more rotation and translation commands may be used in each nesting level.

Animation is driven by datarefs. A dataref is a flight simulator variable with a published well-known string name. 1100+ datarefs are defined by X-Plane and listed on the X-Plane SDK website; plug-ins can also create additional datarefs that can drive animation. Animation commands allow for a scaling of datarefs to convert easily from the native units of the sim to ranges that are useful for animation.

To calculate the extent of a translation or rotation, X-Plane finds a pair of key frames, or dataref/animation pairs, and then interpolates between the appropriate pair. Values that are not between any pairs are extrapolated from the nearest pair.

X-Plane 8 only allows for two key frames (a "start" and "end"). X-Plane 9 allows for two or more key frames.

MANIPULATION
A manipulation is an action taken by a user on an object that changes the state of X-Plane. By setting the manipulation state, you define what clicking on triangles within an object accomplishes. Manipulations interact with animations under certain conditions.

The current manipulation is changed via manipulator commands, which are a form of state command; any given triangle can only have one manipulation associated with it.

X-Plane 920 supports the following types of manipulations:
 * No Manipulation. If a mesh section is tagged as having no manipulation, it is not processed for click testing.  The mouse clicks go "through" those triangles. This is the fastest manipulation - all other manipulations consume per-CPU resources.
 * Panel Texture Manipulations. A click to the triangle causes a click to the 2-d or 3-d panel, with the texture coordinates "mapping" where the click takes effect.  Click locations are undefined if the panel texture is not in use.  (In practice, this manipulation is never available on a non-panel-textured triangle, due to the OBJ file syntax.)  The mapping correctly maps through both ATTR_cockpit and ATTR_cockpit_region.
 * XY Drag Manipulations. Two datarefs are changed based on the drag distance along the X and Y axis in screen space.  This is primarily provided for 2-d controls like yokes.
 * Axis Drag Manipulations. A dataref is changed based on a drag along an arbitrary object-space axis.  The axis is "locked" at the moment of click, so changes to the drag location (in object space) due to the pilot's head turning or due to animations do not affect the axis.  Effectively at the instant of click-down the axis is converted from 3-d to 2-d pixels on screen and left that way.  This provides a more predictable drag experience 			for users.
 * Command Manipulations. Clicking on the mesh section causes a command to be actuated while the mouse is down.
 * Command Axis Manipulations. Dragging along either dimension of an arbitrary object-space axis invokes one of two commands, depending on the drag direction.
 * No-Op Manipulations. No action is taken, but this manipulator "blocks" the click, so that no further mouse processing is done.  This makes triangles "solid" for mouse clicking.

X-Plane 930 adds the following "dataref" manipulators (that is, manipulators that change a dataref in response to a click):
 * Push button. The dataref is changed on click, and then on release.
 * Radio button. The dataref is changed on click by multiple manipulators.
 * Toggle button. The dataref is changed on click between two different values.
 * Delta. The dataref is changed slightly on click or hold, with limits on total range.
 * Wrap. The dataref is changed slightly on click or hold, and wraps around when out of range.

Manipulations are affected by the animation commands that surround them - that is, if an axis manipulation is inside a rotation, the axis will rotate based on the rotation.

Manipulations also take into account the animations on the triangles that are clicked. This includes all animations that affect the triangle. In other words, if you set a command manipulation, draw some triangles, then animate and draw more triangles, both groups of triangles are click-tested, and the click-test location will match the animation, even though the animation is after the beginning of the manipulation. (In other words, mouse click testing always matches drawing.)

OBJECT GEOMETRY TYPES
The fundamental geometry types for OBJ8 are:
 * Triangles. Triangles are textured and have a normal defined per vertex for lighting purposes.  The front of the triangle is the face where the vertices appear in clockwise sequence.
 * Lines. Lines have an RGB color.
 * Lights. Lights have a color and may flash.  Starting with X-Plane 850 more complex lights are also defined.

OBJ7 NOTE: RGB values in OBJ8 are always from the scale 0-1, even for lights and lines. This means the special light commands map to 9.9, 9.8, etc. instead of 99, 98.

MESH PLANES
Conceptually an object has four "planes" of information that a triangle can be part of:
 * Drawing plane - the user can see the triangle. All triangles normally are in the drawing plane.
 * Physics plane - the triangle causes collisions in the physics engine. Authors put a triangle in the physics plane with ATTR_hard, etc.
 * Manipulation plane - the triangle can be clicked with the mouse. Authors put a triangle in the manipulation plane with a manipulator or ATTR_cockpit.  Only triangles in the cockpit object can be in the manipulation plane.
 * Camera plane - triangles will impede the movement of the 3-d camera. Authors can put a triangle in the camera plane to constrain where the user can look in 3-d.  Only triangles in the cockpit object can be in the camera plane.

A triangle can be in no planes, or more than one plane. Attributes are used to control whether triangles go to each plane.

The choice of which plane a triangle is in is static. Planes are different from hide animations; a triangle hidden by a hide animation is hidden from everything - physics, drawing, clicking, and camera movement. Planes are provided to allow authors to use different geometry for camera constraint, clicking, physics and drawing.

Lines, lights, and smoke puffs do not ever go in the physics manipulation or camera planes. Therefore it does not make sense to include them in a non-drawn part of the OBJ file.

Some example uses might illustrate the motivation behind multiple planes:
 * A manipulatable triangle can be made non-drawable, allowing an author to place large, easy-to-click "hot-spots" in front of the mesh of a switch that might otherwise be hard to click due to its shape.
 * An author can make a separate mesh to constrain the camera that is not drawn--this separate mesh can be water-tight, much lower in triangle count, and be inset from the walls a bit to keep the camera from getting into strange places.

OBJECT STATE
OBJ8 defines and tracks the following object state:
 * Flat/Smooth shading (default is smooth). In flat shading, the entire triangle is drawn with the same brightness.  In smooth shading, the corners of the triangle have the shading levels appropriate for their normals, and the interior is interpolated. Note that since flat shading can be simulating via per-vertex normals, it is usually better to only use smooth shading.
 * One-sided vs. Two-sided geometry (default is one-sided). With one-sided geometry, a triangle is only drawn if the front of the triangle is visible to the user. With two-sided, both sides are drawn.
 * Panel vs. object texture (default is object). Normally triangles are textured via the texture (and light overlay) named in the TEXTURE and TEXTURE_LIT attributes. When panel texture is turned on, the plane's 2-d panel is used as a texture. OBJ7 NOTE: in OBJ7 a special quad_cock command was used to indicate the alternate texture.  In OBJ8 the texture change is managed via state. The lighting model for panel texturing may be "flat" (meaning no lighting calculations are provided) or "real" (meaning the full 3-d lighting system is used, matching the rest of the object); which lighting system is invoked depends on which attribute is used to select panel-texture drawing.
 * Depth testing on or off (default is on). Normally X-Plane uses "depth testing" to make sure that near objects always appear "on top of" far objects (in a 2-d sense).  With this state you can turn this test off.   WARNING: turning off depth testing is almost always the wrong thing to do and is not recommended. [New in 900:] Turning off depth testing is deprecated.
 * Polygon offset amount (default is 0). This is an amount to draw your geometry above the terrain, with zero being none and one being the minimum amount above the terrain that can be represented by the OpenGL hardware.  The object is not drawn differently in its position; this offset is only used to make the decision about whether your object appears "on top of" the terrain in a two-dimensional flat screen sense.
 * Blend off/on (default on). Normally an alpha pixel in the object texture that is neither fully opaque nor fully transparent is drawn as translucent with the background showing through.  However this can cause artifacts in some conditions.  When blending is turned off, all alpha values above 50% are treated as fully opaque and all alpha values below 50% are treated as fully transparent.   NOTE: even if a bitmap has only fully opaque or transparent pixels, some may be rendered translucent due to the effects of interpolation as a texture is resampled.
 * Polygon physical properties (default is none). Normally triangles in an OBJ8 model do not interact with the X-plane physics model; when this state is on, they do.  Doing physics calculations against triangles can be slow for large numbers of triangles, so do not simply turn this on for every object.   OBJ7 NOTE: in OBJ7 a special hard_quad was used to indicate a physics-interacting polygon.  In OBJ8 state is used for this purpose. [New in 850:] Starting with X-Plane 850 you can specify the type of physical surface for geometry.  Before 850, the choice was simply physical or not. [New in 900:] Starting with X-Plane 900 you can specify a hard surface to be a "deck", meaning the user can fly under it or land on top of it.  Before 900 only "solid" physical surfaces were available--flying under a solid physical surface counts as a collision.
 * Materials. You can change the balance of color contributions from the lighting model for your geometry.  Those parameters are:
 * Diffuse (RGB) - the brightness of the geometry due to the sun.
 * Emissive (RGB) - the brightness of the geometry due to it radiating light.
 * Shininess (RGB) - the sharpness of specular highlights (0-1).
 * The relationship between these colors and OpenGL: the diffuse color sets the diffuse and ambient OpenGL colors. The emissive color maps to the emissive OpenGL color.  The shininess ratio sets all three components of the specular hilight color with a specular exponent of 0.5.   The defaults are full diffuse, no shininess and emissive, but use ATTR_reset to restore the default 		lighting properties for X-Plane.
 * [New in 920:] The current manipulation.
 * [New in 930:] Enable/disable state for the drawing and camera planes.

TEXTURE APPLICATION
X-Plane's lighting/texturing model consists of separate albedo and emissive inputs. An X-Plane object can reference three textures:
 * The "daytime" (albedo) texture for the object, specified via the TEXTURE command. This command is mandatory - if the texture name is blank, a gray proxy texture is used.
 * The "_LIT" (emissive) texture for the object, specified via the TEXTURE_LIT command. This command is optional.
 * A normal map, specified by TEXTURE_NORMAL. The normal map is optional, and is ignored unless the user has enabled per-pixel lighting.

Normally these three textures are used to texture triangles. When ATTR_cockpit_region is used, the panel, the panel replaces the albedo and emissive textures, and normal mapping is disabled.

When ATTR_cockpit is used, the panel replaces the albedo texture, and 3-d lighting is disabled.

For more information on Normal Map format and application, see: Normal Maps.

IMPORTANT: the shininess level in the normal map alpha channel is modulated by the input to ATTR_shiny_rat, which defaults to 0.0. Thus you must use ATTR_shiny_rat to see the effects of the alpha channel in a normal map.

OBJECT ATTRIBUTES
Objects currently have four attributes: the texture name, the lit texture name, a weight if the object is use as a slung load, and panel regions. File names are interpreted relative to the object file itself, and must include an extension. X-Plane will search for bitmap formats with alternate extensions, e.g. if you specify TEXTURE foo.png but only foo.dds is available, foo.dds will be loaded. See COCKPIT FEATURES below.

COCKPIT FEATURES
The OBJ format is used to model objects that are part of airplanes, part of the cockpit environment, and part of the scenery system. Some features are only appropriate to the cockpit.

Cockpit features can only be used in objects that are attached to the object as the "cockpit object"--this object undergoes special processing. Other attached airplane objects and scenery objects cannot use these features.

Changing the object texture to the "panel" texture does two things: it changes the texture used to draw from the OBJ's texture (specified with the TEXTURE command) to the 2-d panel. The 2-d panel is used in its full size, even if it is not a power of 2. (Note: non-power-of-2 panels cause processing inefficiency.) The transparent windows of the 2-d panel are transparent when it is used as a texture. Also, it changes the current manipulation so that clicks on a part of the 3-d cockpit object have the effect is the same as clicking in the same location mapped to the 2-d panel.

[New in 900:] Instead of using the entire cockpit panel as a texture (using ATTR_cockpit), an object can establish up to four cockpit "regions". These are textures defined by a sub-rectangle within the 2-d cockpit. Cockpit regions differ from using the full cockpit as follows:
 * Cockpit regions must be a power of 2 in width and height.
 * There can be up to four cockpit regions.
 * Cockpit regions are not transparent--if the 2-d panel is transparent, the cockpit region texture in that area is undefined.

Cockpit regions are recommended for efficiency reasons: between the use of transparency, non-power-of-2 panels, and the huge amount of a 2-d panel that is not useful for rendering, the 2-d panel ends up using a lot more VRAM and building a lot more texture area dynamically than necessary. By simply using a few smaller cockpit regions over key parts of the 2-d panel, greater frame rate can be achieved.

OBJECT SYNTAX
OBJ8 files are ASCII text files; the legal character set is the set of printable 7-bit ASCII files.

Lines are defined by newline character sequences, which are one of:
 * Macintosh: a single CR (13)
 * Unix: a single LF (10)
 * DOS: a CR followed by an LF

Any one choice of newline sequences may be used consistently throughout the file.

One or more Tabs (8) and/or spaces (32) are treated as white space.

A sequence of legal characters that does not contain any newlines may be referred to as a line, and a sequence of legal characters that does not contain any newlines or whitespace may be referred to as a word.

Word and keyword identification is case-sensitive. Numbers are represented by an optional minus sign, one or more digits, optionally followed by a period and one or more digits. All numbers in objects may be floating point.

The object file consists of a 3-line header followed by a series of records, each of which is one line. A record's type is identified by the first word of the record. Blank lines are legal after the header, and records starting with a # are treated as blank lines, allowing for comments.

The header lines consist of:
 * Line 1: either the characters A or I - it is recommended that A be used for Macintosh line ending files and I for Unix or DOS line ending files.
 * Line 2: the file version number (currently 800) followed by optional whitespace and additional comment characters.
 * Line 3: the word OBJ.

Each single-line record is identified by its first word; see the command listing	below for precise record descriptions. Coordinates are specified as a triplet of numbers representing XYZ Cartesian coordinates in meters.

Normals are specified as a triplet of fractions forming a 3-space vector whose length is 1. The vector is interpretted in the same coordinate space as the geometry.

Texture coordinates are specified as a pair of fractions from 0-1. The first one represents a ratio from the left to the right side of the texture, the second from the bottom to the top.

Colors are represented as fractions from 0-1 representing minimum to full color intensity. Colors are usually RGB triplets.

OBJECT SEMANTICS
Records fall into three catagories: attributes, data, and commands. The order of the file must feature all attributes first, then all data, then all commands. Attribute records can be in any order. Data record types can be in any order, but ordering within a type of data record defines the indexing interpretation. Commands are executed in the order of the records in the file.

An OBJ8 may either feature or not feature LOD. A file that does not feature LOD may not have the ATTR_LOD command. A file that does feature LOD must have an	ATTR_LOD command as the first command record, and also follow the LOD ordering rules. These rules are:
 * LODs must be presented in order from nearest to farthest.
 * The far distance of one record must be the near distance of the next. No overlaps or gaps are allowed.
 * The first LOD must start at zero.
 * No LOD record may have the near and far distance be equal.

There is no requirement for an object to reset state to its initial setting at the end of an LOD; the simulator takes care of this.

Command records are not reordered by the sim at all. This makes translucency tricks possible.

All animation commands must be within an ANIM_begin / ANIM_end pair.

All ANIM_begin/ANIM_end pairs must be properly balanced within each LOD.

Animation commands (ANIM__rotate and ANIM_translate) must occur immediately after ANIM_begin. However any number of animation commands may be used consecutively after a single ANIM_begin.

The POINT_COUNTS and TEXTURE attributes are required.

Hard polygons are not allowed in any LOD except for the first one.

Cockpit features (panel texture/panel regions, manipulation, camera plane enable) can only be used in objects that are attached to an airplane via the COCKPIT_INN.obj or COCKPIT_OUT.obj mechanism.

[New in 900:] Key frame tables must be listed from lowest to highest key frame dataref value.

This is not required, but it is recommended: if your object has lights and multiple LODs, use the exact same lights in each LOD. X-Plane's OBJ engine does special processing on lights to both increase the distance at which they are visible and improve framerate. If the lights specified in each LOD are different, you may either get incorrect drawing, or lower framerate. The fastest code path is to let X-Plane do the same lights at every LOD.

TEXTURE &lt;tex_file_name&gt;
This defines the texture to be used with this object. Use this record with only white space to indicate that the object has no texture requirement.

TEXTURE_LIT &lt;tex_file_name&gt;
This defines the lighting overlay. Omit this record if you do not require a lighting overlay.

TEXTURE_NORMAL &lt;tex_file_name&gt;
[New in 940:]This defines an additional texture to be used as a specular + normal map. See "texture application" above	for the formats of texture and normal maps.

POINT_COUNTS &lt;tris&gt; &lt;lines&gt; &lt;lites&gt; &lt;indices&gt;
This defines the size of the data tables. Four integer numbers define the number of entries in each table.

slung_load_weight &lt;mass weight in pounds&gt;
This defines the weight of the object, for use in the physics engine if the object is being carried by a plane or helicopter.

COCKPIT_REGION &lt;left&rt; &lt;bottom&rt; &lt;right&rt; &lt;top&rt;
[New in 900:]This defines a cocpit region - the rectangle of the region is in pixels where 0,0 is the lower left of the 2-d cockpit panel. The cockpit region can have any position as long as (1) its width and height are powers of (2) it does not go off the edge of the 2-d panel. Panel regions are referred to by index numbers: the first COCKPIT_REGION is number 0. There can be up to four cockpit regions in an object.

VT &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;nx&gt; &lt;ny&gt; &lt;nz&gt; &lt;s&gt; &lt;t&gt;
This defines a single entry in the triangle vertex table. These are indexed starting from zero based on the record order. The eight numbers represent a triplet coordinate location, a triplet normal, and a pair forming a texture coordinate. This table is only used for triangles.

VLINE &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;r&gt; &lt;g&gt; &lt;b&gt;
This defines a single entry in the line vertex table, a triplet coordinate location and a triplet color value (RGB, from 0-1). This table is only used for line primitives.

VLIGHT &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;r&gt; &lt;g&gt; &lt;b&gt;
This defines a single entry in the light vertex table. Again we have a coordinate triplet and RGB triplet. Colors are 0-1 with some special rules:
 * If any value is negative, the light is considered to be flashing.
 * If the triplet value is all 9.9, it is a pulsing red light.
 * If the triplet value is all 9.8, it is a strobe light.
 * If the triplet value is all 9.7, it is a traffic-light.

WARNING: the specialized light values based on the 9.x series may not be supported precisely in future OBJ specs, and are not recommended. They are provided for compatibility.

IDX10 &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt; &lt;n&gt;
This defines one or ten entries in the index table. The index table is used to refer to vertices in the triangle or line vertex tables. Indices are zero based, and numbers are zero based into the vertex tables. In other words, an index whose value is "4" can refer to the 4th index in either the line or the triangle table, depending on the command using these indices. IDX10 is provided to pack 10 indices onto one line.

TRIS &lt;offset&gt; &lt;count&gt;
This command draws count/3 triangles based on the vertices referenced by the indices starting at 'offset' in the index table and running consecutively upward. (In otherwords, the indices must be adjacent, but they can refer to non-adjacent vertices). Count must be a multiple of 3. Vertices come from the triangle table.

LINES &lt;offset&gt; &lt;count&gt;
This command draws count/2 line segments based on the vertices referenced by the indices starting at 'offset' in the index table and running consecutively upward. Vertices come from the line table. Count must be a multiple of 2.

LIGHTS &lt;offset&gt; &lt;count&gt;
This command draws 'count' point lights whose positions are stored consecutively starting at 'offset' in the light table. Unlike the LINES and TRIS command, this command does not utilize the index table. This means that while triangles and lines can issue the same vertex multiple times in a single command, the lights command cannot repeat a light vertex multiple times without multiple light commands.

NOTE: the ability to share vertices efficiently is important for triangles and lines which may be parts of meshes, but is not useful for lights.

LIGHT_NAMED &lt;name&gt; &lt;x&gt; &lt;y&gt; &lt;z&gt;
[New in 850:] Named lights allow a light to be created based on pre-existing types. The X Y Z parameters specify the light location.

Note: the list of available lights will be published in the future.

LIGHT_CUSTOM &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;r&gt; &lt;g&gt; &lt;b&gt; &lt;a&gt; &lt;s&gt; &lt;s1&gt; &lt;t1&gt; &lt;s2&gt; &lt;t2&gt; &lt;dataref&gt;
[New in 850:] A custom light allows an object to contain a light with almost any properties. Here are a few differences between custom lights and traditional object lights:
 * Custom lights are always textured. The RGB color is a tinting of this texture.
 * Custom lights get their texture from the object texture - you must draw some kind of light halo into the object.

A custom light has nine parameters (besides location). Each time the light is drawn, the parameters from the OBJ file are run through a dataref, which may modify or replace some or all of the parameters. How the dataref interacts with the parameters depends on the light--for example, some simply replace all parameters, some modify only one parameter, and some use the parameters as hints for their operation. See the plug-in SDK dataref docs for specific dataref info - X-Plane ships with several datarefs that are useful for custom lights, and plug-in authors can add more.

If the dataref is not found (or if "NULL" is passed as a dataref name) then the 9 parameters are drawn unmodified. In this way a custom light gives you complete control over the drawing of lights even without plug-ins.

The parameters are:
 * RGBA - the color of the light (a tint that is applied to the texture) and alpha level, which makes the light dimmer. An alpha of 0.0 means the light will not be drawn.
 * s - the size of the light - this is not in a particular unit (like meters), but larger numbers produce bigger brighter lights.
 * s1,t1,s2,t2 - the texture coordinates (fractions from 0 to 1). S refers to horizontal coordinates, and T for vertical coordinates.

LIGHT_PARAM &lt;name&gt; &lt;x&gt; &lt;y&gt; &lt;z&gt; [<&ltadditional params&gt;]
[New in 940:] A parameterized light is like a named light, except that some of the attributes of the light can be numerically modified. X, Y, and Z define the position of the light. The name selects a pre-defined light. The additional parameters vary in number and definition based on the particular parameterized light selected.

smoke_white &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;s&gt;
These commands cause the object to periodically emit a puff of block or white smoke from the location specified by x,y,z. S is a size number indicating the relative intensity of the smoke.

TODO: what is the units of the smoke puff size parameter?

ATTR_LOD &lt;near&gt; &lt;far&gt;
LOD indicates the beginning of a new LOD, which should be used to represent the object when the viewer is between near (inclusive) and far (exclusive) meters.

ATTR_shiny_rat &lt;ratio&gt;
These commands change the material state for geometry based on the OpenGL lighting model.

ATTR_reset
This command resets the material state to its default.

ATTR_poly_os &lt;n&gt;
This command sets the polygon offset state to N, a non-negative integer.

ATTR_layer_group &lt;name&gt; &lt;offset&gt;
[New in 850:] X-Plane draws scenery in "layer groups" - all elements in the same layer group are drawn before all other groups, but within a layer group the drawing order may be optimized by X-Plane. Normally layer groups are determined by X-Plane based on the type of drawing. Objects have always had their own layer group.

When the ATTR_layer_group is included somewhere in an object (it need only be used once, even if you have multiple LODs) then the object is drawn in a different layer group. The offset is used to prioritize further--for example. the group + 1 is drawn after the group, and the group - 2 is drawn two layers before objects. You can use an offset from -5 to + 5.

The valid layer names are: terrain, beaches, shoulders, taxiways, runways, markings, airports, roads, objects, light_objects, cars Note: the group "airports" covers all airport drawing. Within this group are the sub-groups shoulders, taxiways, runways, and markings. Markings are for taxilines and thus are on top of all other layers.

ATTR_cockpit
ATTR_cockpit sets the current texture to the panel texture and the current manipulator to the panel-click manipulator.

The panel texture uses "flat" lighting (materials and lights are ignored, color matches the 2-d or 3-d panel) when it is invoked using this attribute.

ATTR_no_cockpit
ATTR_no_cockpit sets the current texture to the object texture and the current manipulator to none.

ATTR_cockpit_region &lt;region number&gt;
[New in 900:] The ATTR_cockpit_region attribute changes the texture of the object to a specific region of the cockpit texture. Use ATTR_no_cockpit when done. The current manipulation is set to panel clicking.

The panel texture uses "real" lighting (materials and lights are utilized, color matches the object texture) when it is invoked using this attribute.

The rest of the state commands affect the above published state.

ATTR_light_level &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt;
[New in 930:] ATTR_light_level changes the brightness of the _LIT texture for the object. The dataref is interpreted as a value between v1 and v2. Values outside v1 and v2 are clamped. This attribute overrides the sim's decision about object lighting.

ATTR_light_level_reset
[New in 930:] ATTR_light_level_reset resets the _LIT texture to the default brightness. (This brightness is typically full at night or none during the day.           Command                 State                   New Value            ATTR_hard               Hard Polygon            On            ATTR_no_hard            Hard Polygon            Non-Off*            ATTR_shade_flat         Shading                 Flat            ATTR_shade_smooth       Shading                 Smooth*            ATTR_no_depth           Depth Check             Off            ATTR_depth              Depth Check             On*            ATTR_no_cull            Two-Sided Geometry      Two-sided            ATTR_cull               Two-Sided Geometry      One-sided*            ATTR_no_blend           Blending                Off            ATTR_blend              Blending                On*            [new in 930]            ATTR_solid_camera       Camera plane            Enable            ATTR_no_solid_camera    Camera plane            Disable* ATTR_draw_enable       Draw plane              Enable* ATTR_draw_disable      Draw plane              Disable * This is the default [New in 850:] Starting in X-Plane 8.50 ATTR_no_blend can take an optional decimal ratio (between 0.0 and 1.0) that specifies the cutoff for the alpha channel. Alpha levels below this level are rendered as fully transparent and alpha levels above this level are fully opaque. If this fraction is not specified, no_blend uses a default cutoff ratio of 0.5.

[New in 850:] Starting in X-Plane 8.50 ATTR_hard can be followed by an additional surface name. This surface name controls the bumpiness of the hard polygon, allowing an object to emulate some of the natural X-Plane surfaces, like grass and rocks. If no surface type is specified then a smooth surface is used.

The valid recognized surface names are: water, concrete, asphalt, grass, dirt, gravel, lakebed, snow, shoulder, blastpad

[New in 900:] Starting in X-Plane 9, ATTR_hard_deck can be used instead of ATTR_hard. It sets a hard surface, but allows the user to fly under the surface.

ANIM_begin
This command marks the beginning of an animation subsection. All further geometry commands are affected by the animation commands between this ANIM_begin and the command until an ANIM_end is encountered.

ANIM_end
This defines the end of an animation section. Geometry following this is not affected by the animation commands.

ANIM_rotate &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;r1&gt; &lt;r2&gt; &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt;
This defines a rotation command. X, Y and Z define an axis of rotation - they should form a unit-length vector. r1 and r2 represent the angle of counterclockwise rotation when the dataref is at its minimum and maximum values respectively, when looking down at the 'arrow' of the vector. (So if the vector is 0,1,0 then a positive rotation is counterclockwise when viewed from above.). v1 and v2 are the minimum and maximum dataref values for calibration purposes. Dataref is the string name of a sim dataref.

ANIM_trans &lt;x1&gt; &lt;y1&gt; &lt;z1&gt; &lt;x2&gt; &lt;y2&gt; &lt;z2&gt; &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt;
This defines a translation command. x,y,z 1 and 2 are two offset distances, for when the dataref is at its minimum and maximum values; v1 and v2 are the expected min and max for the dataref and dataref is the string name of the dataref.

ANIM_hide &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt;
[New in 850:] If the dataref's value is within the two values (inclusively) then drawing is suspended. Drawing is resumed when a show command restarts drawing or when the animation group (defined by ANIM_begin/ANIM_end ends).

Note: hiding animation suspends all triangle/polygon, line and light drawing but does not stop the processing of attributes. State will change even after a hide commands. Thus the state of any given part of the object does not depend on animation commands.

ANIM_show &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt;
[New in 850:] If the dataref's value is within the two values (inclusively) then drawing is resumed. This has no effect unless drawing was previously suspended.

Shows and hides are not counted, e.g. if you hide twice and show once, drawing is resumed.

ANIM_rotate_begin &lt;x&gt; &lt;y&gt; &lt;z&gt; &lt;dataref&gt;
[New in 900:] This begins an ANIM_rotate command, but with a key frame table to follow. XYZ is the axis of rotation.

ANIM_rotate_key &lt;value&gt; &lt;angle&gt;
New in 900:] This adds a key frame to a rotation animation. The value represents a possible dataref value--the angle is the corresponding rotation.

ANIM_rotate_end
[New in 900:] This ends a rotation animation with key frames. It is required after the key frames and must be used to balance every ANIM_rotate_begin.

ANIM_trans_begin &lt;dataref&gt;
[New in 900:] This begins an ANIM_trans command but with a key frame table that follows. The dataref is specified, but the actual translates are per-keyframe.

ANIM_trans_key &lt;value&gt; &lt;x&gt; &lt;y&gt; &lt;z&gt;
[New in 900:] This adds a key frame to a translation animation. For the given value, three distances, in X, Y and Z are provided - these are distances to translate the contained geometry.

ANIM_trans_end
[New in 900:] This ends a key-framed translation animation and must be used to balance any ANIM_trans_begin commands.

ANIM_keyframe_loop &lt;loop&gt;
[New in 900:] Normally the dataref value for an animation is looke up in the key frame table and an animation is intepretted or extrapolated. If the ANIM_keyframe_loop command is present, the corresponding animation (the animation defined right before the ANIM_keyframe_loop command) will have its dataref divided by the loop amount and the remainder is used. This makes it possible to change an ever-increasing dataref into a looping dataref.

MANIPULATION COMMANDS
All manipulations except for ATTR_manip_none take a cursor manipulation (defining which cursor to show while the user's mouse is over the mesh) and a tool tip (shown if the user has help-tips enabled and the cursor hovers over the mesh). The help tip string can be any string without newlines; the cursor enumeration is one of the following names:

four_arrows hand button rotate_small rotate_small_left rotate_small_right rotate_medium rotate_medium_left rotate_medium_right rotate_large rotate_large_left rotate_large_right up_down down up left_right right left arrow

ATTR_manip_none
[New in 920:] This sets the current manipulation to no manipulation - clicks to the geometry will track through to any mesh behind this one.

Note: click-testing the mesh burns CPU on a per-triangle basis; click-testing very complex meshes can be quite slow. By putting an ATTR_manip_none attribute after ATTR_cockpit but before TRIS, you can create triangles that use the cockpit texture but do not have the associated cockpit manipulator. For geometry that does not need click testing (e.g. an EFIS screen with no buttons) this can reduce the number of click-tested triangles and improve through-put.

ATTR_manip_drag_xy &lt;cursor&gt; &lt;dx&gt; &lt;dy&gt; &lt;v1min&gt; &lt;v1max&gt; &lt;v2min&gt; &lt;v2max&gt; &lt;dref1&gt; &lt;dref2&gt; &lt;tooltip&gt;
[New in 920:] This sets the current manipulation to an X-Y axis manpulation. The parameters v1min and v1max define the minimum and maximum values to be written to the first dataref as the mouse is dragged along the X axis. The parameters v2min and v2max define the minimum and maximum values to be written to the second dataref as the mouse is dragged along the Y axis. Two dataref names and a tool tip follow.

When an axis drag begins, the position of the axis on screen is based on the current dataref value. For example, if the X dataref has minimum and maximum values of 0 and 4 and is currently set to 1, then when the click starts, 25% of the axis will be to the left of the current mouse position and 75% will be to the right. If the dx axis length is 200 then the user can drag 50 pixels to the left and 150 pixels to the right to manipulate the dataref.

ATTR_manip_drag_axis &lt;cursor&gt; &lt;dx&gt; &lt;dy&gt; &lt;dz&gt; &lt;v1&gt; &lt;v2&gt; &lt;dataref&gt; &lt;tooltip&gt;
[New in 920:] This sets the current manipulation to an axis in 3-d space. dx, dy, and dz describe an axis (the length is in meters). v1 and v2 define the range that the dataref can take. Like the above xy drag, the axis' relative position is determined by the current dataref value. The axix's orientation is affected by animations, but is "frozen" on mouse-down.

ATTR_manip_command &lt;cursor&gt; &lt;command&gt; &lt;tooltip&gt;
[New in 920:] This sets the current manpiulation to a comand, specified by the command parameter. The command will be actuated while the mouse is held down over the mesh.

ATTR_manip_command_axis &lt;cursor&gt; &lt;dx&gt; &lt;dy&gt; &lt;dz&gt; &lt;positive command&gt; &lt;negative command&gt; &lt;tooltip&gt;
[New in 920:] This sets the current manipulation to an axis drag where dragging in the direction of the vector invokes the positive command and dragging in the negative direction invokes the negative command. The command is invoked until the mouse is released or returns to the neutral or opposite position. Axis definition is the same as in ATTR_manip_drag_axis.

ATTR_manip_noop
[New in 920:] This sets the current manipulation to "no-op" (no operation). Unlike "none", the mouse click is "swallowed" by the triangles and will not actuate clicks on a mesh behind the no-op mesh.

ATTR_manip_push &lt;cursor&gt; &lt;v_down&gt; &lt;v_up&gt; &lt;dref&gt; &lt;tooltip&gt;
[New in 930:] This sets the current manipulation to be a "push" button. When the mouse is clicked, this manipulator sets the dataref to the "down" value; when the mouse is released, the dataref is reset to the "up" value. The intention is to model push buttons.

ATTR_manip_radio &lt;cursor&gt; &lt;v_down&gt; &lt;dref&gt; &lt;tooltip&gt;
[New in 930:] This sets the current manipulator to be a "radio" button. Whe nthe mouse is clicked, the dataref is set to the down value. By setting different meshes to have radio manipulators with the same dataref but different values, you can create radio-button-like behavior.

ATTR_manip_toggle &lt;cursor&gt; &lt;v_on&gt; &lt;v_off&gt; &lt;dref&gt; &lt;tooltip&gt;
[New in 930:] This sets the current manipulator to a "toggle" dataref. When the mouse is clicked down, if the dataref is already at the "on" value, it is set to the "off" value - otherwise it is set to the "on" value. This can be used to make toggle switches like a gear handle.

ATTR_manip_delta &lt;cursor&gt; &lt;v_down&gt; &lt;v_hold&gt; &lt;v_min&gt; &lt;v_max&gt; &lt;dref&gt; &lt;tooltip&gt;
[New in 930:] This sets the current manipulator to a "delta" manipulator. When the mouse is first clicked, the dataref is incremented by the "down" value. if the mouse is held it is further incremented by the "hold" value (for every seocnd the mouse is held down). The dataref will be clamped between the minimum and maximum value. To decrement, use negative values.

The intention of the delta manipulator is to build multiple "hot spots" with invisible meshes, one to increment, one to decrement.

ATTR_manip_wrap &lt;cursor&gt; &lt;v_down&gt; &lt;v_hold&gt; &lt;v_min&gt; &lt;v_max&gt; &lt;dref&gt; &lt;tooltip&gt;
[New in 930:] This sets the manipulator to the "wrap" manipulator. The wrap manipulator functions the same as the delta manipulator, except if the dataref exceeds the range min to max, the dataref will wrap around to the other side of the range. This can be use for a control like an OBS knob.